{"version":3,"file":"js/application.js","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;;;;;;;;;;ACvDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACzMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACrGA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACzRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3CA;AAIA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAMA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAKA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAEA;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;AAEA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxEA;AAEA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;AAIA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA;AAYA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AAMA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7DA;AAIA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzBA;AAQA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AASA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtDA;AAaA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrDA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAIA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AAQA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1DA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AAUA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChFA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpDA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACfA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AAGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AAKA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AAIA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;;AAEA;AACA;AACA;AACA;;AAEA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAPA;AASA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAWA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrJA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtHA;AAEA;AAAA;AAsHA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChJA;AACA;AAGA;AACA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AAAA;AAxBA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AACA;AAKA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlBA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAzCA;AAAA;AAAA;AAAA;AA2CA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/JA;AAMA;AAAA;AANA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AARA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AAGA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAhBA;AAAA;AAAA;AAAA;AAkBA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnCA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1BA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAGA;AACA;AACA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AACA;AACA;AAEA;AAAA;AAYA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAIA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAIA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApLA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3BA;AAEA;AACA;AACA;AAOA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArFA;AAMA;AAAA;AAiFA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3IA;AAGA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAfA;AAAA;AAAA;AAAA;AAiBA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlCA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;AACA;AACA;AAKA;AACA;AACA;AACA;AAAA;AAcA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArBA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAEA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhBA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AAEA;AACA;AACA;AACA;AAAA;AAaA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAwBA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AAxDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AANA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChDA;AAEA;AAAA;AA0BA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA9EA;AAgFA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/GA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAIA;AAJA;AAAA;AAAA;AAAA;AAuBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhCA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AA9BA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAdA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnBA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AANA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AACA;AAEA;AACA;AAAA;AAiBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnCA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvBA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;;AAAA;AARA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAPA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AAGA;AACA;AACA;AAFA;AAGA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAXA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAsBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;;AAEA;AAAA;AAvFA;AAgBA;AAAA;AAwEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7HA;AAoBA;AACA;AACA;AAEA;AAEA;AAEA;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;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5EA;AAEA;AACA;AAEA;AAAA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;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;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAGA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAIA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAGA;AAAA;AAjRA;AAoBA;AAAA;AApBA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AACA;AACA;AACA;AACA;AAEA;AAGA;AAAA;AAeA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAvEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5BA;AAEA;AACA;AACA;AAGA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvBA;AAGA;AAAA;AAsBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9CA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAcA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArHA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AACA;AACA;AAEA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AALA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAPA;AAAA;AAAA;AAAA;AASA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAPA;AAAA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtMA;AAGA;AAAA;AAqMA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnPA;AAEA;AACA;AACA;AACA;AAGA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1FA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1EA;AACA;AAAA;AA2EA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5GA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAPA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlDA;AACA;AAAA;AAmDA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9EA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AAEA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAGA;AAGA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAGA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AACA;AAtBA;AAAA;AAAA;AAAA;AA2BA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AA7IA;AAWA;AAAA;AAoIA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpLA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAzBA;AACA;AAAA;AA0BA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjDA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AACA;AATA;AAAA;AAAA;AAAA;AAYA;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtGA;AACA;AAAA;AAuGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrIA;AAEA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3DA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AAjEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvCA;AACA;AAEA;AAEA;AAEA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAGA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAIA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhHA;AACA;AAAA;AAiHA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9IA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAGA;AAGA;AAGA;AAGA;AACA;AAEA;AACA;AACA;AAGA;AACA;AAEA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAhBA;AAAA;AAAA;AAAA;AAmBA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlUA;AAKA;AAAA;AA+TA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvXA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAvBA;AAyBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnDA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/CA;AAEA;AAAA;AA+CA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrFA;AAEA;AAEA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA9CA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AACA;AAGA;AAAA;AAAA;AAaA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7DA;AA+DA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnFA;AAGA;AAGA;AACA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApFA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AAKA;AAGA;AACA;AAEA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlFA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAEA;AACA;AAIA;AAGA;AACA;AACA;AAEA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAIA;AAIA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AAIA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtGA;AACA;AAAA;AAuGA;AACA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxIA;AAGA;AAIA;AAAA;AAoBA;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;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AAKA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;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;AAAA;AAAA;AAAA;AAGA;AAAA;AA/EA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA;AACA;AACA;AAKA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AARA;AAAA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvCA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;AACA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAZA;AAAA;AAAA;AAAA;AAcA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA5EA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAwBA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;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;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AAQA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7GA;AACA;AAAA;AA8GA;AACA;AACA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxJA;AACA;AAEA;AAEA;AACA;AAAA;AAgBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhDA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzBA;AACA;AACA;AACA;AAKA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlDA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArCA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AAEA;AACA;AAAA;AAiBA;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;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AARA;AAAA;AAAA;AAAA;AAWA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxCA;AAIA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA5FA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAGA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/EA;AAQA;AAAA;AAyEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzHA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAKA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1EA;AAIA;AAAA;AAwEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpHA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAIA;AAUA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlLA;AASA;AAAA;AA2KA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjOA;AAGA;AACA;AACA;AAAA;AAeA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA9DA;AACA;AAAA;AA+DA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChGA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAhBA;AAAA;AAAA;AAAA;AAmBA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnHA;AACA;AAAA;AAoHA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjJA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7CA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAGA;;AAEA;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;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA5CA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7JA;AAGA;AAAA;AA4JA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7MA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAvBA;AAyBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AA9EA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAgBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAHA;AAAA;;AAKA;AACA;AACA;AAGA;AAGA;;AAEA;AACA;AACA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AATA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3DA;AA6DA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAGA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhDA;AAEA;AAAA;AAgDA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtFA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnBA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACfA;AACA;AACA;AAGA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7DA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAkBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAGA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAtJA;AACA;AAAA;AAuJA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrMA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtCA;AAEA;AAAA;AAsCA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChEA;AAEA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;;AAEA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAdA;AACA;AAAA;AAeA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtCA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAIA;AAAA;AAlCA;AACA;AAAA;AAmCA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7DA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAGA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3BA;AACA;AAAA;AA4BA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzDA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAMA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAnFA;AACA;AAAA;AAoFA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5GA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAMA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAGA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAJA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AA7DA;AA+DA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtFA;AAKA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAcA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAHA;AAAA;AAAA;AAAA;AAMA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAHA;AAAA;AAAA;AAAA;AAMA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAHA;AAAA;AAAA;AAAA;AAMA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAHA;AAAA;AAAA;AAAA;AAMA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAHA;AAAA;AAAA;AAAA;AAMA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAHA;AAAA;AAAA;AAAA;AAMA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AACA;AAEA;AAEA;AACA;AAAA;AAQA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApXA;AACA;AAAA;AAqXA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxZA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAHA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3DA;AACA;AAAA;AA4DA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzFA;AAEA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAUA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAzEA;AACA;AAAA;AA0EA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9GA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AAAA;AAWA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA5FA;AACA;AAAA;AA6FA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClIA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAIA;AAJA;AAKA;AAAA;AAAA;AAAA;AAEA;AACA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAbA;AAAA;AAAA;AAAA;AAcA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAhDA;AAAA;AAAA;AAAA;AAiDA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAhMA;AACA;AAAA;AAgMA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnOA;AACA;AACA;AACA;AACA;AAAA;AAYA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAXA;AACA;AAAA;AAYA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1CA;AACA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AAIA;AAEA;AAAA;AAwCA;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;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnMA;AAsBA;AAAA;AA+KA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7QA;AAEA;AACA;AACA;AACA;AACA;AAOA;AACA;AAEA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AA9FA;AACA;AAAA;AA+FA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9IA;AAGA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAYA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;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;;AAEA;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;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnLA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzBA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAOA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAMA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlIA;AAIA;AAAA;AAgIA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzKA;AAMA;AACA;AACA;AAAA;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAjDA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;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;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAHA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnJA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AACA;AAKA;AACA;AACA;AACA;AAAA;AAmBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAjEA;AACA;AAAA;AAkEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9GA;AAEA;AACA;AACA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArDA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArKA;AACA;AAAA;AAsKA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/LA;AAOA;AACA;AAAA;AAcA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAhDA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3BA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAEA;AAEA;AACA;AASA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArJA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AAOA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAKA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/KA;AAIA;AAAA;AA6KA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtNA;AAMA;AACA;AACA;AACA;AAAA;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAlDA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjCA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AASA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAPA;AAAA;AAAA;AAAA;AAUA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtGA;AAIA;AAAA;AAoGA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5JA;AACA;AACA;AACA;;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxIA;AACA;AAAA;AAyIA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjLA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAeA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AAvEA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjCA;AAEA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AAAA;AAYA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAXA;AAYA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlFA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AACA;AACA;AAEA;AAEA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AAEA;AACA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AA9BA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACfA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AAFA;AAGA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AACA;AAGA;AAGA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAHA;AAAA;AAKA;AACA;AACA;AACA;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;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArIA;AAIA;AAAA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxIA;AACA;AAAA;AAyIA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjKA;AACA;AACA;AAKA;AACA;AACA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AArDA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AAEA;AACA;AACA;AAGA;AAAA;AAWA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AA/CA;AACA;AAAA;AAgDA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/EA;AAEA;AACA;AAEA;AACA;AAGA;AAEA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;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;AAEA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxFA;AACA;AAAA;AAyFA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3HA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtCA;AACA;AAAA;AAuCA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnEA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvEA;AACA;AAAA;AAwEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrGA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AANA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxDA;AACA;AAAA;AAyDA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvFA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;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;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxCA;AAGA;AAAA;AAuCA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtEA;AACA;AACA;AAEA;AAEA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArCA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AACA;AACA;AAGA;AACA;AACA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxHA;AACA;AAAA;AAyHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1JA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAcA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAEA;AAEA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAEA;;AAEA;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;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtUA;AAGA;AAAA;AAqUA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9XA;AAEA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAGA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAlBA;AAAA;AAAA;AAAA;AAqBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAxBA;AAAA;AAAA;AAAA;AA2BA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxOA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3BA;AACA;AACA;AACA;AACA;AACA;AAKA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhGA;AAIA;AAAA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3BA;AACA;AACA;AAGA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAZA;AAAA;AAAA;AAAA;AAeA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjGA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AAEA;AACA;AAGA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAEA;AACA;AAGA;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAiBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAGA;AAEA;AACA;AAGA;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAHA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AARA;AAAA;AAAA;AAAA;AASA;AAAA;AAAA;AAAA;AAAA;AAGA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAFA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnNA;AAqNA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/PA;AAEA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAgBA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAGA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnJA;AACA;AAAA;AAoJA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnMA;AAGA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAgBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAPA;AAAA;AAAA;AAAA;AAUA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3HA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChCA;AAGA;AACA;AAEA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtCA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAjBA;AAAA;AAAA;AAAA;AAkBA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3GA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzBA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;AAGA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAGA;AAGA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAPA;AAAA;AAAA;AAAA;AAQA;AAVA;AAAA;AAAA;AAAA;AAWA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7GA;AAKA;AAAA;AA0GA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtJA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAUA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtFA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAEA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AALA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA9DA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAEA;AACA;AACA;AAEA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/CA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtDA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAEA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAGA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAGA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AARA;AAAA;AAAA;AAAA;AASA;AAXA;AAAA;AAAA;AAAA;AAYA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3GA;AAKA;AAAA;AAwGA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClJA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArCA;AACA;AAAA;AAsCA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAYA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxDA;AACA;AAAA;AAyDA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChGA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AAGA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AA1CA;AAAA;AAAA;AAAA;AA6CA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhJA;AACA;AAAA;AAiJA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChLA;AACA;AAEA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AACA;AACA;AACA;AAEA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAdA;AAAA;AAAA;AAAA;AAkBA;AACA;AAIA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7CA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AACA;AACA;AACA;AAEA;AAAA;AAWA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAJA;AAAA;AAAA;AAAA;AAMA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AAAA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAzEA;AACA;AAAA;AA0EA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxGA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjDA;AACA;AAAA;AAkDA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/EA;AAEA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAcA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArCA;AACA;AAAA;AAsCA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAIA;AACA;AAAA;AAeA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AANA;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AALA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/IA;AAIA;AAAA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AAEA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAAA;AAeA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjFA;AACA;AAAA;AAkFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxHA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAiBA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AACA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvEA;AACA;AAAA;AAwEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAeA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAJA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3EA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApFA;AACA;AAAA;AAqFA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrHA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAIA;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;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAhBA;AAAA;AAAA;AAAA;AAiBA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AAnEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAGA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AACA;AAAA;AAGA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAdA;AAAA;AAAA;AAAA;AAeA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvGA;AAGA;AAAA;AAsGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1IA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlHA;AAGA;AAAA;AAiHA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9JA;AACA;AAEA;AAEA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AACA;AACA;AACA;AAAA;AAaA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAOA;AAAA;AANA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxDA;AAQA;AAAA;AARA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAEA;AAEA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AAGA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AARA;AAAA;AAAA;AAAA;AAUA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3VA;AAcA;AAAA;AAsVA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7XA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AAIA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAhEA;AACA;AAAA;AAiEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClGA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;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;AAAA;AAEA;AAEA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AApGA;AAGA;AAAA;AAHA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvBA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAAA;AAAA;AAAA;AAAA;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnDA;AAEA;AAAA;AAFA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAtCA;AACA;AAAA;AAuCA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtEA;AAEA;AAGA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AA1BA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AApDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AA9CA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AA/DA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AAlEA;AAKA;AAAA;AALA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AACA;AACA;AAEA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtCA;AACA;AAAA;AAuCA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;;AAEA;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;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAGA;AAAA;AAzGA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;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;AAGA;AAAA;AAnDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAAA;AAUA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;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;AAAA;AAEA;AACA;AACA;;AAEA;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;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA5TA;AAMA;AAAA;AAwTA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9WA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AAnSA;AAIA;AAAA;AAJA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtCA;AAEA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;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;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;AACA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxBA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;AACA;AACA;AACA;AAEA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAYA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAIA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;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;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAhBA;AAAA;AAAA;AAAA;AAmBA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/PA;AASA;AAAA;AATA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvCA;AAEA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;;AAEA;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;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAxFA;AAKA;AAAA;AALA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA;AAEA;AACA;AACA;AACA;AAEA;AASA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAWA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;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;;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;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AAJA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnNA;AAKA;AAAA;AAgNA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvQA;AAEA;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAGA;AACA;;AAEA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AApBA;AAAA;AAAA;AAAA;AAsBA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;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;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3KA;AACA;AAAA;AA4KA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/MA;AACA;AACA;AAAA;AAcA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAjEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AAEA;AACA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AADA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AALA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AArKA;AAGA;AAAA;AAoKA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9MA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1DA;AAEA;AAAA;AA0DA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5FA;AAEA;AACA;AACA;AAEA;AACA;AASA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AAIA;AAEA;AAAA;AAGA;AAEA;AACA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAOA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AAMA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAHA;AAAA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AACA;AAtBA;AAAA;AAAA;AAAA;AAyBA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1QA;AAOA;AAAA;AAqQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7UA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvBA;AACA;AAAA;AAwBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxDA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAcA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAzFA;AAIA;AAAA;AAuFA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChIA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAgBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAGA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApHA;AAIA;AAAA;AAkHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpKA;AAEA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAAA;AAcA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAGA;;AAEA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAvHA;AACA;AAAA;AAwHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrKA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1BA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;AAEA;AACA;AACA;AACA;AACA;AAKA;AACA;AAEA;AACA;AACA;AAAA;AAgBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AApCA;AAAA;AAAA;AAAA;AAuCA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjKA;AACA;AAAA;AAkKA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9MA;AAEA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AALA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAlEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;AAEA;AACA;AAIA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AANA;AAAA;;AAQA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AApDA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;AAEA;AACA;AAGA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;;AAEA;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;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1DA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAEA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAZA;AAAA;AAAA;AAAA;AAeA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAjPA;AACA;AAAA;AAkPA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvRA;AAEA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAVA;AAAA;AAAA;AAAA;AAaA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA7FA;AACA;AAAA;AA8FA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrIA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AAvBA;AAyBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnDA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA1NA;AASA;AAAA;AAmNA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzQA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtIA;AAMA;AAAA;AAkIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7KA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;AACA;AACA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAGA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AAGA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AArDA;AAAA;AAAA;AAAA;AAuDA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAtLA;AACA;AAAA;AAuLA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7NA;AAGA;AAKA;AACA;AACA;AAAA;AAUA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAIA;;AAEA;AACA;AACA;AACA;AACA;AAIA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AArEA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;AAAA;AASA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAAA;AAaA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAzFA;AAOA;AAAA;AAPA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5BA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAwBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA/EA;AAEA;AAAA;AA+EA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjIA;AAIA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnCA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACfA;AAEA;AACA;AACA;AAAA;AAYA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnEA;AACA;AAAA;AAoEA;AACA;AACA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxFA;AACA;AAEA;AAEA;AACA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA5DA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAMA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAEA;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;AAKA;AACA;AAEA;AAEA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AA3DA;AACA;AAAA;AADA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;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;AAGA;AAEA;AACA;AAAA;AAkBA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AANA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAllBA;AAIA;AAAA;AAglBA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAEA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7pBA;AAEA;AACA;AACA;AAGA;AACA;AAAA;AAWA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAnCA;AACA;AAAA;AAoCA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3DA;;AAEA;AACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAEA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;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;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;;AAEA;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;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAIA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;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;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;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;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;;AAEA;AACA;AACA;AACA;AACA;AAEA;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;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAAA;AACA;AAEA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACryCA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;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;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;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;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;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;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;AAEA;AACA;AACA;AACA;;AAEA;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;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;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;AAEA;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;;AAEA;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;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrwBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;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;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;;AAEA;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;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AAEA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;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;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;;AAEA;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;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5tCA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;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;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;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;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAIA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChwCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AACA;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;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrKA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAMA;AACA;AACA;AACA;;AAEA;AACA;;AAQA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAEA;AACA;AACA;;AAGA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AACA;AACA;AACA;AACA;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;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACv0BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAEA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAIA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjlBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;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;AAMA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;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;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;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;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AAEA;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;AAAA;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAIA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvyBA;AACA;AACA;AACA;AACA;;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjEA;AACA;AACA;AACA;AACA;;AAEA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrDA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAMA;AACA;AAAA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACleA;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;;AAGA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AAEA;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;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvuBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;AACA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;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;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;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClWA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChEA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7FA;;AAEA;AAEA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;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;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;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;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAIA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AAGA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9KA;;AAEA;AACA;;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;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;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;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;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;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;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;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;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACltBA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjCA;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;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;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;;AAEA;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;AACA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;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;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AAGA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;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;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;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;AACA;AACA;AACA;;AAEA;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;AAAA;AAAA;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;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC55BA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;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;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAGA;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AAEA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvBA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzCA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;AAEA;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;AAEA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzDA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtGA;AAEA;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;AAEA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrDA;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;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnCA;AACA;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;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;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;AAEA;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;AAEA;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;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;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;AAEA;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;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;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;AAAA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAKA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChXA;AACA;AAEA;AACA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjDA;AAEA;AAEA;AACA;AACA;AAEA;AAIA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAEA;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpDA;AAEA;AACA;AAEA;AAGA;AACA;AACA;AACA;AAEA;AAKA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;;AACA;AACA;AACA;AAIA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AAGA;;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrDA;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;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1DA;AACA;AACA;AACA;AAIA;AACA;AAIA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5BA;AAMA;AAAA;AAKA;AACA;AANA;AAYA;AACA;AACA;AAdA;AAoBA;AACA;AACA;AAtBA;AA4BA;AACA;AACA;AA9BA;AAoCA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AA3CA;AAiDA;AACA;AACA;AAnDA;AAyDA;AACA;AACA;AA3DA;AAiEA;AACA;AAlEA;AAwEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AA/EA;AAqFA;AACA;AAtFA;AA4FA;AAAA;AAAA;AAAA;AACA;AA7FA;AAmGA;AAAA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1GA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1CA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;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;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;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;AAEA;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;AAAA;AAEA;AACA;AAEA;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;AAEA;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;AAEA;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;AAEA;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;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;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3aA;AACA;AACA;AACA;AAKA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAKA;AACA;AACA;AAIA;AACA;AAIA;AACA;AAIA;AACA;AAIA;AACA;AAEA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5CA;AAGA;AAAA;AAKA;AACA;AANA;AAYA;AAEA;AAdA;AAoBA;AAIA;AAxBA;AA8BA;AACA;AA/BA;AAqCA;AACA;AAtCA;AA4CA;AACA;AA7CA;AAmDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAnEA;AAyEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzEA;AAAA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAhBA;AAuBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA9BA;AAoCA;AACA;AArCA;AA2CA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChDA;AACA;AACA;AACA;AAAA;AACA;;AACA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjCA;AAUA;AACA;AACA;AAGA;AAAA;AAMA;AAGA;AAGA;AACA;AACA;AACA;AACA;AACA;AAjBA;AAuBA;AACA;AAxBA;AA2BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAlCA;AAwCA;AACA;AAEA;AACA;AA5CA;AAkDA;AACA;AACA;AACA;AACA;AACA;AACA;AAxDA;AA+DA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAxFA;AA8FA;AAEA;AACA;AAAA;AAEA;AAnGA;AAyGA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAEA;AAtHA;AA4HA;AACA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAnJA;AAyJA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAtKA;AA4KA;AACA;AAEA;AAEA;AAEA;AAAA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvMA;AAEA;AAAA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAZA;AAkBA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AAOA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxHA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;AAEA;AAEA;AAGA;AAAA;AAQA;AACA;AACA;AAEA;AACA;AAAA;AAMA;AACA;AAAA;AAMA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAMA;AACA;AACA;AACA;AACA;AAAA;AAMA;AAEA;AACA;AAtEA;AACA;;AAEA;AACA;AACA;AAkEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/EA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA;AAGA;AAAA;AAQA;AACA;AACA;AACA;AACA;AACA;AAZA;AACA;;AAEA;AACA;AACA;AAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AAOA;AAPA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA;AAKA;AALA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACYA;AA0EA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpFA;AAIA;AAJA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACaA;AAKA;AALA;AAAA;AAAA;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACuBA;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpEA;AAQA;AAMA;AAOA;AAgBA;AASA;AAsBA;AAqBA;AAKA;AAKA;AAoCA;AAaA;AAMA;AASA;AAOA;AAMA;AAUA;AAMA;AAQA;AAMA;AAKA;AAMA;AAKA;AAIA;AAIA;AAMA;AAKA;AAgBA;AAQA;AAQA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChRA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACHA;AAgIA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3JA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;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;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;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;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;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;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAGA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/xCA;;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrCA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxBA;;AAEA;AAEA;AACA;AAAA;AAAA;AACA;;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;AAEA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9CA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;;AAEA;AACA;AACA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxHA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCA;AACA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACFA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACRA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxDA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAGA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvBA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACJA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;;AAEA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvDA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzDA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACJA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjBA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACZA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9BA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;;AAEA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACJA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACXA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACdA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;;AAEA;AACA;AACA;AAAA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACTA;;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnBA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;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;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;AAEA;AACA;AACA;AAEA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;;;;;;;;;;;;ACjGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAGA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAIA;;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;AAAA;AAAA;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;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;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;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAEA;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;;AAEA;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;AAEA;AACA;AACA;AACA;AAEA;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;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AAEA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAEA;AACA;AAGA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACt7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAdA;AAAA;AAAA;AAAA;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;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;AAGA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;;AAEA;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;AACA;;AAEA;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;;AAEA;AACA;AACA;;;;;;;;;;;;;AC3uBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;;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;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;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;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;ACzpBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAEA;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;AACA;AAEA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;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;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAAA;AAAA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;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;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;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;ACvcA;;;;;;;;;;;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACnSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","sources":["webpack://fab-manager/./app/frontend/images/ sync ^\\.\\/.*$","webpack://fab-manager/./app/frontend/src/javascript/components/ sync ^.+\\.(","webpack://fab-manager/./app/frontend/src/javascript/controllers/ sync .*","webpack://fab-manager/./app/frontend/src/javascript/directives/ sync .*","webpack://fab-manager/./app/frontend/src/javascript/filters/ sync .*","webpack://fab-manager/./app/frontend/src/javascript/services/ sync .*","webpack://fab-manager/./app/frontend/src/javascript/typings/ sync .*","webpack://fab-manager/./app/frontend/templates/ sync ^\\.\\/.*$","webpack://fab-manager/./app/frontend/src/javascript/api/age-range.ts","webpack://fab-manager/./app/frontend/src/javascript/api/auth-provider.ts","webpack://fab-manager/./app/frontend/src/javascript/api/authentication.ts","webpack://fab-manager/./app/frontend/src/javascript/api/brazillian.ts","webpack://fab-manager/./app/frontend/src/javascript/api/cart.ts","webpack://fab-manager/./app/frontend/src/javascript/api/checkout.ts","webpack://fab-manager/./app/frontend/src/javascript/api/clients/api-client.ts","webpack://fab-manager/./app/frontend/src/javascript/api/clients/sso-client.ts","webpack://fab-manager/./app/frontend/src/javascript/api/clients/stripe-client.ts","webpack://fab-manager/./app/frontend/src/javascript/api/coupon.ts","webpack://fab-manager/./app/frontend/src/javascript/api/credit.ts","webpack://fab-manager/./app/frontend/src/javascript/api/custom-asset.ts","webpack://fab-manager/./app/frontend/src/javascript/api/event-category.ts","webpack://fab-manager/./app/frontend/src/javascript/api/event-price-category.ts","webpack://fab-manager/./app/frontend/src/javascript/api/event-theme.ts","webpack://fab-manager/./app/frontend/src/javascript/api/event.ts","webpack://fab-manager/./app/frontend/src/javascript/api/external/sso.ts","webpack://fab-manager/./app/frontend/src/javascript/api/external/stripe.ts","webpack://fab-manager/./app/frontend/src/javascript/api/getnet.ts","webpack://fab-manager/./app/frontend/src/javascript/api/group.ts","webpack://fab-manager/./app/frontend/src/javascript/api/local-payment.ts","webpack://fab-manager/./app/frontend/src/javascript/api/machine-category.ts","webpack://fab-manager/./app/frontend/src/javascript/api/machine.ts","webpack://fab-manager/./app/frontend/src/javascript/api/member.ts","webpack://fab-manager/./app/frontend/src/javascript/api/notification.ts","webpack://fab-manager/./app/frontend/src/javascript/api/notification_preference.ts","webpack://fab-manager/./app/frontend/src/javascript/api/notification_types.ts","webpack://fab-manager/./app/frontend/src/javascript/api/order.ts","webpack://fab-manager/./app/frontend/src/javascript/api/pagseguro.ts","webpack://fab-manager/./app/frontend/src/javascript/api/payment-schedule.ts","webpack://fab-manager/./app/frontend/src/javascript/api/payzen.ts","webpack://fab-manager/./app/frontend/src/javascript/api/plan-category.ts","webpack://fab-manager/./app/frontend/src/javascript/api/plan.ts","webpack://fab-manager/./app/frontend/src/javascript/api/prepaid-pack.ts","webpack://fab-manager/./app/frontend/src/javascript/api/price.ts","webpack://fab-manager/./app/frontend/src/javascript/api/product-category.ts","webpack://fab-manager/./app/frontend/src/javascript/api/product.ts","webpack://fab-manager/./app/frontend/src/javascript/api/profile-custom-field.ts","webpack://fab-manager/./app/frontend/src/javascript/api/reservation.ts","webpack://fab-manager/./app/frontend/src/javascript/api/setting.ts","webpack://fab-manager/./app/frontend/src/javascript/api/space.ts","webpack://fab-manager/./app/frontend/src/javascript/api/status.ts","webpack://fab-manager/./app/frontend/src/javascript/api/stripe.ts","webpack://fab-manager/./app/frontend/src/javascript/api/subscription.ts","webpack://fab-manager/./app/frontend/src/javascript/api/supporting-document-file.ts","webpack://fab-manager/./app/frontend/src/javascript/api/supporting-document-refusal.ts","webpack://fab-manager/./app/frontend/src/javascript/api/supporting-document-type.ts","webpack://fab-manager/./app/frontend/src/javascript/api/tag.ts","webpack://fab-manager/./app/frontend/src/javascript/api/training.ts","webpack://fab-manager/./app/frontend/src/javascript/api/user-pack.ts","webpack://fab-manager/./app/frontend/src/javascript/api/user.ts","webpack://fab-manager/./app/frontend/src/javascript/api/wallet.ts","webpack://fab-manager/./app/frontend/src/javascript/app.js","webpack://fab-manager/./app/frontend/src/javascript/components/accounting/accounting-codes-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/accounting/advanced-accounting-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/angular/switch.ts","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/boolean-mapping-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/data-mapping-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/database-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/date-mapping-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/integer-mapping-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/oauth2-data-mapping-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/openid-connect-data-mapping-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/openid-connect-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/provider-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/string-mapping-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/authentication-provider/type-mapping-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/accordion-item.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/destroy-button.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/edit-destroy-buttons.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/error-boundary.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-alert.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-button.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-input.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-output-copy.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-pagination.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-panel.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-popover.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-state-label.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/fab-tabs.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/html-translate.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/labelled-input.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/loader.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/text-editor/fab-text-editor.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/text-editor/iframe.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/base/text-editor/menu-bar.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/cart/abstract-item.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/cart/cart-button.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/cart/cart-order-product.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/cart/cart-order-reservation.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/cart/store-cart.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/coupon/coupon-input.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/dashboard/orders/orders-dashboard.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/dashboard/reservations/credits-panel.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/dashboard/reservations/prepaid-packs-panel.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/dashboard/reservations/reservations-dashboard.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/dashboard/reservations/reservations-panel.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/document-filters.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/editorial-block/editorial-block-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/editorial-block/editorial-block.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/events/event-card.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/events/event-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/events/events-editorial-block.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/events/events-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/events/update-recurrent-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/abstract-form-item.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-checklist.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-file-upload.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-image-upload.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-input.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-multi-file-upload.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-multi-image-upload.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-multi-select.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-rich-text.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-select.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-switch.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/form-unsaved-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/form/unsaved-form-alert.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/group/change-group.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/invoices/invoices-settings-panel.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/invoices/vat-settings-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machine-card.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machine-categories-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machine-category-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machine-category-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machine-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machines-editorial-block.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machines-filters.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machines-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/machines-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/pending-training-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/required-training-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/machines/reserve-button.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/notifications/notification-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/notifications/notification-inline.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/notifications/notifications-category.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/notifications/notifications-center.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/notifications/notifications-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/notifications/notifications-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment-schedule/payment-schedule-item-actions.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment-schedule/payment-schedule-summary.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment-schedule/payment-schedules-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment-schedule/payment-schedules-table.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment-schedule/select-schedule.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment-schedule/update-payment-mean-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/card-payment-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/getnet/getnet-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/getnet/getnet-keys-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/getnet/getnet-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-keys-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/payzen/payzen-card-update-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/payzen/payzen-keys-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/payzen/payzen-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/payzen/payzen-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/select-gateway-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/payment-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-card-update-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-card-update.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-confirm-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-confirm.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-elements.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-keys-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/update-card-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/payment/wallet-info.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plan-categories/delete-plan-category.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plan-categories/manage-plan-category.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plan-categories/plan-categories-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plan-categories/plan-category-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/partner-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/plan-card.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/plan-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/plan-limit-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/plan-limit-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/plan-pricing-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/plans-filter.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/plans/plans-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/prepaid-packs/propose-packs-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/editable-price.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/machines/configure-packs-button.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/machines/create-pack.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/machines/edit-pack.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/machines/machines-pricing.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/machines/pack-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/spaces/configure-extended-prices-button.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/spaces/create-extended-price.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/spaces/edit-extended-price.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/pricing/spaces/spaces-pricing.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/profile-completion/completion-header-info.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/profile-completion/profile-form-option.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/profile-custom-fields/profile-custom-fields-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/projects/projects-setting-option-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/projects/projects-setting-option.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/projects/projects-setting.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/projects/status/status-filter.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/projects/status/status-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/reservations/ongoing-reservation-panel.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/reservations/reservations-summary.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/settings/boolean-setting.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/settings/check-list-setting.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/settings/setting-history-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/settings/user-validation-setting.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/socials/edit-socials.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/socials/fab-socials.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/spaces/space-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/categories/manage-product-category.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/categories/product-categories-item.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/categories/product-categories-tree.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/categories/product-categories.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/categories/product-category-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/clone-product-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/edit-product.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/filters/active-filters-tags.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/filters/categories-filter.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/filters/keyword-filter.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/filters/machines-filter.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/filters/stock-filter.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/new-product.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/order-actions.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/order-item.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/orders.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/product-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/product-item.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/product-price.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/product-stock-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/product-stock-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/products.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/show-order.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/store-list-header.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/store-product-item.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/store-product.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/store-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/store/store.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/subscriptions/cancel-subscription-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/subscriptions/free-extend-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/subscriptions/renew-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/subscriptions/subscribe-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/delete-supporting-documents-type-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/supporting-documents-files.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/supporting-documents-type-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/supporting-documents-type-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/supporting-documents-types-list.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/supporting-documents/supporting-documents-validation.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/trainings/training-editorial-block.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/trainings/training-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/trainings/trainings-settings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/trainings/trainings.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/avatar-input.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/avatar.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/change-password.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/change-role-modal.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/gender-input.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/member-select.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/password-input.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/password-strength.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/user-profile-form.tsx","webpack://fab-manager/./app/frontend/src/javascript/components/user/user-validation.tsx","webpack://fab-manager/./app/frontend/src/javascript/controllers/about.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/abuses.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/authentications.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/calendar.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/coupons.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/events.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/graphs.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/groups.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/invoices.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/machines.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/members.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/open_api_clients.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/orders.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/plans.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/price_category.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/pricing.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/projects.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/settings.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/statistics.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/store.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/store_products.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/tags.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/admin/trainings.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/application.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/calendar.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/cart.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/cookies.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/dashboard.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/header.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/home.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/main_nav.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/members.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/notifications.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/orders.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/plans.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/privacy.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/products.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/profile.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/projects.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/store.js","webpack://fab-manager/./app/frontend/src/javascript/controllers/wallet.js","webpack://fab-manager/./app/frontend/src/javascript/directives/bs-jasny-fileinput.js","webpack://fab-manager/./app/frontend/src/javascript/directives/cart.js","webpack://fab-manager/./app/frontend/src/javascript/directives/compile.js","webpack://fab-manager/./app/frontend/src/javascript/directives/confirmation_needed.js","webpack://fab-manager/./app/frontend/src/javascript/directives/coupon.js","webpack://fab-manager/./app/frontend/src/javascript/directives/directives.js","webpack://fab-manager/./app/frontend/src/javascript/directives/fab_user_avatar.js","webpack://fab-manager/./app/frontend/src/javascript/directives/home/events.js","webpack://fab-manager/./app/frontend/src/javascript/directives/home/news.js","webpack://fab-manager/./app/frontend/src/javascript/directives/home/projects.js","webpack://fab-manager/./app/frontend/src/javascript/directives/home/twitter.js","webpack://fab-manager/./app/frontend/src/javascript/directives/members.js","webpack://fab-manager/./app/frontend/src/javascript/directives/post_render.js","webpack://fab-manager/./app/frontend/src/javascript/directives/selectMember.js","webpack://fab-manager/./app/frontend/src/javascript/directives/settings/number-setting.js","webpack://fab-manager/./app/frontend/src/javascript/directives/settings/select-multiple-setting.js","webpack://fab-manager/./app/frontend/src/javascript/directives/settings/select-setting.js","webpack://fab-manager/./app/frontend/src/javascript/directives/settings/text-setting.js","webpack://fab-manager/./app/frontend/src/javascript/directives/socialLink.js","webpack://fab-manager/./app/frontend/src/javascript/directives/validators.js","webpack://fab-manager/./app/frontend/src/javascript/filters/filters.js","webpack://fab-manager/./app/frontend/src/javascript/hooks/use-cart.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/api.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/cart-token.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/coupon.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/deferred.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/devise-modal.js","webpack://fab-manager/./app/frontend/src/javascript/lib/dirDisqus.js","webpack://fab-manager/./app/frontend/src/javascript/lib/file-upload.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/format.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/gtm.js","webpack://fab-manager/./app/frontend/src/javascript/lib/humanize.js","webpack://fab-manager/./app/frontend/src/javascript/lib/i18n.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/localise.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/order.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/parsing.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/polyfill.js","webpack://fab-manager/./app/frontend/src/javascript/lib/product.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/setting.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/summernote-ext-nugget.js","webpack://fab-manager/./app/frontend/src/javascript/lib/use-previous.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/user.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/validation.ts","webpack://fab-manager/./app/frontend/src/javascript/lib/wallet.ts","webpack://fab-manager/./app/frontend/src/javascript/models/custom-asset.ts","webpack://fab-manager/./app/frontend/src/javascript/models/gateway.ts","webpack://fab-manager/./app/frontend/src/javascript/models/notification-type.ts","webpack://fab-manager/./app/frontend/src/javascript/models/payment-schedule.ts","webpack://fab-manager/./app/frontend/src/javascript/models/payment.ts","webpack://fab-manager/./app/frontend/src/javascript/models/product.ts","webpack://fab-manager/./app/frontend/src/javascript/models/setting.ts","webpack://fab-manager/./app/frontend/src/javascript/models/social-network.ts","webpack://fab-manager/./app/frontend/src/javascript/models/user.ts","webpack://fab-manager/./app/frontend/src/javascript/router.js","webpack://fab-manager/./app/frontend/src/javascript/services/_t.js","webpack://fab-manager/./app/frontend/src/javascript/services/abuse.js","webpack://fab-manager/./app/frontend/src/javascript/services/accounting_period.js","webpack://fab-manager/./app/frontend/src/javascript/services/admin.js","webpack://fab-manager/./app/frontend/src/javascript/services/age_range.js","webpack://fab-manager/./app/frontend/src/javascript/services/auth.js","webpack://fab-manager/./app/frontend/src/javascript/services/authProvider.js","webpack://fab-manager/./app/frontend/src/javascript/services/availability.js","webpack://fab-manager/./app/frontend/src/javascript/services/brazillianData.js","webpack://fab-manager/./app/frontend/src/javascript/services/calendar.js","webpack://fab-manager/./app/frontend/src/javascript/services/category.js","webpack://fab-manager/./app/frontend/src/javascript/services/component.js","webpack://fab-manager/./app/frontend/src/javascript/services/coupon.js","webpack://fab-manager/./app/frontend/src/javascript/services/credit.js","webpack://fab-manager/./app/frontend/src/javascript/services/csrf.js","webpack://fab-manager/./app/frontend/src/javascript/services/customAsset.js","webpack://fab-manager/./app/frontend/src/javascript/services/diacritics.js","webpack://fab-manager/./app/frontend/src/javascript/services/dialogs.js","webpack://fab-manager/./app/frontend/src/javascript/services/elastic.js","webpack://fab-manager/./app/frontend/src/javascript/services/event.js","webpack://fab-manager/./app/frontend/src/javascript/services/event_theme.js","webpack://fab-manager/./app/frontend/src/javascript/services/export.js","webpack://fab-manager/./app/frontend/src/javascript/services/fab_analytics.js","webpack://fab-manager/./app/frontend/src/javascript/services/group.js","webpack://fab-manager/./app/frontend/src/javascript/services/help.js","webpack://fab-manager/./app/frontend/src/javascript/services/helpers.js","webpack://fab-manager/./app/frontend/src/javascript/services/ical.js","webpack://fab-manager/./app/frontend/src/javascript/services/icalendar.js","webpack://fab-manager/./app/frontend/src/javascript/services/import.js","webpack://fab-manager/./app/frontend/src/javascript/services/invoice.js","webpack://fab-manager/./app/frontend/src/javascript/services/licence.js","webpack://fab-manager/./app/frontend/src/javascript/services/local_payment.js","webpack://fab-manager/./app/frontend/src/javascript/services/machine.js","webpack://fab-manager/./app/frontend/src/javascript/services/machine_category.js","webpack://fab-manager/./app/frontend/src/javascript/services/member.js","webpack://fab-manager/./app/frontend/src/javascript/services/notification.js","webpack://fab-manager/./app/frontend/src/javascript/services/open_api_client.js","webpack://fab-manager/./app/frontend/src/javascript/services/openlab_project.js","webpack://fab-manager/./app/frontend/src/javascript/services/pagination_service.js","webpack://fab-manager/./app/frontend/src/javascript/services/payment.js","webpack://fab-manager/./app/frontend/src/javascript/services/plan.js","webpack://fab-manager/./app/frontend/src/javascript/services/plan_category.js","webpack://fab-manager/./app/frontend/src/javascript/services/price.js","webpack://fab-manager/./app/frontend/src/javascript/services/price_category.js","webpack://fab-manager/./app/frontend/src/javascript/services/pricing.js","webpack://fab-manager/./app/frontend/src/javascript/services/profile_custom_field.js","webpack://fab-manager/./app/frontend/src/javascript/services/project.js","webpack://fab-manager/./app/frontend/src/javascript/services/reservation.js","webpack://fab-manager/./app/frontend/src/javascript/services/session.js","webpack://fab-manager/./app/frontend/src/javascript/services/setting.js","webpack://fab-manager/./app/frontend/src/javascript/services/slots_reservation.js","webpack://fab-manager/./app/frontend/src/javascript/services/socialNetworks.js","webpack://fab-manager/./app/frontend/src/javascript/services/space.js","webpack://fab-manager/./app/frontend/src/javascript/services/statistics.js","webpack://fab-manager/./app/frontend/src/javascript/services/status.js","webpack://fab-manager/./app/frontend/src/javascript/services/subscription.js","webpack://fab-manager/./app/frontend/src/javascript/services/supporting_document_type.js","webpack://fab-manager/./app/frontend/src/javascript/services/tag.js","webpack://fab-manager/./app/frontend/src/javascript/services/theme.js","webpack://fab-manager/./app/frontend/src/javascript/services/training.js","webpack://fab-manager/./app/frontend/src/javascript/services/trainings_pricing.js","webpack://fab-manager/./app/frontend/src/javascript/services/translations.js","webpack://fab-manager/./app/frontend/src/javascript/services/user.js","webpack://fab-manager/./app/frontend/src/javascript/services/version.js","webpack://fab-manager/./app/frontend/src/javascript/services/wallet.js","webpack://fab-manager/./app/frontend/application.js.erb","webpack://fab-manager/./app/frontend/src/javascript/controllers/events.js.erb","webpack://fab-manager/./app/frontend/src/javascript/controllers/machines.js.erb","webpack://fab-manager/./app/frontend/src/javascript/controllers/spaces.js.erb","webpack://fab-manager/./app/frontend/src/javascript/controllers/trainings.js.erb","webpack://fab-manager/./app/frontend/application.scss?f2f6","webpack://fab-manager/./node_modules/moment/locale/ sync ^\\.\\/.*$","webpack://fab-manager/./app/frontend/templates/admin/open_api_clients/index.html.erb","webpack://fab-manager/./app/frontend/templates/shared/header.html.erb","webpack://fab-manager/./app/frontend/templates/shared/publicProfile.html.erb","webpack://fab-manager/./app/frontend/templates/admin/abuses/index.html","webpack://fab-manager/./app/frontend/templates/admin/admins/new.html","webpack://fab-manager/./app/frontend/templates/admin/authentications/edit.html","webpack://fab-manager/./app/frontend/templates/admin/authentications/index.html","webpack://fab-manager/./app/frontend/templates/admin/authentications/new.html","webpack://fab-manager/./app/frontend/templates/admin/calendar/calendar.html","webpack://fab-manager/./app/frontend/templates/admin/calendar/deleteRecurrent.html","webpack://fab-manager/./app/frontend/templates/admin/calendar/eventModal.html","webpack://fab-manager/./app/frontend/templates/admin/calendar/icalendar.html","webpack://fab-manager/./app/frontend/templates/admin/coupons/_form.html","webpack://fab-manager/./app/frontend/templates/admin/coupons/edit.html","webpack://fab-manager/./app/frontend/templates/admin/coupons/new.html","webpack://fab-manager/./app/frontend/templates/admin/events/filters.html","webpack://fab-manager/./app/frontend/templates/admin/events/index.html","webpack://fab-manager/./app/frontend/templates/admin/events/monitoring.html","webpack://fab-manager/./app/frontend/templates/admin/events/price_form.html","webpack://fab-manager/./app/frontend/templates/admin/events/prices.html","webpack://fab-manager/./app/frontend/templates/admin/events/reservations.html","webpack://fab-manager/./app/frontend/templates/admin/groups/index.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/_period.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/accountingExportModal.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/avoirModal.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/closePeriodModal.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/codes.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/index.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/list.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/payment.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/settings.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/settings/editCode.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/settings/editNumber.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/settings/editReference.html","webpack://fab-manager/./app/frontend/templates/admin/invoices/settings/stripeKeys.html","webpack://fab-manager/./app/frontend/templates/admin/machines/categories.html","webpack://fab-manager/./app/frontend/templates/admin/machines/index.html","webpack://fab-manager/./app/frontend/templates/admin/machines/machines.html","webpack://fab-manager/./app/frontend/templates/admin/managers/new.html","webpack://fab-manager/./app/frontend/templates/admin/members/_form.html","webpack://fab-manager/./app/frontend/templates/admin/members/administrators.html","webpack://fab-manager/./app/frontend/templates/admin/members/change_role_modal.html","webpack://fab-manager/./app/frontend/templates/admin/members/edit.html","webpack://fab-manager/./app/frontend/templates/admin/members/import.html","webpack://fab-manager/./app/frontend/templates/admin/members/import_result.html","webpack://fab-manager/./app/frontend/templates/admin/members/index.html","webpack://fab-manager/./app/frontend/templates/admin/members/managers.html","webpack://fab-manager/./app/frontend/templates/admin/members/members.html","webpack://fab-manager/./app/frontend/templates/admin/members/new.html","webpack://fab-manager/./app/frontend/templates/admin/members/partners.html","webpack://fab-manager/./app/frontend/templates/admin/members/users.html","webpack://fab-manager/./app/frontend/templates/admin/orders/show.html","webpack://fab-manager/./app/frontend/templates/admin/plans/categories.html","webpack://fab-manager/./app/frontend/templates/admin/plans/edit.html","webpack://fab-manager/./app/frontend/templates/admin/plans/new.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/coupons.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/credits.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/index.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/machine_hours.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/sendCoupon.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/spaces.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/subscriptions.html","webpack://fab-manager/./app/frontend/templates/admin/pricing/trainings.html","webpack://fab-manager/./app/frontend/templates/admin/projects/index.html","webpack://fab-manager/./app/frontend/templates/admin/projects/licences.html","webpack://fab-manager/./app/frontend/templates/admin/projects/materials.html","webpack://fab-manager/./app/frontend/templates/admin/projects/settings.html","webpack://fab-manager/./app/frontend/templates/admin/projects/themes.html","webpack://fab-manager/./app/frontend/templates/admin/settings/about.html","webpack://fab-manager/./app/frontend/templates/admin/settings/analyticsModal.html","webpack://fab-manager/./app/frontend/templates/admin/settings/compte.html","webpack://fab-manager/./app/frontend/templates/admin/settings/general.html","webpack://fab-manager/./app/frontend/templates/admin/settings/home_page.html","webpack://fab-manager/./app/frontend/templates/admin/settings/index.html","webpack://fab-manager/./app/frontend/templates/admin/settings/newSelectOption.html","webpack://fab-manager/./app/frontend/templates/admin/settings/number.html","webpack://fab-manager/./app/frontend/templates/admin/settings/privacy.html","webpack://fab-manager/./app/frontend/templates/admin/settings/reservations.html","webpack://fab-manager/./app/frontend/templates/admin/settings/save_policy.html","webpack://fab-manager/./app/frontend/templates/admin/settings/select-multiple.html","webpack://fab-manager/./app/frontend/templates/admin/settings/select.html","webpack://fab-manager/./app/frontend/templates/admin/settings/text.html","webpack://fab-manager/./app/frontend/templates/admin/statistics/export.html","webpack://fab-manager/./app/frontend/templates/admin/statistics/graphs.html","webpack://fab-manager/./app/frontend/templates/admin/statistics/index.html","webpack://fab-manager/./app/frontend/templates/admin/store/categories.html","webpack://fab-manager/./app/frontend/templates/admin/store/index.html","webpack://fab-manager/./app/frontend/templates/admin/store/orders.html","webpack://fab-manager/./app/frontend/templates/admin/store/product_edit.html","webpack://fab-manager/./app/frontend/templates/admin/store/product_new.html","webpack://fab-manager/./app/frontend/templates/admin/store/products.html","webpack://fab-manager/./app/frontend/templates/admin/store/settings.html","webpack://fab-manager/./app/frontend/templates/admin/tags/index.html","webpack://fab-manager/./app/frontend/templates/admin/trainings/edit.html","webpack://fab-manager/./app/frontend/templates/admin/trainings/index.html","webpack://fab-manager/./app/frontend/templates/admin/trainings/modal_edit.html","webpack://fab-manager/./app/frontend/templates/admin/trainings/new.html","webpack://fab-manager/./app/frontend/templates/admin/trainings/validTrainingModal.html","webpack://fab-manager/./app/frontend/templates/admin/versions/upgradeModal.html","webpack://fab-manager/./app/frontend/templates/calendar/calendar.html","webpack://fab-manager/./app/frontend/templates/calendar/chooseMachine.html","webpack://fab-manager/./app/frontend/templates/calendar/filter.html","webpack://fab-manager/./app/frontend/templates/calendar/filterAside.html","webpack://fab-manager/./app/frontend/templates/cart/index.html","webpack://fab-manager/./app/frontend/templates/dashboard/events.html","webpack://fab-manager/./app/frontend/templates/dashboard/invoices.html","webpack://fab-manager/./app/frontend/templates/dashboard/nav.html","webpack://fab-manager/./app/frontend/templates/dashboard/orders.html","webpack://fab-manager/./app/frontend/templates/dashboard/payment_schedules.html","webpack://fab-manager/./app/frontend/templates/dashboard/profile.html","webpack://fab-manager/./app/frontend/templates/dashboard/projects.html","webpack://fab-manager/./app/frontend/templates/dashboard/reservations.html","webpack://fab-manager/./app/frontend/templates/dashboard/settings.html","webpack://fab-manager/./app/frontend/templates/dashboard/supporting_document_files.html","webpack://fab-manager/./app/frontend/templates/dashboard/trainings.html","webpack://fab-manager/./app/frontend/templates/dashboard/wallet.html","webpack://fab-manager/./app/frontend/templates/events/deleteRecurrent.html","webpack://fab-manager/./app/frontend/templates/events/edit.html","webpack://fab-manager/./app/frontend/templates/events/index.html","webpack://fab-manager/./app/frontend/templates/events/modify_event_reservation_modal.html","webpack://fab-manager/./app/frontend/templates/events/new.html","webpack://fab-manager/./app/frontend/templates/events/show.html","webpack://fab-manager/./app/frontend/templates/home.html","webpack://fab-manager/./app/frontend/templates/home/events.html","webpack://fab-manager/./app/frontend/templates/home/members.html","webpack://fab-manager/./app/frontend/templates/home/news.html","webpack://fab-manager/./app/frontend/templates/home/projects.html","webpack://fab-manager/./app/frontend/templates/home/twitter.html","webpack://fab-manager/./app/frontend/templates/machines/edit.html","webpack://fab-manager/./app/frontend/templates/machines/index.html","webpack://fab-manager/./app/frontend/templates/machines/new.html","webpack://fab-manager/./app/frontend/templates/machines/reserve.html","webpack://fab-manager/./app/frontend/templates/machines/show.html","webpack://fab-manager/./app/frontend/templates/members/index.html","webpack://fab-manager/./app/frontend/templates/members/show.html","webpack://fab-manager/./app/frontend/templates/notifications/index.html","webpack://fab-manager/./app/frontend/templates/orders/show.html","webpack://fab-manager/./app/frontend/templates/plans/_plan.html","webpack://fab-manager/./app/frontend/templates/plans/index.html","webpack://fab-manager/./app/frontend/templates/products/show.html","webpack://fab-manager/./app/frontend/templates/profile/_token.html","webpack://fab-manager/./app/frontend/templates/profile/complete.html","webpack://fab-manager/./app/frontend/templates/profile/resend_code_modal.html","webpack://fab-manager/./app/frontend/templates/projects/_form.html","webpack://fab-manager/./app/frontend/templates/projects/edit.html","webpack://fab-manager/./app/frontend/templates/projects/index.html","webpack://fab-manager/./app/frontend/templates/projects/new.html","webpack://fab-manager/./app/frontend/templates/projects/show.html","webpack://fab-manager/./app/frontend/templates/shared/ConfirmationNewModal.html","webpack://fab-manager/./app/frontend/templates/shared/_admin_form.html","webpack://fab-manager/./app/frontend/templates/shared/_cart.html","webpack://fab-manager/./app/frontend/templates/shared/_coupon.html","webpack://fab-manager/./app/frontend/templates/shared/_manager_form.html","webpack://fab-manager/./app/frontend/templates/shared/_member_select.html","webpack://fab-manager/./app/frontend/templates/shared/_partner_new_modal.html","webpack://fab-manager/./app/frontend/templates/shared/_reserve_slot_same_time.html","webpack://fab-manager/./app/frontend/templates/shared/_reserve_slot_tags_mismatch.html","webpack://fab-manager/./app/frontend/templates/shared/_reserve_slot_without_plan.html","webpack://fab-manager/./app/frontend/templates/shared/_social_link.html","webpack://fab-manager/./app/frontend/templates/shared/_user_avatar.html","webpack://fab-manager/./app/frontend/templates/shared/about.html","webpack://fab-manager/./app/frontend/templates/shared/confirm_modal.html","webpack://fab-manager/./app/frontend/templates/shared/confirm_modify_slot_modal.html","webpack://fab-manager/./app/frontend/templates/shared/cookies.html","webpack://fab-manager/./app/frontend/templates/shared/deviseModal.html","webpack://fab-manager/./app/frontend/templates/shared/help_modal.html","webpack://fab-manager/./app/frontend/templates/shared/leftnav.html","webpack://fab-manager/./app/frontend/templates/shared/passwordEditModal.html","webpack://fab-manager/./app/frontend/templates/shared/passwordNewModal.html","webpack://fab-manager/./app/frontend/templates/shared/privacy.html","webpack://fab-manager/./app/frontend/templates/shared/signalAbuseModal.html","webpack://fab-manager/./app/frontend/templates/shared/signupModal.html","webpack://fab-manager/./app/frontend/templates/shared/tour-step-template.html","webpack://fab-manager/./app/frontend/templates/shared/valid_reservation_modal.html","webpack://fab-manager/./app/frontend/templates/spaces/edit.html","webpack://fab-manager/./app/frontend/templates/spaces/index.html","webpack://fab-manager/./app/frontend/templates/spaces/new.html","webpack://fab-manager/./app/frontend/templates/spaces/reserve.html","webpack://fab-manager/./app/frontend/templates/spaces/show.html","webpack://fab-manager/./app/frontend/templates/store/index.html","webpack://fab-manager/./app/frontend/templates/trainings/index.html","webpack://fab-manager/./app/frontend/templates/trainings/reserve.html","webpack://fab-manager/./app/frontend/templates/trainings/show.html","webpack://fab-manager/./app/frontend/templates/wallet/credit_modal.html","webpack://fab-manager/./app/frontend/templates/wallet/show.html","webpack://fab-manager/./app/frontend/templates/wallet/transactions.html"],"sourcesContent":["var map = {\n\t\"./arrow-left\": \"./app/frontend/images/arrow-left.png\",\n\t\"./arrow-left.png\": \"./app/frontend/images/arrow-left.png\",\n\t\"./default-image\": \"./app/frontend/images/default-image.png\",\n\t\"./default-image.png\": \"./app/frontend/images/default-image.png\",\n\t\"./fabmanager-logo\": \"./app/frontend/images/fabmanager-logo.png\",\n\t\"./fabmanager-logo.png\": \"./app/frontend/images/fabmanager-logo.png\",\n\t\"./getnet\": \"./app/frontend/images/getnet.png\",\n\t\"./getnet.png\": \"./app/frontend/images/getnet.png\",\n\t\"./github\": \"./app/frontend/images/github.svg\",\n\t\"./github.svg\": \"./app/frontend/images/github.svg\",\n\t\"./icons\": \"./app/frontend/images/icons.svg\",\n\t\"./icons.svg\": \"./app/frontend/images/icons.svg\",\n\t\"./mastercard\": \"./app/frontend/images/mastercard.png\",\n\t\"./mastercard.png\": \"./app/frontend/images/mastercard.png\",\n\t\"./no_avatar\": \"./app/frontend/images/no_avatar.png\",\n\t\"./no_avatar.png\": \"./app/frontend/images/no_avatar.png\",\n\t\"./no_image\": \"./app/frontend/images/no_image.png\",\n\t\"./no_image.png\": \"./app/frontend/images/no_image.png\",\n\t\"./pagseguro-logo\": \"./app/frontend/images/pagseguro-logo.png\",\n\t\"./pagseguro-logo.png\": \"./app/frontend/images/pagseguro-logo.png\",\n\t\"./payzen-secure\": \"./app/frontend/images/payzen-secure.png\",\n\t\"./payzen-secure.png\": \"./app/frontend/images/payzen-secure.png\",\n\t\"./powered_by_stripe\": \"./app/frontend/images/powered_by_stripe.png\",\n\t\"./powered_by_stripe.png\": \"./app/frontend/images/powered_by_stripe.png\",\n\t\"./security-site\": \"./app/frontend/images/security-site.png\",\n\t\"./security-site.png\": \"./app/frontend/images/security-site.png\",\n\t\"./social-icons\": \"./app/frontend/images/social-icons.svg\",\n\t\"./social-icons.svg\": \"./app/frontend/images/social-icons.svg\",\n\t\"./social/dailymotion\": \"./app/frontend/images/social/dailymotion.png\",\n\t\"./social/dailymotion.png\": \"./app/frontend/images/social/dailymotion.png\",\n\t\"./social/echosciences\": \"./app/frontend/images/social/echosciences.png\",\n\t\"./social/echosciences.png\": \"./app/frontend/images/social/echosciences.png\",\n\t\"./visa\": \"./app/frontend/images/visa.png\",\n\t\"./visa.png\": \"./app/frontend/images/visa.png\"\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 = \"./app/frontend/images sync recursive ^\\\\.\\\\/.*$\";","var map = {\n\t\"./accounting/accounting-codes-settings.tsx\": \"./app/frontend/src/javascript/components/accounting/accounting-codes-settings.tsx\",\n\t\"./accounting/advanced-accounting-form.tsx\": \"./app/frontend/src/javascript/components/accounting/advanced-accounting-form.tsx\",\n\t\"./angular/switch.ts\": \"./app/frontend/src/javascript/components/angular/switch.ts\",\n\t\"./authentication-provider/boolean-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/boolean-mapping-form.tsx\",\n\t\"./authentication-provider/data-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/data-mapping-form.tsx\",\n\t\"./authentication-provider/database-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/database-form.tsx\",\n\t\"./authentication-provider/date-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/date-mapping-form.tsx\",\n\t\"./authentication-provider/integer-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/integer-mapping-form.tsx\",\n\t\"./authentication-provider/oauth2-data-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/oauth2-data-mapping-form.tsx\",\n\t\"./authentication-provider/oauth2-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx\",\n\t\"./authentication-provider/openid-connect-data-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/openid-connect-data-mapping-form.tsx\",\n\t\"./authentication-provider/openid-connect-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/openid-connect-form.tsx\",\n\t\"./authentication-provider/provider-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/provider-form.tsx\",\n\t\"./authentication-provider/string-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/string-mapping-form.tsx\",\n\t\"./authentication-provider/type-mapping-modal.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/type-mapping-modal.tsx\",\n\t\"./base/accordion-item.tsx\": \"./app/frontend/src/javascript/components/base/accordion-item.tsx\",\n\t\"./base/destroy-button.tsx\": \"./app/frontend/src/javascript/components/base/destroy-button.tsx\",\n\t\"./base/edit-destroy-buttons.tsx\": \"./app/frontend/src/javascript/components/base/edit-destroy-buttons.tsx\",\n\t\"./base/error-boundary.tsx\": \"./app/frontend/src/javascript/components/base/error-boundary.tsx\",\n\t\"./base/fab-alert.tsx\": \"./app/frontend/src/javascript/components/base/fab-alert.tsx\",\n\t\"./base/fab-button.tsx\": \"./app/frontend/src/javascript/components/base/fab-button.tsx\",\n\t\"./base/fab-input.tsx\": \"./app/frontend/src/javascript/components/base/fab-input.tsx\",\n\t\"./base/fab-modal.tsx\": \"./app/frontend/src/javascript/components/base/fab-modal.tsx\",\n\t\"./base/fab-output-copy.tsx\": \"./app/frontend/src/javascript/components/base/fab-output-copy.tsx\",\n\t\"./base/fab-pagination.tsx\": \"./app/frontend/src/javascript/components/base/fab-pagination.tsx\",\n\t\"./base/fab-panel.tsx\": \"./app/frontend/src/javascript/components/base/fab-panel.tsx\",\n\t\"./base/fab-popover.tsx\": \"./app/frontend/src/javascript/components/base/fab-popover.tsx\",\n\t\"./base/fab-state-label.tsx\": \"./app/frontend/src/javascript/components/base/fab-state-label.tsx\",\n\t\"./base/fab-tabs.tsx\": \"./app/frontend/src/javascript/components/base/fab-tabs.tsx\",\n\t\"./base/html-translate.tsx\": \"./app/frontend/src/javascript/components/base/html-translate.tsx\",\n\t\"./base/labelled-input.tsx\": \"./app/frontend/src/javascript/components/base/labelled-input.tsx\",\n\t\"./base/loader.tsx\": \"./app/frontend/src/javascript/components/base/loader.tsx\",\n\t\"./base/text-editor/fab-text-editor.tsx\": \"./app/frontend/src/javascript/components/base/text-editor/fab-text-editor.tsx\",\n\t\"./base/text-editor/iframe.tsx\": \"./app/frontend/src/javascript/components/base/text-editor/iframe.tsx\",\n\t\"./base/text-editor/menu-bar.tsx\": \"./app/frontend/src/javascript/components/base/text-editor/menu-bar.tsx\",\n\t\"./cart/abstract-item.tsx\": \"./app/frontend/src/javascript/components/cart/abstract-item.tsx\",\n\t\"./cart/cart-button.tsx\": \"./app/frontend/src/javascript/components/cart/cart-button.tsx\",\n\t\"./cart/cart-order-product.tsx\": \"./app/frontend/src/javascript/components/cart/cart-order-product.tsx\",\n\t\"./cart/cart-order-reservation.tsx\": \"./app/frontend/src/javascript/components/cart/cart-order-reservation.tsx\",\n\t\"./cart/store-cart.tsx\": \"./app/frontend/src/javascript/components/cart/store-cart.tsx\",\n\t\"./coupon/coupon-input.tsx\": \"./app/frontend/src/javascript/components/coupon/coupon-input.tsx\",\n\t\"./dashboard/orders/orders-dashboard.tsx\": \"./app/frontend/src/javascript/components/dashboard/orders/orders-dashboard.tsx\",\n\t\"./dashboard/reservations/credits-panel.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/credits-panel.tsx\",\n\t\"./dashboard/reservations/prepaid-packs-panel.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/prepaid-packs-panel.tsx\",\n\t\"./dashboard/reservations/reservations-dashboard.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/reservations-dashboard.tsx\",\n\t\"./dashboard/reservations/reservations-panel.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/reservations-panel.tsx\",\n\t\"./document-filters.tsx\": \"./app/frontend/src/javascript/components/document-filters.tsx\",\n\t\"./editorial-block/editorial-block-form.tsx\": \"./app/frontend/src/javascript/components/editorial-block/editorial-block-form.tsx\",\n\t\"./editorial-block/editorial-block.tsx\": \"./app/frontend/src/javascript/components/editorial-block/editorial-block.tsx\",\n\t\"./events/event-card.tsx\": \"./app/frontend/src/javascript/components/events/event-card.tsx\",\n\t\"./events/event-form.tsx\": \"./app/frontend/src/javascript/components/events/event-form.tsx\",\n\t\"./events/events-editorial-block.tsx\": \"./app/frontend/src/javascript/components/events/events-editorial-block.tsx\",\n\t\"./events/events-settings.tsx\": \"./app/frontend/src/javascript/components/events/events-settings.tsx\",\n\t\"./events/update-recurrent-modal.tsx\": \"./app/frontend/src/javascript/components/events/update-recurrent-modal.tsx\",\n\t\"./form/abstract-form-item.tsx\": \"./app/frontend/src/javascript/components/form/abstract-form-item.tsx\",\n\t\"./form/form-checklist.tsx\": \"./app/frontend/src/javascript/components/form/form-checklist.tsx\",\n\t\"./form/form-file-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-file-upload.tsx\",\n\t\"./form/form-image-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-image-upload.tsx\",\n\t\"./form/form-input.tsx\": \"./app/frontend/src/javascript/components/form/form-input.tsx\",\n\t\"./form/form-multi-file-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-multi-file-upload.tsx\",\n\t\"./form/form-multi-image-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-multi-image-upload.tsx\",\n\t\"./form/form-multi-select.tsx\": \"./app/frontend/src/javascript/components/form/form-multi-select.tsx\",\n\t\"./form/form-rich-text.tsx\": \"./app/frontend/src/javascript/components/form/form-rich-text.tsx\",\n\t\"./form/form-select.tsx\": \"./app/frontend/src/javascript/components/form/form-select.tsx\",\n\t\"./form/form-switch.tsx\": \"./app/frontend/src/javascript/components/form/form-switch.tsx\",\n\t\"./form/form-unsaved-list.tsx\": \"./app/frontend/src/javascript/components/form/form-unsaved-list.tsx\",\n\t\"./form/unsaved-form-alert.tsx\": \"./app/frontend/src/javascript/components/form/unsaved-form-alert.tsx\",\n\t\"./group/change-group.tsx\": \"./app/frontend/src/javascript/components/group/change-group.tsx\",\n\t\"./invoices/invoices-settings-panel.tsx\": \"./app/frontend/src/javascript/components/invoices/invoices-settings-panel.tsx\",\n\t\"./invoices/vat-settings-modal.tsx\": \"./app/frontend/src/javascript/components/invoices/vat-settings-modal.tsx\",\n\t\"./machines/machine-card.tsx\": \"./app/frontend/src/javascript/components/machines/machine-card.tsx\",\n\t\"./machines/machine-categories-list.tsx\": \"./app/frontend/src/javascript/components/machines/machine-categories-list.tsx\",\n\t\"./machines/machine-category-form.tsx\": \"./app/frontend/src/javascript/components/machines/machine-category-form.tsx\",\n\t\"./machines/machine-category-modal.tsx\": \"./app/frontend/src/javascript/components/machines/machine-category-modal.tsx\",\n\t\"./machines/machine-form.tsx\": \"./app/frontend/src/javascript/components/machines/machine-form.tsx\",\n\t\"./machines/machines-editorial-block.tsx\": \"./app/frontend/src/javascript/components/machines/machines-editorial-block.tsx\",\n\t\"./machines/machines-filters.tsx\": \"./app/frontend/src/javascript/components/machines/machines-filters.tsx\",\n\t\"./machines/machines-list.tsx\": \"./app/frontend/src/javascript/components/machines/machines-list.tsx\",\n\t\"./machines/machines-settings.tsx\": \"./app/frontend/src/javascript/components/machines/machines-settings.tsx\",\n\t\"./machines/pending-training-modal.tsx\": \"./app/frontend/src/javascript/components/machines/pending-training-modal.tsx\",\n\t\"./machines/required-training-modal.tsx\": \"./app/frontend/src/javascript/components/machines/required-training-modal.tsx\",\n\t\"./machines/reserve-button.tsx\": \"./app/frontend/src/javascript/components/machines/reserve-button.tsx\",\n\t\"./notifications/notification-form.tsx\": \"./app/frontend/src/javascript/components/notifications/notification-form.tsx\",\n\t\"./notifications/notification-inline.tsx\": \"./app/frontend/src/javascript/components/notifications/notification-inline.tsx\",\n\t\"./notifications/notifications-category.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-category.tsx\",\n\t\"./notifications/notifications-center.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-center.tsx\",\n\t\"./notifications/notifications-list.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-list.tsx\",\n\t\"./notifications/notifications-settings.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-settings.tsx\",\n\t\"./payment-schedule/payment-schedule-item-actions.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedule-item-actions.tsx\",\n\t\"./payment-schedule/payment-schedule-summary.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedule-summary.tsx\",\n\t\"./payment-schedule/payment-schedules-dashboard.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx\",\n\t\"./payment-schedule/payment-schedules-list.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedules-list.tsx\",\n\t\"./payment-schedule/payment-schedules-table.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedules-table.tsx\",\n\t\"./payment-schedule/select-schedule.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/select-schedule.tsx\",\n\t\"./payment-schedule/update-payment-mean-modal.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/update-payment-mean-modal.tsx\",\n\t\"./payment/abstract-payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx\",\n\t\"./payment/card-payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/card-payment-modal.tsx\",\n\t\"./payment/getnet/getnet-form.tsx\": \"./app/frontend/src/javascript/components/payment/getnet/getnet-form.tsx\",\n\t\"./payment/getnet/getnet-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/getnet/getnet-keys-form.tsx\",\n\t\"./payment/getnet/getnet-modal.tsx\": \"./app/frontend/src/javascript/components/payment/getnet/getnet-modal.tsx\",\n\t\"./payment/local-payment/local-payment-form.tsx\": \"./app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx\",\n\t\"./payment/local-payment/local-payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx\",\n\t\"./payment/pagseguro/pagseguro-form.tsx\": \"./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-form.tsx\",\n\t\"./payment/pagseguro/pagseguro-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-keys-form.tsx\",\n\t\"./payment/pagseguro/pagseguro-modal.tsx\": \"./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-modal.tsx\",\n\t\"./payment/payzen/payzen-card-update-modal.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-card-update-modal.tsx\",\n\t\"./payment/payzen/payzen-form.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx\",\n\t\"./payment/payzen/payzen-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-keys-form.tsx\",\n\t\"./payment/payzen/payzen-modal.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-modal.tsx\",\n\t\"./payment/payzen/payzen-settings.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-settings.tsx\",\n\t\"./payment/select-gateway-modal.tsx\": \"./app/frontend/src/javascript/components/payment/select-gateway-modal.tsx\",\n\t\"./payment/stripe/payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/payment-modal.tsx\",\n\t\"./payment/stripe/stripe-card-update-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-card-update-modal.tsx\",\n\t\"./payment/stripe/stripe-card-update.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-card-update.tsx\",\n\t\"./payment/stripe/stripe-confirm-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-confirm-modal.tsx\",\n\t\"./payment/stripe/stripe-confirm.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-confirm.tsx\",\n\t\"./payment/stripe/stripe-elements.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-elements.tsx\",\n\t\"./payment/stripe/stripe-form.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx\",\n\t\"./payment/stripe/stripe-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-keys-form.tsx\",\n\t\"./payment/stripe/stripe-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx\",\n\t\"./payment/update-card-modal.tsx\": \"./app/frontend/src/javascript/components/payment/update-card-modal.tsx\",\n\t\"./payment/wallet-info.tsx\": \"./app/frontend/src/javascript/components/payment/wallet-info.tsx\",\n\t\"./plan-categories/delete-plan-category.tsx\": \"./app/frontend/src/javascript/components/plan-categories/delete-plan-category.tsx\",\n\t\"./plan-categories/manage-plan-category.tsx\": \"./app/frontend/src/javascript/components/plan-categories/manage-plan-category.tsx\",\n\t\"./plan-categories/plan-categories-list.tsx\": \"./app/frontend/src/javascript/components/plan-categories/plan-categories-list.tsx\",\n\t\"./plan-categories/plan-category-form.tsx\": \"./app/frontend/src/javascript/components/plan-categories/plan-category-form.tsx\",\n\t\"./plans/partner-modal.tsx\": \"./app/frontend/src/javascript/components/plans/partner-modal.tsx\",\n\t\"./plans/plan-card.tsx\": \"./app/frontend/src/javascript/components/plans/plan-card.tsx\",\n\t\"./plans/plan-form.tsx\": \"./app/frontend/src/javascript/components/plans/plan-form.tsx\",\n\t\"./plans/plan-limit-form.tsx\": \"./app/frontend/src/javascript/components/plans/plan-limit-form.tsx\",\n\t\"./plans/plan-limit-modal.tsx\": \"./app/frontend/src/javascript/components/plans/plan-limit-modal.tsx\",\n\t\"./plans/plan-pricing-form.tsx\": \"./app/frontend/src/javascript/components/plans/plan-pricing-form.tsx\",\n\t\"./plans/plans-filter.tsx\": \"./app/frontend/src/javascript/components/plans/plans-filter.tsx\",\n\t\"./plans/plans-list.tsx\": \"./app/frontend/src/javascript/components/plans/plans-list.tsx\",\n\t\"./prepaid-packs/packs-summary.tsx\": \"./app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx\",\n\t\"./prepaid-packs/propose-packs-modal.tsx\": \"./app/frontend/src/javascript/components/prepaid-packs/propose-packs-modal.tsx\",\n\t\"./pricing/editable-price.tsx\": \"./app/frontend/src/javascript/components/pricing/editable-price.tsx\",\n\t\"./pricing/machines/configure-packs-button.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/configure-packs-button.tsx\",\n\t\"./pricing/machines/create-pack.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/create-pack.tsx\",\n\t\"./pricing/machines/edit-pack.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/edit-pack.tsx\",\n\t\"./pricing/machines/machines-pricing.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/machines-pricing.tsx\",\n\t\"./pricing/machines/pack-form.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/pack-form.tsx\",\n\t\"./pricing/spaces/configure-extended-prices-button.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/configure-extended-prices-button.tsx\",\n\t\"./pricing/spaces/create-extended-price.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/create-extended-price.tsx\",\n\t\"./pricing/spaces/delete-extended-price.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx\",\n\t\"./pricing/spaces/edit-extended-price.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/edit-extended-price.tsx\",\n\t\"./pricing/spaces/extended-price-form.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx\",\n\t\"./pricing/spaces/spaces-pricing.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/spaces-pricing.tsx\",\n\t\"./profile-completion/completion-header-info.tsx\": \"./app/frontend/src/javascript/components/profile-completion/completion-header-info.tsx\",\n\t\"./profile-completion/profile-form-option.tsx\": \"./app/frontend/src/javascript/components/profile-completion/profile-form-option.tsx\",\n\t\"./profile-custom-fields/profile-custom-fields-list.tsx\": \"./app/frontend/src/javascript/components/profile-custom-fields/profile-custom-fields-list.tsx\",\n\t\"./projects/projects-setting-option-form.tsx\": \"./app/frontend/src/javascript/components/projects/projects-setting-option-form.tsx\",\n\t\"./projects/projects-setting-option.tsx\": \"./app/frontend/src/javascript/components/projects/projects-setting-option.tsx\",\n\t\"./projects/projects-setting.tsx\": \"./app/frontend/src/javascript/components/projects/projects-setting.tsx\",\n\t\"./projects/status/status-filter.tsx\": \"./app/frontend/src/javascript/components/projects/status/status-filter.tsx\",\n\t\"./projects/status/status-settings.tsx\": \"./app/frontend/src/javascript/components/projects/status/status-settings.tsx\",\n\t\"./reservations/ongoing-reservation-panel.tsx\": \"./app/frontend/src/javascript/components/reservations/ongoing-reservation-panel.tsx\",\n\t\"./reservations/reservations-summary.tsx\": \"./app/frontend/src/javascript/components/reservations/reservations-summary.tsx\",\n\t\"./settings/boolean-setting.tsx\": \"./app/frontend/src/javascript/components/settings/boolean-setting.tsx\",\n\t\"./settings/check-list-setting.tsx\": \"./app/frontend/src/javascript/components/settings/check-list-setting.tsx\",\n\t\"./settings/setting-history-modal.tsx\": \"./app/frontend/src/javascript/components/settings/setting-history-modal.tsx\",\n\t\"./settings/user-validation-setting.tsx\": \"./app/frontend/src/javascript/components/settings/user-validation-setting.tsx\",\n\t\"./socials/edit-socials.tsx\": \"./app/frontend/src/javascript/components/socials/edit-socials.tsx\",\n\t\"./socials/fab-socials.tsx\": \"./app/frontend/src/javascript/components/socials/fab-socials.tsx\",\n\t\"./spaces/space-form.tsx\": \"./app/frontend/src/javascript/components/spaces/space-form.tsx\",\n\t\"./store/categories/manage-product-category.tsx\": \"./app/frontend/src/javascript/components/store/categories/manage-product-category.tsx\",\n\t\"./store/categories/product-categories-item.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-categories-item.tsx\",\n\t\"./store/categories/product-categories-tree.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-categories-tree.tsx\",\n\t\"./store/categories/product-categories.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-categories.tsx\",\n\t\"./store/categories/product-category-form.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-category-form.tsx\",\n\t\"./store/clone-product-modal.tsx\": \"./app/frontend/src/javascript/components/store/clone-product-modal.tsx\",\n\t\"./store/edit-product.tsx\": \"./app/frontend/src/javascript/components/store/edit-product.tsx\",\n\t\"./store/filters/active-filters-tags.tsx\": \"./app/frontend/src/javascript/components/store/filters/active-filters-tags.tsx\",\n\t\"./store/filters/categories-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/categories-filter.tsx\",\n\t\"./store/filters/keyword-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/keyword-filter.tsx\",\n\t\"./store/filters/machines-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/machines-filter.tsx\",\n\t\"./store/filters/stock-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/stock-filter.tsx\",\n\t\"./store/new-product.tsx\": \"./app/frontend/src/javascript/components/store/new-product.tsx\",\n\t\"./store/order-actions.tsx\": \"./app/frontend/src/javascript/components/store/order-actions.tsx\",\n\t\"./store/order-item.tsx\": \"./app/frontend/src/javascript/components/store/order-item.tsx\",\n\t\"./store/orders.tsx\": \"./app/frontend/src/javascript/components/store/orders.tsx\",\n\t\"./store/product-form.tsx\": \"./app/frontend/src/javascript/components/store/product-form.tsx\",\n\t\"./store/product-item.tsx\": \"./app/frontend/src/javascript/components/store/product-item.tsx\",\n\t\"./store/product-price.tsx\": \"./app/frontend/src/javascript/components/store/product-price.tsx\",\n\t\"./store/product-stock-form.tsx\": \"./app/frontend/src/javascript/components/store/product-stock-form.tsx\",\n\t\"./store/product-stock-modal.tsx\": \"./app/frontend/src/javascript/components/store/product-stock-modal.tsx\",\n\t\"./store/products.tsx\": \"./app/frontend/src/javascript/components/store/products.tsx\",\n\t\"./store/show-order.tsx\": \"./app/frontend/src/javascript/components/store/show-order.tsx\",\n\t\"./store/store-list-header.tsx\": \"./app/frontend/src/javascript/components/store/store-list-header.tsx\",\n\t\"./store/store-product-item.tsx\": \"./app/frontend/src/javascript/components/store/store-product-item.tsx\",\n\t\"./store/store-product.tsx\": \"./app/frontend/src/javascript/components/store/store-product.tsx\",\n\t\"./store/store-settings.tsx\": \"./app/frontend/src/javascript/components/store/store-settings.tsx\",\n\t\"./store/store.tsx\": \"./app/frontend/src/javascript/components/store/store.tsx\",\n\t\"./subscriptions/cancel-subscription-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/cancel-subscription-modal.tsx\",\n\t\"./subscriptions/free-extend-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/free-extend-modal.tsx\",\n\t\"./subscriptions/renew-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/renew-modal.tsx\",\n\t\"./subscriptions/subscribe-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/subscribe-modal.tsx\",\n\t\"./supporting-documents/delete-supporting-documents-type-modal.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/delete-supporting-documents-type-modal.tsx\",\n\t\"./supporting-documents/supporting-documents-files.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-files.tsx\",\n\t\"./supporting-documents/supporting-documents-refusal-form.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-form.tsx\",\n\t\"./supporting-documents/supporting-documents-refusal-modal.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx\",\n\t\"./supporting-documents/supporting-documents-type-form.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-type-form.tsx\",\n\t\"./supporting-documents/supporting-documents-type-modal.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-type-modal.tsx\",\n\t\"./supporting-documents/supporting-documents-types-list.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-types-list.tsx\",\n\t\"./supporting-documents/supporting-documents-validation.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-validation.tsx\",\n\t\"./trainings/training-editorial-block.tsx\": \"./app/frontend/src/javascript/components/trainings/training-editorial-block.tsx\",\n\t\"./trainings/training-form.tsx\": \"./app/frontend/src/javascript/components/trainings/training-form.tsx\",\n\t\"./trainings/trainings-settings.tsx\": \"./app/frontend/src/javascript/components/trainings/trainings-settings.tsx\",\n\t\"./trainings/trainings.tsx\": \"./app/frontend/src/javascript/components/trainings/trainings.tsx\",\n\t\"./user/avatar-input.tsx\": \"./app/frontend/src/javascript/components/user/avatar-input.tsx\",\n\t\"./user/avatar.tsx\": \"./app/frontend/src/javascript/components/user/avatar.tsx\",\n\t\"./user/change-password.tsx\": \"./app/frontend/src/javascript/components/user/change-password.tsx\",\n\t\"./user/change-role-modal.tsx\": \"./app/frontend/src/javascript/components/user/change-role-modal.tsx\",\n\t\"./user/gender-input.tsx\": \"./app/frontend/src/javascript/components/user/gender-input.tsx\",\n\t\"./user/member-select.tsx\": \"./app/frontend/src/javascript/components/user/member-select.tsx\",\n\t\"./user/password-input.tsx\": \"./app/frontend/src/javascript/components/user/password-input.tsx\",\n\t\"./user/password-strength.tsx\": \"./app/frontend/src/javascript/components/user/password-strength.tsx\",\n\t\"./user/user-profile-form.tsx\": \"./app/frontend/src/javascript/components/user/user-profile-form.tsx\",\n\t\"./user/user-validation.tsx\": \"./app/frontend/src/javascript/components/user/user-validation.tsx\",\n\t\"src/javascript/components/accounting/accounting-codes-settings.tsx\": \"./app/frontend/src/javascript/components/accounting/accounting-codes-settings.tsx\",\n\t\"src/javascript/components/accounting/advanced-accounting-form.tsx\": \"./app/frontend/src/javascript/components/accounting/advanced-accounting-form.tsx\",\n\t\"src/javascript/components/angular/switch.ts\": \"./app/frontend/src/javascript/components/angular/switch.ts\",\n\t\"src/javascript/components/authentication-provider/boolean-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/boolean-mapping-form.tsx\",\n\t\"src/javascript/components/authentication-provider/data-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/data-mapping-form.tsx\",\n\t\"src/javascript/components/authentication-provider/database-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/database-form.tsx\",\n\t\"src/javascript/components/authentication-provider/date-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/date-mapping-form.tsx\",\n\t\"src/javascript/components/authentication-provider/integer-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/integer-mapping-form.tsx\",\n\t\"src/javascript/components/authentication-provider/oauth2-data-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/oauth2-data-mapping-form.tsx\",\n\t\"src/javascript/components/authentication-provider/oauth2-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx\",\n\t\"src/javascript/components/authentication-provider/openid-connect-data-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/openid-connect-data-mapping-form.tsx\",\n\t\"src/javascript/components/authentication-provider/openid-connect-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/openid-connect-form.tsx\",\n\t\"src/javascript/components/authentication-provider/provider-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/provider-form.tsx\",\n\t\"src/javascript/components/authentication-provider/string-mapping-form.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/string-mapping-form.tsx\",\n\t\"src/javascript/components/authentication-provider/type-mapping-modal.tsx\": \"./app/frontend/src/javascript/components/authentication-provider/type-mapping-modal.tsx\",\n\t\"src/javascript/components/base/accordion-item.tsx\": \"./app/frontend/src/javascript/components/base/accordion-item.tsx\",\n\t\"src/javascript/components/base/destroy-button.tsx\": \"./app/frontend/src/javascript/components/base/destroy-button.tsx\",\n\t\"src/javascript/components/base/edit-destroy-buttons.tsx\": \"./app/frontend/src/javascript/components/base/edit-destroy-buttons.tsx\",\n\t\"src/javascript/components/base/error-boundary.tsx\": \"./app/frontend/src/javascript/components/base/error-boundary.tsx\",\n\t\"src/javascript/components/base/fab-alert.tsx\": \"./app/frontend/src/javascript/components/base/fab-alert.tsx\",\n\t\"src/javascript/components/base/fab-button.tsx\": \"./app/frontend/src/javascript/components/base/fab-button.tsx\",\n\t\"src/javascript/components/base/fab-input.tsx\": \"./app/frontend/src/javascript/components/base/fab-input.tsx\",\n\t\"src/javascript/components/base/fab-modal.tsx\": \"./app/frontend/src/javascript/components/base/fab-modal.tsx\",\n\t\"src/javascript/components/base/fab-output-copy.tsx\": \"./app/frontend/src/javascript/components/base/fab-output-copy.tsx\",\n\t\"src/javascript/components/base/fab-pagination.tsx\": \"./app/frontend/src/javascript/components/base/fab-pagination.tsx\",\n\t\"src/javascript/components/base/fab-panel.tsx\": \"./app/frontend/src/javascript/components/base/fab-panel.tsx\",\n\t\"src/javascript/components/base/fab-popover.tsx\": \"./app/frontend/src/javascript/components/base/fab-popover.tsx\",\n\t\"src/javascript/components/base/fab-state-label.tsx\": \"./app/frontend/src/javascript/components/base/fab-state-label.tsx\",\n\t\"src/javascript/components/base/fab-tabs.tsx\": \"./app/frontend/src/javascript/components/base/fab-tabs.tsx\",\n\t\"src/javascript/components/base/html-translate.tsx\": \"./app/frontend/src/javascript/components/base/html-translate.tsx\",\n\t\"src/javascript/components/base/labelled-input.tsx\": \"./app/frontend/src/javascript/components/base/labelled-input.tsx\",\n\t\"src/javascript/components/base/loader.tsx\": \"./app/frontend/src/javascript/components/base/loader.tsx\",\n\t\"src/javascript/components/base/text-editor/fab-text-editor.tsx\": \"./app/frontend/src/javascript/components/base/text-editor/fab-text-editor.tsx\",\n\t\"src/javascript/components/base/text-editor/iframe.tsx\": \"./app/frontend/src/javascript/components/base/text-editor/iframe.tsx\",\n\t\"src/javascript/components/base/text-editor/menu-bar.tsx\": \"./app/frontend/src/javascript/components/base/text-editor/menu-bar.tsx\",\n\t\"src/javascript/components/cart/abstract-item.tsx\": \"./app/frontend/src/javascript/components/cart/abstract-item.tsx\",\n\t\"src/javascript/components/cart/cart-button.tsx\": \"./app/frontend/src/javascript/components/cart/cart-button.tsx\",\n\t\"src/javascript/components/cart/cart-order-product.tsx\": \"./app/frontend/src/javascript/components/cart/cart-order-product.tsx\",\n\t\"src/javascript/components/cart/cart-order-reservation.tsx\": \"./app/frontend/src/javascript/components/cart/cart-order-reservation.tsx\",\n\t\"src/javascript/components/cart/store-cart.tsx\": \"./app/frontend/src/javascript/components/cart/store-cart.tsx\",\n\t\"src/javascript/components/coupon/coupon-input.tsx\": \"./app/frontend/src/javascript/components/coupon/coupon-input.tsx\",\n\t\"src/javascript/components/dashboard/orders/orders-dashboard.tsx\": \"./app/frontend/src/javascript/components/dashboard/orders/orders-dashboard.tsx\",\n\t\"src/javascript/components/dashboard/reservations/credits-panel.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/credits-panel.tsx\",\n\t\"src/javascript/components/dashboard/reservations/prepaid-packs-panel.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/prepaid-packs-panel.tsx\",\n\t\"src/javascript/components/dashboard/reservations/reservations-dashboard.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/reservations-dashboard.tsx\",\n\t\"src/javascript/components/dashboard/reservations/reservations-panel.tsx\": \"./app/frontend/src/javascript/components/dashboard/reservations/reservations-panel.tsx\",\n\t\"src/javascript/components/document-filters.tsx\": \"./app/frontend/src/javascript/components/document-filters.tsx\",\n\t\"src/javascript/components/editorial-block/editorial-block-form.tsx\": \"./app/frontend/src/javascript/components/editorial-block/editorial-block-form.tsx\",\n\t\"src/javascript/components/editorial-block/editorial-block.tsx\": \"./app/frontend/src/javascript/components/editorial-block/editorial-block.tsx\",\n\t\"src/javascript/components/events/event-card.tsx\": \"./app/frontend/src/javascript/components/events/event-card.tsx\",\n\t\"src/javascript/components/events/event-form.tsx\": \"./app/frontend/src/javascript/components/events/event-form.tsx\",\n\t\"src/javascript/components/events/events-editorial-block.tsx\": \"./app/frontend/src/javascript/components/events/events-editorial-block.tsx\",\n\t\"src/javascript/components/events/events-settings.tsx\": \"./app/frontend/src/javascript/components/events/events-settings.tsx\",\n\t\"src/javascript/components/events/update-recurrent-modal.tsx\": \"./app/frontend/src/javascript/components/events/update-recurrent-modal.tsx\",\n\t\"src/javascript/components/form/abstract-form-item.tsx\": \"./app/frontend/src/javascript/components/form/abstract-form-item.tsx\",\n\t\"src/javascript/components/form/form-checklist.tsx\": \"./app/frontend/src/javascript/components/form/form-checklist.tsx\",\n\t\"src/javascript/components/form/form-file-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-file-upload.tsx\",\n\t\"src/javascript/components/form/form-image-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-image-upload.tsx\",\n\t\"src/javascript/components/form/form-input.tsx\": \"./app/frontend/src/javascript/components/form/form-input.tsx\",\n\t\"src/javascript/components/form/form-multi-file-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-multi-file-upload.tsx\",\n\t\"src/javascript/components/form/form-multi-image-upload.tsx\": \"./app/frontend/src/javascript/components/form/form-multi-image-upload.tsx\",\n\t\"src/javascript/components/form/form-multi-select.tsx\": \"./app/frontend/src/javascript/components/form/form-multi-select.tsx\",\n\t\"src/javascript/components/form/form-rich-text.tsx\": \"./app/frontend/src/javascript/components/form/form-rich-text.tsx\",\n\t\"src/javascript/components/form/form-select.tsx\": \"./app/frontend/src/javascript/components/form/form-select.tsx\",\n\t\"src/javascript/components/form/form-switch.tsx\": \"./app/frontend/src/javascript/components/form/form-switch.tsx\",\n\t\"src/javascript/components/form/form-unsaved-list.tsx\": \"./app/frontend/src/javascript/components/form/form-unsaved-list.tsx\",\n\t\"src/javascript/components/form/unsaved-form-alert.tsx\": \"./app/frontend/src/javascript/components/form/unsaved-form-alert.tsx\",\n\t\"src/javascript/components/group/change-group.tsx\": \"./app/frontend/src/javascript/components/group/change-group.tsx\",\n\t\"src/javascript/components/invoices/invoices-settings-panel.tsx\": \"./app/frontend/src/javascript/components/invoices/invoices-settings-panel.tsx\",\n\t\"src/javascript/components/invoices/vat-settings-modal.tsx\": \"./app/frontend/src/javascript/components/invoices/vat-settings-modal.tsx\",\n\t\"src/javascript/components/machines/machine-card.tsx\": \"./app/frontend/src/javascript/components/machines/machine-card.tsx\",\n\t\"src/javascript/components/machines/machine-categories-list.tsx\": \"./app/frontend/src/javascript/components/machines/machine-categories-list.tsx\",\n\t\"src/javascript/components/machines/machine-category-form.tsx\": \"./app/frontend/src/javascript/components/machines/machine-category-form.tsx\",\n\t\"src/javascript/components/machines/machine-category-modal.tsx\": \"./app/frontend/src/javascript/components/machines/machine-category-modal.tsx\",\n\t\"src/javascript/components/machines/machine-form.tsx\": \"./app/frontend/src/javascript/components/machines/machine-form.tsx\",\n\t\"src/javascript/components/machines/machines-editorial-block.tsx\": \"./app/frontend/src/javascript/components/machines/machines-editorial-block.tsx\",\n\t\"src/javascript/components/machines/machines-filters.tsx\": \"./app/frontend/src/javascript/components/machines/machines-filters.tsx\",\n\t\"src/javascript/components/machines/machines-list.tsx\": \"./app/frontend/src/javascript/components/machines/machines-list.tsx\",\n\t\"src/javascript/components/machines/machines-settings.tsx\": \"./app/frontend/src/javascript/components/machines/machines-settings.tsx\",\n\t\"src/javascript/components/machines/pending-training-modal.tsx\": \"./app/frontend/src/javascript/components/machines/pending-training-modal.tsx\",\n\t\"src/javascript/components/machines/required-training-modal.tsx\": \"./app/frontend/src/javascript/components/machines/required-training-modal.tsx\",\n\t\"src/javascript/components/machines/reserve-button.tsx\": \"./app/frontend/src/javascript/components/machines/reserve-button.tsx\",\n\t\"src/javascript/components/notifications/notification-form.tsx\": \"./app/frontend/src/javascript/components/notifications/notification-form.tsx\",\n\t\"src/javascript/components/notifications/notification-inline.tsx\": \"./app/frontend/src/javascript/components/notifications/notification-inline.tsx\",\n\t\"src/javascript/components/notifications/notifications-category.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-category.tsx\",\n\t\"src/javascript/components/notifications/notifications-center.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-center.tsx\",\n\t\"src/javascript/components/notifications/notifications-list.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-list.tsx\",\n\t\"src/javascript/components/notifications/notifications-settings.tsx\": \"./app/frontend/src/javascript/components/notifications/notifications-settings.tsx\",\n\t\"src/javascript/components/payment-schedule/payment-schedule-item-actions.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedule-item-actions.tsx\",\n\t\"src/javascript/components/payment-schedule/payment-schedule-summary.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedule-summary.tsx\",\n\t\"src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedules-dashboard.tsx\",\n\t\"src/javascript/components/payment-schedule/payment-schedules-list.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedules-list.tsx\",\n\t\"src/javascript/components/payment-schedule/payment-schedules-table.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/payment-schedules-table.tsx\",\n\t\"src/javascript/components/payment-schedule/select-schedule.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/select-schedule.tsx\",\n\t\"src/javascript/components/payment-schedule/update-payment-mean-modal.tsx\": \"./app/frontend/src/javascript/components/payment-schedule/update-payment-mean-modal.tsx\",\n\t\"src/javascript/components/payment/abstract-payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/abstract-payment-modal.tsx\",\n\t\"src/javascript/components/payment/card-payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/card-payment-modal.tsx\",\n\t\"src/javascript/components/payment/getnet/getnet-form.tsx\": \"./app/frontend/src/javascript/components/payment/getnet/getnet-form.tsx\",\n\t\"src/javascript/components/payment/getnet/getnet-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/getnet/getnet-keys-form.tsx\",\n\t\"src/javascript/components/payment/getnet/getnet-modal.tsx\": \"./app/frontend/src/javascript/components/payment/getnet/getnet-modal.tsx\",\n\t\"src/javascript/components/payment/local-payment/local-payment-form.tsx\": \"./app/frontend/src/javascript/components/payment/local-payment/local-payment-form.tsx\",\n\t\"src/javascript/components/payment/local-payment/local-payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/local-payment/local-payment-modal.tsx\",\n\t\"src/javascript/components/payment/pagseguro/pagseguro-form.tsx\": \"./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-form.tsx\",\n\t\"src/javascript/components/payment/pagseguro/pagseguro-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-keys-form.tsx\",\n\t\"src/javascript/components/payment/pagseguro/pagseguro-modal.tsx\": \"./app/frontend/src/javascript/components/payment/pagseguro/pagseguro-modal.tsx\",\n\t\"src/javascript/components/payment/payzen/payzen-card-update-modal.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-card-update-modal.tsx\",\n\t\"src/javascript/components/payment/payzen/payzen-form.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx\",\n\t\"src/javascript/components/payment/payzen/payzen-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-keys-form.tsx\",\n\t\"src/javascript/components/payment/payzen/payzen-modal.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-modal.tsx\",\n\t\"src/javascript/components/payment/payzen/payzen-settings.tsx\": \"./app/frontend/src/javascript/components/payment/payzen/payzen-settings.tsx\",\n\t\"src/javascript/components/payment/select-gateway-modal.tsx\": \"./app/frontend/src/javascript/components/payment/select-gateway-modal.tsx\",\n\t\"src/javascript/components/payment/stripe/payment-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/payment-modal.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-card-update-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-card-update-modal.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-card-update.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-card-update.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-confirm-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-confirm-modal.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-confirm.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-confirm.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-elements.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-elements.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-form.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-keys-form.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-keys-form.tsx\",\n\t\"src/javascript/components/payment/stripe/stripe-modal.tsx\": \"./app/frontend/src/javascript/components/payment/stripe/stripe-modal.tsx\",\n\t\"src/javascript/components/payment/update-card-modal.tsx\": \"./app/frontend/src/javascript/components/payment/update-card-modal.tsx\",\n\t\"src/javascript/components/payment/wallet-info.tsx\": \"./app/frontend/src/javascript/components/payment/wallet-info.tsx\",\n\t\"src/javascript/components/plan-categories/delete-plan-category.tsx\": \"./app/frontend/src/javascript/components/plan-categories/delete-plan-category.tsx\",\n\t\"src/javascript/components/plan-categories/manage-plan-category.tsx\": \"./app/frontend/src/javascript/components/plan-categories/manage-plan-category.tsx\",\n\t\"src/javascript/components/plan-categories/plan-categories-list.tsx\": \"./app/frontend/src/javascript/components/plan-categories/plan-categories-list.tsx\",\n\t\"src/javascript/components/plan-categories/plan-category-form.tsx\": \"./app/frontend/src/javascript/components/plan-categories/plan-category-form.tsx\",\n\t\"src/javascript/components/plans/partner-modal.tsx\": \"./app/frontend/src/javascript/components/plans/partner-modal.tsx\",\n\t\"src/javascript/components/plans/plan-card.tsx\": \"./app/frontend/src/javascript/components/plans/plan-card.tsx\",\n\t\"src/javascript/components/plans/plan-form.tsx\": \"./app/frontend/src/javascript/components/plans/plan-form.tsx\",\n\t\"src/javascript/components/plans/plan-limit-form.tsx\": \"./app/frontend/src/javascript/components/plans/plan-limit-form.tsx\",\n\t\"src/javascript/components/plans/plan-limit-modal.tsx\": \"./app/frontend/src/javascript/components/plans/plan-limit-modal.tsx\",\n\t\"src/javascript/components/plans/plan-pricing-form.tsx\": \"./app/frontend/src/javascript/components/plans/plan-pricing-form.tsx\",\n\t\"src/javascript/components/plans/plans-filter.tsx\": \"./app/frontend/src/javascript/components/plans/plans-filter.tsx\",\n\t\"src/javascript/components/plans/plans-list.tsx\": \"./app/frontend/src/javascript/components/plans/plans-list.tsx\",\n\t\"src/javascript/components/prepaid-packs/packs-summary.tsx\": \"./app/frontend/src/javascript/components/prepaid-packs/packs-summary.tsx\",\n\t\"src/javascript/components/prepaid-packs/propose-packs-modal.tsx\": \"./app/frontend/src/javascript/components/prepaid-packs/propose-packs-modal.tsx\",\n\t\"src/javascript/components/pricing/editable-price.tsx\": \"./app/frontend/src/javascript/components/pricing/editable-price.tsx\",\n\t\"src/javascript/components/pricing/machines/configure-packs-button.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/configure-packs-button.tsx\",\n\t\"src/javascript/components/pricing/machines/create-pack.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/create-pack.tsx\",\n\t\"src/javascript/components/pricing/machines/edit-pack.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/edit-pack.tsx\",\n\t\"src/javascript/components/pricing/machines/machines-pricing.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/machines-pricing.tsx\",\n\t\"src/javascript/components/pricing/machines/pack-form.tsx\": \"./app/frontend/src/javascript/components/pricing/machines/pack-form.tsx\",\n\t\"src/javascript/components/pricing/spaces/configure-extended-prices-button.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/configure-extended-prices-button.tsx\",\n\t\"src/javascript/components/pricing/spaces/create-extended-price.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/create-extended-price.tsx\",\n\t\"src/javascript/components/pricing/spaces/delete-extended-price.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/delete-extended-price.tsx\",\n\t\"src/javascript/components/pricing/spaces/edit-extended-price.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/edit-extended-price.tsx\",\n\t\"src/javascript/components/pricing/spaces/extended-price-form.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/extended-price-form.tsx\",\n\t\"src/javascript/components/pricing/spaces/spaces-pricing.tsx\": \"./app/frontend/src/javascript/components/pricing/spaces/spaces-pricing.tsx\",\n\t\"src/javascript/components/profile-completion/completion-header-info.tsx\": \"./app/frontend/src/javascript/components/profile-completion/completion-header-info.tsx\",\n\t\"src/javascript/components/profile-completion/profile-form-option.tsx\": \"./app/frontend/src/javascript/components/profile-completion/profile-form-option.tsx\",\n\t\"src/javascript/components/profile-custom-fields/profile-custom-fields-list.tsx\": \"./app/frontend/src/javascript/components/profile-custom-fields/profile-custom-fields-list.tsx\",\n\t\"src/javascript/components/projects/projects-setting-option-form.tsx\": \"./app/frontend/src/javascript/components/projects/projects-setting-option-form.tsx\",\n\t\"src/javascript/components/projects/projects-setting-option.tsx\": \"./app/frontend/src/javascript/components/projects/projects-setting-option.tsx\",\n\t\"src/javascript/components/projects/projects-setting.tsx\": \"./app/frontend/src/javascript/components/projects/projects-setting.tsx\",\n\t\"src/javascript/components/projects/status/status-filter.tsx\": \"./app/frontend/src/javascript/components/projects/status/status-filter.tsx\",\n\t\"src/javascript/components/projects/status/status-settings.tsx\": \"./app/frontend/src/javascript/components/projects/status/status-settings.tsx\",\n\t\"src/javascript/components/reservations/ongoing-reservation-panel.tsx\": \"./app/frontend/src/javascript/components/reservations/ongoing-reservation-panel.tsx\",\n\t\"src/javascript/components/reservations/reservations-summary.tsx\": \"./app/frontend/src/javascript/components/reservations/reservations-summary.tsx\",\n\t\"src/javascript/components/settings/boolean-setting.tsx\": \"./app/frontend/src/javascript/components/settings/boolean-setting.tsx\",\n\t\"src/javascript/components/settings/check-list-setting.tsx\": \"./app/frontend/src/javascript/components/settings/check-list-setting.tsx\",\n\t\"src/javascript/components/settings/setting-history-modal.tsx\": \"./app/frontend/src/javascript/components/settings/setting-history-modal.tsx\",\n\t\"src/javascript/components/settings/user-validation-setting.tsx\": \"./app/frontend/src/javascript/components/settings/user-validation-setting.tsx\",\n\t\"src/javascript/components/socials/edit-socials.tsx\": \"./app/frontend/src/javascript/components/socials/edit-socials.tsx\",\n\t\"src/javascript/components/socials/fab-socials.tsx\": \"./app/frontend/src/javascript/components/socials/fab-socials.tsx\",\n\t\"src/javascript/components/spaces/space-form.tsx\": \"./app/frontend/src/javascript/components/spaces/space-form.tsx\",\n\t\"src/javascript/components/store/categories/manage-product-category.tsx\": \"./app/frontend/src/javascript/components/store/categories/manage-product-category.tsx\",\n\t\"src/javascript/components/store/categories/product-categories-item.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-categories-item.tsx\",\n\t\"src/javascript/components/store/categories/product-categories-tree.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-categories-tree.tsx\",\n\t\"src/javascript/components/store/categories/product-categories.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-categories.tsx\",\n\t\"src/javascript/components/store/categories/product-category-form.tsx\": \"./app/frontend/src/javascript/components/store/categories/product-category-form.tsx\",\n\t\"src/javascript/components/store/clone-product-modal.tsx\": \"./app/frontend/src/javascript/components/store/clone-product-modal.tsx\",\n\t\"src/javascript/components/store/edit-product.tsx\": \"./app/frontend/src/javascript/components/store/edit-product.tsx\",\n\t\"src/javascript/components/store/filters/active-filters-tags.tsx\": \"./app/frontend/src/javascript/components/store/filters/active-filters-tags.tsx\",\n\t\"src/javascript/components/store/filters/categories-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/categories-filter.tsx\",\n\t\"src/javascript/components/store/filters/keyword-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/keyword-filter.tsx\",\n\t\"src/javascript/components/store/filters/machines-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/machines-filter.tsx\",\n\t\"src/javascript/components/store/filters/stock-filter.tsx\": \"./app/frontend/src/javascript/components/store/filters/stock-filter.tsx\",\n\t\"src/javascript/components/store/new-product.tsx\": \"./app/frontend/src/javascript/components/store/new-product.tsx\",\n\t\"src/javascript/components/store/order-actions.tsx\": \"./app/frontend/src/javascript/components/store/order-actions.tsx\",\n\t\"src/javascript/components/store/order-item.tsx\": \"./app/frontend/src/javascript/components/store/order-item.tsx\",\n\t\"src/javascript/components/store/orders.tsx\": \"./app/frontend/src/javascript/components/store/orders.tsx\",\n\t\"src/javascript/components/store/product-form.tsx\": \"./app/frontend/src/javascript/components/store/product-form.tsx\",\n\t\"src/javascript/components/store/product-item.tsx\": \"./app/frontend/src/javascript/components/store/product-item.tsx\",\n\t\"src/javascript/components/store/product-price.tsx\": \"./app/frontend/src/javascript/components/store/product-price.tsx\",\n\t\"src/javascript/components/store/product-stock-form.tsx\": \"./app/frontend/src/javascript/components/store/product-stock-form.tsx\",\n\t\"src/javascript/components/store/product-stock-modal.tsx\": \"./app/frontend/src/javascript/components/store/product-stock-modal.tsx\",\n\t\"src/javascript/components/store/products.tsx\": \"./app/frontend/src/javascript/components/store/products.tsx\",\n\t\"src/javascript/components/store/show-order.tsx\": \"./app/frontend/src/javascript/components/store/show-order.tsx\",\n\t\"src/javascript/components/store/store-list-header.tsx\": \"./app/frontend/src/javascript/components/store/store-list-header.tsx\",\n\t\"src/javascript/components/store/store-product-item.tsx\": \"./app/frontend/src/javascript/components/store/store-product-item.tsx\",\n\t\"src/javascript/components/store/store-product.tsx\": \"./app/frontend/src/javascript/components/store/store-product.tsx\",\n\t\"src/javascript/components/store/store-settings.tsx\": \"./app/frontend/src/javascript/components/store/store-settings.tsx\",\n\t\"src/javascript/components/store/store.tsx\": \"./app/frontend/src/javascript/components/store/store.tsx\",\n\t\"src/javascript/components/subscriptions/cancel-subscription-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/cancel-subscription-modal.tsx\",\n\t\"src/javascript/components/subscriptions/free-extend-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/free-extend-modal.tsx\",\n\t\"src/javascript/components/subscriptions/renew-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/renew-modal.tsx\",\n\t\"src/javascript/components/subscriptions/subscribe-modal.tsx\": \"./app/frontend/src/javascript/components/subscriptions/subscribe-modal.tsx\",\n\t\"src/javascript/components/supporting-documents/delete-supporting-documents-type-modal.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/delete-supporting-documents-type-modal.tsx\",\n\t\"src/javascript/components/supporting-documents/supporting-documents-files.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-files.tsx\",\n\t\"src/javascript/components/supporting-documents/supporting-documents-refusal-form.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-form.tsx\",\n\t\"src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-refusal-modal.tsx\",\n\t\"src/javascript/components/supporting-documents/supporting-documents-type-form.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-type-form.tsx\",\n\t\"src/javascript/components/supporting-documents/supporting-documents-type-modal.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-type-modal.tsx\",\n\t\"src/javascript/components/supporting-documents/supporting-documents-types-list.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-types-list.tsx\",\n\t\"src/javascript/components/supporting-documents/supporting-documents-validation.tsx\": \"./app/frontend/src/javascript/components/supporting-documents/supporting-documents-validation.tsx\",\n\t\"src/javascript/components/trainings/training-editorial-block.tsx\": \"./app/frontend/src/javascript/components/trainings/training-editorial-block.tsx\",\n\t\"src/javascript/components/trainings/training-form.tsx\": \"./app/frontend/src/javascript/components/trainings/training-form.tsx\",\n\t\"src/javascript/components/trainings/trainings-settings.tsx\": \"./app/frontend/src/javascript/components/trainings/trainings-settings.tsx\",\n\t\"src/javascript/components/trainings/trainings.tsx\": \"./app/frontend/src/javascript/components/trainings/trainings.tsx\",\n\t\"src/javascript/components/user/avatar-input.tsx\": \"./app/frontend/src/javascript/components/user/avatar-input.tsx\",\n\t\"src/javascript/components/user/avatar.tsx\": \"./app/frontend/src/javascript/components/user/avatar.tsx\",\n\t\"src/javascript/components/user/change-password.tsx\": \"./app/frontend/src/javascript/components/user/change-password.tsx\",\n\t\"src/javascript/components/user/change-role-modal.tsx\": \"./app/frontend/src/javascript/components/user/change-role-modal.tsx\",\n\t\"src/javascript/components/user/gender-input.tsx\": \"./app/frontend/src/javascript/components/user/gender-input.tsx\",\n\t\"src/javascript/components/user/member-select.tsx\": \"./app/frontend/src/javascript/components/user/member-select.tsx\",\n\t\"src/javascript/components/user/password-input.tsx\": \"./app/frontend/src/javascript/components/user/password-input.tsx\",\n\t\"src/javascript/components/user/password-strength.tsx\": \"./app/frontend/src/javascript/components/user/password-strength.tsx\",\n\t\"src/javascript/components/user/user-profile-form.tsx\": \"./app/frontend/src/javascript/components/user/user-profile-form.tsx\",\n\t\"src/javascript/components/user/user-validation.tsx\": \"./app/frontend/src/javascript/components/user/user-validation.tsx\"\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 = \"./app/frontend/src/javascript/components sync recursive ^.+\\\\.(?%21md).+\";","var map = {\n\t\"./about\": \"./app/frontend/src/javascript/controllers/about.js\",\n\t\"./about.js\": \"./app/frontend/src/javascript/controllers/about.js\",\n\t\"./admin/abuses\": \"./app/frontend/src/javascript/controllers/admin/abuses.js\",\n\t\"./admin/abuses.js\": \"./app/frontend/src/javascript/controllers/admin/abuses.js\",\n\t\"./admin/authentications\": \"./app/frontend/src/javascript/controllers/admin/authentications.js\",\n\t\"./admin/authentications.js\": \"./app/frontend/src/javascript/controllers/admin/authentications.js\",\n\t\"./admin/calendar\": \"./app/frontend/src/javascript/controllers/admin/calendar.js\",\n\t\"./admin/calendar.js\": \"./app/frontend/src/javascript/controllers/admin/calendar.js\",\n\t\"./admin/coupons\": \"./app/frontend/src/javascript/controllers/admin/coupons.js\",\n\t\"./admin/coupons.js\": \"./app/frontend/src/javascript/controllers/admin/coupons.js\",\n\t\"./admin/events\": \"./app/frontend/src/javascript/controllers/admin/events.js\",\n\t\"./admin/events.js\": \"./app/frontend/src/javascript/controllers/admin/events.js\",\n\t\"./admin/graphs\": \"./app/frontend/src/javascript/controllers/admin/graphs.js\",\n\t\"./admin/graphs.js\": \"./app/frontend/src/javascript/controllers/admin/graphs.js\",\n\t\"./admin/groups\": \"./app/frontend/src/javascript/controllers/admin/groups.js\",\n\t\"./admin/groups.js\": \"./app/frontend/src/javascript/controllers/admin/groups.js\",\n\t\"./admin/invoices\": \"./app/frontend/src/javascript/controllers/admin/invoices.js\",\n\t\"./admin/invoices.js\": \"./app/frontend/src/javascript/controllers/admin/invoices.js\",\n\t\"./admin/machines\": \"./app/frontend/src/javascript/controllers/admin/machines.js\",\n\t\"./admin/machines.js\": \"./app/frontend/src/javascript/controllers/admin/machines.js\",\n\t\"./admin/members\": \"./app/frontend/src/javascript/controllers/admin/members.js\",\n\t\"./admin/members.js\": \"./app/frontend/src/javascript/controllers/admin/members.js\",\n\t\"./admin/open_api_clients\": \"./app/frontend/src/javascript/controllers/admin/open_api_clients.js\",\n\t\"./admin/open_api_clients.js\": \"./app/frontend/src/javascript/controllers/admin/open_api_clients.js\",\n\t\"./admin/orders\": \"./app/frontend/src/javascript/controllers/admin/orders.js\",\n\t\"./admin/orders.js\": \"./app/frontend/src/javascript/controllers/admin/orders.js\",\n\t\"./admin/plans\": \"./app/frontend/src/javascript/controllers/admin/plans.js\",\n\t\"./admin/plans.js\": \"./app/frontend/src/javascript/controllers/admin/plans.js\",\n\t\"./admin/price_category\": \"./app/frontend/src/javascript/controllers/admin/price_category.js\",\n\t\"./admin/price_category.js\": \"./app/frontend/src/javascript/controllers/admin/price_category.js\",\n\t\"./admin/pricing\": \"./app/frontend/src/javascript/controllers/admin/pricing.js\",\n\t\"./admin/pricing.js\": \"./app/frontend/src/javascript/controllers/admin/pricing.js\",\n\t\"./admin/projects\": \"./app/frontend/src/javascript/controllers/admin/projects.js\",\n\t\"./admin/projects.js\": \"./app/frontend/src/javascript/controllers/admin/projects.js\",\n\t\"./admin/settings\": \"./app/frontend/src/javascript/controllers/admin/settings.js\",\n\t\"./admin/settings.js\": \"./app/frontend/src/javascript/controllers/admin/settings.js\",\n\t\"./admin/statistics\": \"./app/frontend/src/javascript/controllers/admin/statistics.js\",\n\t\"./admin/statistics.js\": \"./app/frontend/src/javascript/controllers/admin/statistics.js\",\n\t\"./admin/store\": \"./app/frontend/src/javascript/controllers/admin/store.js\",\n\t\"./admin/store.js\": \"./app/frontend/src/javascript/controllers/admin/store.js\",\n\t\"./admin/store_products\": \"./app/frontend/src/javascript/controllers/admin/store_products.js\",\n\t\"./admin/store_products.js\": \"./app/frontend/src/javascript/controllers/admin/store_products.js\",\n\t\"./admin/tags\": \"./app/frontend/src/javascript/controllers/admin/tags.js\",\n\t\"./admin/tags.js\": \"./app/frontend/src/javascript/controllers/admin/tags.js\",\n\t\"./admin/trainings\": \"./app/frontend/src/javascript/controllers/admin/trainings.js\",\n\t\"./admin/trainings.js\": \"./app/frontend/src/javascript/controllers/admin/trainings.js\",\n\t\"./application\": \"./app/frontend/src/javascript/controllers/application.js\",\n\t\"./application.js\": \"./app/frontend/src/javascript/controllers/application.js\",\n\t\"./calendar\": \"./app/frontend/src/javascript/controllers/calendar.js\",\n\t\"./calendar.js\": \"./app/frontend/src/javascript/controllers/calendar.js\",\n\t\"./cart\": \"./app/frontend/src/javascript/controllers/cart.js\",\n\t\"./cart.js\": \"./app/frontend/src/javascript/controllers/cart.js\",\n\t\"./cookies\": \"./app/frontend/src/javascript/controllers/cookies.js\",\n\t\"./cookies.js\": \"./app/frontend/src/javascript/controllers/cookies.js\",\n\t\"./dashboard\": \"./app/frontend/src/javascript/controllers/dashboard.js\",\n\t\"./dashboard.js\": \"./app/frontend/src/javascript/controllers/dashboard.js\",\n\t\"./events.js\": \"./app/frontend/src/javascript/controllers/events.js.erb\",\n\t\"./events.js.erb\": \"./app/frontend/src/javascript/controllers/events.js.erb\",\n\t\"./header\": \"./app/frontend/src/javascript/controllers/header.js\",\n\t\"./header.js\": \"./app/frontend/src/javascript/controllers/header.js\",\n\t\"./home\": \"./app/frontend/src/javascript/controllers/home.js\",\n\t\"./home.js\": \"./app/frontend/src/javascript/controllers/home.js\",\n\t\"./machines.js\": \"./app/frontend/src/javascript/controllers/machines.js.erb\",\n\t\"./machines.js.erb\": \"./app/frontend/src/javascript/controllers/machines.js.erb\",\n\t\"./main_nav\": \"./app/frontend/src/javascript/controllers/main_nav.js\",\n\t\"./main_nav.js\": \"./app/frontend/src/javascript/controllers/main_nav.js\",\n\t\"./members\": \"./app/frontend/src/javascript/controllers/members.js\",\n\t\"./members.js\": \"./app/frontend/src/javascript/controllers/members.js\",\n\t\"./notifications\": \"./app/frontend/src/javascript/controllers/notifications.js\",\n\t\"./notifications.js\": \"./app/frontend/src/javascript/controllers/notifications.js\",\n\t\"./orders\": \"./app/frontend/src/javascript/controllers/orders.js\",\n\t\"./orders.js\": \"./app/frontend/src/javascript/controllers/orders.js\",\n\t\"./plans\": \"./app/frontend/src/javascript/controllers/plans.js\",\n\t\"./plans.js\": \"./app/frontend/src/javascript/controllers/plans.js\",\n\t\"./privacy\": \"./app/frontend/src/javascript/controllers/privacy.js\",\n\t\"./privacy.js\": \"./app/frontend/src/javascript/controllers/privacy.js\",\n\t\"./products\": \"./app/frontend/src/javascript/controllers/products.js\",\n\t\"./products.js\": \"./app/frontend/src/javascript/controllers/products.js\",\n\t\"./profile\": \"./app/frontend/src/javascript/controllers/profile.js\",\n\t\"./profile.js\": \"./app/frontend/src/javascript/controllers/profile.js\",\n\t\"./projects\": \"./app/frontend/src/javascript/controllers/projects.js\",\n\t\"./projects.js\": \"./app/frontend/src/javascript/controllers/projects.js\",\n\t\"./spaces.js\": \"./app/frontend/src/javascript/controllers/spaces.js.erb\",\n\t\"./spaces.js.erb\": \"./app/frontend/src/javascript/controllers/spaces.js.erb\",\n\t\"./store\": \"./app/frontend/src/javascript/controllers/store.js\",\n\t\"./store.js\": \"./app/frontend/src/javascript/controllers/store.js\",\n\t\"./trainings.js\": \"./app/frontend/src/javascript/controllers/trainings.js.erb\",\n\t\"./trainings.js.erb\": \"./app/frontend/src/javascript/controllers/trainings.js.erb\",\n\t\"./wallet\": \"./app/frontend/src/javascript/controllers/wallet.js\",\n\t\"./wallet.js\": \"./app/frontend/src/javascript/controllers/wallet.js\",\n\t\"src/javascript/controllers/about\": \"./app/frontend/src/javascript/controllers/about.js\",\n\t\"src/javascript/controllers/about.js\": \"./app/frontend/src/javascript/controllers/about.js\",\n\t\"src/javascript/controllers/admin/abuses\": \"./app/frontend/src/javascript/controllers/admin/abuses.js\",\n\t\"src/javascript/controllers/admin/abuses.js\": \"./app/frontend/src/javascript/controllers/admin/abuses.js\",\n\t\"src/javascript/controllers/admin/authentications\": \"./app/frontend/src/javascript/controllers/admin/authentications.js\",\n\t\"src/javascript/controllers/admin/authentications.js\": \"./app/frontend/src/javascript/controllers/admin/authentications.js\",\n\t\"src/javascript/controllers/admin/calendar\": \"./app/frontend/src/javascript/controllers/admin/calendar.js\",\n\t\"src/javascript/controllers/admin/calendar.js\": \"./app/frontend/src/javascript/controllers/admin/calendar.js\",\n\t\"src/javascript/controllers/admin/coupons\": \"./app/frontend/src/javascript/controllers/admin/coupons.js\",\n\t\"src/javascript/controllers/admin/coupons.js\": \"./app/frontend/src/javascript/controllers/admin/coupons.js\",\n\t\"src/javascript/controllers/admin/events\": \"./app/frontend/src/javascript/controllers/admin/events.js\",\n\t\"src/javascript/controllers/admin/events.js\": \"./app/frontend/src/javascript/controllers/admin/events.js\",\n\t\"src/javascript/controllers/admin/graphs\": \"./app/frontend/src/javascript/controllers/admin/graphs.js\",\n\t\"src/javascript/controllers/admin/graphs.js\": \"./app/frontend/src/javascript/controllers/admin/graphs.js\",\n\t\"src/javascript/controllers/admin/groups\": \"./app/frontend/src/javascript/controllers/admin/groups.js\",\n\t\"src/javascript/controllers/admin/groups.js\": \"./app/frontend/src/javascript/controllers/admin/groups.js\",\n\t\"src/javascript/controllers/admin/invoices\": \"./app/frontend/src/javascript/controllers/admin/invoices.js\",\n\t\"src/javascript/controllers/admin/invoices.js\": \"./app/frontend/src/javascript/controllers/admin/invoices.js\",\n\t\"src/javascript/controllers/admin/machines\": \"./app/frontend/src/javascript/controllers/admin/machines.js\",\n\t\"src/javascript/controllers/admin/machines.js\": \"./app/frontend/src/javascript/controllers/admin/machines.js\",\n\t\"src/javascript/controllers/admin/members\": \"./app/frontend/src/javascript/controllers/admin/members.js\",\n\t\"src/javascript/controllers/admin/members.js\": \"./app/frontend/src/javascript/controllers/admin/members.js\",\n\t\"src/javascript/controllers/admin/open_api_clients\": \"./app/frontend/src/javascript/controllers/admin/open_api_clients.js\",\n\t\"src/javascript/controllers/admin/open_api_clients.js\": \"./app/frontend/src/javascript/controllers/admin/open_api_clients.js\",\n\t\"src/javascript/controllers/admin/orders\": \"./app/frontend/src/javascript/controllers/admin/orders.js\",\n\t\"src/javascript/controllers/admin/orders.js\": \"./app/frontend/src/javascript/controllers/admin/orders.js\",\n\t\"src/javascript/controllers/admin/plans\": \"./app/frontend/src/javascript/controllers/admin/plans.js\",\n\t\"src/javascript/controllers/admin/plans.js\": \"./app/frontend/src/javascript/controllers/admin/plans.js\",\n\t\"src/javascript/controllers/admin/price_category\": \"./app/frontend/src/javascript/controllers/admin/price_category.js\",\n\t\"src/javascript/controllers/admin/price_category.js\": \"./app/frontend/src/javascript/controllers/admin/price_category.js\",\n\t\"src/javascript/controllers/admin/pricing\": \"./app/frontend/src/javascript/controllers/admin/pricing.js\",\n\t\"src/javascript/controllers/admin/pricing.js\": \"./app/frontend/src/javascript/controllers/admin/pricing.js\",\n\t\"src/javascript/controllers/admin/projects\": \"./app/frontend/src/javascript/controllers/admin/projects.js\",\n\t\"src/javascript/controllers/admin/projects.js\": \"./app/frontend/src/javascript/controllers/admin/projects.js\",\n\t\"src/javascript/controllers/admin/settings\": \"./app/frontend/src/javascript/controllers/admin/settings.js\",\n\t\"src/javascript/controllers/admin/settings.js\": \"./app/frontend/src/javascript/controllers/admin/settings.js\",\n\t\"src/javascript/controllers/admin/statistics\": \"./app/frontend/src/javascript/controllers/admin/statistics.js\",\n\t\"src/javascript/controllers/admin/statistics.js\": \"./app/frontend/src/javascript/controllers/admin/statistics.js\",\n\t\"src/javascript/controllers/admin/store\": \"./app/frontend/src/javascript/controllers/admin/store.js\",\n\t\"src/javascript/controllers/admin/store.js\": \"./app/frontend/src/javascript/controllers/admin/store.js\",\n\t\"src/javascript/controllers/admin/store_products\": \"./app/frontend/src/javascript/controllers/admin/store_products.js\",\n\t\"src/javascript/controllers/admin/store_products.js\": \"./app/frontend/src/javascript/controllers/admin/store_products.js\",\n\t\"src/javascript/controllers/admin/tags\": \"./app/frontend/src/javascript/controllers/admin/tags.js\",\n\t\"src/javascript/controllers/admin/tags.js\": \"./app/frontend/src/javascript/controllers/admin/tags.js\",\n\t\"src/javascript/controllers/admin/trainings\": \"./app/frontend/src/javascript/controllers/admin/trainings.js\",\n\t\"src/javascript/controllers/admin/trainings.js\": \"./app/frontend/src/javascript/controllers/admin/trainings.js\",\n\t\"src/javascript/controllers/application\": \"./app/frontend/src/javascript/controllers/application.js\",\n\t\"src/javascript/controllers/application.js\": \"./app/frontend/src/javascript/controllers/application.js\",\n\t\"src/javascript/controllers/calendar\": \"./app/frontend/src/javascript/controllers/calendar.js\",\n\t\"src/javascript/controllers/calendar.js\": \"./app/frontend/src/javascript/controllers/calendar.js\",\n\t\"src/javascript/controllers/cart\": \"./app/frontend/src/javascript/controllers/cart.js\",\n\t\"src/javascript/controllers/cart.js\": \"./app/frontend/src/javascript/controllers/cart.js\",\n\t\"src/javascript/controllers/cookies\": \"./app/frontend/src/javascript/controllers/cookies.js\",\n\t\"src/javascript/controllers/cookies.js\": \"./app/frontend/src/javascript/controllers/cookies.js\",\n\t\"src/javascript/controllers/dashboard\": \"./app/frontend/src/javascript/controllers/dashboard.js\",\n\t\"src/javascript/controllers/dashboard.js\": \"./app/frontend/src/javascript/controllers/dashboard.js\",\n\t\"src/javascript/controllers/events.js\": \"./app/frontend/src/javascript/controllers/events.js.erb\",\n\t\"src/javascript/controllers/events.js.erb\": \"./app/frontend/src/javascript/controllers/events.js.erb\",\n\t\"src/javascript/controllers/header\": \"./app/frontend/src/javascript/controllers/header.js\",\n\t\"src/javascript/controllers/header.js\": \"./app/frontend/src/javascript/controllers/header.js\",\n\t\"src/javascript/controllers/home\": \"./app/frontend/src/javascript/controllers/home.js\",\n\t\"src/javascript/controllers/home.js\": \"./app/frontend/src/javascript/controllers/home.js\",\n\t\"src/javascript/controllers/machines.js\": \"./app/frontend/src/javascript/controllers/machines.js.erb\",\n\t\"src/javascript/controllers/machines.js.erb\": \"./app/frontend/src/javascript/controllers/machines.js.erb\",\n\t\"src/javascript/controllers/main_nav\": \"./app/frontend/src/javascript/controllers/main_nav.js\",\n\t\"src/javascript/controllers/main_nav.js\": \"./app/frontend/src/javascript/controllers/main_nav.js\",\n\t\"src/javascript/controllers/members\": \"./app/frontend/src/javascript/controllers/members.js\",\n\t\"src/javascript/controllers/members.js\": \"./app/frontend/src/javascript/controllers/members.js\",\n\t\"src/javascript/controllers/notifications\": \"./app/frontend/src/javascript/controllers/notifications.js\",\n\t\"src/javascript/controllers/notifications.js\": \"./app/frontend/src/javascript/controllers/notifications.js\",\n\t\"src/javascript/controllers/orders\": \"./app/frontend/src/javascript/controllers/orders.js\",\n\t\"src/javascript/controllers/orders.js\": \"./app/frontend/src/javascript/controllers/orders.js\",\n\t\"src/javascript/controllers/plans\": \"./app/frontend/src/javascript/controllers/plans.js\",\n\t\"src/javascript/controllers/plans.js\": \"./app/frontend/src/javascript/controllers/plans.js\",\n\t\"src/javascript/controllers/privacy\": \"./app/frontend/src/javascript/controllers/privacy.js\",\n\t\"src/javascript/controllers/privacy.js\": \"./app/frontend/src/javascript/controllers/privacy.js\",\n\t\"src/javascript/controllers/products\": \"./app/frontend/src/javascript/controllers/products.js\",\n\t\"src/javascript/controllers/products.js\": \"./app/frontend/src/javascript/controllers/products.js\",\n\t\"src/javascript/controllers/profile\": \"./app/frontend/src/javascript/controllers/profile.js\",\n\t\"src/javascript/controllers/profile.js\": \"./app/frontend/src/javascript/controllers/profile.js\",\n\t\"src/javascript/controllers/projects\": \"./app/frontend/src/javascript/controllers/projects.js\",\n\t\"src/javascript/controllers/projects.js\": \"./app/frontend/src/javascript/controllers/projects.js\",\n\t\"src/javascript/controllers/spaces.js\": \"./app/frontend/src/javascript/controllers/spaces.js.erb\",\n\t\"src/javascript/controllers/spaces.js.erb\": \"./app/frontend/src/javascript/controllers/spaces.js.erb\",\n\t\"src/javascript/controllers/store\": \"./app/frontend/src/javascript/controllers/store.js\",\n\t\"src/javascript/controllers/store.js\": \"./app/frontend/src/javascript/controllers/store.js\",\n\t\"src/javascript/controllers/trainings.js\": \"./app/frontend/src/javascript/controllers/trainings.js.erb\",\n\t\"src/javascript/controllers/trainings.js.erb\": \"./app/frontend/src/javascript/controllers/trainings.js.erb\",\n\t\"src/javascript/controllers/wallet\": \"./app/frontend/src/javascript/controllers/wallet.js\",\n\t\"src/javascript/controllers/wallet.js\": \"./app/frontend/src/javascript/controllers/wallet.js\"\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 = \"./app/frontend/src/javascript/controllers sync recursive .*\";","var map = {\n\t\"./bs-jasny-fileinput\": \"./app/frontend/src/javascript/directives/bs-jasny-fileinput.js\",\n\t\"./bs-jasny-fileinput.js\": \"./app/frontend/src/javascript/directives/bs-jasny-fileinput.js\",\n\t\"./cart\": \"./app/frontend/src/javascript/directives/cart.js\",\n\t\"./cart.js\": \"./app/frontend/src/javascript/directives/cart.js\",\n\t\"./compile\": \"./app/frontend/src/javascript/directives/compile.js\",\n\t\"./compile.js\": \"./app/frontend/src/javascript/directives/compile.js\",\n\t\"./confirmation_needed\": \"./app/frontend/src/javascript/directives/confirmation_needed.js\",\n\t\"./confirmation_needed.js\": \"./app/frontend/src/javascript/directives/confirmation_needed.js\",\n\t\"./coupon\": \"./app/frontend/src/javascript/directives/coupon.js\",\n\t\"./coupon.js\": \"./app/frontend/src/javascript/directives/coupon.js\",\n\t\"./directives\": \"./app/frontend/src/javascript/directives/directives.js\",\n\t\"./directives.js\": \"./app/frontend/src/javascript/directives/directives.js\",\n\t\"./fab_user_avatar\": \"./app/frontend/src/javascript/directives/fab_user_avatar.js\",\n\t\"./fab_user_avatar.js\": \"./app/frontend/src/javascript/directives/fab_user_avatar.js\",\n\t\"./home/events\": \"./app/frontend/src/javascript/directives/home/events.js\",\n\t\"./home/events.js\": \"./app/frontend/src/javascript/directives/home/events.js\",\n\t\"./home/news\": \"./app/frontend/src/javascript/directives/home/news.js\",\n\t\"./home/news.js\": \"./app/frontend/src/javascript/directives/home/news.js\",\n\t\"./home/projects\": \"./app/frontend/src/javascript/directives/home/projects.js\",\n\t\"./home/projects.js\": \"./app/frontend/src/javascript/directives/home/projects.js\",\n\t\"./home/twitter\": \"./app/frontend/src/javascript/directives/home/twitter.js\",\n\t\"./home/twitter.js\": \"./app/frontend/src/javascript/directives/home/twitter.js\",\n\t\"./members\": \"./app/frontend/src/javascript/directives/members.js\",\n\t\"./members.js\": \"./app/frontend/src/javascript/directives/members.js\",\n\t\"./post_render\": \"./app/frontend/src/javascript/directives/post_render.js\",\n\t\"./post_render.js\": \"./app/frontend/src/javascript/directives/post_render.js\",\n\t\"./selectMember\": \"./app/frontend/src/javascript/directives/selectMember.js\",\n\t\"./selectMember.js\": \"./app/frontend/src/javascript/directives/selectMember.js\",\n\t\"./settings/number-setting\": \"./app/frontend/src/javascript/directives/settings/number-setting.js\",\n\t\"./settings/number-setting.js\": \"./app/frontend/src/javascript/directives/settings/number-setting.js\",\n\t\"./settings/select-multiple-setting\": \"./app/frontend/src/javascript/directives/settings/select-multiple-setting.js\",\n\t\"./settings/select-multiple-setting.js\": \"./app/frontend/src/javascript/directives/settings/select-multiple-setting.js\",\n\t\"./settings/select-setting\": \"./app/frontend/src/javascript/directives/settings/select-setting.js\",\n\t\"./settings/select-setting.js\": \"./app/frontend/src/javascript/directives/settings/select-setting.js\",\n\t\"./settings/text-setting\": \"./app/frontend/src/javascript/directives/settings/text-setting.js\",\n\t\"./settings/text-setting.js\": \"./app/frontend/src/javascript/directives/settings/text-setting.js\",\n\t\"./socialLink\": \"./app/frontend/src/javascript/directives/socialLink.js\",\n\t\"./socialLink.js\": \"./app/frontend/src/javascript/directives/socialLink.js\",\n\t\"./validators\": \"./app/frontend/src/javascript/directives/validators.js\",\n\t\"./validators.js\": \"./app/frontend/src/javascript/directives/validators.js\",\n\t\"src/javascript/directives/bs-jasny-fileinput\": \"./app/frontend/src/javascript/directives/bs-jasny-fileinput.js\",\n\t\"src/javascript/directives/bs-jasny-fileinput.js\": \"./app/frontend/src/javascript/directives/bs-jasny-fileinput.js\",\n\t\"src/javascript/directives/cart\": \"./app/frontend/src/javascript/directives/cart.js\",\n\t\"src/javascript/directives/cart.js\": \"./app/frontend/src/javascript/directives/cart.js\",\n\t\"src/javascript/directives/compile\": \"./app/frontend/src/javascript/directives/compile.js\",\n\t\"src/javascript/directives/compile.js\": \"./app/frontend/src/javascript/directives/compile.js\",\n\t\"src/javascript/directives/confirmation_needed\": \"./app/frontend/src/javascript/directives/confirmation_needed.js\",\n\t\"src/javascript/directives/confirmation_needed.js\": \"./app/frontend/src/javascript/directives/confirmation_needed.js\",\n\t\"src/javascript/directives/coupon\": \"./app/frontend/src/javascript/directives/coupon.js\",\n\t\"src/javascript/directives/coupon.js\": \"./app/frontend/src/javascript/directives/coupon.js\",\n\t\"src/javascript/directives/directives\": \"./app/frontend/src/javascript/directives/directives.js\",\n\t\"src/javascript/directives/directives.js\": \"./app/frontend/src/javascript/directives/directives.js\",\n\t\"src/javascript/directives/fab_user_avatar\": \"./app/frontend/src/javascript/directives/fab_user_avatar.js\",\n\t\"src/javascript/directives/fab_user_avatar.js\": \"./app/frontend/src/javascript/directives/fab_user_avatar.js\",\n\t\"src/javascript/directives/home/events\": \"./app/frontend/src/javascript/directives/home/events.js\",\n\t\"src/javascript/directives/home/events.js\": \"./app/frontend/src/javascript/directives/home/events.js\",\n\t\"src/javascript/directives/home/news\": \"./app/frontend/src/javascript/directives/home/news.js\",\n\t\"src/javascript/directives/home/news.js\": \"./app/frontend/src/javascript/directives/home/news.js\",\n\t\"src/javascript/directives/home/projects\": \"./app/frontend/src/javascript/directives/home/projects.js\",\n\t\"src/javascript/directives/home/projects.js\": \"./app/frontend/src/javascript/directives/home/projects.js\",\n\t\"src/javascript/directives/home/twitter\": \"./app/frontend/src/javascript/directives/home/twitter.js\",\n\t\"src/javascript/directives/home/twitter.js\": \"./app/frontend/src/javascript/directives/home/twitter.js\",\n\t\"src/javascript/directives/members\": \"./app/frontend/src/javascript/directives/members.js\",\n\t\"src/javascript/directives/members.js\": \"./app/frontend/src/javascript/directives/members.js\",\n\t\"src/javascript/directives/post_render\": \"./app/frontend/src/javascript/directives/post_render.js\",\n\t\"src/javascript/directives/post_render.js\": \"./app/frontend/src/javascript/directives/post_render.js\",\n\t\"src/javascript/directives/selectMember\": \"./app/frontend/src/javascript/directives/selectMember.js\",\n\t\"src/javascript/directives/selectMember.js\": \"./app/frontend/src/javascript/directives/selectMember.js\",\n\t\"src/javascript/directives/settings/number-setting\": \"./app/frontend/src/javascript/directives/settings/number-setting.js\",\n\t\"src/javascript/directives/settings/number-setting.js\": \"./app/frontend/src/javascript/directives/settings/number-setting.js\",\n\t\"src/javascript/directives/settings/select-multiple-setting\": \"./app/frontend/src/javascript/directives/settings/select-multiple-setting.js\",\n\t\"src/javascript/directives/settings/select-multiple-setting.js\": \"./app/frontend/src/javascript/directives/settings/select-multiple-setting.js\",\n\t\"src/javascript/directives/settings/select-setting\": \"./app/frontend/src/javascript/directives/settings/select-setting.js\",\n\t\"src/javascript/directives/settings/select-setting.js\": \"./app/frontend/src/javascript/directives/settings/select-setting.js\",\n\t\"src/javascript/directives/settings/text-setting\": \"./app/frontend/src/javascript/directives/settings/text-setting.js\",\n\t\"src/javascript/directives/settings/text-setting.js\": \"./app/frontend/src/javascript/directives/settings/text-setting.js\",\n\t\"src/javascript/directives/socialLink\": \"./app/frontend/src/javascript/directives/socialLink.js\",\n\t\"src/javascript/directives/socialLink.js\": \"./app/frontend/src/javascript/directives/socialLink.js\",\n\t\"src/javascript/directives/validators\": \"./app/frontend/src/javascript/directives/validators.js\",\n\t\"src/javascript/directives/validators.js\": \"./app/frontend/src/javascript/directives/validators.js\"\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 = \"./app/frontend/src/javascript/directives sync recursive .*\";","var map = {\n\t\"./filters\": \"./app/frontend/src/javascript/filters/filters.js\",\n\t\"./filters.js\": \"./app/frontend/src/javascript/filters/filters.js\",\n\t\"src/javascript/filters/filters\": \"./app/frontend/src/javascript/filters/filters.js\",\n\t\"src/javascript/filters/filters.js\": \"./app/frontend/src/javascript/filters/filters.js\"\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 = \"./app/frontend/src/javascript/filters sync recursive .*\";","var map = {\n\t\"./_t\": \"./app/frontend/src/javascript/services/_t.js\",\n\t\"./_t.js\": \"./app/frontend/src/javascript/services/_t.js\",\n\t\"./abuse\": \"./app/frontend/src/javascript/services/abuse.js\",\n\t\"./abuse.js\": \"./app/frontend/src/javascript/services/abuse.js\",\n\t\"./accounting_period\": \"./app/frontend/src/javascript/services/accounting_period.js\",\n\t\"./accounting_period.js\": \"./app/frontend/src/javascript/services/accounting_period.js\",\n\t\"./admin\": \"./app/frontend/src/javascript/services/admin.js\",\n\t\"./admin.js\": \"./app/frontend/src/javascript/services/admin.js\",\n\t\"./age_range\": \"./app/frontend/src/javascript/services/age_range.js\",\n\t\"./age_range.js\": \"./app/frontend/src/javascript/services/age_range.js\",\n\t\"./auth\": \"./app/frontend/src/javascript/services/auth.js\",\n\t\"./auth.js\": \"./app/frontend/src/javascript/services/auth.js\",\n\t\"./authProvider\": \"./app/frontend/src/javascript/services/authProvider.js\",\n\t\"./authProvider.js\": \"./app/frontend/src/javascript/services/authProvider.js\",\n\t\"./availability\": \"./app/frontend/src/javascript/services/availability.js\",\n\t\"./availability.js\": \"./app/frontend/src/javascript/services/availability.js\",\n\t\"./brazillianData\": \"./app/frontend/src/javascript/services/brazillianData.js\",\n\t\"./brazillianData.js\": \"./app/frontend/src/javascript/services/brazillianData.js\",\n\t\"./calendar\": \"./app/frontend/src/javascript/services/calendar.js\",\n\t\"./calendar.js\": \"./app/frontend/src/javascript/services/calendar.js\",\n\t\"./category\": \"./app/frontend/src/javascript/services/category.js\",\n\t\"./category.js\": \"./app/frontend/src/javascript/services/category.js\",\n\t\"./component\": \"./app/frontend/src/javascript/services/component.js\",\n\t\"./component.js\": \"./app/frontend/src/javascript/services/component.js\",\n\t\"./coupon\": \"./app/frontend/src/javascript/services/coupon.js\",\n\t\"./coupon.js\": \"./app/frontend/src/javascript/services/coupon.js\",\n\t\"./credit\": \"./app/frontend/src/javascript/services/credit.js\",\n\t\"./credit.js\": \"./app/frontend/src/javascript/services/credit.js\",\n\t\"./csrf\": \"./app/frontend/src/javascript/services/csrf.js\",\n\t\"./csrf.js\": \"./app/frontend/src/javascript/services/csrf.js\",\n\t\"./customAsset\": \"./app/frontend/src/javascript/services/customAsset.js\",\n\t\"./customAsset.js\": \"./app/frontend/src/javascript/services/customAsset.js\",\n\t\"./diacritics\": \"./app/frontend/src/javascript/services/diacritics.js\",\n\t\"./diacritics.js\": \"./app/frontend/src/javascript/services/diacritics.js\",\n\t\"./dialogs\": \"./app/frontend/src/javascript/services/dialogs.js\",\n\t\"./dialogs.js\": \"./app/frontend/src/javascript/services/dialogs.js\",\n\t\"./elastic\": \"./app/frontend/src/javascript/services/elastic.js\",\n\t\"./elastic.js\": \"./app/frontend/src/javascript/services/elastic.js\",\n\t\"./event\": \"./app/frontend/src/javascript/services/event.js\",\n\t\"./event.js\": \"./app/frontend/src/javascript/services/event.js\",\n\t\"./event_theme\": \"./app/frontend/src/javascript/services/event_theme.js\",\n\t\"./event_theme.js\": \"./app/frontend/src/javascript/services/event_theme.js\",\n\t\"./export\": \"./app/frontend/src/javascript/services/export.js\",\n\t\"./export.js\": \"./app/frontend/src/javascript/services/export.js\",\n\t\"./fab_analytics\": \"./app/frontend/src/javascript/services/fab_analytics.js\",\n\t\"./fab_analytics.js\": \"./app/frontend/src/javascript/services/fab_analytics.js\",\n\t\"./group\": \"./app/frontend/src/javascript/services/group.js\",\n\t\"./group.js\": \"./app/frontend/src/javascript/services/group.js\",\n\t\"./help\": \"./app/frontend/src/javascript/services/help.js\",\n\t\"./help.js\": \"./app/frontend/src/javascript/services/help.js\",\n\t\"./helpers\": \"./app/frontend/src/javascript/services/helpers.js\",\n\t\"./helpers.js\": \"./app/frontend/src/javascript/services/helpers.js\",\n\t\"./ical\": \"./app/frontend/src/javascript/services/ical.js\",\n\t\"./ical.js\": \"./app/frontend/src/javascript/services/ical.js\",\n\t\"./icalendar\": \"./app/frontend/src/javascript/services/icalendar.js\",\n\t\"./icalendar.js\": \"./app/frontend/src/javascript/services/icalendar.js\",\n\t\"./import\": \"./app/frontend/src/javascript/services/import.js\",\n\t\"./import.js\": \"./app/frontend/src/javascript/services/import.js\",\n\t\"./invoice\": \"./app/frontend/src/javascript/services/invoice.js\",\n\t\"./invoice.js\": \"./app/frontend/src/javascript/services/invoice.js\",\n\t\"./licence\": \"./app/frontend/src/javascript/services/licence.js\",\n\t\"./licence.js\": \"./app/frontend/src/javascript/services/licence.js\",\n\t\"./local_payment\": \"./app/frontend/src/javascript/services/local_payment.js\",\n\t\"./local_payment.js\": \"./app/frontend/src/javascript/services/local_payment.js\",\n\t\"./machine\": \"./app/frontend/src/javascript/services/machine.js\",\n\t\"./machine.js\": \"./app/frontend/src/javascript/services/machine.js\",\n\t\"./machine_category\": \"./app/frontend/src/javascript/services/machine_category.js\",\n\t\"./machine_category.js\": \"./app/frontend/src/javascript/services/machine_category.js\",\n\t\"./member\": \"./app/frontend/src/javascript/services/member.js\",\n\t\"./member.js\": \"./app/frontend/src/javascript/services/member.js\",\n\t\"./notification\": \"./app/frontend/src/javascript/services/notification.js\",\n\t\"./notification.js\": \"./app/frontend/src/javascript/services/notification.js\",\n\t\"./open_api_client\": \"./app/frontend/src/javascript/services/open_api_client.js\",\n\t\"./open_api_client.js\": \"./app/frontend/src/javascript/services/open_api_client.js\",\n\t\"./openlab_project\": \"./app/frontend/src/javascript/services/openlab_project.js\",\n\t\"./openlab_project.js\": \"./app/frontend/src/javascript/services/openlab_project.js\",\n\t\"./pagination_service\": \"./app/frontend/src/javascript/services/pagination_service.js\",\n\t\"./pagination_service.js\": \"./app/frontend/src/javascript/services/pagination_service.js\",\n\t\"./payment\": \"./app/frontend/src/javascript/services/payment.js\",\n\t\"./payment.js\": \"./app/frontend/src/javascript/services/payment.js\",\n\t\"./plan\": \"./app/frontend/src/javascript/services/plan.js\",\n\t\"./plan.js\": \"./app/frontend/src/javascript/services/plan.js\",\n\t\"./plan_category\": \"./app/frontend/src/javascript/services/plan_category.js\",\n\t\"./plan_category.js\": \"./app/frontend/src/javascript/services/plan_category.js\",\n\t\"./price\": \"./app/frontend/src/javascript/services/price.js\",\n\t\"./price.js\": \"./app/frontend/src/javascript/services/price.js\",\n\t\"./price_category\": \"./app/frontend/src/javascript/services/price_category.js\",\n\t\"./price_category.js\": \"./app/frontend/src/javascript/services/price_category.js\",\n\t\"./pricing\": \"./app/frontend/src/javascript/services/pricing.js\",\n\t\"./pricing.js\": \"./app/frontend/src/javascript/services/pricing.js\",\n\t\"./profile_custom_field\": \"./app/frontend/src/javascript/services/profile_custom_field.js\",\n\t\"./profile_custom_field.js\": \"./app/frontend/src/javascript/services/profile_custom_field.js\",\n\t\"./project\": \"./app/frontend/src/javascript/services/project.js\",\n\t\"./project.js\": \"./app/frontend/src/javascript/services/project.js\",\n\t\"./reservation\": \"./app/frontend/src/javascript/services/reservation.js\",\n\t\"./reservation.js\": \"./app/frontend/src/javascript/services/reservation.js\",\n\t\"./session\": \"./app/frontend/src/javascript/services/session.js\",\n\t\"./session.js\": \"./app/frontend/src/javascript/services/session.js\",\n\t\"./setting\": \"./app/frontend/src/javascript/services/setting.js\",\n\t\"./setting.js\": \"./app/frontend/src/javascript/services/setting.js\",\n\t\"./slots_reservation\": \"./app/frontend/src/javascript/services/slots_reservation.js\",\n\t\"./slots_reservation.js\": \"./app/frontend/src/javascript/services/slots_reservation.js\",\n\t\"./socialNetworks\": \"./app/frontend/src/javascript/services/socialNetworks.js\",\n\t\"./socialNetworks.js\": \"./app/frontend/src/javascript/services/socialNetworks.js\",\n\t\"./space\": \"./app/frontend/src/javascript/services/space.js\",\n\t\"./space.js\": \"./app/frontend/src/javascript/services/space.js\",\n\t\"./statistics\": \"./app/frontend/src/javascript/services/statistics.js\",\n\t\"./statistics.js\": \"./app/frontend/src/javascript/services/statistics.js\",\n\t\"./status\": \"./app/frontend/src/javascript/services/status.js\",\n\t\"./status.js\": \"./app/frontend/src/javascript/services/status.js\",\n\t\"./subscription\": \"./app/frontend/src/javascript/services/subscription.js\",\n\t\"./subscription.js\": \"./app/frontend/src/javascript/services/subscription.js\",\n\t\"./supporting_document_type\": \"./app/frontend/src/javascript/services/supporting_document_type.js\",\n\t\"./supporting_document_type.js\": \"./app/frontend/src/javascript/services/supporting_document_type.js\",\n\t\"./tag\": \"./app/frontend/src/javascript/services/tag.js\",\n\t\"./tag.js\": \"./app/frontend/src/javascript/services/tag.js\",\n\t\"./theme\": \"./app/frontend/src/javascript/services/theme.js\",\n\t\"./theme.js\": \"./app/frontend/src/javascript/services/theme.js\",\n\t\"./training\": \"./app/frontend/src/javascript/services/training.js\",\n\t\"./training.js\": \"./app/frontend/src/javascript/services/training.js\",\n\t\"./trainings_pricing\": \"./app/frontend/src/javascript/services/trainings_pricing.js\",\n\t\"./trainings_pricing.js\": \"./app/frontend/src/javascript/services/trainings_pricing.js\",\n\t\"./translations\": \"./app/frontend/src/javascript/services/translations.js\",\n\t\"./translations.js\": \"./app/frontend/src/javascript/services/translations.js\",\n\t\"./user\": \"./app/frontend/src/javascript/services/user.js\",\n\t\"./user.js\": \"./app/frontend/src/javascript/services/user.js\",\n\t\"./version\": \"./app/frontend/src/javascript/services/version.js\",\n\t\"./version.js\": \"./app/frontend/src/javascript/services/version.js\",\n\t\"./wallet\": \"./app/frontend/src/javascript/services/wallet.js\",\n\t\"./wallet.js\": \"./app/frontend/src/javascript/services/wallet.js\",\n\t\"src/javascript/services/_t\": \"./app/frontend/src/javascript/services/_t.js\",\n\t\"src/javascript/services/_t.js\": \"./app/frontend/src/javascript/services/_t.js\",\n\t\"src/javascript/services/abuse\": \"./app/frontend/src/javascript/services/abuse.js\",\n\t\"src/javascript/services/abuse.js\": \"./app/frontend/src/javascript/services/abuse.js\",\n\t\"src/javascript/services/accounting_period\": \"./app/frontend/src/javascript/services/accounting_period.js\",\n\t\"src/javascript/services/accounting_period.js\": \"./app/frontend/src/javascript/services/accounting_period.js\",\n\t\"src/javascript/services/admin\": \"./app/frontend/src/javascript/services/admin.js\",\n\t\"src/javascript/services/admin.js\": \"./app/frontend/src/javascript/services/admin.js\",\n\t\"src/javascript/services/age_range\": \"./app/frontend/src/javascript/services/age_range.js\",\n\t\"src/javascript/services/age_range.js\": \"./app/frontend/src/javascript/services/age_range.js\",\n\t\"src/javascript/services/auth\": \"./app/frontend/src/javascript/services/auth.js\",\n\t\"src/javascript/services/auth.js\": \"./app/frontend/src/javascript/services/auth.js\",\n\t\"src/javascript/services/authProvider\": \"./app/frontend/src/javascript/services/authProvider.js\",\n\t\"src/javascript/services/authProvider.js\": \"./app/frontend/src/javascript/services/authProvider.js\",\n\t\"src/javascript/services/availability\": \"./app/frontend/src/javascript/services/availability.js\",\n\t\"src/javascript/services/availability.js\": \"./app/frontend/src/javascript/services/availability.js\",\n\t\"src/javascript/services/brazillianData\": \"./app/frontend/src/javascript/services/brazillianData.js\",\n\t\"src/javascript/services/brazillianData.js\": \"./app/frontend/src/javascript/services/brazillianData.js\",\n\t\"src/javascript/services/calendar\": \"./app/frontend/src/javascript/services/calendar.js\",\n\t\"src/javascript/services/calendar.js\": \"./app/frontend/src/javascript/services/calendar.js\",\n\t\"src/javascript/services/category\": \"./app/frontend/src/javascript/services/category.js\",\n\t\"src/javascript/services/category.js\": \"./app/frontend/src/javascript/services/category.js\",\n\t\"src/javascript/services/component\": \"./app/frontend/src/javascript/services/component.js\",\n\t\"src/javascript/services/component.js\": \"./app/frontend/src/javascript/services/component.js\",\n\t\"src/javascript/services/coupon\": \"./app/frontend/src/javascript/services/coupon.js\",\n\t\"src/javascript/services/coupon.js\": \"./app/frontend/src/javascript/services/coupon.js\",\n\t\"src/javascript/services/credit\": \"./app/frontend/src/javascript/services/credit.js\",\n\t\"src/javascript/services/credit.js\": \"./app/frontend/src/javascript/services/credit.js\",\n\t\"src/javascript/services/csrf\": \"./app/frontend/src/javascript/services/csrf.js\",\n\t\"src/javascript/services/csrf.js\": \"./app/frontend/src/javascript/services/csrf.js\",\n\t\"src/javascript/services/customAsset\": \"./app/frontend/src/javascript/services/customAsset.js\",\n\t\"src/javascript/services/customAsset.js\": \"./app/frontend/src/javascript/services/customAsset.js\",\n\t\"src/javascript/services/diacritics\": \"./app/frontend/src/javascript/services/diacritics.js\",\n\t\"src/javascript/services/diacritics.js\": \"./app/frontend/src/javascript/services/diacritics.js\",\n\t\"src/javascript/services/dialogs\": \"./app/frontend/src/javascript/services/dialogs.js\",\n\t\"src/javascript/services/dialogs.js\": \"./app/frontend/src/javascript/services/dialogs.js\",\n\t\"src/javascript/services/elastic\": \"./app/frontend/src/javascript/services/elastic.js\",\n\t\"src/javascript/services/elastic.js\": \"./app/frontend/src/javascript/services/elastic.js\",\n\t\"src/javascript/services/event\": \"./app/frontend/src/javascript/services/event.js\",\n\t\"src/javascript/services/event.js\": \"./app/frontend/src/javascript/services/event.js\",\n\t\"src/javascript/services/event_theme\": \"./app/frontend/src/javascript/services/event_theme.js\",\n\t\"src/javascript/services/event_theme.js\": \"./app/frontend/src/javascript/services/event_theme.js\",\n\t\"src/javascript/services/export\": \"./app/frontend/src/javascript/services/export.js\",\n\t\"src/javascript/services/export.js\": \"./app/frontend/src/javascript/services/export.js\",\n\t\"src/javascript/services/fab_analytics\": \"./app/frontend/src/javascript/services/fab_analytics.js\",\n\t\"src/javascript/services/fab_analytics.js\": \"./app/frontend/src/javascript/services/fab_analytics.js\",\n\t\"src/javascript/services/group\": \"./app/frontend/src/javascript/services/group.js\",\n\t\"src/javascript/services/group.js\": \"./app/frontend/src/javascript/services/group.js\",\n\t\"src/javascript/services/help\": \"./app/frontend/src/javascript/services/help.js\",\n\t\"src/javascript/services/help.js\": \"./app/frontend/src/javascript/services/help.js\",\n\t\"src/javascript/services/helpers\": \"./app/frontend/src/javascript/services/helpers.js\",\n\t\"src/javascript/services/helpers.js\": \"./app/frontend/src/javascript/services/helpers.js\",\n\t\"src/javascript/services/ical\": \"./app/frontend/src/javascript/services/ical.js\",\n\t\"src/javascript/services/ical.js\": \"./app/frontend/src/javascript/services/ical.js\",\n\t\"src/javascript/services/icalendar\": \"./app/frontend/src/javascript/services/icalendar.js\",\n\t\"src/javascript/services/icalendar.js\": \"./app/frontend/src/javascript/services/icalendar.js\",\n\t\"src/javascript/services/import\": \"./app/frontend/src/javascript/services/import.js\",\n\t\"src/javascript/services/import.js\": \"./app/frontend/src/javascript/services/import.js\",\n\t\"src/javascript/services/invoice\": \"./app/frontend/src/javascript/services/invoice.js\",\n\t\"src/javascript/services/invoice.js\": \"./app/frontend/src/javascript/services/invoice.js\",\n\t\"src/javascript/services/licence\": \"./app/frontend/src/javascript/services/licence.js\",\n\t\"src/javascript/services/licence.js\": \"./app/frontend/src/javascript/services/licence.js\",\n\t\"src/javascript/services/local_payment\": \"./app/frontend/src/javascript/services/local_payment.js\",\n\t\"src/javascript/services/local_payment.js\": \"./app/frontend/src/javascript/services/local_payment.js\",\n\t\"src/javascript/services/machine\": \"./app/frontend/src/javascript/services/machine.js\",\n\t\"src/javascript/services/machine.js\": \"./app/frontend/src/javascript/services/machine.js\",\n\t\"src/javascript/services/machine_category\": \"./app/frontend/src/javascript/services/machine_category.js\",\n\t\"src/javascript/services/machine_category.js\": \"./app/frontend/src/javascript/services/machine_category.js\",\n\t\"src/javascript/services/member\": \"./app/frontend/src/javascript/services/member.js\",\n\t\"src/javascript/services/member.js\": \"./app/frontend/src/javascript/services/member.js\",\n\t\"src/javascript/services/notification\": \"./app/frontend/src/javascript/services/notification.js\",\n\t\"src/javascript/services/notification.js\": \"./app/frontend/src/javascript/services/notification.js\",\n\t\"src/javascript/services/open_api_client\": \"./app/frontend/src/javascript/services/open_api_client.js\",\n\t\"src/javascript/services/open_api_client.js\": \"./app/frontend/src/javascript/services/open_api_client.js\",\n\t\"src/javascript/services/openlab_project\": \"./app/frontend/src/javascript/services/openlab_project.js\",\n\t\"src/javascript/services/openlab_project.js\": \"./app/frontend/src/javascript/services/openlab_project.js\",\n\t\"src/javascript/services/pagination_service\": \"./app/frontend/src/javascript/services/pagination_service.js\",\n\t\"src/javascript/services/pagination_service.js\": \"./app/frontend/src/javascript/services/pagination_service.js\",\n\t\"src/javascript/services/payment\": \"./app/frontend/src/javascript/services/payment.js\",\n\t\"src/javascript/services/payment.js\": \"./app/frontend/src/javascript/services/payment.js\",\n\t\"src/javascript/services/plan\": \"./app/frontend/src/javascript/services/plan.js\",\n\t\"src/javascript/services/plan.js\": \"./app/frontend/src/javascript/services/plan.js\",\n\t\"src/javascript/services/plan_category\": \"./app/frontend/src/javascript/services/plan_category.js\",\n\t\"src/javascript/services/plan_category.js\": \"./app/frontend/src/javascript/services/plan_category.js\",\n\t\"src/javascript/services/price\": \"./app/frontend/src/javascript/services/price.js\",\n\t\"src/javascript/services/price.js\": \"./app/frontend/src/javascript/services/price.js\",\n\t\"src/javascript/services/price_category\": \"./app/frontend/src/javascript/services/price_category.js\",\n\t\"src/javascript/services/price_category.js\": \"./app/frontend/src/javascript/services/price_category.js\",\n\t\"src/javascript/services/pricing\": \"./app/frontend/src/javascript/services/pricing.js\",\n\t\"src/javascript/services/pricing.js\": \"./app/frontend/src/javascript/services/pricing.js\",\n\t\"src/javascript/services/profile_custom_field\": \"./app/frontend/src/javascript/services/profile_custom_field.js\",\n\t\"src/javascript/services/profile_custom_field.js\": \"./app/frontend/src/javascript/services/profile_custom_field.js\",\n\t\"src/javascript/services/project\": \"./app/frontend/src/javascript/services/project.js\",\n\t\"src/javascript/services/project.js\": \"./app/frontend/src/javascript/services/project.js\",\n\t\"src/javascript/services/reservation\": \"./app/frontend/src/javascript/services/reservation.js\",\n\t\"src/javascript/services/reservation.js\": \"./app/frontend/src/javascript/services/reservation.js\",\n\t\"src/javascript/services/session\": \"./app/frontend/src/javascript/services/session.js\",\n\t\"src/javascript/services/session.js\": \"./app/frontend/src/javascript/services/session.js\",\n\t\"src/javascript/services/setting\": \"./app/frontend/src/javascript/services/setting.js\",\n\t\"src/javascript/services/setting.js\": \"./app/frontend/src/javascript/services/setting.js\",\n\t\"src/javascript/services/slots_reservation\": \"./app/frontend/src/javascript/services/slots_reservation.js\",\n\t\"src/javascript/services/slots_reservation.js\": \"./app/frontend/src/javascript/services/slots_reservation.js\",\n\t\"src/javascript/services/socialNetworks\": \"./app/frontend/src/javascript/services/socialNetworks.js\",\n\t\"src/javascript/services/socialNetworks.js\": \"./app/frontend/src/javascript/services/socialNetworks.js\",\n\t\"src/javascript/services/space\": \"./app/frontend/src/javascript/services/space.js\",\n\t\"src/javascript/services/space.js\": \"./app/frontend/src/javascript/services/space.js\",\n\t\"src/javascript/services/statistics\": \"./app/frontend/src/javascript/services/statistics.js\",\n\t\"src/javascript/services/statistics.js\": \"./app/frontend/src/javascript/services/statistics.js\",\n\t\"src/javascript/services/status\": \"./app/frontend/src/javascript/services/status.js\",\n\t\"src/javascript/services/status.js\": \"./app/frontend/src/javascript/services/status.js\",\n\t\"src/javascript/services/subscription\": \"./app/frontend/src/javascript/services/subscription.js\",\n\t\"src/javascript/services/subscription.js\": \"./app/frontend/src/javascript/services/subscription.js\",\n\t\"src/javascript/services/supporting_document_type\": \"./app/frontend/src/javascript/services/supporting_document_type.js\",\n\t\"src/javascript/services/supporting_document_type.js\": \"./app/frontend/src/javascript/services/supporting_document_type.js\",\n\t\"src/javascript/services/tag\": \"./app/frontend/src/javascript/services/tag.js\",\n\t\"src/javascript/services/tag.js\": \"./app/frontend/src/javascript/services/tag.js\",\n\t\"src/javascript/services/theme\": \"./app/frontend/src/javascript/services/theme.js\",\n\t\"src/javascript/services/theme.js\": \"./app/frontend/src/javascript/services/theme.js\",\n\t\"src/javascript/services/training\": \"./app/frontend/src/javascript/services/training.js\",\n\t\"src/javascript/services/training.js\": \"./app/frontend/src/javascript/services/training.js\",\n\t\"src/javascript/services/trainings_pricing\": \"./app/frontend/src/javascript/services/trainings_pricing.js\",\n\t\"src/javascript/services/trainings_pricing.js\": \"./app/frontend/src/javascript/services/trainings_pricing.js\",\n\t\"src/javascript/services/translations\": \"./app/frontend/src/javascript/services/translations.js\",\n\t\"src/javascript/services/translations.js\": \"./app/frontend/src/javascript/services/translations.js\",\n\t\"src/javascript/services/user\": \"./app/frontend/src/javascript/services/user.js\",\n\t\"src/javascript/services/user.js\": \"./app/frontend/src/javascript/services/user.js\",\n\t\"src/javascript/services/version\": \"./app/frontend/src/javascript/services/version.js\",\n\t\"src/javascript/services/version.js\": \"./app/frontend/src/javascript/services/version.js\",\n\t\"src/javascript/services/wallet\": \"./app/frontend/src/javascript/services/wallet.js\",\n\t\"src/javascript/services/wallet.js\": \"./app/frontend/src/javascript/services/wallet.js\"\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 = \"./app/frontend/src/javascript/services sync recursive .*\";","var map = {\n\t\"./date-iso.d\": \"./app/frontend/src/javascript/typings/date-iso.d.ts\",\n\t\"./date-iso.d.ts\": \"./app/frontend/src/javascript/typings/date-iso.d.ts\",\n\t\"./import-png.d\": \"./app/frontend/src/javascript/typings/import-png.d.ts\",\n\t\"./import-png.d.ts\": \"./app/frontend/src/javascript/typings/import-png.d.ts\",\n\t\"./import-svg.d\": \"./app/frontend/src/javascript/typings/import-svg.d.ts\",\n\t\"./import-svg.d.ts\": \"./app/frontend/src/javascript/typings/import-svg.d.ts\",\n\t\"src/javascript/typings/date-iso.d\": \"./app/frontend/src/javascript/typings/date-iso.d.ts\",\n\t\"src/javascript/typings/date-iso.d.ts\": \"./app/frontend/src/javascript/typings/date-iso.d.ts\",\n\t\"src/javascript/typings/import-png.d\": \"./app/frontend/src/javascript/typings/import-png.d.ts\",\n\t\"src/javascript/typings/import-png.d.ts\": \"./app/frontend/src/javascript/typings/import-png.d.ts\",\n\t\"src/javascript/typings/import-svg.d\": \"./app/frontend/src/javascript/typings/import-svg.d.ts\",\n\t\"src/javascript/typings/import-svg.d.ts\": \"./app/frontend/src/javascript/typings/import-svg.d.ts\"\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 = \"./app/frontend/src/javascript/typings sync recursive .*\";","var map = {\n\t\"./admin/abuses\": \"./app/frontend/templates/admin/abuses/index.html\",\n\t\"./admin/abuses/\": \"./app/frontend/templates/admin/abuses/index.html\",\n\t\"./admin/abuses/index\": \"./app/frontend/templates/admin/abuses/index.html\",\n\t\"./admin/abuses/index.html\": \"./app/frontend/templates/admin/abuses/index.html\",\n\t\"./admin/admins/new\": \"./app/frontend/templates/admin/admins/new.html\",\n\t\"./admin/admins/new.html\": \"./app/frontend/templates/admin/admins/new.html\",\n\t\"./admin/authentications\": \"./app/frontend/templates/admin/authentications/index.html\",\n\t\"./admin/authentications/\": \"./app/frontend/templates/admin/authentications/index.html\",\n\t\"./admin/authentications/edit\": \"./app/frontend/templates/admin/authentications/edit.html\",\n\t\"./admin/authentications/edit.html\": \"./app/frontend/templates/admin/authentications/edit.html\",\n\t\"./admin/authentications/index\": \"./app/frontend/templates/admin/authentications/index.html\",\n\t\"./admin/authentications/index.html\": \"./app/frontend/templates/admin/authentications/index.html\",\n\t\"./admin/authentications/new\": \"./app/frontend/templates/admin/authentications/new.html\",\n\t\"./admin/authentications/new.html\": \"./app/frontend/templates/admin/authentications/new.html\",\n\t\"./admin/calendar/calendar\": \"./app/frontend/templates/admin/calendar/calendar.html\",\n\t\"./admin/calendar/calendar.html\": \"./app/frontend/templates/admin/calendar/calendar.html\",\n\t\"./admin/calendar/deleteRecurrent\": \"./app/frontend/templates/admin/calendar/deleteRecurrent.html\",\n\t\"./admin/calendar/deleteRecurrent.html\": \"./app/frontend/templates/admin/calendar/deleteRecurrent.html\",\n\t\"./admin/calendar/eventModal\": \"./app/frontend/templates/admin/calendar/eventModal.html\",\n\t\"./admin/calendar/eventModal.html\": \"./app/frontend/templates/admin/calendar/eventModal.html\",\n\t\"./admin/calendar/icalendar\": \"./app/frontend/templates/admin/calendar/icalendar.html\",\n\t\"./admin/calendar/icalendar.html\": \"./app/frontend/templates/admin/calendar/icalendar.html\",\n\t\"./admin/coupons/_form\": \"./app/frontend/templates/admin/coupons/_form.html\",\n\t\"./admin/coupons/_form.html\": \"./app/frontend/templates/admin/coupons/_form.html\",\n\t\"./admin/coupons/edit\": \"./app/frontend/templates/admin/coupons/edit.html\",\n\t\"./admin/coupons/edit.html\": \"./app/frontend/templates/admin/coupons/edit.html\",\n\t\"./admin/coupons/new\": \"./app/frontend/templates/admin/coupons/new.html\",\n\t\"./admin/coupons/new.html\": \"./app/frontend/templates/admin/coupons/new.html\",\n\t\"./admin/events\": \"./app/frontend/templates/admin/events/index.html\",\n\t\"./admin/events/\": \"./app/frontend/templates/admin/events/index.html\",\n\t\"./admin/events/filters\": \"./app/frontend/templates/admin/events/filters.html\",\n\t\"./admin/events/filters.html\": \"./app/frontend/templates/admin/events/filters.html\",\n\t\"./admin/events/index\": \"./app/frontend/templates/admin/events/index.html\",\n\t\"./admin/events/index.html\": \"./app/frontend/templates/admin/events/index.html\",\n\t\"./admin/events/monitoring\": \"./app/frontend/templates/admin/events/monitoring.html\",\n\t\"./admin/events/monitoring.html\": \"./app/frontend/templates/admin/events/monitoring.html\",\n\t\"./admin/events/price_form\": \"./app/frontend/templates/admin/events/price_form.html\",\n\t\"./admin/events/price_form.html\": \"./app/frontend/templates/admin/events/price_form.html\",\n\t\"./admin/events/prices\": \"./app/frontend/templates/admin/events/prices.html\",\n\t\"./admin/events/prices.html\": \"./app/frontend/templates/admin/events/prices.html\",\n\t\"./admin/events/reservations\": \"./app/frontend/templates/admin/events/reservations.html\",\n\t\"./admin/events/reservations.html\": \"./app/frontend/templates/admin/events/reservations.html\",\n\t\"./admin/groups\": \"./app/frontend/templates/admin/groups/index.html\",\n\t\"./admin/groups/\": \"./app/frontend/templates/admin/groups/index.html\",\n\t\"./admin/groups/index\": \"./app/frontend/templates/admin/groups/index.html\",\n\t\"./admin/groups/index.html\": \"./app/frontend/templates/admin/groups/index.html\",\n\t\"./admin/invoices\": \"./app/frontend/templates/admin/invoices/index.html\",\n\t\"./admin/invoices/\": \"./app/frontend/templates/admin/invoices/index.html\",\n\t\"./admin/invoices/_period\": \"./app/frontend/templates/admin/invoices/_period.html\",\n\t\"./admin/invoices/_period.html\": \"./app/frontend/templates/admin/invoices/_period.html\",\n\t\"./admin/invoices/accountingExportModal\": \"./app/frontend/templates/admin/invoices/accountingExportModal.html\",\n\t\"./admin/invoices/accountingExportModal.html\": \"./app/frontend/templates/admin/invoices/accountingExportModal.html\",\n\t\"./admin/invoices/avoirModal\": \"./app/frontend/templates/admin/invoices/avoirModal.html\",\n\t\"./admin/invoices/avoirModal.html\": \"./app/frontend/templates/admin/invoices/avoirModal.html\",\n\t\"./admin/invoices/closePeriodModal\": \"./app/frontend/templates/admin/invoices/closePeriodModal.html\",\n\t\"./admin/invoices/closePeriodModal.html\": \"./app/frontend/templates/admin/invoices/closePeriodModal.html\",\n\t\"./admin/invoices/codes\": \"./app/frontend/templates/admin/invoices/codes.html\",\n\t\"./admin/invoices/codes.html\": \"./app/frontend/templates/admin/invoices/codes.html\",\n\t\"./admin/invoices/index\": \"./app/frontend/templates/admin/invoices/index.html\",\n\t\"./admin/invoices/index.html\": \"./app/frontend/templates/admin/invoices/index.html\",\n\t\"./admin/invoices/list\": \"./app/frontend/templates/admin/invoices/list.html\",\n\t\"./admin/invoices/list.html\": \"./app/frontend/templates/admin/invoices/list.html\",\n\t\"./admin/invoices/payment\": \"./app/frontend/templates/admin/invoices/payment.html\",\n\t\"./admin/invoices/payment.html\": \"./app/frontend/templates/admin/invoices/payment.html\",\n\t\"./admin/invoices/settings\": \"./app/frontend/templates/admin/invoices/settings.html\",\n\t\"./admin/invoices/settings.html\": \"./app/frontend/templates/admin/invoices/settings.html\",\n\t\"./admin/invoices/settings/editCode\": \"./app/frontend/templates/admin/invoices/settings/editCode.html\",\n\t\"./admin/invoices/settings/editCode.html\": \"./app/frontend/templates/admin/invoices/settings/editCode.html\",\n\t\"./admin/invoices/settings/editNumber\": \"./app/frontend/templates/admin/invoices/settings/editNumber.html\",\n\t\"./admin/invoices/settings/editNumber.html\": \"./app/frontend/templates/admin/invoices/settings/editNumber.html\",\n\t\"./admin/invoices/settings/editReference\": \"./app/frontend/templates/admin/invoices/settings/editReference.html\",\n\t\"./admin/invoices/settings/editReference.html\": \"./app/frontend/templates/admin/invoices/settings/editReference.html\",\n\t\"./admin/invoices/settings/stripeKeys\": \"./app/frontend/templates/admin/invoices/settings/stripeKeys.html\",\n\t\"./admin/invoices/settings/stripeKeys.html\": \"./app/frontend/templates/admin/invoices/settings/stripeKeys.html\",\n\t\"./admin/machines\": \"./app/frontend/templates/admin/machines/index.html\",\n\t\"./admin/machines/\": \"./app/frontend/templates/admin/machines/index.html\",\n\t\"./admin/machines/categories\": \"./app/frontend/templates/admin/machines/categories.html\",\n\t\"./admin/machines/categories.html\": \"./app/frontend/templates/admin/machines/categories.html\",\n\t\"./admin/machines/index\": \"./app/frontend/templates/admin/machines/index.html\",\n\t\"./admin/machines/index.html\": \"./app/frontend/templates/admin/machines/index.html\",\n\t\"./admin/machines/machines\": \"./app/frontend/templates/admin/machines/machines.html\",\n\t\"./admin/machines/machines.html\": \"./app/frontend/templates/admin/machines/machines.html\",\n\t\"./admin/managers/new\": \"./app/frontend/templates/admin/managers/new.html\",\n\t\"./admin/managers/new.html\": \"./app/frontend/templates/admin/managers/new.html\",\n\t\"./admin/members\": \"./app/frontend/templates/admin/members/index.html\",\n\t\"./admin/members/\": \"./app/frontend/templates/admin/members/index.html\",\n\t\"./admin/members/_form\": \"./app/frontend/templates/admin/members/_form.html\",\n\t\"./admin/members/_form.html\": \"./app/frontend/templates/admin/members/_form.html\",\n\t\"./admin/members/administrators\": \"./app/frontend/templates/admin/members/administrators.html\",\n\t\"./admin/members/administrators.html\": \"./app/frontend/templates/admin/members/administrators.html\",\n\t\"./admin/members/change_role_modal\": \"./app/frontend/templates/admin/members/change_role_modal.html\",\n\t\"./admin/members/change_role_modal.html\": \"./app/frontend/templates/admin/members/change_role_modal.html\",\n\t\"./admin/members/edit\": \"./app/frontend/templates/admin/members/edit.html\",\n\t\"./admin/members/edit.html\": \"./app/frontend/templates/admin/members/edit.html\",\n\t\"./admin/members/import\": \"./app/frontend/templates/admin/members/import.html\",\n\t\"./admin/members/import.html\": \"./app/frontend/templates/admin/members/import.html\",\n\t\"./admin/members/import_result\": \"./app/frontend/templates/admin/members/import_result.html\",\n\t\"./admin/members/import_result.html\": \"./app/frontend/templates/admin/members/import_result.html\",\n\t\"./admin/members/index\": \"./app/frontend/templates/admin/members/index.html\",\n\t\"./admin/members/index.html\": \"./app/frontend/templates/admin/members/index.html\",\n\t\"./admin/members/managers\": \"./app/frontend/templates/admin/members/managers.html\",\n\t\"./admin/members/managers.html\": \"./app/frontend/templates/admin/members/managers.html\",\n\t\"./admin/members/members\": \"./app/frontend/templates/admin/members/members.html\",\n\t\"./admin/members/members.html\": \"./app/frontend/templates/admin/members/members.html\",\n\t\"./admin/members/new\": \"./app/frontend/templates/admin/members/new.html\",\n\t\"./admin/members/new.html\": \"./app/frontend/templates/admin/members/new.html\",\n\t\"./admin/members/partners\": \"./app/frontend/templates/admin/members/partners.html\",\n\t\"./admin/members/partners.html\": \"./app/frontend/templates/admin/members/partners.html\",\n\t\"./admin/members/users\": \"./app/frontend/templates/admin/members/users.html\",\n\t\"./admin/members/users.html\": \"./app/frontend/templates/admin/members/users.html\",\n\t\"./admin/open_api_clients/index.html\": \"./app/frontend/templates/admin/open_api_clients/index.html.erb\",\n\t\"./admin/open_api_clients/index.html.erb\": \"./app/frontend/templates/admin/open_api_clients/index.html.erb\",\n\t\"./admin/orders/show\": \"./app/frontend/templates/admin/orders/show.html\",\n\t\"./admin/orders/show.html\": \"./app/frontend/templates/admin/orders/show.html\",\n\t\"./admin/plans/categories\": \"./app/frontend/templates/admin/plans/categories.html\",\n\t\"./admin/plans/categories.html\": \"./app/frontend/templates/admin/plans/categories.html\",\n\t\"./admin/plans/edit\": \"./app/frontend/templates/admin/plans/edit.html\",\n\t\"./admin/plans/edit.html\": \"./app/frontend/templates/admin/plans/edit.html\",\n\t\"./admin/plans/new\": \"./app/frontend/templates/admin/plans/new.html\",\n\t\"./admin/plans/new.html\": \"./app/frontend/templates/admin/plans/new.html\",\n\t\"./admin/pricing\": \"./app/frontend/templates/admin/pricing/index.html\",\n\t\"./admin/pricing/\": \"./app/frontend/templates/admin/pricing/index.html\",\n\t\"./admin/pricing/coupons\": \"./app/frontend/templates/admin/pricing/coupons.html\",\n\t\"./admin/pricing/coupons.html\": \"./app/frontend/templates/admin/pricing/coupons.html\",\n\t\"./admin/pricing/credits\": \"./app/frontend/templates/admin/pricing/credits.html\",\n\t\"./admin/pricing/credits.html\": \"./app/frontend/templates/admin/pricing/credits.html\",\n\t\"./admin/pricing/index\": \"./app/frontend/templates/admin/pricing/index.html\",\n\t\"./admin/pricing/index.html\": \"./app/frontend/templates/admin/pricing/index.html\",\n\t\"./admin/pricing/machine_hours\": \"./app/frontend/templates/admin/pricing/machine_hours.html\",\n\t\"./admin/pricing/machine_hours.html\": \"./app/frontend/templates/admin/pricing/machine_hours.html\",\n\t\"./admin/pricing/sendCoupon\": \"./app/frontend/templates/admin/pricing/sendCoupon.html\",\n\t\"./admin/pricing/sendCoupon.html\": \"./app/frontend/templates/admin/pricing/sendCoupon.html\",\n\t\"./admin/pricing/spaces\": \"./app/frontend/templates/admin/pricing/spaces.html\",\n\t\"./admin/pricing/spaces.html\": \"./app/frontend/templates/admin/pricing/spaces.html\",\n\t\"./admin/pricing/subscriptions\": \"./app/frontend/templates/admin/pricing/subscriptions.html\",\n\t\"./admin/pricing/subscriptions.html\": \"./app/frontend/templates/admin/pricing/subscriptions.html\",\n\t\"./admin/pricing/trainings\": \"./app/frontend/templates/admin/pricing/trainings.html\",\n\t\"./admin/pricing/trainings.html\": \"./app/frontend/templates/admin/pricing/trainings.html\",\n\t\"./admin/projects\": \"./app/frontend/templates/admin/projects/index.html\",\n\t\"./admin/projects/\": \"./app/frontend/templates/admin/projects/index.html\",\n\t\"./admin/projects/index\": \"./app/frontend/templates/admin/projects/index.html\",\n\t\"./admin/projects/index.html\": \"./app/frontend/templates/admin/projects/index.html\",\n\t\"./admin/projects/licences\": \"./app/frontend/templates/admin/projects/licences.html\",\n\t\"./admin/projects/licences.html\": \"./app/frontend/templates/admin/projects/licences.html\",\n\t\"./admin/projects/materials\": \"./app/frontend/templates/admin/projects/materials.html\",\n\t\"./admin/projects/materials.html\": \"./app/frontend/templates/admin/projects/materials.html\",\n\t\"./admin/projects/settings\": \"./app/frontend/templates/admin/projects/settings.html\",\n\t\"./admin/projects/settings.html\": \"./app/frontend/templates/admin/projects/settings.html\",\n\t\"./admin/projects/themes\": \"./app/frontend/templates/admin/projects/themes.html\",\n\t\"./admin/projects/themes.html\": \"./app/frontend/templates/admin/projects/themes.html\",\n\t\"./admin/settings\": \"./app/frontend/templates/admin/settings/index.html\",\n\t\"./admin/settings/\": \"./app/frontend/templates/admin/settings/index.html\",\n\t\"./admin/settings/about\": \"./app/frontend/templates/admin/settings/about.html\",\n\t\"./admin/settings/about.html\": \"./app/frontend/templates/admin/settings/about.html\",\n\t\"./admin/settings/analyticsModal\": \"./app/frontend/templates/admin/settings/analyticsModal.html\",\n\t\"./admin/settings/analyticsModal.html\": \"./app/frontend/templates/admin/settings/analyticsModal.html\",\n\t\"./admin/settings/compte\": \"./app/frontend/templates/admin/settings/compte.html\",\n\t\"./admin/settings/compte.html\": \"./app/frontend/templates/admin/settings/compte.html\",\n\t\"./admin/settings/general\": \"./app/frontend/templates/admin/settings/general.html\",\n\t\"./admin/settings/general.html\": \"./app/frontend/templates/admin/settings/general.html\",\n\t\"./admin/settings/home_page\": \"./app/frontend/templates/admin/settings/home_page.html\",\n\t\"./admin/settings/home_page.html\": \"./app/frontend/templates/admin/settings/home_page.html\",\n\t\"./admin/settings/index\": \"./app/frontend/templates/admin/settings/index.html\",\n\t\"./admin/settings/index.html\": \"./app/frontend/templates/admin/settings/index.html\",\n\t\"./admin/settings/newSelectOption\": \"./app/frontend/templates/admin/settings/newSelectOption.html\",\n\t\"./admin/settings/newSelectOption.html\": \"./app/frontend/templates/admin/settings/newSelectOption.html\",\n\t\"./admin/settings/number\": \"./app/frontend/templates/admin/settings/number.html\",\n\t\"./admin/settings/number.html\": \"./app/frontend/templates/admin/settings/number.html\",\n\t\"./admin/settings/privacy\": \"./app/frontend/templates/admin/settings/privacy.html\",\n\t\"./admin/settings/privacy.html\": \"./app/frontend/templates/admin/settings/privacy.html\",\n\t\"./admin/settings/reservations\": \"./app/frontend/templates/admin/settings/reservations.html\",\n\t\"./admin/settings/reservations.html\": \"./app/frontend/templates/admin/settings/reservations.html\",\n\t\"./admin/settings/save_policy\": \"./app/frontend/templates/admin/settings/save_policy.html\",\n\t\"./admin/settings/save_policy.html\": \"./app/frontend/templates/admin/settings/save_policy.html\",\n\t\"./admin/settings/select\": \"./app/frontend/templates/admin/settings/select.html\",\n\t\"./admin/settings/select-multiple\": \"./app/frontend/templates/admin/settings/select-multiple.html\",\n\t\"./admin/settings/select-multiple.html\": \"./app/frontend/templates/admin/settings/select-multiple.html\",\n\t\"./admin/settings/select.html\": \"./app/frontend/templates/admin/settings/select.html\",\n\t\"./admin/settings/text\": \"./app/frontend/templates/admin/settings/text.html\",\n\t\"./admin/settings/text.html\": \"./app/frontend/templates/admin/settings/text.html\",\n\t\"./admin/statistics\": \"./app/frontend/templates/admin/statistics/index.html\",\n\t\"./admin/statistics/\": \"./app/frontend/templates/admin/statistics/index.html\",\n\t\"./admin/statistics/export\": \"./app/frontend/templates/admin/statistics/export.html\",\n\t\"./admin/statistics/export.html\": \"./app/frontend/templates/admin/statistics/export.html\",\n\t\"./admin/statistics/graphs\": \"./app/frontend/templates/admin/statistics/graphs.html\",\n\t\"./admin/statistics/graphs.html\": \"./app/frontend/templates/admin/statistics/graphs.html\",\n\t\"./admin/statistics/index\": \"./app/frontend/templates/admin/statistics/index.html\",\n\t\"./admin/statistics/index.html\": \"./app/frontend/templates/admin/statistics/index.html\",\n\t\"./admin/store\": \"./app/frontend/templates/admin/store/index.html\",\n\t\"./admin/store/\": \"./app/frontend/templates/admin/store/index.html\",\n\t\"./admin/store/categories\": \"./app/frontend/templates/admin/store/categories.html\",\n\t\"./admin/store/categories.html\": \"./app/frontend/templates/admin/store/categories.html\",\n\t\"./admin/store/index\": \"./app/frontend/templates/admin/store/index.html\",\n\t\"./admin/store/index.html\": \"./app/frontend/templates/admin/store/index.html\",\n\t\"./admin/store/orders\": \"./app/frontend/templates/admin/store/orders.html\",\n\t\"./admin/store/orders.html\": \"./app/frontend/templates/admin/store/orders.html\",\n\t\"./admin/store/product_edit\": \"./app/frontend/templates/admin/store/product_edit.html\",\n\t\"./admin/store/product_edit.html\": \"./app/frontend/templates/admin/store/product_edit.html\",\n\t\"./admin/store/product_new\": \"./app/frontend/templates/admin/store/product_new.html\",\n\t\"./admin/store/product_new.html\": \"./app/frontend/templates/admin/store/product_new.html\",\n\t\"./admin/store/products\": \"./app/frontend/templates/admin/store/products.html\",\n\t\"./admin/store/products.html\": \"./app/frontend/templates/admin/store/products.html\",\n\t\"./admin/store/settings\": \"./app/frontend/templates/admin/store/settings.html\",\n\t\"./admin/store/settings.html\": \"./app/frontend/templates/admin/store/settings.html\",\n\t\"./admin/tags\": \"./app/frontend/templates/admin/tags/index.html\",\n\t\"./admin/tags/\": \"./app/frontend/templates/admin/tags/index.html\",\n\t\"./admin/tags/index\": \"./app/frontend/templates/admin/tags/index.html\",\n\t\"./admin/tags/index.html\": \"./app/frontend/templates/admin/tags/index.html\",\n\t\"./admin/trainings\": \"./app/frontend/templates/admin/trainings/index.html\",\n\t\"./admin/trainings/\": \"./app/frontend/templates/admin/trainings/index.html\",\n\t\"./admin/trainings/edit\": \"./app/frontend/templates/admin/trainings/edit.html\",\n\t\"./admin/trainings/edit.html\": \"./app/frontend/templates/admin/trainings/edit.html\",\n\t\"./admin/trainings/index\": \"./app/frontend/templates/admin/trainings/index.html\",\n\t\"./admin/trainings/index.html\": \"./app/frontend/templates/admin/trainings/index.html\",\n\t\"./admin/trainings/modal_edit\": \"./app/frontend/templates/admin/trainings/modal_edit.html\",\n\t\"./admin/trainings/modal_edit.html\": \"./app/frontend/templates/admin/trainings/modal_edit.html\",\n\t\"./admin/trainings/new\": \"./app/frontend/templates/admin/trainings/new.html\",\n\t\"./admin/trainings/new.html\": \"./app/frontend/templates/admin/trainings/new.html\",\n\t\"./admin/trainings/validTrainingModal\": \"./app/frontend/templates/admin/trainings/validTrainingModal.html\",\n\t\"./admin/trainings/validTrainingModal.html\": \"./app/frontend/templates/admin/trainings/validTrainingModal.html\",\n\t\"./admin/versions/upgradeModal\": \"./app/frontend/templates/admin/versions/upgradeModal.html\",\n\t\"./admin/versions/upgradeModal.html\": \"./app/frontend/templates/admin/versions/upgradeModal.html\",\n\t\"./calendar/calendar\": \"./app/frontend/templates/calendar/calendar.html\",\n\t\"./calendar/calendar.html\": \"./app/frontend/templates/calendar/calendar.html\",\n\t\"./calendar/chooseMachine\": \"./app/frontend/templates/calendar/chooseMachine.html\",\n\t\"./calendar/chooseMachine.html\": \"./app/frontend/templates/calendar/chooseMachine.html\",\n\t\"./calendar/filter\": \"./app/frontend/templates/calendar/filter.html\",\n\t\"./calendar/filter.html\": \"./app/frontend/templates/calendar/filter.html\",\n\t\"./calendar/filterAside\": \"./app/frontend/templates/calendar/filterAside.html\",\n\t\"./calendar/filterAside.html\": \"./app/frontend/templates/calendar/filterAside.html\",\n\t\"./cart\": \"./app/frontend/templates/cart/index.html\",\n\t\"./cart/\": \"./app/frontend/templates/cart/index.html\",\n\t\"./cart/index\": \"./app/frontend/templates/cart/index.html\",\n\t\"./cart/index.html\": \"./app/frontend/templates/cart/index.html\",\n\t\"./dashboard/events\": \"./app/frontend/templates/dashboard/events.html\",\n\t\"./dashboard/events.html\": \"./app/frontend/templates/dashboard/events.html\",\n\t\"./dashboard/invoices\": \"./app/frontend/templates/dashboard/invoices.html\",\n\t\"./dashboard/invoices.html\": \"./app/frontend/templates/dashboard/invoices.html\",\n\t\"./dashboard/nav\": \"./app/frontend/templates/dashboard/nav.html\",\n\t\"./dashboard/nav.html\": \"./app/frontend/templates/dashboard/nav.html\",\n\t\"./dashboard/orders\": \"./app/frontend/templates/dashboard/orders.html\",\n\t\"./dashboard/orders.html\": \"./app/frontend/templates/dashboard/orders.html\",\n\t\"./dashboard/payment_schedules\": \"./app/frontend/templates/dashboard/payment_schedules.html\",\n\t\"./dashboard/payment_schedules.html\": \"./app/frontend/templates/dashboard/payment_schedules.html\",\n\t\"./dashboard/profile\": \"./app/frontend/templates/dashboard/profile.html\",\n\t\"./dashboard/profile.html\": \"./app/frontend/templates/dashboard/profile.html\",\n\t\"./dashboard/projects\": \"./app/frontend/templates/dashboard/projects.html\",\n\t\"./dashboard/projects.html\": \"./app/frontend/templates/dashboard/projects.html\",\n\t\"./dashboard/reservations\": \"./app/frontend/templates/dashboard/reservations.html\",\n\t\"./dashboard/reservations.html\": \"./app/frontend/templates/dashboard/reservations.html\",\n\t\"./dashboard/settings\": \"./app/frontend/templates/dashboard/settings.html\",\n\t\"./dashboard/settings.html\": \"./app/frontend/templates/dashboard/settings.html\",\n\t\"./dashboard/supporting_document_files\": \"./app/frontend/templates/dashboard/supporting_document_files.html\",\n\t\"./dashboard/supporting_document_files.html\": \"./app/frontend/templates/dashboard/supporting_document_files.html\",\n\t\"./dashboard/trainings\": \"./app/frontend/templates/dashboard/trainings.html\",\n\t\"./dashboard/trainings.html\": \"./app/frontend/templates/dashboard/trainings.html\",\n\t\"./dashboard/wallet\": \"./app/frontend/templates/dashboard/wallet.html\",\n\t\"./dashboard/wallet.html\": \"./app/frontend/templates/dashboard/wallet.html\",\n\t\"./events\": \"./app/frontend/templates/events/index.html\",\n\t\"./events/\": \"./app/frontend/templates/events/index.html\",\n\t\"./events/deleteRecurrent\": \"./app/frontend/templates/events/deleteRecurrent.html\",\n\t\"./events/deleteRecurrent.html\": \"./app/frontend/templates/events/deleteRecurrent.html\",\n\t\"./events/edit\": \"./app/frontend/templates/events/edit.html\",\n\t\"./events/edit.html\": \"./app/frontend/templates/events/edit.html\",\n\t\"./events/index\": \"./app/frontend/templates/events/index.html\",\n\t\"./events/index.html\": \"./app/frontend/templates/events/index.html\",\n\t\"./events/modify_event_reservation_modal\": \"./app/frontend/templates/events/modify_event_reservation_modal.html\",\n\t\"./events/modify_event_reservation_modal.html\": \"./app/frontend/templates/events/modify_event_reservation_modal.html\",\n\t\"./events/new\": \"./app/frontend/templates/events/new.html\",\n\t\"./events/new.html\": \"./app/frontend/templates/events/new.html\",\n\t\"./events/show\": \"./app/frontend/templates/events/show.html\",\n\t\"./events/show.html\": \"./app/frontend/templates/events/show.html\",\n\t\"./home\": \"./app/frontend/templates/home.html\",\n\t\"./home.html\": \"./app/frontend/templates/home.html\",\n\t\"./home/events\": \"./app/frontend/templates/home/events.html\",\n\t\"./home/events.html\": \"./app/frontend/templates/home/events.html\",\n\t\"./home/members\": \"./app/frontend/templates/home/members.html\",\n\t\"./home/members.html\": \"./app/frontend/templates/home/members.html\",\n\t\"./home/news\": \"./app/frontend/templates/home/news.html\",\n\t\"./home/news.html\": \"./app/frontend/templates/home/news.html\",\n\t\"./home/projects\": \"./app/frontend/templates/home/projects.html\",\n\t\"./home/projects.html\": \"./app/frontend/templates/home/projects.html\",\n\t\"./home/twitter\": \"./app/frontend/templates/home/twitter.html\",\n\t\"./home/twitter.html\": \"./app/frontend/templates/home/twitter.html\",\n\t\"./machines\": \"./app/frontend/templates/machines/index.html\",\n\t\"./machines/\": \"./app/frontend/templates/machines/index.html\",\n\t\"./machines/edit\": \"./app/frontend/templates/machines/edit.html\",\n\t\"./machines/edit.html\": \"./app/frontend/templates/machines/edit.html\",\n\t\"./machines/index\": \"./app/frontend/templates/machines/index.html\",\n\t\"./machines/index.html\": \"./app/frontend/templates/machines/index.html\",\n\t\"./machines/new\": \"./app/frontend/templates/machines/new.html\",\n\t\"./machines/new.html\": \"./app/frontend/templates/machines/new.html\",\n\t\"./machines/reserve\": \"./app/frontend/templates/machines/reserve.html\",\n\t\"./machines/reserve.html\": \"./app/frontend/templates/machines/reserve.html\",\n\t\"./machines/show\": \"./app/frontend/templates/machines/show.html\",\n\t\"./machines/show.html\": \"./app/frontend/templates/machines/show.html\",\n\t\"./members\": \"./app/frontend/templates/members/index.html\",\n\t\"./members/\": \"./app/frontend/templates/members/index.html\",\n\t\"./members/index\": \"./app/frontend/templates/members/index.html\",\n\t\"./members/index.html\": \"./app/frontend/templates/members/index.html\",\n\t\"./members/show\": \"./app/frontend/templates/members/show.html\",\n\t\"./members/show.html\": \"./app/frontend/templates/members/show.html\",\n\t\"./notifications\": \"./app/frontend/templates/notifications/index.html\",\n\t\"./notifications/\": \"./app/frontend/templates/notifications/index.html\",\n\t\"./notifications/index\": \"./app/frontend/templates/notifications/index.html\",\n\t\"./notifications/index.html\": \"./app/frontend/templates/notifications/index.html\",\n\t\"./orders/show\": \"./app/frontend/templates/orders/show.html\",\n\t\"./orders/show.html\": \"./app/frontend/templates/orders/show.html\",\n\t\"./plans\": \"./app/frontend/templates/plans/index.html\",\n\t\"./plans/\": \"./app/frontend/templates/plans/index.html\",\n\t\"./plans/_plan\": \"./app/frontend/templates/plans/_plan.html\",\n\t\"./plans/_plan.html\": \"./app/frontend/templates/plans/_plan.html\",\n\t\"./plans/index\": \"./app/frontend/templates/plans/index.html\",\n\t\"./plans/index.html\": \"./app/frontend/templates/plans/index.html\",\n\t\"./products/show\": \"./app/frontend/templates/products/show.html\",\n\t\"./products/show.html\": \"./app/frontend/templates/products/show.html\",\n\t\"./profile/_token\": \"./app/frontend/templates/profile/_token.html\",\n\t\"./profile/_token.html\": \"./app/frontend/templates/profile/_token.html\",\n\t\"./profile/complete\": \"./app/frontend/templates/profile/complete.html\",\n\t\"./profile/complete.html\": \"./app/frontend/templates/profile/complete.html\",\n\t\"./profile/resend_code_modal\": \"./app/frontend/templates/profile/resend_code_modal.html\",\n\t\"./profile/resend_code_modal.html\": \"./app/frontend/templates/profile/resend_code_modal.html\",\n\t\"./projects\": \"./app/frontend/templates/projects/index.html\",\n\t\"./projects/\": \"./app/frontend/templates/projects/index.html\",\n\t\"./projects/_form\": \"./app/frontend/templates/projects/_form.html\",\n\t\"./projects/_form.html\": \"./app/frontend/templates/projects/_form.html\",\n\t\"./projects/edit\": \"./app/frontend/templates/projects/edit.html\",\n\t\"./projects/edit.html\": \"./app/frontend/templates/projects/edit.html\",\n\t\"./projects/index\": \"./app/frontend/templates/projects/index.html\",\n\t\"./projects/index.html\": \"./app/frontend/templates/projects/index.html\",\n\t\"./projects/new\": \"./app/frontend/templates/projects/new.html\",\n\t\"./projects/new.html\": \"./app/frontend/templates/projects/new.html\",\n\t\"./projects/show\": \"./app/frontend/templates/projects/show.html\",\n\t\"./projects/show.html\": \"./app/frontend/templates/projects/show.html\",\n\t\"./shared/ConfirmationNewModal\": \"./app/frontend/templates/shared/ConfirmationNewModal.html\",\n\t\"./shared/ConfirmationNewModal.html\": \"./app/frontend/templates/shared/ConfirmationNewModal.html\",\n\t\"./shared/_admin_form\": \"./app/frontend/templates/shared/_admin_form.html\",\n\t\"./shared/_admin_form.html\": \"./app/frontend/templates/shared/_admin_form.html\",\n\t\"./shared/_cart\": \"./app/frontend/templates/shared/_cart.html\",\n\t\"./shared/_cart.html\": \"./app/frontend/templates/shared/_cart.html\",\n\t\"./shared/_coupon\": \"./app/frontend/templates/shared/_coupon.html\",\n\t\"./shared/_coupon.html\": \"./app/frontend/templates/shared/_coupon.html\",\n\t\"./shared/_manager_form\": \"./app/frontend/templates/shared/_manager_form.html\",\n\t\"./shared/_manager_form.html\": \"./app/frontend/templates/shared/_manager_form.html\",\n\t\"./shared/_member_select\": \"./app/frontend/templates/shared/_member_select.html\",\n\t\"./shared/_member_select.html\": \"./app/frontend/templates/shared/_member_select.html\",\n\t\"./shared/_partner_new_modal\": \"./app/frontend/templates/shared/_partner_new_modal.html\",\n\t\"./shared/_partner_new_modal.html\": \"./app/frontend/templates/shared/_partner_new_modal.html\",\n\t\"./shared/_reserve_slot_same_time\": \"./app/frontend/templates/shared/_reserve_slot_same_time.html\",\n\t\"./shared/_reserve_slot_same_time.html\": \"./app/frontend/templates/shared/_reserve_slot_same_time.html\",\n\t\"./shared/_reserve_slot_tags_mismatch\": \"./app/frontend/templates/shared/_reserve_slot_tags_mismatch.html\",\n\t\"./shared/_reserve_slot_tags_mismatch.html\": \"./app/frontend/templates/shared/_reserve_slot_tags_mismatch.html\",\n\t\"./shared/_reserve_slot_without_plan\": \"./app/frontend/templates/shared/_reserve_slot_without_plan.html\",\n\t\"./shared/_reserve_slot_without_plan.html\": \"./app/frontend/templates/shared/_reserve_slot_without_plan.html\",\n\t\"./shared/_social_link\": \"./app/frontend/templates/shared/_social_link.html\",\n\t\"./shared/_social_link.html\": \"./app/frontend/templates/shared/_social_link.html\",\n\t\"./shared/_user_avatar\": \"./app/frontend/templates/shared/_user_avatar.html\",\n\t\"./shared/_user_avatar.html\": \"./app/frontend/templates/shared/_user_avatar.html\",\n\t\"./shared/about\": \"./app/frontend/templates/shared/about.html\",\n\t\"./shared/about.html\": \"./app/frontend/templates/shared/about.html\",\n\t\"./shared/confirm_modal\": \"./app/frontend/templates/shared/confirm_modal.html\",\n\t\"./shared/confirm_modal.html\": \"./app/frontend/templates/shared/confirm_modal.html\",\n\t\"./shared/confirm_modify_slot_modal\": \"./app/frontend/templates/shared/confirm_modify_slot_modal.html\",\n\t\"./shared/confirm_modify_slot_modal.html\": \"./app/frontend/templates/shared/confirm_modify_slot_modal.html\",\n\t\"./shared/cookies\": \"./app/frontend/templates/shared/cookies.html\",\n\t\"./shared/cookies.html\": \"./app/frontend/templates/shared/cookies.html\",\n\t\"./shared/deviseModal\": \"./app/frontend/templates/shared/deviseModal.html\",\n\t\"./shared/deviseModal.html\": \"./app/frontend/templates/shared/deviseModal.html\",\n\t\"./shared/header.html\": \"./app/frontend/templates/shared/header.html.erb\",\n\t\"./shared/header.html.erb\": \"./app/frontend/templates/shared/header.html.erb\",\n\t\"./shared/help_modal\": \"./app/frontend/templates/shared/help_modal.html\",\n\t\"./shared/help_modal.html\": \"./app/frontend/templates/shared/help_modal.html\",\n\t\"./shared/leftnav\": \"./app/frontend/templates/shared/leftnav.html\",\n\t\"./shared/leftnav.html\": \"./app/frontend/templates/shared/leftnav.html\",\n\t\"./shared/passwordEditModal\": \"./app/frontend/templates/shared/passwordEditModal.html\",\n\t\"./shared/passwordEditModal.html\": \"./app/frontend/templates/shared/passwordEditModal.html\",\n\t\"./shared/passwordNewModal\": \"./app/frontend/templates/shared/passwordNewModal.html\",\n\t\"./shared/passwordNewModal.html\": \"./app/frontend/templates/shared/passwordNewModal.html\",\n\t\"./shared/privacy\": \"./app/frontend/templates/shared/privacy.html\",\n\t\"./shared/privacy.html\": \"./app/frontend/templates/shared/privacy.html\",\n\t\"./shared/publicProfile.html\": \"./app/frontend/templates/shared/publicProfile.html.erb\",\n\t\"./shared/publicProfile.html.erb\": \"./app/frontend/templates/shared/publicProfile.html.erb\",\n\t\"./shared/signalAbuseModal\": \"./app/frontend/templates/shared/signalAbuseModal.html\",\n\t\"./shared/signalAbuseModal.html\": \"./app/frontend/templates/shared/signalAbuseModal.html\",\n\t\"./shared/signupModal\": \"./app/frontend/templates/shared/signupModal.html\",\n\t\"./shared/signupModal.html\": \"./app/frontend/templates/shared/signupModal.html\",\n\t\"./shared/tour-step-template\": \"./app/frontend/templates/shared/tour-step-template.html\",\n\t\"./shared/tour-step-template.html\": \"./app/frontend/templates/shared/tour-step-template.html\",\n\t\"./shared/valid_reservation_modal\": \"./app/frontend/templates/shared/valid_reservation_modal.html\",\n\t\"./shared/valid_reservation_modal.html\": \"./app/frontend/templates/shared/valid_reservation_modal.html\",\n\t\"./spaces\": \"./app/frontend/templates/spaces/index.html\",\n\t\"./spaces/\": \"./app/frontend/templates/spaces/index.html\",\n\t\"./spaces/edit\": \"./app/frontend/templates/spaces/edit.html\",\n\t\"./spaces/edit.html\": \"./app/frontend/templates/spaces/edit.html\",\n\t\"./spaces/index\": \"./app/frontend/templates/spaces/index.html\",\n\t\"./spaces/index.html\": \"./app/frontend/templates/spaces/index.html\",\n\t\"./spaces/new\": \"./app/frontend/templates/spaces/new.html\",\n\t\"./spaces/new.html\": \"./app/frontend/templates/spaces/new.html\",\n\t\"./spaces/reserve\": \"./app/frontend/templates/spaces/reserve.html\",\n\t\"./spaces/reserve.html\": \"./app/frontend/templates/spaces/reserve.html\",\n\t\"./spaces/show\": \"./app/frontend/templates/spaces/show.html\",\n\t\"./spaces/show.html\": \"./app/frontend/templates/spaces/show.html\",\n\t\"./store\": \"./app/frontend/templates/store/index.html\",\n\t\"./store/\": \"./app/frontend/templates/store/index.html\",\n\t\"./store/index\": \"./app/frontend/templates/store/index.html\",\n\t\"./store/index.html\": \"./app/frontend/templates/store/index.html\",\n\t\"./trainings\": \"./app/frontend/templates/trainings/index.html\",\n\t\"./trainings/\": \"./app/frontend/templates/trainings/index.html\",\n\t\"./trainings/index\": \"./app/frontend/templates/trainings/index.html\",\n\t\"./trainings/index.html\": \"./app/frontend/templates/trainings/index.html\",\n\t\"./trainings/reserve\": \"./app/frontend/templates/trainings/reserve.html\",\n\t\"./trainings/reserve.html\": \"./app/frontend/templates/trainings/reserve.html\",\n\t\"./trainings/show\": \"./app/frontend/templates/trainings/show.html\",\n\t\"./trainings/show.html\": \"./app/frontend/templates/trainings/show.html\",\n\t\"./wallet/credit_modal\": \"./app/frontend/templates/wallet/credit_modal.html\",\n\t\"./wallet/credit_modal.html\": \"./app/frontend/templates/wallet/credit_modal.html\",\n\t\"./wallet/show\": \"./app/frontend/templates/wallet/show.html\",\n\t\"./wallet/show.html\": \"./app/frontend/templates/wallet/show.html\",\n\t\"./wallet/transactions\": \"./app/frontend/templates/wallet/transactions.html\",\n\t\"./wallet/transactions.html\": \"./app/frontend/templates/wallet/transactions.html\"\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 = \"./app/frontend/templates sync recursive ^\\\\.\\\\/.*$\";","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { AgeRange } from '../models/event';\n\nexport default class AgeRangeAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/age_ranges');\n return res?.data;\n }\n}\n","import { ActiveProviderResponse, AuthenticationProvider, MappingFields } from '../models/authentication-provider';\nimport { AxiosResponse } from 'axios';\nimport apiClient from './clients/api-client';\n\nexport default class AuthProviderAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/auth_providers');\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/auth_providers/${id}`);\n return res?.data;\n }\n\n static async create (authProvider: AuthenticationProvider): Promise {\n const res: AxiosResponse = await apiClient.post('/api/auth_providers', authProvider);\n return res?.data;\n }\n\n static async update (authProvider: AuthenticationProvider): Promise {\n const res: AxiosResponse = await apiClient.put(`/api/auth_providers/${authProvider.id}`, authProvider);\n return res?.data;\n }\n\n static async delete (id: number): Promise {\n await apiClient.delete(`/api/auth_providers/${id}`);\n }\n\n static async mappingFields (): Promise {\n const res: AxiosResponse = await apiClient.get('/api/auth_providers/mapping_fields');\n return res?.data;\n }\n\n static async strategyName (authProvider: AuthenticationProvider): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/auth_providers/strategy_name?providable_type=${authProvider.providable_type}&name=${authProvider.name}`);\n return res?.data;\n }\n\n static async active (): Promise {\n const res: AxiosResponse = await apiClient.get('/api/auth_providers/active');\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { User } from '../models/user';\n\nexport default class Authentication {\n static async login (email: string, password: string): Promise {\n const res: AxiosResponse = await apiClient.post('/users/sign_in.json', { email, password });\n return res?.data;\n }\n\n static async logout (): Promise {\n return apiClient.delete('/users/sign_out.json');\n }\n\n static async verifyPassword (password: string): Promise {\n try {\n const res: AxiosResponse = await apiClient.post('/password/verify.json', { password });\n return (res.status === 200);\n } catch (e) {\n return false;\n }\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { BrazillianState } from '../models/brazillian-state';\nimport { BrazillianCity } from '../models/brazillian-city';\nimport { BrazillianZipcode } from '../models/brazillian-zipcode';\n\nexport default class BrazillianAPI {\n static async states (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/brazillian_data/all_states');\n return res?.data;\n }\n\n static async cities (uf: string): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/brazillian_data/cities/${uf}`);\n return res?.data;\n }\n\n static async zipcode (zip: string): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/brazillian_data/zipcode/${zip}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Order, OrderableType, OrderErrors } from '../models/order';\nimport { CartItem, CartItemResponse } from '../models/cart_item';\n\nexport default class CartAPI {\n static async create (token?: string): Promise {\n const res: AxiosResponse = await apiClient.post('/api/cart', { order_token: token });\n return res?.data;\n }\n\n static async createItem (order: Order, item: CartItem): Promise {\n const res: AxiosResponse = await apiClient.post('/api/cart/create_item', { order_token: order.token, ...item });\n return res?.data;\n }\n\n static async addItem (order: Order, orderableId: number, orderableType: OrderableType, quantity: number): Promise {\n const res: AxiosResponse = await apiClient.put('/api/cart/add_item', { order_token: order.token, orderable_id: orderableId, orderable_type: orderableType, quantity });\n return res?.data;\n }\n\n static async removeItem (order: Order, orderableId: number, orderableType: OrderableType): Promise {\n const res: AxiosResponse = await apiClient.put('/api/cart/remove_item', { order_token: order.token, orderable_id: orderableId, orderable_type: orderableType });\n return res?.data;\n }\n\n static async setQuantity (order: Order, orderableId: number, orderableType: OrderableType, quantity: number): Promise {\n const res: AxiosResponse = await apiClient.put('/api/cart/set_quantity', { order_token: order.token, orderable_id: orderableId, orderable_type: orderableType, quantity });\n return res?.data;\n }\n\n static async setOffer (order: Order, orderableId: number, orderableType: OrderableType, isOffered: boolean): Promise {\n const res: AxiosResponse = await apiClient.put('/api/cart/set_offer', { order_token: order.token, orderable_id: orderableId, orderable_type: orderableType, is_offered: isOffered, customer_id: order.user?.id });\n return res?.data;\n }\n\n static async refreshItem (order: Order, orderableId: number, orderableType: OrderableType): Promise {\n const res: AxiosResponse = await apiClient.put('/api/cart/refresh_item', { order_token: order.token, orderable_id: orderableId, orderable_type: orderableType });\n return res?.data;\n }\n\n static async validate (order: Order): Promise {\n const res: AxiosResponse = await apiClient.post('/api/cart/validate', { order_token: order.token });\n return res?.data;\n }\n\n static async setCustomer (order: Order, customerId: number): Promise {\n const res: AxiosResponse = await apiClient.put('/api/cart/set_customer', { order_token: order.token, user_id: customerId });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { OrderPayment, Order } from '../models/order';\n\nexport default class CheckoutAPI {\n static async payment (order: Order, paymentId?: string): Promise {\n const res: AxiosResponse = await apiClient.post('/api/checkout/payment', {\n order_token: order.token,\n coupon_code: order.coupon?.code,\n payment_id: paymentId,\n customer_id: order.user.id\n });\n return res?.data;\n }\n\n static async confirmPayment (order: Order, paymentId: string): Promise {\n const res: AxiosResponse = await apiClient.post('/api/checkout/confirm_payment', {\n order_token: order.token,\n coupon_code: order.coupon?.code,\n payment_id: paymentId,\n customer_id: order.user.id\n });\n return res?.data;\n }\n}\n","import axios, { AxiosInstance } from 'axios';\nimport ParsingLib from '../../lib/parsing';\n\ntype Error = { error: string };\n\nconst token: HTMLMetaElement = document.querySelector('[name=\"csrf-token\"]');\nconst client: AxiosInstance = axios.create({\n headers: {\n common: {\n 'X-CSRF-Token': token?.content || 'no-csrf-token'\n }\n }\n});\n\nclient.interceptors.response.use(function (response) {\n // Any status code that lie within the range of 2xx cause this function to trigger\n return response;\n}, function (error) {\n // 304 Not Modified should be considered as a success\n if (error.response?.status === 304) { return Promise.resolve(error.response); }\n\n // Any status codes that falls outside the range of 2xx cause this function to trigger\n const message = error.response?.data || error.message || error;\n return Promise.reject(extractHumanReadableMessage(message));\n});\n\nfunction extractHumanReadableMessage (error: string|Error): string {\n if (typeof error === 'string') {\n if (error.match(/^/)) {\n // parse ruby error pages (when an unhandled exception is raised)\n const parser = new DOMParser();\n const htmlDoc = parser.parseFromString(error, 'text/html');\n if (htmlDoc.querySelectorAll('h2').length > 2) {\n return htmlDoc.querySelector('h2').textContent;\n } else {\n if (htmlDoc.querySelector('.exception-message .message')) {\n return htmlDoc.querySelector('.exception-message .message').textContent;\n }\n return htmlDoc.querySelector('h1').textContent;\n }\n }\n return error;\n }\n\n // parse Rails errors (as JSON) or API errors (i.e. the API returns a JSON like {error: ...})\n let message = '';\n if (error instanceof Object) {\n // API errors\n if (Object.prototype.hasOwnProperty.call(error, 'error') && typeof error.error === 'string') {\n return error.error;\n }\n // iterate through all the keys to build the message\n for (const key in error) {\n if (Object.prototype.hasOwnProperty.call(error, key)) {\n if (!ParsingLib.isInteger(key)) {\n message += `${key} : `;\n }\n if (error[key] instanceof Array) {\n // standard rails messages are stored as {field: [error1, error2]}\n // we rebuild them as \"field: error1, error2\"\n message += error[key].join(', ');\n } else {\n message += error[key];\n }\n }\n }\n return message;\n }\n\n return JSON.stringify(error);\n}\n\nexport default client;\n","import axios, { AxiosInstance } from 'axios';\n\nfunction client (host: string): AxiosInstance {\n return axios.create({\n baseURL: host\n });\n}\n\nexport default client;\n","import axios, { AxiosInstance } from 'axios';\n\nfunction client (key: string): AxiosInstance {\n return axios.create({\n baseURL: 'https://api.stripe.com/v1/',\n headers: {\n common: {\n Authorization: `Bearer ${key}`\n }\n }\n });\n}\n\nexport default client;\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Coupon } from '../models/coupon';\n\nexport default class CouponAPI {\n static async validate (code: string, amount: number, userId?: number): Promise {\n const res: AxiosResponse = await apiClient.post('/api/coupons/validate', { code, amount, user_id: userId });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Credit, CreditableType } from '../models/credit';\n\nexport default class CreditAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/credits');\n return res?.data;\n }\n\n static async userResource (userId: number, resource: CreditableType): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/credits/user/${userId}/${resource}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { CustomAsset, CustomAssetName } from '../models/custom-asset';\n\nexport default class CustomAssetAPI {\n static async get (name: CustomAssetName): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/custom_assets/${name}`);\n return res?.data?.custom_asset;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { EventCategory } from '../models/event';\n\nexport default class EventCategoryAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/categories');\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { EventPriceCategory } from '../models/event';\n\nexport default class EventPriceCategoryAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/price_categories');\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { EventTheme } from '../models/event';\n\nexport default class EventThemeAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/event_themes');\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Event, EventUpdateResult } from '../models/event';\nimport ApiLib from '../lib/api';\n\nexport default class EventAPI {\n static async create (event: Event): Promise {\n const data = ApiLib.serializeAttachments(event, 'event', ['event_files_attributes', 'event_image_attributes']);\n const res: AxiosResponse = await apiClient.post('/api/events', data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async update (event: Event, mode: 'single' | 'next' | 'all'): Promise {\n const data = ApiLib.serializeAttachments(event, 'event', ['event_files_attributes', 'event_image_attributes']);\n data.set('edit_mode', mode);\n const res: AxiosResponse = await apiClient.put(`/api/events/${event.id}`, data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n}\n","import ssoClient from '../clients/sso-client';\nimport { AxiosResponse } from 'axios';\nimport { OpenIdConfiguration } from '../../models/sso';\n\nexport default class SsoClient {\n /**\n * @see https://openid.net/specs/openid-connect-discovery-1_0.html\n */\n static async openIdConfiguration (host: string): Promise {\n const res: AxiosResponse = await ssoClient(host).get('.well-known/openid-configuration');\n return res?.data;\n }\n}\n","import stripeClient from '../clients/stripe-client';\nimport { AxiosResponse } from 'axios';\nimport { ListCharges, PIIToken } from '../../models/stripe';\n\nexport default class StripeAPI {\n /**\n * @see https://stripe.com/docs/api/tokens/create_pii\n */\n static async createPIIToken (key: string, piiId: string): Promise {\n const params = new URLSearchParams();\n params.append('pii[id_number]', piiId);\n\n const config = {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded'\n }\n };\n\n const res: AxiosResponse = await stripeClient(key).post('tokens', params, config);\n return res?.data;\n }\n\n /**\n * @see https://stripe.com/docs/api/charges/list\n */\n static async listAllCharges (key: string): Promise {\n const res: AxiosResponse = await stripeClient(key).get('charges');\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ShoppingCart } from '../models/payment';\nimport { User } from '../models/user';\nimport {\n CreatePaymentResponse,\n CreateTokenResponse,\n SdkTestResponse,\n Card\n} from '../models/getnet';\nimport { Invoice } from '../models/invoice';\n\nexport default class GetnetAPI {\n static async sdkTest (endpoint: string, sellerId: string, clientId: string, clientSecret: string): Promise {\n const res: AxiosResponse = await apiClient.post('/api/getnet/sdk_test', { endpoint, seller_id: sellerId, client_id: clientId, client_secret: clientSecret });\n return res?.data;\n }\n\n static async tokenCard (cardNumber: string, customer: User): Promise {\n const res: AxiosResponse = await apiClient.post('/api/getnet/token_card', { card_number: cardNumber, customer_id: customer.id });\n return res?.data;\n }\n\n static async createPayment (card: Card, cart: ShoppingCart, customer: User): Promise {\n const res: AxiosResponse = await apiClient.post('/api/getnet/create_payment', { cart_items: cart, customer_id: customer.id, card });\n return res?.data;\n }\n\n static async confirm (orderId: string, cart: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/getnet/confirm_payment', { cart_items: cart, order_id: orderId });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Group, GroupIndexFilter } from '../models/group';\nimport ApiLib from '../lib/api';\n\nexport default class GroupAPI {\n static async index (filters?: GroupIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/groups${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ShoppingCart } from '../models/payment';\nimport { PaymentSchedule } from '../models/payment-schedule';\nimport { Invoice } from '../models/invoice';\n\nexport default class LocalPaymentAPI {\n static async confirmPayment (cartItems: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/local_payment/confirm_payment', cartItems);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { MachineCategory } from '../models/machine-category';\n\nexport default class MachineCategoryAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/machine_categories');\n return res?.data;\n }\n\n static async create (category: MachineCategory): Promise {\n const res: AxiosResponse = await apiClient.post('/api/machine_categories', { machine_category: category });\n return res?.data;\n }\n\n static async update (category: MachineCategory): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/machine_categories/${category.id}`, { machine_category: category });\n return res?.data;\n }\n\n static async destroy (categoryId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/machine_categories/${categoryId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Machine, MachineIndexFilter } from '../models/machine';\nimport ApiLib from '../lib/api';\n\nexport default class MachineAPI {\n static async index (filters?: MachineIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/machines${ApiLib.filtersToQuery(filters, false)}`);\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/machines/${id}`);\n return res?.data;\n }\n\n static async create (machine: Machine): Promise {\n const data = ApiLib.serializeAttachments(machine, 'machine', ['machine_files_attributes', 'machine_image_attributes']);\n const res: AxiosResponse = await apiClient.post('/api/machines', data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async update (machine: Machine): Promise {\n const data = ApiLib.serializeAttachments(machine, 'machine', ['machine_files_attributes', 'machine_image_attributes']);\n const res: AxiosResponse = await apiClient.put(`/api/machines/${machine.id}`, data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { serialize } from 'object-to-formdata-tz';\nimport { User, MemberIndexFilter, UserRole } from '../models/user';\n\nexport default class MemberAPI {\n static async list (filters: MemberIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.post('/api/members/list', filters);\n return res?.data;\n }\n\n static async search (name: string): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/members/search/${name}`);\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/members/${id}`);\n return res?.data;\n }\n\n static async create (user: User): Promise {\n const data = serialize({ user });\n if (user.profile_attributes?.user_avatar_attributes?.attachment_files[0]) {\n data.set('user[profile_attributes][user_avatar_attributes][attachment]', user.profile_attributes.user_avatar_attributes.attachment_files[0]);\n }\n const res: AxiosResponse = await apiClient.post('/api/members', data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async update (user: User): Promise {\n const data = serialize({ user }, { allowEmptyArrays: true });\n if (user.profile_attributes?.user_avatar_attributes?.attachment_files[0]) {\n data.set('user[profile_attributes][user_avatar_attributes][attachment]', user.profile_attributes.user_avatar_attributes.attachment_files[0]);\n }\n const res: AxiosResponse = await apiClient.patch(`/api/members/${user.id}`, data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async updateRole (user: User, role: UserRole, groupId?: number): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/members/${user.id}/update_role`, { role, group_id: groupId });\n return res?.data;\n }\n\n static async current (): Promise {\n const res: AxiosResponse = await apiClient.get('/api/members/current');\n return res?.data;\n }\n\n static async validate (member: User): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/members/${member.id}/validate`, { user: member });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { NotificationsIndex, Notification } from '../models/notification';\n\nexport default class NotificationAPI {\n static async index (page?: number): Promise {\n const withPage = page ? `?page=${page}` : '';\n const res: AxiosResponse = await apiClient.get(`/api/notifications${withPage}`);\n return res?.data;\n }\n\n static async update (updatedNotification: Notification): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/notifications/${updatedNotification.id}`, { notification: updatedNotification });\n return res?.data;\n }\n\n static async update_all (): Promise {\n await apiClient.patch('/api/notifications');\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { NotificationPreference } from '../models/notification-preference';\n\nexport default class NotificationPreferencesAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/notification_preferences');\n return res?.data;\n }\n\n static async update (updatedPreference: NotificationPreference): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/notification_preferences/${updatedPreference.notification_type}`, { notification_preference: updatedPreference });\n return res?.data;\n }\n\n static async bulk_update (updatedPreferences: Array): Promise {\n const res: AxiosResponse = await apiClient.patch('/api/notification_preferences/bulk_update', { notification_preferences: updatedPreferences });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { NotificationTypeIndexFilter, NotificationType } from '../models/notification-type';\nimport ApiLib from '../lib/api';\n\nexport default class NotificationTypesAPI {\n static async index (filters?:NotificationTypeIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/notification_types${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Order, OrderIndexFilter, OrderIndex } from '../models/order';\nimport ApiLib from '../lib/api';\n\nexport default class OrderAPI {\n static async index (filters?: OrderIndexFilter): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/orders${ApiLib.filtersToQuery(filters, false)}`);\n return res?.data;\n }\n\n static async get (id: number | string): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/orders/${id}`);\n return res?.data;\n }\n\n static async updateState (order: Order, state: string, note?: string): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/orders/${order.id}`, { order: { state, note } });\n return res?.data;\n }\n\n static async withdrawalInstructions (order?: Order): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/orders/${order?.id}/withdrawal_instructions`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ShoppingCart } from '../models/payment';\nimport { User } from '../models/user';\nimport {\n SdkTestResponse,\n PaymentLinkResponse\n} from '../models/pagseguro';\nexport default class PagseguroAPI {\n static async testToken (token: string, email: string): Promise {\n const res: AxiosResponse = await apiClient.post('/api/pagseguro/test_token', { token, email });\n return res?.data;\n }\n\n static async createPaymentLink (cart: ShoppingCart, customer: User): Promise {\n const res: AxiosResponse = await apiClient.post('/api/pagseguro/create_payment_link', { cart_items: cart, customer_id: customer.id });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport {\n CancelScheduleResponse,\n CashCheckResponse, PayItemResponse,\n PaymentSchedule,\n PaymentScheduleIndexRequest, PaymentScheduleItem, RefreshItemResponse\n} from '../models/payment-schedule';\n\nexport default class PaymentScheduleAPI {\n static async list (query: PaymentScheduleIndexRequest): Promise> {\n const res: AxiosResponse = await apiClient.post('/api/payment_schedules/list', query);\n return res?.data;\n }\n\n static async index (query: PaymentScheduleIndexRequest): Promise> {\n const res: AxiosResponse = await apiClient.get(`/api/payment_schedules?page=${query.query.page}&size=${query.query.size}`);\n return res?.data;\n }\n\n static async cashCheck (paymentScheduleItemId: number): Promise {\n const res: AxiosResponse = await apiClient.post(`/api/payment_schedules/items/${paymentScheduleItemId}/cash_check`);\n return res?.data;\n }\n\n static async confirmTransfer (paymentScheduleItemId: number): Promise {\n const res: AxiosResponse = await apiClient.post(`/api/payment_schedules/items/${paymentScheduleItemId}/confirm_transfer`);\n return res?.data;\n }\n\n static async getItem (paymentScheduleItemId: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/payment_schedules/items/${paymentScheduleItemId}`);\n return res?.data;\n }\n\n static async refreshItem (paymentScheduleItemId: number): Promise {\n const res: AxiosResponse = await apiClient.post(`/api/payment_schedules/items/${paymentScheduleItemId}/refresh_item`);\n return res?.data;\n }\n\n static async payItem (paymentScheduleItemId: number): Promise {\n const res: AxiosResponse = await apiClient.post(`/api/payment_schedules/items/${paymentScheduleItemId}/pay_item`);\n return res?.data;\n }\n\n static async cancel (paymentScheduleId: number): Promise {\n const res: AxiosResponse = await apiClient.put(`/api/payment_schedules/${paymentScheduleId}/cancel`);\n return res?.data;\n }\n\n static async update (paymentSchedule: PaymentSchedule): Promise {\n const res:AxiosResponse = await apiClient.patch(`/api/payment_schedules/${paymentSchedule.id}`, paymentSchedule);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ShoppingCart } from '../models/payment';\nimport { User } from '../models/user';\nimport {\n CheckHashResponse,\n CreatePaymentResponse,\n CreateTokenResponse,\n SdkTestResponse\n} from '../models/payzen';\nimport { Invoice } from '../models/invoice';\nimport { PaymentSchedule } from '../models/payment-schedule';\n\nexport default class PayzenAPI {\n static async chargeSDKTest (baseURL: string, username: string, password: string): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/sdk_test', { base_url: baseURL, username, password });\n return res?.data;\n }\n\n static async chargeCreatePayment (cart: ShoppingCart, customer: User): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/create_payment', { cart_items: cart, customer_id: customer.id });\n return res?.data;\n }\n\n static async chargeCreateToken (cart: ShoppingCart, customer: User): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/create_token', { cart_items: cart, customer_id: customer.id });\n return res?.data;\n }\n\n static async checkHash (algorithm: string, hashKey: string, hash: string, data: string): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/check_hash', { algorithm, hash_key: hashKey, hash, data });\n return res?.data;\n }\n\n static async confirm (orderId: string, cart: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/confirm_payment', { cart_items: cart, order_id: orderId });\n return res?.data;\n }\n\n static async confirmPaymentSchedule (orderId: string, transactionUuid: string, cart: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/confirm_payment_schedule', { cart_items: cart, order_id: orderId, transaction_uuid: transactionUuid });\n return res?.data;\n }\n\n static async updateToken (paymentScheduleId: number): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/update_token', { payment_schedule_id: paymentScheduleId });\n return res?.data;\n }\n\n static async checkCart (cart: ShoppingCart, customer: User): Promise {\n const res: AxiosResponse = await apiClient.post('/api/payzen/check_cart', { cart_items: cart, customer_id: customer.id });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { PlanCategory } from '../models/plan-category';\n\nexport default class PlanCategoryAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/plan_categories');\n return res?.data;\n }\n\n static async create (category: PlanCategory): Promise {\n const res: AxiosResponse = await apiClient.post('/api/plan_categories', { plan_category: category });\n return res?.data;\n }\n\n static async update (category: PlanCategory): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/plan_categories/${category.id}`, { plan_category: category });\n return res?.data;\n }\n\n static async destroy (categoryId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/plan_categories/${categoryId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Plan, PlansDuration } from '../models/plan';\nimport ApiLib from '../lib/api';\n\nexport default class PlanAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/plans');\n return res?.data;\n }\n\n static async durations (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/plans/durations');\n return res?.data;\n }\n\n static async create (plan: Plan): Promise {\n const data = ApiLib.serializeAttachments(plan, 'plan', ['plan_file_attributes']);\n const res: AxiosResponse = await apiClient.post('/api/plans', data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async update (plan: Plan): Promise {\n const data = ApiLib.serializeAttachments(plan, 'plan', ['plan_file_attributes']);\n const res: AxiosResponse = await apiClient.put(`/api/plans/${plan.id}`, data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/plans/${id}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { PackIndexFilter, PrepaidPack } from '../models/prepaid-pack';\nimport ApiLib from '../lib/api';\n\nexport default class PrepaidPackAPI {\n static async index (filters?: PackIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/prepaid_packs${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/prepaid_packs/${id}`);\n return res?.data;\n }\n\n static async create (pack: PrepaidPack): Promise {\n const res: AxiosResponse = await apiClient.post('/api/prepaid_packs', { pack });\n return res?.data;\n }\n\n static async update (pack: PrepaidPack): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/prepaid_packs/${pack.id}`, { pack });\n return res?.data;\n }\n\n static async destroy (packId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/prepaid_packs/${packId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ShoppingCart } from '../models/payment';\nimport { ComputePriceResult, Price, PriceIndexFilter } from '../models/price';\nimport ApiLib from '../lib/api';\n\nexport default class PriceAPI {\n static async compute (cart: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/prices/compute', cart);\n return res?.data;\n }\n\n static async index (filters?: PriceIndexFilter): Promise> {\n const res: AxiosResponse = await apiClient.get(`/api/prices${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async create (price: Price): Promise {\n const res: AxiosResponse = await apiClient.post('/api/prices', { price });\n return res?.data;\n }\n\n static async update (price: Price): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/prices/${price.id}`, { price });\n return res?.data;\n }\n\n static async destroy (priceId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/prices/${priceId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ProductCategory } from '../models/product-category';\n\nexport default class ProductCategoryAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/product_categories');\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/product_categories/${id}`);\n return res?.data;\n }\n\n static async create (productCategory: ProductCategory): Promise {\n const res: AxiosResponse = await apiClient.post('/api/product_categories', { product_category: productCategory });\n return res?.data;\n }\n\n static async update (productCategory: ProductCategory): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/product_categories/${productCategory.id}`, { product_category: productCategory });\n return res?.data;\n }\n\n static async destroy (productCategoryId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/product_categories/${productCategoryId}`);\n return res?.data;\n }\n\n static async updatePosition (productCategory: ProductCategory, position: number): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/product_categories/${productCategory.id}/position`, { position });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport {\n Product,\n ProductIndexFilter,\n ProductsIndex,\n StockMovementIndex, StockMovementIndexFilter\n} from '../models/product';\nimport ApiLib from '../lib/api';\nimport ProductLib from '../lib/product';\n\nexport default class ProductAPI {\n static async index (filters?: ProductIndexFilter): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/products${ApiLib.filtersToQuery(ProductLib.indexFiltersToIds(filters), false)}`);\n return res?.data;\n }\n\n static async get (id: number | string): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/products/${id}`);\n return res?.data;\n }\n\n static async create (product: Product): Promise {\n const data = ApiLib.serializeAttachments(product, 'product', ['product_files_attributes', 'product_images_attributes']);\n const res: AxiosResponse = await apiClient.post('/api/products', data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async update (product: Product): Promise {\n const data = ApiLib.serializeAttachments(product, 'product', ['product_files_attributes', 'product_images_attributes']);\n const res: AxiosResponse = await apiClient.patch(`/api/products/${product.id}`, data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async clone (product: Product, data: Product): Promise {\n const res: AxiosResponse = await apiClient.put(`/api/products/${product.id}/clone`, {\n product: data\n });\n return res?.data;\n }\n\n static async destroy (productId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/products/${productId}`);\n return res?.data;\n }\n\n static async stockMovements (productId: number, filters: StockMovementIndexFilter): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/products/${productId}/stock_movements${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ProfileCustomField, ProfileCustomFieldIndexFilters } from '../models/profile-custom-field';\nimport ApiLib from '../lib/api';\n\nexport default class ProfileCustomFieldAPI {\n static async index (filters?: ProfileCustomFieldIndexFilters): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/profile_custom_fields${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/profile_custom_fields/${id}`);\n return res?.data;\n }\n\n static async create (profileCustomField: ProfileCustomField): Promise {\n const res: AxiosResponse = await apiClient.post('/api/profile_custom_fields', { profile_custom_field: profileCustomField });\n return res?.data;\n }\n\n static async update (profileCustomField: ProfileCustomField): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/profile_custom_fields/${profileCustomField.id}`, { profile_custom_field: profileCustomField });\n return res?.data;\n }\n\n static async destroy (profileCustomFieldId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/profile_custom_fields/${profileCustomFieldId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Reservation, ReservationIndexFilter } from '../models/reservation';\nimport ApiLib from '../lib/api';\n\nexport default class ReservationAPI {\n static async index (filters: ReservationIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/reservations${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport {\n Setting,\n SettingBulkArray,\n SettingBulkResult,\n SettingError, SettingGetOptions,\n SettingName,\n SettingValue\n} from '../models/setting';\nimport ApiLib from '../lib/api';\n\nexport default class SettingAPI {\n static async get (name: SettingName, options?: SettingGetOptions): Promise {\n const res: AxiosResponse<{setting: Setting}> = await apiClient.get(`/api/settings/${name}${ApiLib.filtersToQuery(options)}`);\n return res?.data?.setting;\n }\n\n static async query (names: readonly SettingName[]): Promise> {\n const params = new URLSearchParams();\n params.append('names', `['${names.join(\"','\")}']`);\n\n const res: AxiosResponse = await apiClient.get(`/api/settings?${params.toString()}`);\n return SettingAPI.toSettingsMap(names, res?.data);\n }\n\n static async update (name: SettingName, value: SettingValue): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/settings/${name}`, { setting: { value } });\n if (res.status === 304) { return { name, value: `${value}` }; }\n return res?.data?.setting;\n }\n\n static async bulkUpdate (settings: Map, transactional = false): Promise> {\n const res: AxiosResponse = await apiClient.patch(`/api/settings/bulk_update?transactional=${transactional}`, { settings: SettingAPI.toObjectArray(settings) });\n return SettingAPI.toBulkMap(res?.data?.settings);\n }\n\n static async isPresent (name: SettingName): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/settings/is_present/${name}`);\n return res?.data?.isPresent;\n }\n\n private static toSettingsMap (names: readonly SettingName[], data: Record): Map {\n const map = new Map();\n names.forEach(name => {\n map.set(name, data[name] || '');\n });\n return map;\n }\n\n private static toBulkMap (data: Array): Map {\n const map = new Map();\n data.forEach(item => {\n const itemData: SettingBulkResult = { status: true };\n if ('error' in item) {\n itemData.error = item.error;\n itemData.status = false;\n }\n if ('value' in item) {\n itemData.value = item.value;\n }\n if ('localized' in item) {\n itemData.localized = item.localized;\n }\n\n map.set(item.name, itemData);\n });\n return map;\n }\n\n private static toObjectArray (data: Map): SettingBulkArray {\n const array = [];\n data.forEach((value, key) => {\n array.push({\n name: key,\n value\n });\n });\n return array;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Space } from '../models/space';\nimport ApiLib from '../lib/api';\n\nexport default class SpaceAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/spaces');\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/spaces/${id}`);\n return res?.data;\n }\n\n static async create (space: Space): Promise {\n const data = ApiLib.serializeAttachments(space, 'space', ['space_files_attributes', 'space_image_attributes']);\n const res: AxiosResponse = await apiClient.post('/api/spaces', data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async update (space: Space): Promise {\n const data = ApiLib.serializeAttachments(space, 'space', ['space_files_attributes', 'space_image_attributes']);\n const res: AxiosResponse = await apiClient.put(`/api/spaces/${space.id}`, data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Status } from '../models/status';\n\nexport default class StatusAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/statuses');\n return res?.data;\n }\n\n static async create (newStatus: Status): Promise {\n const res: AxiosResponse = await apiClient.post('/api/statuses', { status: newStatus });\n return res?.data;\n }\n\n static async update (updatedStatus: Status): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/statuses/${updatedStatus.id}`, { status: updatedStatus });\n return res?.data;\n }\n\n static async destroy (statusId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/statuses/${statusId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { ShoppingCart, IntentConfirmation, PaymentConfirmation, UpdateCardResponse } from '../models/payment';\nimport { PaymentSchedule } from '../models/payment-schedule';\nimport { Invoice } from '../models/invoice';\n\nexport default class StripeAPI {\n static async confirmMethod (paymentMethodId: string, cartItems: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/stripe/confirm_payment', {\n payment_method_id: paymentMethodId,\n cart_items: cartItems\n });\n return res?.data;\n }\n\n static async confirmIntent (paymentMethodId: string, cartItems: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/stripe/confirm_payment', {\n payment_intent_id: paymentMethodId,\n cart_items: cartItems\n });\n return res?.data;\n }\n\n static async setupSubscription (paymentMethodId: string, cartItems: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/stripe/setup_subscription', {\n payment_method_id: paymentMethodId,\n cart_items: cartItems\n });\n return res?.data;\n }\n\n static async setupIntent (userId: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/stripe/setup_intent/${userId}`);\n return res?.data;\n }\n\n static async confirmSubscription (subscriptionId: string, cartItems: ShoppingCart): Promise {\n const res: AxiosResponse = await apiClient.post('/api/stripe/confirm_subscription', {\n subscription_id: subscriptionId,\n cart_items: cartItems\n });\n return res?.data;\n }\n\n static async updateCard (userId: number, paymentMethodId: string, paymentScheduleId?: number): Promise {\n const res: AxiosResponse = await apiClient.post('/api/stripe/update_card', {\n user_id: userId,\n payment_method_id: paymentMethodId,\n payment_schedule_id: paymentScheduleId\n });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { Subscription, SubscriptionPaymentDetails } from '../models/subscription';\nimport { AxiosResponse } from 'axios';\n\nexport default class SubscriptionAPI {\n static async cancel (id: number): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/subscriptions/${id}/cancel`);\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/subscriptions/${id}`);\n return res?.data;\n }\n\n static async paymentsDetails (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/subscriptions/${id}/payment_details`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { SupportingDocumentFile, SupportingDocumentFileIndexFilter } from '../models/supporting-document-file';\nimport ApiLib from '../lib/api';\n\nexport default class SupportingDocumentFileAPI {\n static async index (filters?: SupportingDocumentFileIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/supporting_document_files${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/supporting_document_files/${id}`);\n return res?.data;\n }\n\n static async create (proofOfIdentityFile: FormData): Promise {\n const res: AxiosResponse = await apiClient.post('/api/supporting_document_files', proofOfIdentityFile);\n return res?.data;\n }\n\n static async update (id: number, proofOfIdentityFile: FormData): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/supporting_document_files/${id}`, proofOfIdentityFile);\n return res?.data;\n }\n\n static async destroy (proofOfIdentityFileId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/supporting_document_files/${proofOfIdentityFileId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { SupportingDocumentRefusal, SupportingDocumentRefusalIndexFilter } from '../models/supporting-document-refusal';\nimport ApiLib from '../lib/api';\n\nexport default class SupportingDocumentRefusalAPI {\n static async index (filters?: SupportingDocumentRefusalIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/supporting_document_refusals${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async create (supportingDocumentRefusal: SupportingDocumentRefusal): Promise {\n const res: AxiosResponse = await apiClient.post('/api/supporting_document_refusals', { supporting_document_refusal: supportingDocumentRefusal });\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { SupportingDocumentType, SupportingDocumentTypeIndexfilter } from '../models/supporting-document-type';\nimport ApiLib from '../lib/api';\n\nexport default class SupportingDocumentTypeAPI {\n static async index (filters?: SupportingDocumentTypeIndexfilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/supporting_document_types${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async get (id: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/supporting_document_types/${id}`);\n return res?.data;\n }\n\n static async create (proofOfIdentityType: SupportingDocumentType): Promise {\n const res: AxiosResponse = await apiClient.post('/api/supporting_document_types', { supporting_document_type: proofOfIdentityType });\n return res?.data;\n }\n\n static async update (proofOfIdentityType: SupportingDocumentType): Promise {\n const res: AxiosResponse = await apiClient.patch(`/api/supporting_document_types/${proofOfIdentityType.id}`, { supporting_document_type: proofOfIdentityType });\n return res?.data;\n }\n\n static async destroy (proofOfIdentityTypeId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/supporting_document_types/${proofOfIdentityTypeId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Tag } from '../models/tag';\n\nexport default class TagAPI {\n static async index (): Promise> {\n const res: AxiosResponse> = await apiClient.get('/api/tags');\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Training, TrainingIndexFilter } from '../models/training';\nimport ApiLib from '../lib/api';\n\nexport default class TrainingAPI {\n static async index (filters?: TrainingIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/trainings${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async create (training: Training): Promise {\n const data = ApiLib.serializeAttachments(training, 'training', ['training_image_attributes']);\n const res: AxiosResponse = await apiClient.post('/api/trainings', data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async update (training: Training): Promise {\n const data = ApiLib.serializeAttachments(training, 'training', ['training_image_attributes']);\n const res: AxiosResponse = await apiClient.put(`/api/trainings/${training.id}`, data, {\n headers: {\n 'Content-Type': 'multipart/form-data'\n }\n });\n return res?.data;\n }\n\n static async destroy (trainingId: number): Promise {\n const res: AxiosResponse = await apiClient.delete(`/api/trainings/${trainingId}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { UserPack, UserPackIndexFilter } from '../models/user-pack';\nimport { AxiosResponse } from 'axios';\nimport ApiLib from '../lib/api';\n\nexport default class UserPackAPI {\n static async index (filters: UserPackIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/user_packs${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport ApiLib from '../lib/api';\nimport { UserIndexFilter, User } from '../models/user';\nimport { AxiosResponse } from 'axios';\nimport { Partner } from '../models/plan';\n\nexport default class UserAPI {\n static async index (filters: UserIndexFilter): Promise> {\n const res: AxiosResponse> = await apiClient.get(`/api/users${ApiLib.filtersToQuery(filters)}`);\n return res?.data;\n }\n\n static async create (user: Partner|User, role: 'partner'|'manager'): Promise {\n const data = {};\n data[role === 'partner' ? 'user' : 'manager'] = user;\n const res: AxiosResponse = await apiClient.post('/api/users', data);\n return res?.data;\n }\n}\n","import apiClient from './clients/api-client';\nimport { AxiosResponse } from 'axios';\nimport { Wallet } from '../models/wallet';\n\nexport default class WalletAPI {\n static async getByUser (userId: number): Promise {\n const res: AxiosResponse = await apiClient.get(`/api/wallet/by_user/${userId}`);\n return res?.data;\n }\n}\n","'use strict';\n\n/**\n* The application file bootstraps the angular app by initializing the main module and\n* creating namespaces and moduled for controllers, filters, services, and directives.\n*/\n\n// eslint-disable-next-line no-var -- Application is a global variable.\nvar Application = Application || {};\n\nApplication.Components = angular.module('application.components', []);\nApplication.Services = angular.module('application.services', []);\nApplication.Controllers = angular.module('application.controllers', []);\nApplication.Filters = angular.module('application.filters', []);\nApplication.Directives = angular.module('application.directives', []);\n\nangular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.router', 'ui.bootstrap',\n 'ngUpload', 'duScroll', 'application.filters', 'application.services', 'application.directives',\n 'frapontillo.bootstrap-switch', 'application.controllers', 'application.router', 'application.components',\n 'ui.select', 'ui.calendar', 'angularMoment', 'Devise', 'angular-growl', 'xeditable',\n 'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch',\n 'angularUtils.directives.dirDisqus', 'summernote', 'elasticsearch', 'angular-medium-editor', 'naif.base64',\n 'minicolors', 'pascalprecht.translate', 'ngFitText', 'ngAside', 'ngCapsLock', 'vcRecaptcha', 'ui.codemirror',\n 'bm.uiTour'])\n .config(['$httpProvider', 'AuthProvider', 'growlProvider', 'unsavedWarningsConfigProvider', 'uibDatepickerPopupConfig', '$provide', '$translateProvider', 'TourConfigProvider', '$sceDelegateProvider',\n function ($httpProvider, AuthProvider, growlProvider, unsavedWarningsConfigProvider, uibDatepickerPopupConfig, $provide, $translateProvider, TourConfigProvider, $sceDelegateProvider) {\n // Google analytics\n // first we check the user acceptance\n const cookiesConsent = document.cookie.replace(/(?:(?:^|.*;\\s*)fab-manager-cookies-consent\\s*=\\s*([^;]*).*$)|^.*$/, '$1');\n if (cookiesConsent === 'accept') {\n GTM.enableAnalytics(Fablab.trackingId);\n } else {\n // if the cookies were not explicitly accepted, delete them\n document.cookie = '_ga=; expires=Thu, 01 Jan 1970 00:00:00 GMT';\n document.cookie = '_gid=; expires=Thu, 01 Jan 1970 00:00:00 GMT';\n }\n\n // Custom messages for the date-picker widget\n uibDatepickerPopupConfig.closeText = Fablab.translations.app.shared.buttons.close;\n uibDatepickerPopupConfig.clearText = Fablab.translations.app.shared.buttons.clear;\n uibDatepickerPopupConfig.currentText = Fablab.translations.app.shared.buttons.today;\n\n // Custom messages for angular-unsavedChanges\n unsavedWarningsConfigProvider.navigateMessage = Fablab.translations.app.shared.messages.you_will_lose_any_unsaved_modification_if_you_quit_this_page;\n unsavedWarningsConfigProvider.reloadMessage = Fablab.translations.app.shared.messages.you_will_lose_any_unsaved_modification_if_you_reload_this_page;\n\n // Set how long the popup messages (growl) will remain\n growlProvider.globalTimeToLive(5000);\n\n // Configure the i18n module to load the partial translations from the given API URL\n $translateProvider.useLoader('$translatePartialLoader', {\n urlTemplate: '/api/translations/{lang}/{part}'\n });\n // Enable the cache to speed-up the loading times on already seen pages\n $translateProvider.useLoaderCache(true);\n // Secure i18n module against XSS attacks by escaping the output\n $translateProvider.useSanitizeValueStrategy('escapeParameters');\n // Use the MessageFormat interpolation by default (used for pluralization)\n $translateProvider.useMessageFormatInterpolation();\n // Set the language of the instance (from ruby configuration)\n $translateProvider.preferredLanguage(Fablab.locale);\n // End the tour when the user clicks the forward or back buttons of the browser\n TourConfigProvider.enableNavigationInterceptors();\n\n $sceDelegateProvider.resourceUrlWhitelist(['self']);\n }]).run(['$rootScope', '$transitions', '$log', 'Auth', 'amMoment', '$state', 'editableOptions',\n function ($rootScope, $transitions, $log, Auth, amMoment, $state, editableOptions) {\n // Angular-moment (date-time manipulations library)\n amMoment.changeLocale(Fablab.moment_locale);\n\n // Angular-xeditable (click-to-edit elements, used in admin backoffice)\n editableOptions.theme = 'bs3';\n\n // Alter the UI-Router's $state, registering into some information concerning the previous $state.\n // This is used to allow the user to navigate to the previous state\n $transitions.onSuccess({ }, function (trans) {\n $state.prevState = trans.$from().name;\n $state.prevParams = Object.fromEntries(\n Object.keys(trans.$from().params).map(k => {\n return [k, trans.$from().params[k].value()];\n })\n );\n\n const path = trans.router.stateService.href(trans.$to(), {}, { absolute: true });\n GTM.trackPage(path, trans.$to().name);\n });\n\n // Global function to allow the user to navigate to the previous screen (ie. $state).\n // If no previous $state were recorded, navigate to the home page\n $rootScope.backPrevLocation = function (event) {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '') {\n $state.prevState = 'app.public.home';\n }\n $state.go($state.prevState, $state.prevParams);\n };\n\n // Configuration of the summernote editor (used in project edition)\n $rootScope.summernoteOpts = {\n lang: Fablab.summernote_locale,\n height: 200,\n toolbar: [\n ['style', ['style']],\n ['font', ['bold', 'italic', 'underline', 'clear']],\n ['color', ['color']],\n ['para', ['ul', 'ol']],\n ['table', ['table']],\n ['insert', ['link', 'picture', 'hr']],\n ['view', ['fullscreen', 'codeview']],\n ['group', ['video']],\n ['help', ['help']]\n ],\n styleTags: ['p', 'blockquote', 'pre', 'h4', 'h5', 'h6'],\n maximumImageFileSize: 4096\n };\n\n // Prevent the usage of the application for members with incomplete profiles: they will be redirected to\n // the 'profile completion' page. This is especially useful for user's accounts imported through SSO.\n $transitions.onStart({}, function (trans) {\n Auth.currentUser().then(function (currentUser) {\n if (currentUser.need_completion && trans.$to().name !== 'app.logged.profileCompletion') {\n $state.go('app.logged.profileCompletion');\n }\n }).catch(() => {\n // no one is logged, just ignore\n });\n });\n\n /**\n * This helper method builds and return an array containing every integers between\n * the provided start and end.\n * @param start {number}\n * @param end {number}\n * @return {Array} [start .. end]\n */\n $rootScope.intArray = function (start, end) {\n const arr = [];\n for (let i = start; i < end; i++) { arr.push(i); }\n return arr;\n };\n }]).constant('angularMomentConfig', {\n timezone: Fablab.timezone\n }).constant('moment', require('moment-timezone'));\n\nangular.isUndefinedOrNull = function (val) {\n return angular.isUndefined(val) || val === null;\n};\n\nmodule.exports = { Application };\n","import { useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { SubmitHandler, useForm } from 'react-hook-form';\nimport { FabButton } from '../base/fab-button';\nimport { FormInput } from '../form/form-input';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { SettingName, SettingValue, accountingSettings } from '../../models/setting';\nimport SettingAPI from '../../api/setting';\nimport SettingLib from '../../lib/setting';\nimport { FormSwitch } from '../form/form-switch';\nimport { FabPanel } from '../base/fab-panel';\n\ndeclare const Application: IApplication;\n\ninterface AccountingCodesSettingsProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void\n}\n\n/**\n * This component allows customization of accounting codes and other related settings\n */\nexport const AccountingCodesSettings: React.FC = ({ onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n const { handleSubmit, register, control, reset } = useForm>();\n\n useEffect(() => {\n SettingAPI.query(accountingSettings)\n .then(settings => {\n const data = SettingLib.bulkMapToObject(settings);\n reset(data);\n })\n .catch(onError);\n }, []);\n\n /**\n * Callback triggered when the user clicks on 'save':\n * Update the settings on the API\n */\n const onSubmit: SubmitHandler> = (data) => {\n SettingAPI.bulkUpdate(SettingLib.objectToBulkMap(data)).then(() => {\n onSuccess(t('app.admin.accounting_codes_settings.update_success'));\n }, reason => {\n onError(reason);\n });\n };\n\n return (\n
\n \n

{t('app.admin.accounting_codes_settings.advanced_accounting')}

\n \n
\n \n

{t('app.admin.accounting_codes_settings.financial')}

\n
{t('app.admin.accounting_codes_settings.card')}
\n
\n \n \n \n
\n
{t('app.admin.accounting_codes_settings.wallet_debit')}
\n
\n \n \n \n
\n
{t('app.admin.accounting_codes_settings.other')}
\n
\n \n \n \n
\n

{t('app.admin.accounting_codes_settings.sales')}

\n
{t('app.admin.accounting_codes_settings.sales_journal')}
\n \n
{t('app.admin.accounting_codes_settings.subscriptions')}
\n
\n \n \n
\n
{t('app.admin.accounting_codes_settings.machine')}
\n
\n \n \n
\n
{t('app.admin.accounting_codes_settings.training')}
\n
\n \n \n
\n
{t('app.admin.accounting_codes_settings.event')}
\n
\n \n \n
\n
{t('app.admin.accounting_codes_settings.space')}
\n
\n \n \n
\n
{t('app.admin.accounting_codes_settings.prepaid_pack')}
\n
\n \n \n
\n
{t('app.admin.accounting_codes_settings.product')}
\n
\n \n \n
\n
{t('app.admin.accounting_codes_settings.error')}
\n
\n \n \n
\n

{t('app.admin.accounting_codes_settings.wallet_credit')}

\n
\n \n \n \n
\n

{t('app.admin.accounting_codes_settings.VAT')}

\n
\n \n \n \n
\n
\n \n \n {t('app.admin.accounting_codes_settings.save')}\n \n \n
\n );\n};\n\nApplication.Components.component('accountingCodesSettings', react2angular(AccountingCodesSettings, ['onSuccess', 'onError']));\n","import { useEffect, useState } from 'react';\nimport SettingAPI from '../../api/setting';\nimport { UseFormRegister } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FormInput } from '../form/form-input';\nimport { useTranslation } from 'react-i18next';\n\ninterface AdvancedAccountingFormProps {\n register: UseFormRegister,\n onError: (message: string) => void\n}\n\n/**\n * This component is a partial form, to be included in a resource form managed by react-hook-form.\n * It will add advanced accounting attributes to the parent form, if they are enabled\n */\nexport const AdvancedAccountingForm = ({ register, onError }: AdvancedAccountingFormProps) => {\n const [isEnabled, setIsEnabled] = useState(false);\n\n const { t } = useTranslation('admin');\n\n useEffect(() => {\n SettingAPI.get('advanced_accounting').then(res => setIsEnabled(res.value === 'true')).catch(onError);\n }, []);\n\n return (<>\n {isEnabled && <>\n
\n

{t('app.admin.advanced_accounting_form.title')}

\n
\n
\n \n \n
\n }\n );\n};\n","import Switch from 'react-switch';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\n\ndeclare const Application: IApplication;\n\n/**\n * This is a compatibility wrapper to allow usage of react-switch inside the angular.js app\n */\nApplication.Components.component('switch', react2angular(Switch, ['checked', 'onChange', 'id', 'className', 'disabled']));\n","import { UseFormRegister, FormState } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport { FormInput } from '../form/form-input';\n\nexport interface BooleanMappingFormProps {\n register: UseFormRegister,\n fieldMappingId: number,\n formState: FormState\n}\n\n/**\n * Partial form to map an internal boolean field to an external API providing a string value.\n */\nexport const BooleanMappingForm = ({ register, fieldMappingId, formState }: BooleanMappingFormProps) => {\n const { t } = useTranslation('admin');\n\n return (\n
\n

{t('app.admin.authentication.boolean_mapping_form.mappings')}

\n \n \n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport { UseFormRegister, useFieldArray, ArrayPath, useWatch, Path, FieldPathValue } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport AuthProviderAPI from '../../api/auth-provider';\nimport { AuthenticationProviderMapping, MappingFields, mappingType, ProvidableType } from '../../models/authentication-provider';\nimport { Control, UnpackNestedValue, UseFormSetValue, FormState } from 'react-hook-form/dist/types/form';\nimport { FormSelect } from '../form/form-select';\nimport { FormInput } from '../form/form-input';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../base/fab-button';\nimport { TypeMappingModal } from './type-mapping-modal';\nimport { useImmer } from 'use-immer';\nimport { Oauth2DataMappingForm } from './oauth2-data-mapping-form';\nimport { OpenidConnectDataMappingForm } from './openid-connect-data-mapping-form';\n\nexport interface DataMappingFormProps {\n register: UseFormRegister,\n control: Control,\n providerType: ProvidableType,\n setValue: UseFormSetValue,\n currentFormValues: Array,\n formState: FormState\n}\n\ntype selectModelFieldOption = { value: string, label: string };\n\n/**\n * Partial form to define the mapping of the data between the API of the authentication provider and the application internals.\n */\nexport const DataMappingForm = ({ register, control, providerType, setValue, currentFormValues, formState }: DataMappingFormProps) => {\n const { t } = useTranslation('admin');\n const [dataMapping, setDataMapping] = useState(null);\n const [isOpenTypeMappingModal, updateIsOpenTypeMappingModal] = useImmer>(new Map());\n\n const { fields, append, remove } = useFieldArray({ control, name: 'auth_provider_mappings_attributes' as ArrayPath });\n const output = useWatch({ name: 'auth_provider_mappings_attributes' as Path, control });\n\n /**\n * Build the list of available models for the data mapping\n */\n const buildModelOptions = (): Array => {\n if (!dataMapping) return [];\n\n return Object.keys(dataMapping).map(model => {\n return {\n label: model,\n value: model\n };\n }) || [];\n };\n\n /**\n * Build the list of fields of the current model for the data mapping\n */\n const buildFieldOptions = (formData: Array, index: number): Array => {\n if (!dataMapping) return [];\n\n return dataMapping[getModel(formData, index)]?.map(field => {\n return {\n label: field[0],\n value: field[0]\n };\n }) || [];\n };\n\n /**\n * Return the name of the modal for the given index, in the current data-mapping form\n */\n const getModel = (formData: Array, index: number): string => {\n return formData ? formData[index]?.local_model : undefined;\n };\n\n /**\n * Return the name of the field for the given index, in the current data-mapping form\n */\n const getField = (formData: Array, index: number): string => {\n return formData ? formData[index]?.local_field : undefined;\n };\n\n /**\n * Return the type of data expected for the given index, in the current data-mapping form\n */\n const getDataType = (formData: Array, index: number): mappingType => {\n const model = getModel(formData, index);\n const field = getField(formData, index);\n if (model && field && dataMapping) {\n return dataMapping[model]?.find(f => f[0] === field)?.[1];\n }\n };\n\n /**\n * Open/closes the \"edit type mapping\" modal dialog for the given mapping index\n */\n const toggleTypeMappingModal = (index: number): () => void => {\n return () => {\n updateIsOpenTypeMappingModal(draft => draft.set(index, !draft.get(index)));\n };\n };\n\n /**\n * Remove the data whom index is provided: mark it as \"to destroy\" or simply remove it if it was unsaved\n */\n const removeMapping = (index: number): void => {\n if (currentFormValues[index].id) {\n setValue(\n `auth_provider_mappings_attributes.${index}._destroy` as Path,\n true as UnpackNestedValue>>\n );\n } else {\n remove(index);\n }\n };\n\n /**\n * Return a className based on the current mapping-item status\n */\n const itemStatus = (index: number): string => {\n if (currentFormValues && currentFormValues[index]?.id) {\n if (currentFormValues[index]._destroy) return 'destroyed-item';\n return 'saved-item';\n }\n return 'new-item';\n };\n\n // fetch the mapping data from the API on mount\n useEffect(() => {\n AuthProviderAPI.mappingFields().then((data) => {\n setDataMapping(data);\n });\n }, []);\n\n return (\n
\n

{t('app.admin.authentication.data_mapping_form.define_the_fields_mapping')}

\n
\n }\n onClick={() => append({})}>\n {t('app.admin.authentication.data_mapping_form.add_a_match')}\n \n
\n {fields.map((item, index) => (\n
\n
\n \n
\n \n \n
\n
\n {providerType === 'OAuth2Provider' && }\n {providerType === 'OpenIdConnectProvider' && }\n
\n
\n
\n }\n onClick={toggleTypeMappingModal(index)}\n disabled={getField(output, index) === undefined}\n tooltip={t('app.admin.authentication.data_mapping_form.data_mapping')} />\n } onClick={() => removeMapping(index)} className=\"delete-button\" />\n \n
\n
\n ))}\n
\n );\n};\n","import { FormInput } from '../form/form-input';\nimport { UseFormRegister } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\n\ninterface DatabaseFormProps {\n register: UseFormRegister,\n}\n\n/**\n * Partial form to fill the settings for a new/existing database provider.\n */\nexport const DatabaseForm = ({ register }: DatabaseFormProps) => {\n return (\n
\n \n
\n );\n};\n","import { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport { FormSelect } from '../form/form-select';\nimport { Control, FormState } from 'react-hook-form/dist/types/form';\n\nexport interface DateMappingFormProps {\n control: Control,\n fieldMappingId: number,\n formState: FormState\n}\n\n/**\n * Partial form for mapping an internal date field to an external API.\n */\nexport const DateMappingForm = ({ control, fieldMappingId, formState }: DateMappingFormProps) => {\n const { t } = useTranslation('admin');\n\n // available date formats\n const dateFormats = [\n {\n label: 'ISO 8601',\n value: 'iso8601'\n },\n {\n label: 'RFC 2822',\n value: 'rfc2822'\n },\n {\n label: 'RFC 3339',\n value: 'rfc3339'\n },\n {\n label: 'Timestamp (s)',\n value: 'timestamp-s'\n },\n {\n label: 'Timestamp (ms)',\n value: 'timestamp-ms'\n }\n ];\n\n return (\n
\n

{t('app.admin.authentication.date_mapping_form.input_format')}

\n \n
\n );\n};\n","import { ArrayPath, useFieldArray, UseFormRegister } from 'react-hook-form';\nimport { Control, FormState } from 'react-hook-form/dist/types/form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../base/fab-button';\nimport { FormInput } from '../form/form-input';\n\nexport interface IntegerMappingFormProps {\n register: UseFormRegister,\n control: Control,\n fieldMappingId: number,\n formState: FormState\n}\n\n/**\n * Partial for to map an internal integer field to an external API providing a string value.\n */\nexport const IntegerMappingForm = ({ register, control, fieldMappingId, formState }: IntegerMappingFormProps) => {\n const { t } = useTranslation('admin');\n\n const { fields, append, remove } = useFieldArray({ control, name: 'auth_provider_mappings_attributes_transformation_mapping' as ArrayPath });\n\n return (\n
\n

{t('app.admin.authentication.integer_mapping_form.mappings')}

\n
\n }\n onClick={() => append({})} />\n
\n {fields.map((item, index) => (\n
\n
\n \n \n
\n
\n } onClick={() => remove(index)} className=\"delete-button\" />\n
\n
\n ))}\n
\n );\n};\n","import { UseFormRegister } from 'react-hook-form';\nimport { Control, FormState } from 'react-hook-form/dist/types/form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FormInput } from '../form/form-input';\nimport { FormSelect } from '../form/form-select';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { useTranslation } from 'react-i18next';\n\ninterface Oauth2DataMappingFormProps {\n register: UseFormRegister,\n control: Control,\n index: number,\n formState: FormState\n}\n\n/**\n * Partial form to set the data mapping for an OAuth 2.0 provider.\n * The data mapping is the way to bind data from the authentication provider API to the Fab-manager's database\n */\nexport const Oauth2DataMappingForm = ({ register, control, index, formState }: Oauth2DataMappingFormProps) => {\n const { t } = useTranslation('admin');\n\n return (\n
\n \n \n }\n label={t('app.admin.authentication.oauth2_data_mapping_form.api_field')} />\n
\n );\n};\n","import { FormInput } from '../form/form-input';\nimport { UseFormRegister, FormState } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport { FabOutputCopy } from '../base/fab-output-copy';\nimport ValidationLib from '../../lib/validation';\n\ninterface Oauth2FormProps {\n register: UseFormRegister,\n formState: FormState,\n strategyName?: string,\n}\n\n/**\n * Partial form to fill the OAuth2 settings for a new/existing authentication provider.\n */\nexport const Oauth2Form = ({ register, strategyName, formState }: Oauth2FormProps) => {\n const { t } = useTranslation('admin');\n\n /**\n * Build the callback URL, based on the strategy name.\n */\n const buildCallbackUrl = (): string => {\n return `${window.location.origin}/users/auth/${strategyName}/callback`;\n };\n\n return (\n
\n
\n \n \n \n \n \n \n \n \n
\n );\n};\n","import { Path, UseFormRegister } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FormInput } from '../form/form-input';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { useTranslation } from 'react-i18next';\nimport { UnpackNestedValue, UseFormSetValue, FormState } from 'react-hook-form/dist/types/form';\nimport { FabButton } from '../base/fab-button';\nimport { FieldPathValue } from 'react-hook-form/dist/types/path';\nimport { AuthenticationProviderMapping } from '../../models/authentication-provider';\n\ninterface OpenidConnectDataMappingFormProps {\n register: UseFormRegister,\n setValue: UseFormSetValue,\n currentFormValues: Array,\n index: number,\n formState: FormState\n}\n\n/**\n * Partial form to set the data mapping for an OpenID Connect provider.\n * The data mapping is the way to bind data from the OIDC claims to the Fab-manager's database\n */\nexport const OpenidConnectDataMappingForm = ({ register, setValue, currentFormValues, index, formState }: OpenidConnectDataMappingFormProps) => {\n const { t } = useTranslation('admin');\n\n const standardConfiguration = {\n 'user.uid': { api_field: 'sub' },\n 'user.email': { api_field: 'email' },\n 'user.username': { api_field: 'preferred_username' },\n 'profile.first_name': { api_field: 'given_name' },\n 'profile.last_name': { api_field: 'family_name' },\n 'profile.avatar': { api_field: 'picture' },\n 'profile.website': { api_field: 'website' },\n 'profile.gender': { api_field: 'gender', transformation: { true_value: 'male', false_value: 'female' } },\n 'profile.birthday': { api_field: 'birthdate', transformation: { format: 'iso8601' } },\n 'profile.phone': { api_field: 'phone_number' },\n 'profile.address': { api_field: 'address.formatted' }\n };\n\n /**\n * Set the data mapping according to the standard OpenID Connect specification\n */\n const openIdStandardConfiguration = (): void => {\n const model = currentFormValues[index]?.local_model;\n const field = currentFormValues[index]?.local_field;\n const configuration = standardConfiguration[`${model}.${field}`];\n if (configuration) {\n setValue(\n `auth_provider_mappings_attributes.${index}.api_field` as Path,\n configuration.api_field as UnpackNestedValue>>\n );\n if (configuration.transformation) {\n Object.keys(configuration.transformation).forEach((key) => {\n setValue(\n `auth_provider_mappings_attributes.${index}.transformation.${key}` as Path,\n configuration.transformation[key] as UnpackNestedValue>>\n );\n });\n }\n }\n };\n\n return (\n
\n \n \n }\n label={t('app.admin.authentication.openid_connect_data_mapping_form.api_field')} />\n }\n className=\"auto-configure-button\"\n onClick={openIdStandardConfiguration}\n tooltip={t('app.admin.authentication.openid_connect_data_mapping_form.openid_standard_configuration')} />\n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { Path, UseFormRegister } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport { FormInput } from '../form/form-input';\nimport { FormSelect } from '../form/form-select';\nimport { Control, FormState, UnpackNestedValue, UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { OpenIdConnectProvider } from '../../models/authentication-provider';\nimport SsoClient from '../../api/external/sso';\nimport { FieldPathValue } from 'react-hook-form/dist/types/path';\nimport { FormMultiSelect } from '../form/form-multi-select';\nimport { difference } from 'lodash';\nimport ValidationLib from '../../lib/validation';\n\ninterface OpenidConnectFormProps {\n register: UseFormRegister,\n control: Control,\n currentFormValues: OpenIdConnectProvider,\n formState: FormState,\n setValue: UseFormSetValue,\n}\n\n/**\n * Partial form to fill the OpenID Connect (OIDC) settings for a new/existing authentication provider.\n */\nexport const OpenidConnectForm = ({ register, control, currentFormValues, formState, setValue }: OpenidConnectFormProps) => {\n const { t } = useTranslation('admin');\n\n // saves the state of the discovery endpoint\n const [discoveryAvailable, setDiscoveryAvailable] = useState(false);\n const [scopesAvailable, setScopesAvailable] = useState(null);\n // this is a workaround for https://github.com/JedWatson/react-select/issues/1879\n const [selectKey, setSelectKey] = useState(0);\n\n // when we have detected a discovery endpoint, we mark it as available\n useEffect(() => {\n setValue(\n 'providable_attributes.discovery' as Path,\n discoveryAvailable as UnpackNestedValue>>\n );\n }, [discoveryAvailable]);\n\n // this will force the scope \"select\" to re-fetch the options\n useEffect(() => {\n setSelectKey(selectKey + 1);\n }, [scopesAvailable]);\n\n // when the component is mounted, we try to discover the discovery endpoint for the current configuration (if any)\n useEffect(() => {\n checkForDiscoveryEndpoint({ target: { value: currentFormValues?.issuer } } as React.ChangeEvent);\n }, []);\n\n /**\n * If the discovery endpoint is available, the user will be able to choose to use it or not.\n * Otherwise, he will need to end the client configuration manually.\n */\n const buildDiscoveryOptions = () => {\n if (discoveryAvailable) {\n return [\n { value: true, label: t('app.admin.authentication.openid_connect_form.discovery_enabled') },\n { value: false, label: t('app.admin.authentication.openid_connect_form.discovery_disabled') }\n ];\n }\n\n return [\n { value: false, label: t('app.admin.authentication.openid_connect_form.discovery_disabled') }\n ];\n };\n\n /**\n * Return the list of scopes that are available for the current configuration.\n * The resulting list is provided through the callback parameter.\n */\n const loadScopes = (inputValue: string, callback: (options: Array<{ value: string, label: string }>) => void): void => {\n const current = currentFormValues?.scope || [];\n if (scopesAvailable) {\n // add custom scopes to the list of available scopes\n const unlisted = difference(current, scopesAvailable);\n callback(scopesAvailable.concat(unlisted).map(scope => ({ value: scope, label: scope })));\n } else {\n callback(current.map(scope => ({ value: scope, label: scope })));\n }\n };\n\n /**\n * Callback that check for the existence of the .well-known/openid-configuration endpoint, for the given issuer.\n * This callback is triggered when the user changes the issuer field.\n */\n const checkForDiscoveryEndpoint = (e: React.ChangeEvent) => {\n SsoClient.openIdConfiguration(e.target.value).then((configuration) => {\n setDiscoveryAvailable(true);\n setScopesAvailable(configuration.scopes_supported);\n }).catch(() => {\n setDiscoveryAvailable(false);\n setScopesAvailable(null);\n });\n };\n\n return (\n
\n
\n \n \n \n }\n loadOptions={loadScopes}\n selectKey={selectKey.toString()}\n creatable\n control={control} />\n }\n options={[\n { value: 'none', label: t('app.admin.authentication.openid_connect_form.prompt_none') },\n { value: 'login', label: t('app.admin.authentication.openid_connect_form.prompt_login') },\n { value: 'consent', label: t('app.admin.authentication.openid_connect_form.prompt_consent') },\n { value: 'select_account', label: t('app.admin.authentication.openid_connect_form.prompt_select_account') }\n ]}\n clearable\n control={control} />\n \n \n

{t('app.admin.authentication.openid_connect_form.client_options')}

\n \n \n {!currentFormValues?.discovery &&
\n \n \n \n {currentFormValues?.client_auth_method === 'jwks' && }\n \n
}\n
\n );\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useForm, SubmitHandler, useWatch } from 'react-hook-form';\nimport { react2angular } from 'react2angular';\nimport { debounce as _debounce } from 'lodash';\nimport {\n AuthenticationProvider,\n AuthenticationProviderMapping,\n OpenIdConnectProvider,\n ProvidableType\n} from '../../models/authentication-provider';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { FormInput } from '../form/form-input';\nimport { useTranslation } from 'react-i18next';\nimport { FormSelect } from '../form/form-select';\nimport { Oauth2Form } from './oauth2-form';\nimport { DataMappingForm } from './data-mapping-form';\nimport { FabButton } from '../base/fab-button';\nimport AuthProviderAPI from '../../api/auth-provider';\nimport { OpenidConnectForm } from './openid-connect-form';\nimport { DatabaseForm } from './database-form';\n\ndeclare const Application: IApplication;\n\n// list of supported authentication methods\nconst METHODS = {\n DatabaseProvider: 'local_database',\n OAuth2Provider: 'oauth2',\n OpenIdConnectProvider: 'openid_connect'\n};\n\ninterface ProviderFormProps {\n action: 'create' | 'update',\n provider?: AuthenticationProvider,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\ntype selectProvidableTypeOption = { value: string, label: string };\n\n/**\n * Form to create or update an authentication provider.\n */\nexport const ProviderForm: React.FC = ({ action, provider, onError, onSuccess }) => {\n const { handleSubmit, register, control, formState, setValue } = useForm({ defaultValues: { ...provider } });\n const output = useWatch({ control });\n const [providableType, setProvidableType] = useState(provider?.providable_type);\n const [strategyName, setStrategyName] = useState(provider?.strategy_name);\n\n const { t } = useTranslation('admin');\n\n useEffect(() => {\n updateStrategyName(output as AuthenticationProvider);\n }, [output?.providable_type, output?.name]);\n\n /**\n * Callback triggered when the form is submitted: process with the provider creation or update.\n */\n const onSubmit: SubmitHandler = (data: AuthenticationProvider) => {\n AuthProviderAPI[action](data).then(() => {\n onSuccess(t(`app.admin.authentication.provider_form.${action}_success`));\n }).catch(error => {\n onError(error);\n });\n };\n\n /**\n * Build the list of available authentication methods to match with react-select requirements.\n */\n const buildProvidableTypeOptions = (): Array => {\n return Object.keys(METHODS).map((method: string) => {\n return { value: method, label: t(`app.admin.authentication.provider_form.methods.${METHODS[method]}`) };\n });\n };\n\n /**\n * Callback triggered when the providable type is changed.\n * Changing the providable type will change the form to match the new type.\n */\n const onProvidableTypeChange = (type: ProvidableType) => {\n setProvidableType(type);\n };\n\n /**\n * Request the API the strategy name for the current \"in-progress\" provider.\n */\n const updateStrategyName = useCallback(_debounce((provider: AuthenticationProvider): void => {\n AuthProviderAPI.strategyName(provider).then(strategyName => {\n setStrategyName(strategyName);\n }).catch(error => {\n onError(error);\n });\n }, 400), []);\n\n return (\n
\n \n \n {providableType === 'DatabaseProvider' && }\n {providableType === 'OAuth2Provider' && }\n {providableType === 'OpenIdConnectProvider' && }\n {providableType && providableType !== 'DatabaseProvider' && } />}\n
\n {t('app.admin.authentication.provider_form.save')}\n
\n \n );\n};\n\nconst ProviderFormWrapper: React.FC = ({ action, provider, onError, onSuccess }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('providerForm', react2angular(ProviderFormWrapper, ['action', 'provider', 'onSuccess', 'onError']));\n","import { ArrayPath, useFieldArray, UseFormRegister } from 'react-hook-form';\nimport { Control, FormState } from 'react-hook-form/dist/types/form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../base/fab-button';\nimport { FormInput } from '../form/form-input';\n\nexport interface StringMappingFormProps {\n register: UseFormRegister,\n control: Control,\n fieldMappingId: number,\n formState: FormState\n}\n\n/**\n * Partial form to map an internal string field to an external API.\n */\nexport const StringMappingForm = ({ register, control, fieldMappingId, formState }: StringMappingFormProps) => {\n const { t } = useTranslation('admin');\n\n const { fields, append, remove } = useFieldArray({ control, name: 'auth_provider_mappings_attributes_transformation_mapping' as ArrayPath });\n\n return (\n
\n

{t('app.admin.authentication.string_mapping_form.mappings')}

\n
\n }\n onClick={() => append({})} />\n
\n {fields.map((item, index) => (\n
\n
\n \n \n
\n
\n } onClick={() => remove(index)} className=\"delete-button\" />\n
\n
\n ))}\n
\n );\n};\n","import { FabModal } from '../base/fab-modal';\nimport { useTranslation } from 'react-i18next';\nimport { IntegerMappingForm } from './integer-mapping-form';\nimport { UseFormRegister } from 'react-hook-form';\nimport { Control, FormState } from 'react-hook-form/dist/types/form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { mappingType } from '../../models/authentication-provider';\nimport { BooleanMappingForm } from './boolean-mapping-form';\nimport { DateMappingForm } from './date-mapping-form';\nimport { StringMappingForm } from './string-mapping-form';\nimport { FormInput } from '../form/form-input';\n\ninterface TypeMappingModalProps {\n model: string,\n field: string,\n type: mappingType,\n isOpen: boolean,\n toggleModal: () => void,\n register: UseFormRegister,\n control: Control,\n fieldMappingId: number,\n formState: FormState\n}\n\n/**\n * Modal dialog to display the expected type for the current data field.\n * Also allows to map the incoming data (from the authentication provider API) to the expected type/data.\n *\n * This component is intended to be used in a react-hook-form context.\n */\nexport const TypeMappingModal = ({ model, field, type, isOpen, toggleModal, register, control, fieldMappingId, formState }:TypeMappingModalProps) => {\n const { t } = useTranslation('admin');\n\n return (\n }\n onConfirm={toggleModal}>\n {model} > {field} ({t('app.admin.authentication.type_mapping_modal.TYPE_expected', { TYPE: t(`app.admin.authentication.type_mapping_modal.types.${type}`) })})\n \n {type === 'integer' && }\n {type === 'boolean' && }\n {type === 'date' && }\n {type === 'string' && }\n \n );\n};\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { CaretDown } from 'phosphor-react';\n\ninterface AccordionItemProps {\n isOpen: boolean,\n onChange: (id: number, isOpen: boolean) => void,\n id: number,\n label: string\n}\n\n/**\n * Renders an accordion item\n */\nexport const AccordionItem: React.FC = ({ isOpen, onChange, id, label, children }) => {\n const [state, setState] = useState(isOpen);\n\n useEffect(() => {\n onChange(id, state);\n }, [state]);\n\n return (\n
\n
setState(!state)}>\n {label}\n \n
\n {children}\n
\n );\n};\n","import { ReactNode, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from './fab-button';\nimport { FabModal } from './fab-modal';\nimport { Trash } from 'phosphor-react';\n\ninterface DestroyButtonProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n itemId: number,\n itemType: string,\n apiDestroy: (itemId: number) => Promise,\n confirmationMessage?: string|ReactNode,\n className?: string,\n iconSize?: number\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog to ask the user for confirmation about the deletion of the provided item.\n */\nexport const DestroyButton: React.FC = ({ onSuccess, onError, itemId, itemType, apiDestroy, confirmationMessage, className, iconSize = 24 }) => {\n const { t } = useTranslation('admin');\n\n const [deletionModal, setDeletionModal] = useState(false);\n\n /**\n * Opens/closes the deletion modal\n */\n const toggleDeletionModal = (): void => {\n setDeletionModal(!deletionModal);\n };\n\n /**\n * The deletion has been confirmed by the user.\n * Call the API to trigger the deletion of the given item\n */\n const onDeleteConfirmed = (): void => {\n apiDestroy(itemId).then(() => {\n onSuccess(t('app.admin.destroy_button.deleted', { TYPE: itemType }));\n }).catch((error) => {\n onError(t('app.admin.destroy_button.unable_to_delete', { TYPE: itemType }) + error);\n });\n toggleDeletionModal();\n };\n\n return (\n
\n \n \n \n \n {confirmationMessage || t('app.admin.destroy_button.delete_confirmation', { TYPE: itemType })}\n \n
\n );\n};\n","import { PencilSimple, Trash } from 'phosphor-react';\nimport * as React from 'react';\nimport { ReactNode, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from './fab-button';\nimport { FabModal } from './fab-modal';\n\ntype EditDestroyButtonsCommon = {\n onError: (message: string) => void,\n onEdit: () => void,\n itemId: number,\n destroy: (itemId: number) => Promise,\n className?: string,\n iconSize?: number,\n showEditButton?: boolean,\n}\n\ntype DeleteSuccess =\n { onDeleteSuccess: (message: string) => void, deleteSuccessMessage: string } |\n { onDeleteSuccess?: never, deleteSuccessMessage?: never }\n\ntype DestroyMessages =\n ({ showDestroyConfirmation?: true } &\n ({ itemType: string, confirmationTitle?: string, confirmationMessage?: string|ReactNode } |\n { itemType?: never, confirmationTitle: string, confirmationMessage: string|ReactNode })) |\n { showDestroyConfirmation: false, itemType?: never, confirmationTitle?: never, confirmationMessage?: never };\n\ntype EditDestroyButtonsProps = EditDestroyButtonsCommon & DeleteSuccess & DestroyMessages;\n\n/**\n * This component shows a group of two buttons.\n * Destroy : shows a modal dialog to ask the user for confirmation about the deletion of the provided item.\n * Edit : triggers the provided function.\n */\nexport const EditDestroyButtons: React.FC = ({ onDeleteSuccess, onError, onEdit, itemId, itemType, destroy, confirmationTitle, confirmationMessage, deleteSuccessMessage, className, iconSize = 20, showEditButton = true, showDestroyConfirmation = true }) => {\n const { t } = useTranslation('admin');\n\n const [deletionModal, setDeletionModal] = useState(false);\n\n /**\n * Opens/closes the deletion modal\n */\n const toggleDeletionModal = (): void => {\n setDeletionModal(!deletionModal);\n };\n\n /**\n * Triggered when the user clicks on the 'destroy' button\n */\n const handleDestroyRequest = (): void => {\n if (showDestroyConfirmation) {\n toggleDeletionModal();\n } else {\n onDeleteConfirmed();\n }\n };\n\n /**\n * The deletion has been confirmed by the user.\n * Call the API to trigger the deletion of the given item\n */\n const onDeleteConfirmed = (): void => {\n destroy(itemId).then(() => {\n typeof onDeleteSuccess === 'function' && onDeleteSuccess(deleteSuccessMessage || t('app.admin.edit_destroy_buttons.deleted'));\n }).catch((error) => {\n onError(t('app.admin.edit_destroy_buttons.unable_to_delete') + error);\n });\n setDeletionModal(false);\n };\n\n return (\n <>\n
\n {showEditButton && \n \n }\n \n \n \n
\n \n {confirmationMessage || t('app.admin.edit_destroy_buttons.delete_confirmation', { TYPE: itemType })}\n \n \n );\n};\n","import { Component } from 'react';\n\ninterface ErrorBoundaryState {\n hasError: boolean;\n}\n\n/**\n * This component will catch javascript errors anywhere in their child component tree and display a message to the user.\n * @see https://reactjs.org/docs/error-boundaries.html\n */\nexport class ErrorBoundary extends Component {\n constructor (props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError () {\n return { hasError: true };\n }\n\n componentDidCatch (error, errorInfo) {\n console.error(error, errorInfo);\n }\n\n render () {\n if (this.state.hasError) {\n return

Something went wrong.

;\n }\n\n return this.props.children;\n }\n}\n","import * as React from 'react';\n\ninterface FabAlertProps {\n level: 'info' | 'warning' | 'danger',\n className?: string,\n}\n\n/**\n * This component shows a styled text paragraph, useful to display important information messages.\n */\nexport const FabAlert: React.FC = ({ level, className, children }) => {\n return (\n
\n {children}\n
\n );\n};\n","import { ReactNode, BaseSyntheticEvent } from 'react';\nimport * as React from 'react';\n\ninterface FabButtonProps {\n onClick?: (event: BaseSyntheticEvent) => void,\n icon?: ReactNode,\n className?: string,\n disabled?: boolean,\n type?: 'submit' | 'reset' | 'button',\n form?: string,\n tooltip?: string,\n}\n\n/**\n * This component is a template for a clickable button that wraps the application style\n */\nexport const FabButton: React.FC = ({ onClick, icon, className, disabled, type, form, tooltip, children }) => {\n /**\n * Check if the current component was provided an icon to display\n */\n const hasIcon = (): boolean => {\n return !!icon;\n };\n\n /**\n * Check if the current button has children properties (like some text)\n */\n const hasChildren = (): boolean => {\n return !!children;\n };\n\n /**\n * Handle the action of the button\n */\n const handleClick = (e: BaseSyntheticEvent): void => {\n if (typeof onClick === 'function') {\n onClick(e);\n }\n };\n\n return (\n \n );\n};\n\nFabButton.defaultProps = { type: 'button' };\n","import { BaseSyntheticEvent, ReactNode, useCallback, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { debounce as _debounce } from 'lodash';\n\ntype inputType = string|number|readonly string [];\n\ninterface FabInputProps {\n id: string,\n onChange?: (value: inputType, validity?: ValidityState) => void,\n defaultValue?: inputType,\n icon?: ReactNode,\n addOn?: ReactNode,\n addOnClassName?: string,\n className?: string,\n disabled?: boolean,\n required?: boolean,\n debounce?: number,\n readOnly?: boolean,\n maxLength?: number,\n pattern?: string,\n placeholder?: string,\n error?: string,\n type?: 'text' | 'date' | 'password' | 'url' | 'time' | 'tel' | 'search' | 'number' | 'month' | 'email' | 'datetime-local' | 'week',\n step?: number | 'any',\n min?: number,\n max?: number,\n}\n\n/**\n * This component is a template for an input component that wraps the application style\n */\nexport const FabInput: React.FC = ({ id, onChange, defaultValue, icon, className, disabled, type, required, debounce, addOn, addOnClassName, readOnly, maxLength, pattern, placeholder, error, step, min, max }) => {\n const [inputValue, setInputValue] = useState(defaultValue);\n\n /**\n * When the component is mounted, initialize the default value for the input.\n * If the default value changes, update the value of the input until there's no content in it.\n */\n useEffect(() => {\n setInputValue(defaultValue);\n if (typeof onChange === 'function') {\n onChange(defaultValue);\n }\n }, [defaultValue]);\n\n /**\n * Check if the current component was provided an icon to display\n */\n const hasIcon = (): boolean => {\n return !!icon;\n };\n\n /**\n * Check if the current component was provided an add-on element to display, at the end of the input\n */\n const hasAddOn = (): boolean => {\n return !!addOn;\n };\n\n /**\n * Check if the current component was provided an error string to display, on the input\n */\n const hasError = (): boolean => {\n return !!error;\n };\n\n /**\n * Debounced (ie. temporised) version of the 'on change' callback.\n */\n const debouncedOnChange = debounce ? useCallback(_debounce(onChange, debounce), [onChange, debounce]) : null;\n\n /**\n * Handle the change of content in the input field, and trigger the parent callback, if any\n */\n const handleChange = (e: BaseSyntheticEvent): void => {\n const { value, validity } = e.target;\n setInputValue(value);\n if (typeof onChange === 'function') {\n if (debounce) {\n debouncedOnChange(value, validity);\n } else {\n onChange(value, validity);\n }\n }\n };\n\n return (\n
\n
\n {hasIcon() && {icon}}\n \n {hasAddOn() && {addOn}}\n
\n {hasError() && {error} }\n
\n );\n};\n\nFabInput.defaultProps = { type: 'text', debounce: 0 };\n","import { ReactNode, BaseSyntheticEvent, useEffect } from 'react';\nimport * as React from 'react';\nimport Modal from 'react-modal';\nimport { useTranslation } from 'react-i18next';\nimport { Loader } from './loader';\nimport { FabButton } from './fab-button';\n\nModal.setAppElement('body');\n\nexport enum ModalSize {\n small = 'sm',\n medium = 'md',\n large = 'lg'\n}\n\ninterface FabModalProps {\n title?: string,\n isOpen: boolean,\n toggleModal: () => void,\n confirmButton?: ReactNode,\n closeButton?: boolean,\n className?: string,\n width?: ModalSize,\n customHeader?: ReactNode,\n customFooter?: ReactNode,\n onConfirm?: (event: BaseSyntheticEvent) => void,\n onClose?: (event: BaseSyntheticEvent) => void,\n preventConfirm?: boolean,\n onCreation?: () => void,\n onConfirmSendFormId?: string,\n}\n\n/**\n * This component is a template for a modal dialog that wraps the application style\n */\nexport const FabModal: React.FC = ({ title, isOpen, toggleModal, children, confirmButton, className, width = 'sm', closeButton, customHeader, customFooter, onConfirm, onClose, preventConfirm, onCreation, onConfirmSendFormId }) => {\n const { t } = useTranslation('shared');\n\n useEffect(() => {\n if (typeof onCreation === 'function' && isOpen) {\n onCreation();\n }\n }, [isOpen]);\n\n /**\n * Callback triggered when the user request to close the modal without confirming.\n */\n const handleClose = (event) => {\n if (typeof onClose === 'function') onClose(event);\n toggleModal();\n };\n\n return (\n \n {closeButton && {t('app.shared.fab_modal.close')}}\n
\n {!customHeader &&

{ title }

}\n {customHeader && customHeader}\n
\n
\n {children}\n
\n {(customFooter || confirmButton) &&
\n \n {confirmButton && !onConfirmSendFormId && {confirmButton}}\n {confirmButton && onConfirmSendFormId && {confirmButton}}\n {customFooter && customFooter}\n \n
}\n
\n );\n};\n","import * as React from 'react';\n\ninterface FabOutputCopyProps {\n text: string,\n onCopy?: () => void,\n label?: string,\n}\n\n/**\n * This component shows a read-only input text filled with the provided text. A button allows to copy the text to the clipboard.\n */\nexport const FabOutputCopy: React.FC = ({ label, text, onCopy }) => {\n const [copied, setCopied] = React.useState(false);\n /**\n * Copy the given text to the clipboard.\n */\n const textToClipboard = () => {\n if (navigator?.clipboard?.writeText) {\n navigator.clipboard.writeText(text).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1000);\n if (onCopy) {\n onCopy();\n }\n });\n }\n };\n\n return (\n
\n \n
\n );\n};\n","import * as React from 'react';\nimport { CaretDoubleLeft, CaretLeft, CaretRight, CaretDoubleRight } from 'phosphor-react';\n\ninterface FabPaginationProps {\n pageCount: number,\n currentPage: number,\n selectPage: (page: number) => void\n}\n\n/**\n * Renders a pagination navigation\n */\nexport const FabPagination: React.FC = ({ pageCount, currentPage, selectPage }) => {\n return (\n \n );\n};\n","import { ReactNode } from 'react';\nimport * as React from 'react';\n\ninterface FabPanelProps {\n className?: string,\n header?: ReactNode,\n size?: 'small' | 'normal'\n}\n\n/**\n * Simple styled panel component\n */\nexport const FabPanel: React.FC = ({ className, header, size, children }) => {\n return (\n
\n {header && <>\n
\n {header}\n
\n
\n {children}\n
\n }\n {!header && <>{ children }}\n
\n );\n};\n","import { ReactNode } from 'react';\nimport * as React from 'react';\n\ninterface FabPopoverProps {\n title: string,\n className?: string,\n headerButton?: ReactNode,\n position?: 'bottom' | 'right' | 'left'\n}\n\n/**\n * This component is a template for a popovers (bottom) that wraps the application style.\n * Please note that the parent element must be set `position: relative;` otherwise the popover won't be placed correctly.\n */\nexport const FabPopover: React.FC = ({ title, className, headerButton, position = 'bottom', children }) => {\n /**\n * Check if the header button should be present\n */\n const hasHeaderButton = (): boolean => {\n return !!headerButton;\n };\n\n return (\n
\n
\n

{title}

\n {hasHeaderButton() && headerButton}\n
\n
\n {children}\n
\n
\n );\n};\n","import * as React from 'react';\n\ninterface FabStateLabelProps {\n status?: string,\n background?: boolean\n}\n\n/**\n * Render a label preceded by a bot\n */\nexport const FabStateLabel: React.FC = ({ status, background, children }) => {\n return (\n \n {children}\n \n );\n};\n","import { ReactNode, useEffect, useState } from 'react';\nimport { Tab, Tabs, TabList, TabPanel } from 'react-tabs';\nimport * as React from 'react';\nimport _ from 'lodash';\nimport { usePrevious } from '../../lib/use-previous';\n\ntype tabId = string|number;\n\ninterface Tab {\n id: tabId,\n title: ReactNode,\n content: ReactNode,\n onSelected?: () => void,\n}\n\ninterface FabTabsProps {\n tabs: Array,\n defaultTab?: tabId,\n className?: string\n}\n\n/**\n * A wrapper around https://github.com/reactjs/react-tabs that provides the Fab-manager's theme for tabs\n */\nexport const FabTabs: React.FC = ({ tabs, defaultTab, className }) => {\n const [active, setActive] = useState(tabs.filter(Boolean).find(t => t.id === defaultTab) || tabs.filter(Boolean)[0]);\n const previousTabs = usePrevious(tabs);\n\n useEffect(() => {\n if (!_.isEqual(previousTabs?.filter(Boolean).map(t => t.id), tabs?.filter(Boolean).map(t => t?.id))) {\n setActive(tabs.filter(Boolean).find(t => t.id === defaultTab) || tabs.filter(Boolean)[0]);\n }\n }, [tabs]);\n\n /**\n * Return the index of the currently selected tabs (i.e. the \"active\" tab)\n */\n const selectedIndex = (): number => {\n return tabs.findIndex(t => t?.id === active?.id) || 0;\n };\n\n /**\n * Callback triggered when the active tab is changed by the user\n */\n const onIndexSelected = (index: number) => {\n setActive(tabs[index]);\n if (typeof tabs[index].onSelected === 'function') {\n tabs[index].onSelected();\n }\n };\n\n return (\n \n \n {tabs.filter(Boolean).map((tab, index) => {tab.title})}\n \n {tabs.filter(Boolean).map((tab, index) => {tab.content})}\n \n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\n\ninterface HtmlTranslateProps {\n trKey: string,\n className?: string,\n options?: Record\n}\n\n/**\n * This component renders a translation with some HTML content.\n */\nexport const HtmlTranslate: React.FC = ({ trKey, className, options }) => {\n const { t } = useTranslation(trKey?.split('.')[1]);\n\n /* eslint-disable fabmanager/component-class-named-as-component */\n return (\n \n );\n /* eslint-enable fabmanager/component-class-named-as-component */\n};\n","import { BaseSyntheticEvent, ReactNode } from 'react';\nimport * as React from 'react';\n\ntype inputType = string|number|readonly string [];\n\ninterface LabelledInputProps {\n id: string,\n type?: 'text' | 'date' | 'password' | 'url' | 'time' | 'tel' | 'search' | 'number' | 'month' | 'email' | 'datetime-local' | 'week',\n label: string | ReactNode,\n value: inputType,\n onChange: (event: BaseSyntheticEvent) => void\n}\n\n/**\n * This component shows input field with its label, styled\n */\nexport const LabelledInput: React.FC = ({ id, type, label, value, onChange }) => {\n return (\n
\n \n \n
\n );\n};\n","import { Suspense } from 'react';\nimport * as React from 'react';\n\n/**\n * This component is a wrapper that display a loader while the children components have their rendering suspended.\n */\nexport const Loader: React.FC = ({ children }) => {\n const loading = (\n
\n \n
\n );\n return (\n \n {children}\n \n );\n};\n","import { forwardRef, RefObject, useEffect, useImperativeHandle, useRef } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useEditor, EditorContent, Editor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport CharacterCount from '@tiptap/extension-character-count';\nimport Underline from '@tiptap/extension-underline';\nimport Link from '@tiptap/extension-link';\nimport Iframe from './iframe';\nimport Image from '@tiptap/extension-image';\nimport { MenuBar } from './menu-bar';\nimport { WarningOctagon } from 'phosphor-react';\n\ninterface FabTextEditorProps {\n heading?: boolean,\n bulletList?: boolean,\n blockquote?: boolean,\n link?: boolean,\n video?: boolean,\n image?: boolean,\n content?: string,\n limit?: number,\n onChange?: (content: string) => void,\n placeholder?: string,\n error?: string,\n disabled?: boolean\n ariaLabel?: string,\n}\n\nexport interface FabTextEditorRef {\n focus: () => void\n}\n\n/**\n * This component is a WYSIWYG text editor\n */\nconst FabTextEditor: React.ForwardRefRenderFunction = ({ heading, bulletList, blockquote, content, limit = 400, video, image, link, onChange, placeholder, error, disabled = false, ariaLabel }, ref: RefObject) => {\n const { t } = useTranslation('shared');\n const placeholderText = placeholder || t('app.shared.text_editor.fab_text_editor.text_placeholder');\n // TODO: Add ctrl+click on link to visit\n\n const editorRef: React.MutableRefObject = useRef(null);\n // the methods in useImperativeHandle are exposed to the parent component\n useImperativeHandle(ref, () => ({\n focus () {\n editorRef.current?.commands?.focus();\n }\n }), []);\n\n // Setup the editor\n // Extensions add functionalities to the editor (Bold, Italic…)\n // Events fire action (onUpdate -> get the content as HTML)\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n heading: {\n levels: [3]\n }\n }),\n Underline,\n Link.configure({\n openOnClick: false\n }),\n Placeholder.configure({\n placeholder: placeholderText\n }),\n CharacterCount.configure({\n limit\n }),\n Iframe,\n Image.configure({\n HTMLAttributes: {\n class: 'fab-text-editor-image'\n }\n })\n ],\n editorProps: {\n attributes: {\n 'aria-label': ariaLabel,\n role: 'textbox'\n }\n },\n content,\n onUpdate: ({ editor }) => {\n if (editor.isEmpty) {\n onChange('');\n } else {\n onChange(editor.getHTML());\n }\n }\n });\n\n useEffect(() => {\n editor?.setEditable(!disabled);\n }, [disabled]);\n\n useEffect(() => {\n if (editor?.getHTML() !== content) {\n editor?.commands.setContent(content);\n }\n }, [content]);\n\n // bind the editor to the ref, once it is ready\n if (!editor) return null;\n editorRef.current = editor;\n\n return (\n
\n \n \n {limit &&
\n {editor?.storage.characterCount.characters()} / {limit}\n
}\n {error &&\n
\n \n

{error}

\n
\n }\n
\n );\n};\n\n// eslint-disable-next-line import/no-default-export\nexport default forwardRef(FabTextEditor);\n","import { Node } from '@tiptap/core';\n\nexport interface IframeOptions {\n allowFullscreen: boolean,\n HTMLAttributes: {\n [key: string]: string\n },\n}\n\ndeclare module '@tiptap/core' {\n interface Commands {\n iframe: {\n /**\n * Add an iframe to embed a video\n */\n setIframe: (options: { src: string }) => ReturnType,\n }\n }\n}\n\n// eslint-disable-next-line import/no-default-export\nexport default Node.create({\n name: 'iframe',\n\n group: 'block',\n\n atom: true,\n\n addOptions () {\n return {\n allowFullscreen: true,\n HTMLAttributes: {\n class: 'fab-text-editor-video'\n }\n };\n },\n\n addAttributes () {\n return {\n src: {\n default: null\n },\n frameborder: {\n default: 0\n },\n allowfullscreen: {\n default: this.options.allowFullscreen,\n parseHTML: () => this.options.allowFullscreen\n }\n };\n },\n\n parseHTML () {\n return [{\n tag: 'iframe'\n }];\n },\n\n renderHTML ({ HTMLAttributes }) {\n return ['div', this.options.HTMLAttributes, ['iframe', HTMLAttributes]];\n },\n\n addCommands () {\n return {\n setIframe: (options: { src: string }) => ({ tr, dispatch }) => {\n const { selection } = tr;\n const node = this.type.create(options);\n\n if (dispatch) {\n tr.replaceRangeWith(selection.from, selection.to, node);\n }\n\n return true;\n }\n };\n }\n});\n","import { useCallback, useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport useOnclickOutside from 'react-cool-onclickoutside';\nimport { Editor } from '@tiptap/react';\nimport { TextAa, TextBolder, TextItalic, TextUnderline, LinkSimpleHorizontal, ListBullets, Quotes, Trash, CheckCircle, VideoCamera, Image } from 'phosphor-react';\n\ninterface MenuBarProps {\n editor?: Editor,\n heading?: boolean,\n bulletList?: boolean,\n blockquote?: boolean,\n link?: boolean,\n video?: boolean,\n image?: boolean,\n disabled?: boolean,\n}\n\n/**\n * This component is the menu bar for the WYSIWYG text editor\n */\nexport const MenuBar: React.FC = ({ editor, heading, bulletList, blockquote, link, video, image, disabled = false }) => {\n const { t } = useTranslation('shared');\n\n const [submenu, setSubmenu] = useState('');\n const resetUrl = { href: '', target: '_blank' };\n const [url, setUrl] = useState(resetUrl);\n const [videoProvider, setVideoProvider] = useState('youtube');\n const [videoId, setVideoId] = useState('');\n const [imageUrl, setImageUrl] = useState('');\n\n // Reset state values when the submenu is closed\n useEffect(() => {\n if (!submenu) {\n setUrl(resetUrl);\n setVideoProvider('youtube');\n setImageUrl('');\n }\n }, [submenu]);\n\n // Close the submenu frame on click outside\n const ref = useOnclickOutside(() => {\n setSubmenu('');\n });\n\n // Toggle submenu's visibility\n const toggleSubmenu = (type) => {\n if (submenu !== type) {\n setSubmenu(type);\n if (type === 'link') {\n if (editor.view.state.selection.from === editor.view.state.selection.to) {\n setSubmenu('');\n return;\n }\n const previousUrl = {\n href: editor.getAttributes('link').href,\n target: editor.getAttributes('link').target || ''\n };\n // display selected text's attributes if it's a link\n if (previousUrl.href) {\n setUrl(previousUrl);\n }\n }\n } else {\n setSubmenu('');\n }\n };\n\n // Set link's target\n const toggleTarget = (evt) => {\n evt.target.checked\n ? setUrl({ href: url.href, target: '_blank' })\n : setUrl({ href: url.href, target: '' });\n };\n\n // Update url\n const linkUrlChange = (evt) => {\n setUrl({ ...url, href: evt.target.value });\n };\n // Support keyboard \"Enter\" key event to validate\n const handleEnter = (evt) => {\n if (evt.keyCode === 13) {\n setLink(true);\n }\n };\n\n // Update the selected link\n const setLink = useCallback((closeLinkMenu?: boolean) => {\n if (url.href === '') {\n unsetLink();\n return;\n }\n editor.chain().focus().extendMarkRange('link').setLink({ href: url.href, target: url.target }).run();\n if (closeLinkMenu) {\n setSubmenu('');\n }\n }, [editor, url]);\n\n // Remove the link tag from the selected text\n const unsetLink = () => {\n editor.chain().focus().extendMarkRange('link').unsetLink().run();\n setSubmenu('');\n };\n\n // Store selected video provider in state\n const handleSelect = (evt) => {\n setVideoProvider(evt.target.value);\n };\n // Store video id in state\n const videoUrlChange = (evt) => {\n const id = evt.target.value.match(/([^/]+$)/g);\n setVideoId(id);\n };\n // Insert iframe containing the video player\n const addIframe = () => {\n let videoUrl = '';\n switch (videoProvider) {\n case 'youtube':\n videoUrl = `https://www.youtube.com/embed/${videoId}`;\n break;\n case 'vimeo':\n videoUrl = `https://player.vimeo.com/video/${videoId}`;\n break;\n case 'dailymotion':\n videoUrl = `https://www.dailymotion.com/embed/video/${videoId}`;\n break;\n default:\n break;\n }\n editor.chain().focus().setIframe({ src: videoUrl }).run();\n setSubmenu('');\n };\n\n // Store image url in state\n const imageUrlChange = (evt) => {\n setImageUrl(evt.target.value);\n };\n // Insert image\n const addImage = () => {\n if (imageUrl) {\n editor.chain().focus().setImage({ src: imageUrl }).run();\n setSubmenu('');\n }\n };\n\n if (!editor) {\n return null;\n }\n\n return (\n <>\n
\n {heading &&\n editor.chain().focus().toggleHeading({ level: 3 }).run()}\n disabled={disabled}\n className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}\n >\n \n \n }\n {bulletList &&\n editor.chain().focus().toggleBulletList().run()}\n disabled={disabled}\n className={editor.isActive('bulletList') ? 'is-active' : ''}\n >\n \n \n }\n {blockquote &&\n editor.chain().focus().toggleBlockquote().run()}\n disabled={disabled}\n className={editor.isActive('blockquote') ? 'is-active' : ''}\n >\n \n \n }\n { (heading || bulletList || blockquote) && }\n editor.chain().focus().toggleBold().run()}\n disabled={disabled}\n className={editor.isActive('bold') ? 'is-active' : ''}\n >\n \n \n editor.chain().focus().toggleItalic().run()}\n disabled={disabled}\n className={editor.isActive('italic') ? 'is-active' : ''}\n >\n \n \n editor.chain().focus().toggleUnderline().run()}\n disabled={disabled}\n className={editor.isActive('underline') ? 'is-active' : ''}\n >\n \n \n {link &&\n toggleSubmenu('link')}\n disabled={disabled}\n className={`ignore-onclickoutside ${editor.isActive('link') ? 'is-active' : ''}`}\n >\n \n \n }\n { (video || image) && }\n { video &&\n (<>\n toggleSubmenu('video')}\n >\n \n \n )\n }\n { image &&\n (<>\n toggleSubmenu('image')}\n >\n \n \n )\n }\n
\n\n
\n { submenu === 'link' &&\n (<>\n
{t('app.shared.text_editor.menu_bar.add_link')}
\n
\n \n \n
\n
\n \n \n
\n )\n }\n { submenu === 'video' &&\n (<>\n
{t('app.shared.text_editor.menu_bar.add_video')}
\n \n
\n \n \n
\n )\n }\n { submenu === 'image' &&\n (<>\n
{t('app.shared.text_editor.menu_bar.add_image')}
\n
\n \n \n
\n )\n }\n
\n \n );\n};\n","import * as React from 'react';\nimport noImage from '../../../../images/no_image.png';\nimport FormatLib from '../../lib/format';\nimport OrderLib from '../../lib/order';\nimport { FabButton } from '../base/fab-button';\nimport Switch from 'react-switch';\nimport type { ItemError, OrderItem } from '../../models/order';\nimport { useTranslation } from 'react-i18next';\nimport { ReactNode } from 'react';\nimport { Order } from '../../models/order';\nimport CartAPI from '../../api/cart';\n\ninterface AbstractItemProps {\n item: OrderItem,\n errors: Array,\n cart: Order,\n setCart: (cart: Order) => void,\n reloadCart: () => Promise,\n onError: (message: string) => void,\n className?: string,\n offerItemLabel?: string,\n privilegedOperator: boolean,\n actions?: ReactNode\n}\n\n/**\n * This component shares the common code for items in the cart (product, cart-item, etc)\n */\nexport const AbstractItem: React.FC = ({ item, errors, cart, setCart, reloadCart, onError, className, offerItemLabel, privilegedOperator, actions, children }) => {\n const { t } = useTranslation('public');\n\n /**\n * Return the callback triggered when then user remove the given item from the cart\n */\n const handleRemoveItem = (item: OrderItem) => {\n return (e: React.BaseSyntheticEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n if (errors.length === 1 && errors[0].error === 'not_found') {\n reloadCart().catch(onError);\n } else {\n CartAPI.removeItem(cart, item.orderable_id, item.orderable_type).then(data => {\n setCart(data);\n }).catch(onError);\n }\n };\n };\n\n /**\n * Return the callback triggered when the privileged user enable/disable the offered attribute for the given item\n */\n const handleToggleOffer = (item: OrderItem) => {\n return (checked: boolean) => {\n CartAPI.setOffer(cart, item.orderable_id, item.orderable_type, checked).then(data => {\n setCart(data);\n }).catch(e => {\n if (e.match(/code 403/)) {\n onError(t('app.public.abstract_item.errors.unauthorized_offering_product'));\n } else {\n onError(e);\n }\n });\n };\n };\n\n return (\n
0 ? 'error' : ''}`}>\n
\n \n
\n {children}\n
\n {actions}\n
\n {t('app.public.abstract_item.total')}\n

{FormatLib.price(OrderLib.itemAmount(item))}

\n
\n \n \n \n
\n {privilegedOperator &&\n
\n \n
\n }\n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { Order } from '../../models/order';\nimport { useCustomEventListener } from 'react-custom-events';\n\ndeclare const Application: IApplication;\n\n/**\n * This component shows my cart button\n */\nconst CartButton: React.FC = () => {\n const { t } = useTranslation('public');\n const [cart, setCart] = useState();\n useCustomEventListener('CartUpdate', (data) => {\n setCart(data);\n });\n\n /**\n * Goto cart page\n */\n const showCart = () => {\n window.location.href = '/#!/store/cart';\n };\n\n return (\n
\n \n {cart && cart.order_items_attributes.length > 0 &&\n {cart.order_items_attributes.length}\n }\n

{t('app.public.cart_button.my_cart')}

\n
\n );\n};\n\nconst CartButtonWrapper: React.FC = () => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('cartButton', react2angular(CartButtonWrapper));\n","import * as React from 'react';\nimport FormatLib from '../../lib/format';\nimport { CaretDown, CaretUp } from 'phosphor-react';\nimport type { OrderProduct, OrderErrors, Order, ItemError } from '../../models/order';\nimport { useTranslation } from 'react-i18next';\nimport _ from 'lodash';\nimport CartAPI from '../../api/cart';\nimport { AbstractItem } from './abstract-item';\nimport { ReactNode } from 'react';\n\ninterface CartOrderProductProps {\n item: OrderProduct,\n cartErrors: OrderErrors,\n className?: string,\n cart: Order,\n setCart: (cart: Order) => void,\n reloadCart: () => Promise,\n onError: (message: string) => void,\n privilegedOperator: boolean,\n}\n\n/**\n * This component shows a product in the cart\n */\nexport const CartOrderProduct: React.FC = ({ item, cartErrors, className, cart, setCart, reloadCart, onError, privilegedOperator }) => {\n const { t } = useTranslation('public');\n\n /**\n * Get the given item's errors\n */\n const getItemErrors = (item: OrderProduct): Array => {\n if (!cartErrors) return [];\n const errors = _.find(cartErrors.details, (e) => e.item_id === item.id);\n return errors?.errors || [{ error: 'not_found' }];\n };\n\n /**\n * Show an human-readable styled error for the given item's error\n */\n const itemError = (item: OrderProduct, error) => {\n if (error.error === 'is_active' || error.error === 'not_found') {\n return

{t('app.public.cart_order_product.errors.product_not_found')}

;\n }\n if (error.error === 'stock' && error.value === 0) {\n return

{t('app.public.cart_order_product.errors.out_of_stock')}

;\n }\n if (error.error === 'stock' && error.value > 0) {\n return

{t('app.public.cart_order_product.errors.stock_limit_QUANTITY', { QUANTITY: error.value })}

;\n }\n if (error.error === 'quantity_min') {\n return

{t('app.public.cart_order_product.errors.quantity_min_QUANTITY', { QUANTITY: error.value })}

;\n }\n if (error.error === 'amount') {\n return
\n

{t('app.public.cart_order_product.errors.price_changed_PRICE', { PRICE: `${FormatLib.price(error.value)} / ${t('app.public.cart_order_product.unit')}` })}

\n {t('app.public.cart_order_product.update_item')}\n
;\n }\n };\n\n /**\n * Refresh product amount\n */\n const refreshItem = (item: OrderProduct) => {\n return (e: React.BaseSyntheticEvent) => {\n e.preventDefault();\n e.stopPropagation();\n CartAPI.refreshItem(cart, item.orderable_id, item.orderable_type).then(data => {\n setCart(data);\n }).catch(onError);\n };\n };\n\n /**\n * Change product quantity\n */\n const changeProductQuantity = (e: React.BaseSyntheticEvent, item: OrderProduct) => {\n CartAPI.setQuantity(cart, item.orderable_id, item.orderable_type, e.target.value)\n .then(data => {\n setCart(data);\n })\n .catch(() => onError(t('app.public.cart_order_product.stock_limit')));\n };\n\n /**\n * Increment/decrement product quantity\n */\n const increaseOrDecreaseProductQuantity = (item: OrderProduct, direction: 'up' | 'down') => {\n CartAPI.setQuantity(cart, item.orderable_id, item.orderable_type, direction === 'up' ? item.quantity + 1 : item.quantity - 1)\n .then(data => {\n setCart(data);\n })\n .catch(() => onError(t('app.public.cart_order_product.stock_limit')));\n };\n\n /**\n * Return the components in the \"actions\" section of the item\n */\n const buildActions = (): ReactNode => {\n return (\n <>\n
\n

{FormatLib.price(item.amount)}

\n / {t('app.public.cart_order_product.unit')}\n
\n
\n changeProductQuantity(e, item)}\n min={item.quantity_min}\n max={item.orderable_external_stock}\n value={item.quantity}\n />\n \n \n
\n \n );\n };\n\n return (\n \n
\n {t('app.public.cart_order_product.reference_short')} {item.orderable_ref || ''}\n

{item.orderable_name}

\n {item.quantity_min > 1 &&\n {t('app.public.cart_order_product.minimum_purchase')}{item.quantity_min}\n }\n {getItemErrors(item).map(e => {\n return itemError(item, e);\n })}\n
\n
\n );\n};\n","import * as React from 'react';\nimport type { OrderErrors, Order } from '../../models/order';\nimport { useTranslation } from 'react-i18next';\nimport _ from 'lodash';\nimport { AbstractItem } from './abstract-item';\nimport { OrderCartItemReservation } from '../../models/order';\nimport FormatLib from '../../lib/format';\n\ninterface CartOrderReservationProps {\n item: OrderCartItemReservation,\n cartErrors: OrderErrors,\n className?: string,\n cart: Order,\n setCart: (cart: Order) => void,\n reloadCart: () => Promise,\n onError: (message: string) => void,\n privilegedOperator: boolean,\n}\n\n/**\n * This component shows a product in the cart\n */\nexport const CartOrderReservation: React.FC = ({ item, cartErrors, className, cart, setCart, reloadCart, onError, privilegedOperator }) => {\n const { t } = useTranslation('public');\n\n /**\n * Get the given item's errors\n */\n const getItemErrors = (item: OrderCartItemReservation) => {\n if (!cartErrors) return [];\n const errors = _.find(cartErrors.details, (e) => e.item_id === item.id);\n return errors?.errors || [{ error: 'not_found' }];\n };\n\n return (\n }\n offerItemLabel={t('app.public.cart_order_reservation.offer_reservation')}\n privilegedOperator={privilegedOperator}>\n
\n

{t('app.public.cart_order_reservation.reservation')} {item.orderable_name}

\n
    {item.slots_reservations.map(sr => (\n
  • \n {\n t('app.public.cart_order_reservation.slot',\n { DATE: FormatLib.date(sr.slot.start_at), START: FormatLib.time(sr.slot.start_at), END: FormatLib.time(sr.slot.end_at) })\n }\n {sr.offered ? t('app.public.cart_order_reservation.offered') : ''}\n
  • \n ))}
\n {getItemErrors(item)}\n
\n
\n );\n};\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport type { IApplication } from '../../models/application';\nimport { FabButton } from '../base/fab-button';\nimport useCart from '../../hooks/use-cart';\nimport FormatLib from '../../lib/format';\nimport CartAPI from '../../api/cart';\nimport type { User } from '../../models/user';\nimport { PaymentModal } from '../payment/stripe/payment-modal';\nimport { PaymentMethod } from '../../models/payment';\nimport type { Order, OrderCartItemReservation, OrderErrors, OrderProduct } from '../../models/order';\nimport { MemberSelect } from '../user/member-select';\nimport { CouponInput } from '../coupon/coupon-input';\nimport type { Coupon } from '../../models/coupon';\nimport OrderLib from '../../lib/order';\nimport _ from 'lodash';\nimport OrderAPI from '../../api/order';\nimport { CartOrderProduct } from './cart-order-product';\nimport { CartOrderReservation } from './cart-order-reservation';\n\ndeclare const Application: IApplication;\n\ninterface StoreCartProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n userLogin: () => void,\n currentUser?: User\n}\n\n/**\n * This component shows user's cart\n */\nconst StoreCart: React.FC = ({ onSuccess, onError, currentUser, userLogin }) => {\n const { t } = useTranslation('public');\n\n const { cart, setCart, reloadCart } = useCart(currentUser);\n const [cartErrors, setCartErrors] = useState(null);\n const [noMemberError, setNoMemberError] = useState(false);\n const [paymentModal, setPaymentModal] = useState(false);\n const [withdrawalInstructions, setWithdrawalInstructions] = useState(null);\n\n useEffect(() => {\n if (cart) {\n checkCart();\n }\n if (cart && !withdrawalInstructions) {\n OrderAPI.withdrawalInstructions(cart)\n .then(setWithdrawalInstructions)\n .catch(onError);\n }\n }, [cart]);\n\n /**\n * Check the current cart's items (available, price, stock, quantity_min)\n */\n const checkCart = async (): Promise => {\n const errors = await CartAPI.validate(cart);\n setCartErrors(errors);\n return errors;\n };\n\n /**\n * Checkout cart\n */\n const checkout = () => {\n if (!currentUser) {\n userLogin();\n } else {\n if (!cart.user) {\n setNoMemberError(true);\n onError(t('app.public.store_cart.select_user'));\n } else {\n setNoMemberError(false);\n checkCart().then(errors => {\n if (!hasCartErrors(errors)) {\n setPaymentModal(true);\n }\n });\n }\n }\n };\n\n /**\n * Check if the carrent cart has any error\n */\n const hasCartErrors = (errors: OrderErrors) => {\n if (!errors) return false;\n for (const item of cart.order_items_attributes) {\n const error = _.find(errors.details, (e) => e.item_id === item.id);\n if (!error || error?.errors?.length > 0) return true;\n }\n return false;\n };\n\n /**\n * Open/closes the payment modal\n */\n const togglePaymentModal = (): void => {\n setPaymentModal(!paymentModal);\n };\n\n /**\n * Handle payment\n */\n const handlePaymentSuccess = (data: Order): void => {\n if (data.state === 'paid') {\n setPaymentModal(false);\n window.location.href = '/#!/store';\n onSuccess(t('app.public.store_cart.checkout_success'));\n } else {\n onError(t('app.public.store_cart.checkout_error'));\n }\n };\n\n /**\n * Change cart's customer by admin/manager\n */\n const handleChangeMember = (user: User): void => {\n CartAPI.setCustomer(cart, user.id).then(setCart).catch(onError);\n };\n\n /**\n * Check if the current operator has administrative rights or is a normal member\n */\n const isPrivileged = (): boolean => {\n return (currentUser?.role === 'admin' || currentUser?.role === 'manager');\n };\n\n /**\n * Check if the current cart is empty ?\n */\n const cartIsEmpty = (): boolean => {\n return cart && cart.order_items_attributes.length === 0;\n };\n\n /**\n * Apply coupon to current cart\n */\n const applyCoupon = (coupon?: Coupon): void => {\n if (coupon !== cart.coupon) {\n setCart({ ...cart, coupon });\n }\n };\n\n return (\n
\n
\n {cart && cartIsEmpty() &&

{t('app.public.store_cart.cart_is_empty')}

}\n {cart && cart.order_items_attributes.map(item => {\n if (item.orderable_type === 'Product') {\n return (\n \n );\n }\n return (\n \n );\n })}\n
\n\n
\n {cart && !cartIsEmpty() &&\n
\n

{t('app.public.store_cart.pickup')}

\n

\n

\n }\n\n {cart && !cartIsEmpty() &&\n
\n \n
\n }\n
\n\n \n\n {cart && !cartIsEmpty() && cart.user &&
\n 'dont need update shopping cart'} />\n
}\n
\n );\n};\n\nconst StoreCartWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('storeCart', react2angular(StoreCartWrapper, ['onSuccess', 'onError', 'currentUser', 'userLogin']));\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabInput } from '../base/fab-input';\nimport { FabAlert } from '../base/fab-alert';\nimport CouponAPI from '../../api/coupon';\nimport { Coupon } from '../../models/coupon';\nimport { User } from '../../models/user';\nimport FormatLib from '../../lib/format';\n\ninterface CouponInputProps {\n amount: number,\n user?: User,\n onChange?: (coupon?: Coupon) => void\n}\n\ninterface Message {\n type: 'info' | 'warning' | 'danger',\n message: string\n}\n\n/**\n * This component renders an input of coupon\n */\nexport const CouponInput: React.FC = ({ user, amount, onChange }) => {\n const { t } = useTranslation('shared');\n const [messages, setMessages] = useState>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(false);\n const [coupon, setCoupon] = useState();\n const [code, setCode] = useState();\n\n useEffect(() => {\n if (user && code) {\n handleChange(code);\n }\n }, [user?.id]);\n\n useEffect(() => {\n if (code) {\n handleChange(code);\n }\n }, [amount]);\n\n /**\n * callback for validate the code\n */\n const handleChange = (value: string) => {\n const mgs = [];\n setMessages([]);\n setError(false);\n setCoupon(null);\n setCode(value);\n if (value) {\n setLoading(true);\n CouponAPI.validate(value, amount, user?.id).then((res) => {\n setCoupon(res);\n if (res.type === 'percent_off') {\n mgs.push({ type: 'info', message: t('app.shared.coupon_input.the_coupon_has_been_applied_you_get_PERCENT_discount', { PERCENT: res.percent_off }) });\n } else {\n mgs.push({ type: 'info', message: t('app.shared.coupon_input.the_coupon_has_been_applied_you_get_AMOUNT_CURRENCY', { AMOUNT: res.amount_off, CURRENCY: FormatLib.currencySymbol() }) });\n }\n if (res.validity_per_user === 'once') {\n mgs.push({ type: 'warning', message: t('app.shared.coupon_input.coupon_validity_once') });\n }\n setMessages(mgs);\n setLoading(false);\n if (typeof onChange === 'function') {\n onChange(res);\n }\n }).catch((err) => {\n const state = err.split(':')[1].trim();\n setError(true);\n setCoupon(null);\n setLoading(false);\n setMessages([{ type: 'danger', message: t(`app.shared.coupon_input.unable_to_apply_the_coupon_because_${state}`) }]);\n onChange(null);\n });\n } else {\n onChange(null);\n }\n };\n\n // input addon\n const inputAddOn = () => {\n if (error) {\n return ;\n } else {\n if (loading) {\n return ;\n }\n if (coupon) {\n return ;\n }\n }\n };\n\n return (\n
\n \n \n {messages.map((m, i) => {\n return (\n \n {m.message}\n \n );\n })}\n
\n );\n};\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../../base/loader';\nimport { IApplication } from '../../../models/application';\nimport { StoreListHeader } from '../../store/store-list-header';\nimport { OrderItem } from '../../store/order-item';\nimport { FabPagination } from '../../base/fab-pagination';\nimport OrderAPI from '../../../api/order';\nimport { Order, OrderSortOption } from '../../../models/order';\nimport { User } from '../../../models/user';\nimport { SelectOption } from '../../../models/select';\n\ndeclare const Application: IApplication;\n\ninterface OrdersDashboardProps {\n currentUser: User,\n onError: (message: string) => void\n}\n\n/**\n * This component shows a list of all orders from the store for the current user\n */\nexport const OrdersDashboard: React.FC = ({ currentUser, onError }) => {\n const { t } = useTranslation('public');\n\n const [orders, setOrders] = useState>([]);\n const [pageCount, setPageCount] = useState(0);\n const [currentPage, setCurrentPage] = useState(1);\n const [totalCount, setTotalCount] = useState(0);\n\n useEffect(() => {\n OrderAPI.index({ user_id: currentUser.id }).then(res => {\n setPageCount(res.total_pages);\n setTotalCount(res.total_count);\n setOrders(res.data);\n }).catch(onError);\n }, []);\n\n /**\n * Creates sorting options to the react-select format\n */\n const buildOptions = (): Array> => {\n return [\n { value: 'created_at-desc', label: t('app.public.orders_dashboard.sort.newest') },\n { value: 'created_at-asc', label: t('app.public.orders_dashboard.sort.oldest') }\n ];\n };\n /**\n * Display option: sorting\n */\n const handleSorting = (option: SelectOption) => {\n OrderAPI.index({ page: 1, sort: option.value }).then(res => {\n setCurrentPage(1);\n setOrders(res.data);\n setPageCount(res.total_pages);\n setTotalCount(res.total_count);\n }).catch(onError);\n };\n\n /**\n * Handle orders pagination\n */\n const handlePagination = (page: number) => {\n if (page !== currentPage) {\n OrderAPI.index({ user_id: currentUser.id, page }).then(res => {\n setCurrentPage(page);\n setOrders(res.data);\n setPageCount(res.total_pages);\n setTotalCount(res.total_count);\n }).catch(onError);\n }\n };\n\n return (\n
\n
\n

{t('app.public.orders_dashboard.heading')}

\n
\n\n
\n \n
\n {orders.map(order => (\n \n ))}\n
\n {pageCount > 1 &&\n \n }\n
\n
\n );\n};\n\nconst OrdersDashboardWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('ordersDashboard', react2angular(OrdersDashboardWrapper, ['onError', 'currentUser']));\n","import { ReactNode, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { FabPanel } from '../../base/fab-panel';\nimport { Loader } from '../../base/loader';\nimport { useTranslation } from 'react-i18next';\nimport { Credit, CreditableType } from '../../../models/credit';\nimport CreditAPI from '../../../api/credit';\nimport { HtmlTranslate } from '../../base/html-translate';\n\ninterface CreditsPanelProps {\n userId: number,\n onError: (message: string) => void,\n reservableType: CreditableType\n}\n\n/**\n * List all available credits for the given user and the given resource\n */\nconst CreditsPanel: React.FC = ({ userId, onError, reservableType }) => {\n const { t } = useTranslation('logged');\n\n const [credits, setCredits] = useState>([]);\n\n useEffect(() => {\n CreditAPI.userResource(userId, reservableType)\n .then(res => setCredits(res))\n .catch(error => onError(error));\n }, []);\n\n /**\n * Compute the remaining hours for the given credit\n */\n const remainingHours = (credit: Credit): number => {\n return credit.hours - credit.hours_used;\n };\n\n /**\n * Display a placeholder when there's no credits to display\n */\n const noCredits = (): ReactNode => {\n return (\n
{t('app.logged.dashboard.reservations_dashboard.credits_panel.no_credits')}
\n );\n };\n\n return (\n \n

{t('app.logged.dashboard.reservations_dashboard.credits_panel.title')}

\n {credits.length !== 0 &&\n
\n {t('app.logged.dashboard.reservations_dashboard.credits_panel.info')}\n
\n }\n\n
\n {credits.map(c =>
\n

{c.creditable.name}

\n

\n
\n {(c.hours_used && c.hours_used > 0) &&\n \n }\n

\n
)}\n
\n {credits.length === 0 && noCredits()}\n
\n );\n};\n\nconst CreditsPanelWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { CreditsPanelWrapper as CreditsPanel };\n","import { FabPanel } from '../../base/fab-panel';\nimport { Loader } from '../../base/loader';\nimport { useTranslation } from 'react-i18next';\nimport { useEffect, useState } from 'react';\nimport { UserPack } from '../../../models/user-pack';\nimport UserPackAPI from '../../../api/user-pack';\nimport FormatLib from '../../../lib/format';\nimport SettingAPI from '../../../api/setting';\nimport { Machine } from '../../../models/machine';\nimport MachineAPI from '../../../api/machine';\nimport { SubmitHandler, useForm } from 'react-hook-form';\nimport { FabButton } from '../../base/fab-button';\nimport { FormSelect } from '../../form/form-select';\nimport { SelectOption } from '../../../models/select';\nimport { ProposePacksModal } from '../../prepaid-packs/propose-packs-modal';\nimport * as React from 'react';\nimport { User } from '../../../models/user';\nimport PrepaidPackAPI from '../../../api/prepaid-pack';\nimport { PrepaidPack } from '../../../models/prepaid-pack';\nimport { HtmlTranslate } from '../../base/html-translate';\n\ninterface PrepaidPacksPanelProps {\n user: User,\n onError: (message: string) => void\n}\n\n/**\n * List all available prepaid packs for the given user\n */\nconst PrepaidPacksPanel: React.FC = ({ user, onError }) => {\n const { t } = useTranslation('logged');\n\n const [machines, setMachines] = useState>([]);\n const [packs, setPacks] = useState>([]);\n const [userPacks, setUserPacks] = useState>([]);\n const [threshold, setThreshold] = useState(null);\n const [selectedMachine, setSelectedMachine] = useState(null);\n const [packsModal, setPacksModal] = useState(false);\n const [packsForSubscribers, setPacksForSubscribers] = useState(false);\n\n const { handleSubmit, control, formState } = useForm<{ machine_id: number }>();\n\n useEffect(() => {\n UserPackAPI.index({ user_id: user.id, history: true })\n .then(setUserPacks)\n .catch(onError);\n SettingAPI.get('renew_pack_threshold')\n .then(data => setThreshold(parseFloat(data.value)))\n .catch(onError);\n MachineAPI.index({ disabled: false })\n .then(setMachines)\n .catch(onError);\n PrepaidPackAPI.index({ disabled: false, group_id: user.group_id, priceable_type: 'Machine' })\n .then(setPacks)\n .catch(onError);\n SettingAPI.get('pack_only_for_subscription')\n .then(data => setPacksForSubscribers(data.value === 'true'))\n .catch(onError);\n }, []);\n\n /**\n * Check if the provided pack has a remaining amount of hours under the defined threshold\n */\n const isLow = (pack: UserPack): boolean => {\n if (threshold < 1) {\n return pack.prepaid_pack.minutes - pack.minutes_used <= pack.prepaid_pack.minutes * threshold;\n }\n return pack.prepaid_pack.minutes - pack.minutes_used <= threshold * 60;\n };\n\n /**\n * Callback triggered when the user clicks on \"buy a pack\"\n */\n const onBuyPack: SubmitHandler<{ machine_id: number }> = (data) => {\n const machine = machines.find(m => m.id === data.machine_id);\n setSelectedMachine(machine);\n togglePacksModal();\n };\n\n /**\n * Open/closes the buy pack modal\n */\n const togglePacksModal = () => {\n setPacksModal(!packsModal);\n };\n\n /**\n * Build the options for the select dropdown, for the given list of machines\n */\n const buildMachinesOptions = (machines: Array): Array> => {\n const packMachinesId = packs.map(p => p.priceable_id);\n return machines.filter(m => packMachinesId.includes(m.id)).map(m => {\n return { label: m.name, value: m.id };\n });\n };\n\n /**\n * Check if the user can buy a pack\n */\n const canBuyPacks = (): boolean => {\n return (packs.length > 0 && (!packsForSubscribers || (packsForSubscribers && user.subscribed_plan != null)));\n };\n\n /**\n * Callback triggered when a prepaid pack was successfully bought: refresh the list of packs for the user\n */\n const onPackBoughtSuccess = () => {\n togglePacksModal();\n UserPackAPI.index({ user_id: user.id, history: true })\n .then(setUserPacks)\n .catch(onError);\n };\n\n return (\n \n

{t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.title')}

\n\n {userPacks.map(pack => (\n
\n
\n {t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.name')}\n {t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.end')}\n {t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.countdown')}\n\n
\n

{pack.prepaid_pack.priceable.name}

\n {FormatLib.date(pack.expires_at) &&

{FormatLib.date(pack.expires_at)}

}\n

{(pack.prepaid_pack.minutes - pack.minutes_used) / 60}H / {pack.prepaid_pack.minutes / 60}H

\n
\n
\n {pack.history?.length > 0 &&\n
\n {t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.history')}\n\n {pack.history.map(prepaidReservation => (\n
\n

{t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.consumed_hours', { COUNT: prepaidReservation.consumed_minutes / 60 })}

\n

{FormatLib.date(prepaidReservation.reservation_date)}

\n
\n ))}\n
\n }\n
\n ))}\n\n {canBuyPacks() &&
\n

{t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.cta_info')}

\n
\n \n \n {t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.cta_button')}\n \n \n {selectedMachine && packsModal &&\n }\n
}\n {packs.length === 0 &&

{t('app.logged.dashboard.reservations_dashboard.prepaid_packs_panel.no_packs')}

}\n {(packsForSubscribers && user.subscribed_plan == null && packs.length > 0) &&\n \n }\n
\n );\n};\n\nconst PrepaidPacksPanelWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { PrepaidPacksPanelWrapper as PrepaidPacksPanel };\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { IApplication } from '../../../models/application';\nimport { react2angular } from 'react2angular';\nimport { ReservationsPanel } from './reservations-panel';\nimport SettingAPI from '../../../api/setting';\nimport { SettingName } from '../../../models/setting';\nimport { CreditsPanel } from './credits-panel';\nimport { useTranslation } from 'react-i18next';\nimport { PrepaidPacksPanel } from './prepaid-packs-panel';\nimport { User } from '../../../models/user';\n\ndeclare const Application: IApplication;\n\ninterface ReservationsDashboardProps {\n onError: (message: string) => void,\n user: User\n}\n\n/**\n * User dashboard showing everything about his spaces/machine reservations and also remaining credits\n */\nconst ReservationsDashboard: React.FC = ({ onError, user }) => {\n const { t } = useTranslation('logged');\n const [modules, setModules] = useState>();\n\n useEffect(() => {\n SettingAPI.query(['spaces_module', 'machines_module'])\n .then(res => setModules(res))\n .catch(error => onError(error));\n }, []);\n\n return (\n
\n {modules?.get('machines_module') !== 'false' &&
\n

{t('app.logged.dashboard.reservations_dashboard.machine_section_title')}

\n \n \n \n
}\n {modules?.get('spaces_module') !== 'false' &&
\n

{t('app.logged.dashboard.reservations_dashboard.space_section_title')}

\n \n \n
}\n
\n );\n};\n\nApplication.Components.component('reservationsDashboard', react2angular(ReservationsDashboard, ['onError', 'user']));\n","import { ReactNode, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { FabPanel } from '../../base/fab-panel';\nimport { Reservation, SlotsReservation } from '../../../models/reservation';\nimport ReservationAPI from '../../../api/reservation';\nimport { useTranslation } from 'react-i18next';\nimport moment from 'moment';\nimport { Loader } from '../../base/loader';\nimport FormatLib from '../../../lib/format';\nimport _ from 'lodash';\nimport { FabButton } from '../../base/fab-button';\n\ninterface SpaceReservationsProps {\n userId: number,\n onError: (message: string) => void,\n reservableType: 'Machine' | 'Space'\n}\n\n/**\n * List all reservations for the given user and the given type\n */\nconst ReservationsPanel: React.FC = ({ userId, onError, reservableType }) => {\n const { t } = useTranslation('logged');\n\n const [reservations, setReservations] = useState>([]);\n const [showMore, setShowMore] = useState(false);\n\n useEffect(() => {\n ReservationAPI.index({ user_id: userId, reservable_type: reservableType })\n .then(res => setReservations(res))\n .catch(error => onError(error));\n }, []);\n\n /**\n * Return the reservations for the given period\n */\n const reservationsByDate = (state: 'past' | 'futur'): Array => {\n return reservations.filter(r => {\n return !!r.slots_reservations_attributes.find(s => filterSlot(s, state));\n });\n };\n\n /**\n * Check if the given slot reservation if past of futur\n */\n const filterSlot = (sr: SlotsReservation, state: 'past' | 'futur'): boolean => {\n return (state === 'past' && moment(sr.slot_attributes.start_at).isBefore()) ||\n (state === 'futur' && moment(sr.slot_attributes.start_at).isAfter());\n };\n\n /**\n * Shows/hide the very old reservations list\n */\n const toggleShowMore = (): void => {\n setShowMore(!showMore);\n };\n\n /**\n * Display a placeholder when there's no reservation to display\n */\n const noReservations = (): ReactNode => {\n return (\n {t('app.logged.dashboard.reservations_dashboard.reservations_panel.no_reservation')}\n );\n };\n\n /**\n * Check if all slots of the given reservation are canceled\n */\n const isCancelled = (reservation: Reservation): boolean => {\n return reservation.slots_reservations_attributes.map(sr => sr.canceled_at).every(ca => ca != null);\n };\n\n /**\n * Render the reservation in a user-friendly way\n */\n const renderReservation = (reservation: Reservation, state: 'past' | 'futur'): ReactNode => {\n return (\n
\n

{reservation.reservable.name}

\n\n
\n {reservation.slots_reservations_attributes.filter(s => filterSlot(s, state)).map(\n slotReservation =>

\n {slotReservation.canceled_at ? t('app.logged.dashboard.reservations_dashboard.reservations_panel.cancelled_slot') : ''} {FormatLib.date(slotReservation.slot_attributes.start_at)} - {FormatLib.time(slotReservation.slot_attributes.start_at)} - {FormatLib.time(slotReservation.slot_attributes.end_at)}\n

\n )}\n
\n
\n );\n };\n\n const futur = reservationsByDate('futur');\n const past = _.orderBy(reservationsByDate('past'), r => r.slots_reservations_attributes[0].slot_attributes.start_at, 'desc');\n\n return (\n \n

{t('app.logged.dashboard.reservations_dashboard.reservations_panel.title')}

\n
\n {futur.length === 0\n ? noReservations()\n :
\n {t('app.logged.dashboard.reservations_dashboard.reservations_panel.upcoming')}\n {t('app.logged.dashboard.reservations_dashboard.reservations_panel.date')}\n\n {futur.map(r => renderReservation(r, 'futur'))}\n
\n }\n\n {past.length > 0 &&\n
\n {t('app.logged.dashboard.reservations_dashboard.reservations_panel.history')}\n\n {past.slice(0, 5).map(r => renderReservation(r, 'past'))}\n {past.length > 5 && !showMore && \n {t('app.logged.dashboard.reservations_dashboard.reservations_panel.show_more')}\n }\n {past.length > 5 && showMore && past.slice(5).map(r => renderReservation(r, 'past'))}\n
\n }\n
\n
\n );\n};\n\nconst ReservationsPanelWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { ReservationsPanelWrapper as ReservationsPanel };\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { LabelledInput } from './base/labelled-input';\nimport { useTranslation } from 'react-i18next';\nimport { TDateISODate } from '../typings/date-iso';\n\ninterface DocumentFiltersProps {\n onFilterChange: (value: { reference: string, customer: string, date: TDateISODate }) => void\n}\n\n/**\n * This component shows 3 input fields for filtering invoices/payment-schedules by reference, customer name and date\n */\nexport const DocumentFilters: React.FC = ({ onFilterChange }) => {\n const { t } = useTranslation('admin');\n\n // stores the value of reference input\n const [referenceFilter, setReferenceFilter] = useState('');\n // stores the value of the customer input\n const [customerFilter, setCustomerFilter] = useState('');\n // stores the value of the date input\n const [dateFilter, setDateFilter] = useState(null);\n\n /**\n * When any filter changes, trigger the callback with the current value of all filters\n */\n useEffect(() => {\n onFilterChange({ reference: referenceFilter, customer: customerFilter, date: dateFilter });\n }, [referenceFilter, customerFilter, dateFilter]);\n\n /**\n * Callback triggered when the input 'reference' is updated.\n */\n const handleReferenceUpdate = (e) => {\n setReferenceFilter(e.target.value);\n };\n\n /**\n * Callback triggered when the input 'customer' is updated.\n */\n const handleCustomerUpdate = (e) => {\n setCustomerFilter(e.target.value);\n };\n\n /**\n * Callback triggered when the input 'date' is updated.\n */\n const handleDateUpdate = (e) => {\n let date = e.target.value;\n if (e.target.value === '') date = null;\n setDateFilter(date);\n };\n\n return (\n
\n \n \n \n
\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Control, FormState, UseFormRegister } from 'react-hook-form';\nimport { FormSwitch } from '../form/form-switch';\nimport { FormRichText } from '../form/form-rich-text';\nimport { FormInput } from '../form/form-input';\nimport { SettingName, SettingValue } from '../../models/setting';\nimport ValidationLib from '../../lib/validation';\nexport type EditorialKeys = 'active_text_block' | 'text_block' | 'active_cta' | 'cta_label' | 'cta_url';\n\ninterface EditorialBlockFormProps {\n register: UseFormRegister>,\n control: Control>,\n formState: FormState>,\n info?: string\n keys: Record\n}\n\n/**\n * Allows to create a formatted text and optional cta button in a form block, to be included in a resource form managed by react-hook-form.\n */\nexport const EditorialBlockForm: React.FC = ({ register, control, formState, info, keys }) => {\n const { t } = useTranslation('admin');\n\n const [isActiveTextBlock, setIsActiveTextBlock] = useState(false);\n const [isActiveCta, setIsActiveCta] = useState(false);\n\n /** Set correct values for switches when formState changes */\n useEffect(() => {\n setIsActiveTextBlock(control._formValues[keys.active_text_block]);\n setIsActiveCta(control._formValues[keys.active_cta]);\n }, [control._formValues]);\n\n /** Callback triggered when the text block switch has changed. */\n const toggleTextBlockSwitch = (value: boolean) => setIsActiveTextBlock(value);\n\n /** Callback triggered when the CTA switch has changed. */\n const toggleTextBlockCta = (value: boolean) => setIsActiveCta(value);\n\n return (\n <>\n
\n

{t('app.admin.editorial_block_form.title')}

\n {info &&

{info}

}\n
\n\n
\n \n\n \n\n {isActiveTextBlock && <>\n \n\n {isActiveCta && <>\n \n \n }\n }\n
\n \n );\n};\n","import React from 'react';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { FabButton } from '../base/fab-button';\nimport { SettingValue } from '../../models/setting';\n\ndeclare const Application: IApplication;\n\ninterface EditorialBlockProps {\n text: SettingValue,\n cta?: SettingValue,\n url?: SettingValue\n}\n\n/**\n * Display a editorial text block with an optional cta button\n */\nexport const EditorialBlock: React.FC = ({ text, cta, url }) => {\n /** Link to url from props */\n const linkTo = (): void => {\n window.location.href = url as string;\n };\n\n return (\n
25 ? 'long-cta' : ''}`}>\n
\n {cta && {cta}}\n
\n );\n};\n\nconst EditorialBlockWrapper: React.FC = ({ ...props }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('editorialBlock', react2angular(EditorialBlockWrapper, ['text', 'cta', 'url']));\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { Event } from '../../models/event';\nimport FormatLib from '../../lib/format';\n\nimport defaultImage from '../../../../images/default-image.png';\n\ndeclare const Application: IApplication;\n\ninterface EventCardProps {\n event: Event,\n cardType: 'sm' | 'md' | 'lg'\n}\n\n/**\n * This component is a box showing the picture of the given event, and a short description of it.\n */\nexport const EventCard: React.FC = ({ event, cardType }) => {\n const { t } = useTranslation('public');\n\n /**\n * Format description to remove HTML tags and set a maximum character count\n */\n const formatText = (text: string, count: number) => {\n text = text.replace(/(<\\/p>|<\\/h4>|<\\/h5>|<\\/h6>|<\\/pre>|<\\/blockquote>)/g, '\\n');\n text = text.replace(//g, '\\n');\n text = text.replace(/<\\/?\\w+[^>]*>/g, '');\n if (text.length > count) {\n text = text.slice(0, count) + '…';\n }\n text = text.replace(/\\n+/g, '
');\n return text;\n };\n\n /**\n * Return the formatted localized date of the event\n */\n const formatDate = (): string => {\n const startDate = new Date(event.start_date);\n const endDate = new Date(event.end_date);\n const singleDayEvent = startDate.getFullYear() === endDate.getFullYear() &&\n startDate.getMonth() === endDate.getMonth() &&\n startDate.getDate() === endDate.getDate();\n return singleDayEvent\n ? t('app.public.event_card.on_the_date', { DATE: FormatLib.date(event.start_date) })\n : t('app.public.event_card.from_date_to_date', { START: FormatLib.date(event.start_date), END: FormatLib.date(event.end_date) });\n };\n\n /**\n * Return the formatted localized hours of the event\n */\n const formatTime = (): string => {\n return event.all_day\n ? t('app.public.event_card.all_day')\n : t('app.public.event_card.from_time_to_time', { START: FormatLib.time(event.start_time), END: FormatLib.time(event.end_time) });\n };\n\n return (\n
\n {event.event_image_attributes\n ?
\n {event.event_image_attributes.attachment_name} {\n currentTarget.onerror = null;\n currentTarget.src = defaultImage;\n }} />\n
\n : cardType !== 'sm' &&\n
\n \n
\n }\n
\n
\n {event.category.name}\n

{event?.title}

\n
\n {cardType !== 'sm' &&\n

\n }\n
\n
\n {cardType !== 'md' &&\n

\n {formatDate()}\n {formatTime()}\n

\n }\n
\n {cardType !== 'md' &&\n event.event_themes.map(theme => {\n return (
\n \n
{theme.name}
\n
);\n })\n }\n {(cardType !== 'md' && event.age_range) &&\n
\n \n
{event.age_range?.name}
\n
\n }\n {cardType === 'md' &&\n <>\n
\n \n
{formatDate()}
\n
\n
\n \n
{formatTime()}
\n
\n \n }\n
\n \n {event.nb_free_places > 0 &&
{t('app.public.event_card.still_available') + event.nb_free_places}
}\n {event.nb_total_places > 0 && event.nb_free_places <= 0 &&
{t('app.public.event_card.event_full')}
}\n {!event.nb_total_places &&
{t('app.public.event_card.without_reservation')}
}\n
\n
\n \n {event.amount === 0 &&
{t('app.public.event_card.free_admission')}
}\n {event.amount > 0 &&
{t('app.public.event_card.full_price') + FormatLib.price(event.amount)}
}\n
\n
\n
\n
\n );\n};\n\nconst EventCardWrapper: React.FC = ({ event, cardType }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('eventCard', react2angular(EventCardWrapper, ['event', 'cardType']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { SubmitHandler, useFieldArray, useForm, useWatch } from 'react-hook-form';\nimport { Event, EventDecoration, EventPriceCategoryAttributes, RecurrenceOption } from '../../models/event';\nimport EventAPI from '../../api/event';\nimport { useTranslation } from 'react-i18next';\nimport { FormInput } from '../form/form-input';\nimport { FormImageUpload } from '../form/form-image-upload';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { ErrorBoundary } from '../base/error-boundary';\nimport { FormRichText } from '../form/form-rich-text';\nimport { FormMultiFileUpload } from '../form/form-multi-file-upload';\nimport { FabButton } from '../base/fab-button';\nimport { FormSwitch } from '../form/form-switch';\nimport { SelectOption } from '../../models/select';\nimport EventCategoryAPI from '../../api/event-category';\nimport { FormSelect } from '../form/form-select';\nimport EventThemeAPI from '../../api/event-theme';\nimport { FormMultiSelect } from '../form/form-multi-select';\nimport AgeRangeAPI from '../../api/age-range';\nimport { Plus, Trash } from 'phosphor-react';\nimport FormatLib from '../../lib/format';\nimport EventPriceCategoryAPI from '../../api/event-price-category';\nimport SettingAPI from '../../api/setting';\nimport { UpdateRecurrentModal } from './update-recurrent-modal';\nimport { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';\n\ndeclare const Application: IApplication;\n\ninterface EventFormProps {\n action: 'create' | 'update',\n event?: Event,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\n/**\n * Form to edit or create events\n */\nexport const EventForm: React.FC = ({ action, event, onError, onSuccess }) => {\n const { handleSubmit, register, control, setValue, formState } = useForm({ defaultValues: { ...event } });\n const output = useWatch({ control });\n const { fields, append, remove } = useFieldArray({ control, name: 'event_price_categories_attributes' });\n\n const { t } = useTranslation('admin');\n\n const [isAllDay, setIsAllDay] = useState(event?.all_day);\n const [categoriesOptions, setCategoriesOptions] = useState>>([]);\n const [themesOptions, setThemesOptions] = useState>>(null);\n const [ageRangeOptions, setAgeRangeOptions] = useState>>(null);\n const [priceCategoriesOptions, setPriceCategoriesOptions] = useState>>(null);\n const [isOpenRecurrentModal, setIsOpenRecurrentModal] = useState(false);\n const [updatingEvent, setUpdatingEvent] = useState(null);\n const [isActiveAccounting, setIsActiveAccounting] = useState(false);\n\n useEffect(() => {\n EventCategoryAPI.index()\n .then(data => setCategoriesOptions(data.map(m => decorationToOption(m))))\n .catch(onError);\n EventThemeAPI.index()\n .then(data => setThemesOptions(data.map(t => decorationToOption(t))))\n .catch(onError);\n AgeRangeAPI.index()\n .then(data => setAgeRangeOptions(data.map(r => decorationToOption(r))))\n .catch(onError);\n EventPriceCategoryAPI.index()\n .then(data => setPriceCategoriesOptions(data.map(c => decorationToOption(c))))\n .catch(onError);\n SettingAPI.get('advanced_accounting').then(res => setIsActiveAccounting(res.value === 'true')).catch(onError);\n }, []);\n\n useEffect(() => {\n // When a new custom price is added to the current event, we mark it as disabled to prevent setting the same category twice\n const selectedCategoriesId = output.event_price_categories_attributes\n ?.filter(epc => !epc._destroy && epc.price_category_id)\n ?.map(epc => epc.price_category_id) || [];\n setPriceCategoriesOptions(priceCategoriesOptions?.map(pco => {\n return {\n ...pco,\n disabled: selectedCategoriesId.includes(pco.value)\n };\n }));\n }, [output.event_price_categories_attributes]);\n\n /**\n * Callback triggered when the user clicks on the 'remove' button, in the additional prices area\n */\n const handlePriceRemove = (price: EventPriceCategoryAttributes, index: number) => {\n if (!price.id) return remove(index);\n\n setValue(`event_price_categories_attributes.${index}._destroy`, true);\n };\n\n /**\n * Callback triggered when the user validates the machine form: handle create or update\n */\n const onSubmit: SubmitHandler = (data: Event) => {\n if (action === 'update') {\n if (event?.recurrence_events?.length > 0) {\n setUpdatingEvent(data);\n toggleRecurrentModal();\n } else {\n handleUpdateRecurrentConfirmed(data, 'single');\n }\n } else {\n EventAPI.create(data).then(res => {\n onSuccess(t(`app.admin.event_form.${action}_success`));\n window.location.href = `/#!/events/${res.id}`;\n }).catch(onError);\n }\n };\n\n /**\n * Open/closes the confirmation modal for updating recurring events\n */\n const toggleRecurrentModal = () => {\n setIsOpenRecurrentModal(!isOpenRecurrentModal);\n };\n\n /**\n * Check if any dates have changed\n */\n const datesHaveChanged = (): boolean => {\n return ((event?.start_date !== (updatingEvent?.start_date as Date)?.toISOString()?.substring(0, 10)) ||\n (event?.end_date !== (updatingEvent?.end_date as Date)?.toISOString()?.substring(0, 10)));\n };\n\n /**\n * When the user has confirmed the update of the other occurences (or not), proceed with the API update\n * and handle the result\n */\n const handleUpdateRecurrentConfirmed = (data: Event, mode: 'single' | 'next' | 'all') => {\n EventAPI.update(data, mode).then(res => {\n if (res.total === res.updated) {\n onSuccess(t('app.admin.event_form.events_updated', { COUNT: res.updated }));\n } else {\n onError(t('app.admin.event_form.events_not_updated', { TOTAL: res.total, COUNT: res.total - res.updated }));\n if (res.details.events.find(d => d.error === 'EventPriceCategory')) {\n onError(t('app.admin.event_form.error_deleting_reserved_price'));\n } else {\n onError(t('app.admin.event_form.other_error'));\n }\n }\n window.location.href = '/#!/events';\n }).catch(onError);\n };\n\n /**\n * Convert an event-decoration (category/theme/etc.) to an option usable by react-select\n */\n const decorationToOption = (item: EventDecoration): SelectOption => {\n return { value: item.id, label: item.name };\n };\n\n /**\n * In 'create' mode, the user can choose if the new event will be recurrent.\n * This method provides teh various options for recurrence\n */\n const buildRecurrenceOptions = (): Array> => {\n return [\n { label: t('app.admin.event_form.recurring.none'), value: 'none' },\n { label: t('app.admin.event_form.recurring.every_days'), value: 'day' },\n { label: t('app.admin.event_form.recurring.every_week'), value: 'week' },\n { label: t('app.admin.event_form.recurring.every_month'), value: 'month' },\n { label: t('app.admin.event_form.recurring.every_year'), value: 'year' }\n ];\n };\n\n return (\n
\n
\n

{t('app.admin.event_form.ACTION_title', { ACTION: action })}

\n \n {t('app.admin.event_form.save')}\n \n
\n
\n
\n
\n

{t('app.admin.event_form.description')}

\n
\n
\n \n \n \n \n {themesOptions?.length > 0 && }\n {ageRangeOptions?.length > 0 && }\n
\n
\n\n
\n
\n

{t('app.admin.event_form.dates_and_opening_hours')}

\n
\n
\n
\n \n \n
\n \n {!isAllDay &&
\n \n \n
}\n {action === 'create' &&
\n \n \n
}\n
\n
\n\n
\n
\n

{t('app.admin.event_form.prices_and_availabilities')}

\n
\n
\n \n \n\n {priceCategoriesOptions &&
\n {fields.map((price, index) => (\n
\n index < fields.length - 1}\n label={t('app.admin.event_form.fare_class')} />\n \n handlePriceRemove(price, index)} icon={} />\n
\n ))}\n append({})}>\n \n {t('app.admin.event_form.add_price')}\n \n
}\n
\n
\n\n
\n
\n

{t('app.admin.event_form.attachments')}

\n
\n
\n
\n

{t('app.admin.event_form.attached_files_pdf')}

\n
\n \n
\n
\n\n {isActiveAccounting &&\n
\n \n
\n }\n\n \n \n
\n );\n};\n\nconst EventFormWrapper: React.FC = (props) => {\n return (\n \n \n \n \n \n );\n};\n\nApplication.Components.component('eventForm', react2angular(EventFormWrapper, ['action', 'event', 'onError', 'onSuccess']));\n","import { useEffect, useState } from 'react';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { EditorialBlock } from '../editorial-block/editorial-block';\nimport SettingAPI from '../../api/setting';\nimport SettingLib from '../../lib/setting';\nimport { SettingValue, eventsSettings } from '../../models/setting';\n\ndeclare const Application: IApplication;\n\ninterface EventsEditorialBlockProps {\n onError: (message: string) => void\n}\n\n/**\n * This component displays to Users (public view) the editorial block (= banner) associated to events.\n */\nexport const EventsEditorialBlock: React.FC = ({ onError }) => {\n // Stores banner retrieved from API\n const [banner, setBanner] = useState>({});\n\n // Retrieve the settings related to the Events Banner from the API\n useEffect(() => {\n SettingAPI.query(eventsSettings)\n .then(settings => {\n setBanner({ ...SettingLib.bulkMapToObject(settings) });\n })\n .catch(onError);\n }, []);\n\n return (\n <>\n {banner.events_banner_active &&\n \n }\n \n );\n};\n\nconst EventsEditorialBlockWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('eventsEditorialBlock', react2angular(EventsEditorialBlockWrapper, ['onError']));\n","import React, { useEffect } from 'react';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { ErrorBoundary } from '../base/error-boundary';\nimport { useTranslation } from 'react-i18next';\nimport { useForm, SubmitHandler } from 'react-hook-form';\nimport { FabButton } from '../base/fab-button';\nimport { EditorialKeys, EditorialBlockForm } from '../editorial-block/editorial-block-form';\nimport SettingAPI from '../../api/setting';\nimport SettingLib from '../../lib/setting';\nimport { SettingName, SettingValue, eventsSettings } from '../../models/setting';\nimport { UnsavedFormAlert } from '../form/unsaved-form-alert';\nimport { UIRouter } from '@uirouter/angularjs';\n\ndeclare const Application: IApplication;\n\ninterface EventsSettingsProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void\n uiRouter?: UIRouter\n}\n\n/**\n * Events settings\n */\nexport const EventsSettings: React.FC = ({ onError, onSuccess, uiRouter }) => {\n const { t } = useTranslation('admin');\n const { register, control, formState, handleSubmit, reset } = useForm>();\n\n /** Link Events Banner Setting Names to generic keys expected by the Editorial Form */\n const bannerKeys: Record = {\n active_text_block: 'events_banner_active',\n text_block: 'events_banner_text',\n active_cta: 'events_banner_cta_active',\n cta_label: 'events_banner_cta_label',\n cta_url: 'events_banner_cta_url'\n };\n\n /** Callback triggered when the form is submitted: save the settings */\n const onSubmit: SubmitHandler> = (data) => {\n SettingAPI.bulkUpdate(SettingLib.objectToBulkMap(data)).then(() => {\n onSuccess(t('app.admin.events_settings.update_success'));\n }, reason => {\n onError(reason);\n });\n };\n\n /** On component mount, fetch existing Events Banner Settings from API, and populate form with these values. */\n useEffect(() => {\n SettingAPI.query(eventsSettings)\n .then(settings => reset(SettingLib.bulkMapToObject(settings)))\n .catch(onError);\n }, []);\n\n return (\n
\n
\n

{t('app.admin.events_settings.title')}

\n {t('app.admin.events_settings.save')}\n
\n
\n {uiRouter && }\n
\n \n
\n \n
\n );\n};\n\nconst EventsSettingsWrapper: React.FC = (props) => {\n return (\n \n \n \n \n \n );\n};\n\nApplication.Components.component('eventsSettings', react2angular(EventsSettingsWrapper, ['onError', 'onSuccess', 'uiRouter']));\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Event } from '../../models/event';\nimport { FabModal } from '../base/fab-modal';\nimport { FabAlert } from '../base/fab-alert';\n\ntype EditionMode = 'single' | 'next' | 'all';\n\ninterface UpdateRecurrentModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n event: Event,\n onConfirmed: (data: Event, mode: EditionMode) => void,\n datesChanged: boolean,\n}\n\n/**\n * Ask the user for confimation about the update of only the current event or also its recurrences\n */\nexport const UpdateRecurrentModal: React.FC = ({ isOpen, toggleModal, event, onConfirmed, datesChanged }) => {\n const { t } = useTranslation('admin');\n\n const [editMode, setEditMode] = useState(null);\n\n /**\n * Callback triggered when the user confirms the update\n */\n const handleConfirmation = () => {\n onConfirmed(event, editMode);\n };\n\n /**\n * The user cannot confirm unless he chooses an option\n */\n const preventConfirm = () => {\n return !editMode;\n };\n\n return (\n \n

{t('app.admin.update_recurrent_modal.edit_recurring_event')}

\n \n \n \n {datesChanged && editMode !== 'single' && \n {t('app.admin.update_recurrent_modal.date_wont_change')}\n }\n
\n );\n};\n","import { PropsWithChildren, ReactNode, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { AbstractFormComponent } from '../../models/form-component';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { get as _get } from 'lodash';\n\nexport type AbstractFormItemProps = PropsWithChildren> & {\n id: string,\n label?: string|ReactNode,\n tooltip?: ReactNode,\n className?: string,\n disabled?: boolean|((id: string) => boolean),\n onLabelClick?: (event: React.MouseEvent) => void,\n inLine?: boolean,\n containerType?: 'label' | 'div'\n}\n\n/**\n * This abstract component should not be used directly.\n * Other forms components that are intended to be used with react-hook-form must extend this component.\n */\nexport const AbstractFormItem = ({ id, label, tooltip, className, disabled, error, warning, rules, formState, onLabelClick, inLine, containerType, children }: AbstractFormItemProps) => {\n const [isDirty, setIsDirty] = useState(false);\n const [fieldError, setFieldError] = useState<{ message: string }>(null);\n const [isDisabled, setIsDisabled] = useState(false);\n\n useEffect(() => {\n setIsDirty(_get(formState?.dirtyFields, id));\n setFieldError(_get(formState?.errors, id));\n }, [formState]);\n\n useEffect(() => {\n if (typeof disabled === 'function') {\n setIsDisabled(disabled(id));\n } else {\n setIsDisabled(disabled);\n }\n }, [disabled]);\n\n // Compose classnames from props\n const classNames = [\n `${className || ''}`,\n `${(isDirty && error) || fieldError ? 'is-incorrect' : ''}`,\n `${isDirty && warning ? 'is-warned' : ''}`,\n `${rules && rules.required ? 'is-required' : ''}`,\n `${isDisabled ? 'is-disabled' : ''}`\n ].join(' ');\n\n /**\n * This function is called when the label is clicked.\n * It is used to focus the input.\n */\n function handleLabelClick (event: React.MouseEvent) {\n if (typeof onLabelClick === 'function') {\n onLabelClick(event);\n }\n }\n\n return React.createElement(containerType, { className: `form-item ${classNames}` }, (\n <>\n {(label && !inLine) &&
\n

{label}

\n {tooltip &&
\n \n
{tooltip}
\n
}\n
}\n\n
\n {inLine &&

{label}

\n {tooltip &&
\n \n
{tooltip}
\n
}\n
}\n {children}\n
\n { fieldError &&
{fieldError.message}
}\n {(isDirty && error) &&
{error.message}
}\n {(isDirty && warning) &&
{warning.message}
}\n \n ));\n};\n\nAbstractFormItem.defaultProps = { containerType: 'label' };\n","import * as React from 'react';\nimport { Controller, Path, FieldPathValue } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FieldPath } from 'react-hook-form/dist/types/path';\nimport { useTranslation } from 'react-i18next';\nimport { UnpackNestedValue } from 'react-hook-form/dist/types';\nimport { FormControlledComponent } from '../../models/form-component';\nimport { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';\nimport { FabButton } from '../base/fab-button';\nimport { ChecklistOption } from '../../models/select';\n\ntype FormChecklistProps = FormControlledComponent & AbstractFormItemProps & {\n defaultValue?: Array,\n options: Array>,\n onChange?: (values: Array) => void,\n}\n\n/**\n * This component is a template for a checklist component to use within React Hook Form\n */\nexport const FormChecklist = ({ id, control, label, tooltip, defaultValue, className, rules, disabled, error, warning, formState, onChange, options }: FormChecklistProps) => {\n const { t } = useTranslation('shared');\n\n /**\n * Verify if the provided option is currently ticked\n */\n const isChecked = (values: Array, option: ChecklistOption): boolean => {\n return !!values?.includes(option.value);\n };\n\n /**\n * Callback triggered when a checkbox is ticked or unticked.\n */\n const toggleCheckbox = (option: ChecklistOption, rhfValues: Array = [], rhfCallback: (value: Array) => void) => {\n return (event: React.ChangeEvent) => {\n let newValues: Array = [];\n if (event.target.checked) {\n newValues = rhfValues.concat(option.value);\n } else {\n newValues = rhfValues.filter(v => v !== option.value);\n }\n rhfCallback(newValues);\n if (typeof onChange === 'function') {\n onChange(newValues);\n }\n };\n };\n\n /**\n * Mark all options as selected\n */\n const selectAll = (rhfCallback: (value: Array) => void) => {\n return () => {\n const newValues: Array = options.map(o => o.value);\n rhfCallback(newValues);\n if (typeof onChange === 'function') {\n onChange(newValues);\n }\n };\n };\n\n /**\n * Mark all options as non-selected\n */\n const unselectAll = (rhfCallback: (value: Array) => void) => {\n return () => {\n rhfCallback([]);\n if (typeof onChange === 'function') {\n onChange([]);\n }\n };\n };\n\n return (\n \n }\n control={control}\n defaultValue={defaultValue as UnpackNestedValue>>}\n rules={rules}\n render={({ field: { onChange, value } }) => {\n return (\n <>\n
\n {options.map((option, k) => {\n return (\n
\n \n \n
\n );\n })}\n
\n
\n {t('app.shared.form_checklist.select_all')}\n {t('app.shared.form_checklist.unselect_all')}\n
\n \n );\n }} />\n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Path } from 'react-hook-form';\nimport { UnpackNestedValue, UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { FieldPathValue } from 'react-hook-form/dist/types/path';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FormInput } from './form-input';\nimport { FormComponent } from '../../models/form-component';\nimport { AbstractFormItemProps } from './abstract-form-item';\nimport { FabButton } from '../base/fab-button';\nimport { FilePdf, Trash } from 'phosphor-react';\nimport { FileType } from '../../models/file';\nimport FileUploadLib from '../../lib/file-upload';\n\ntype FormFileUploadProps = FormComponent & AbstractFormItemProps & {\n setValue: UseFormSetValue,\n defaultFile?: FileType,\n accept?: string,\n onFileChange?: (value: FileType) => void,\n onFileRemove?: () => void,\n}\n\n/**\n * This component allows to upload file, in forms managed by react-hook-form.\n */\nexport const FormFileUpload = ({ id, label, register, defaultFile, className, rules, disabled, error, warning, formState, onFileChange, onFileRemove, accept, setValue }: FormFileUploadProps) => {\n const { t } = useTranslation('shared');\n\n const [file, setFile] = useState(defaultFile);\n\n /**\n * Check if file is selected\n */\n const hasFile = (): boolean => {\n return FileUploadLib.hasFile(file);\n };\n\n /**\n * Callback triggered when the user has ended its selection of a file (or when the selection has been cancelled).\n */\n function onFileSelected (event: React.ChangeEvent) {\n const f = event.target?.files[0];\n if (f) {\n setFile({\n attachment_name: f.name\n });\n setValue(\n `${id}._destroy` as Path,\n false as UnpackNestedValue>>\n );\n if (typeof onFileChange === 'function') {\n onFileChange({ attachment_name: f.name });\n }\n }\n }\n\n /**\n * Callback triggered when the user clicks on the delete button.\n */\n function onRemoveFile () {\n FileUploadLib.onRemoveFile(file, id, setFile, setValue, onFileRemove);\n }\n\n // Compose classnames from props\n const classNames = [\n `${className || ''}`\n ].join(' ');\n\n /**\n * Returns placeholder text\n */\n const placeholder = (): string => hasFile() ? t('app.shared.form_file_upload.edit') : t('app.shared.form_file_upload.browse');\n\n return (\n
\n {hasFile() && (\n {file.attachment_name}\n )}\n
\n {file?.id && file?.attachment_url && (\n \n \n \n )}\n \n {hasFile() &&\n } className=\"is-main\" />\n }\n
\n
\n );\n};\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Path, Controller } from 'react-hook-form';\nimport { UnpackNestedValue, UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { FieldPath, FieldPathValue } from 'react-hook-form/dist/types/path';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FormInput } from './form-input';\nimport { FormComponent, FormControlledComponent } from '../../models/form-component';\nimport { AbstractFormItemProps } from './abstract-form-item';\nimport { FabButton } from '../base/fab-button';\nimport noImage from '../../../../images/no_image.png';\nimport { Trash } from 'phosphor-react';\nimport { ImageType } from '../../models/file';\nimport FileUploadLib from '../../lib/file-upload';\n\ntype FormImageUploadProps = FormComponent & FormControlledComponent & AbstractFormItemProps & {\n setValue: UseFormSetValue,\n defaultImage?: ImageType,\n accept?: string,\n size?: 'small' | 'medium' | 'large',\n mainOption?: boolean,\n onFileChange?: (value: ImageType) => void,\n onFileRemove?: () => void,\n onFileIsMain?: (setIsMain: (isMain: boolean) => void) => void,\n}\n\n/**\n * This component allows to upload image, in forms managed by react-hook-form.\n */\nexport const FormImageUpload = ({ id, label, register, control, defaultImage, className, rules, disabled, error, warning, formState, onFileChange, onFileRemove, accept, setValue, size, onFileIsMain, mainOption = false }: FormImageUploadProps) => {\n const { t } = useTranslation('shared');\n\n const [file, setFile] = useState(defaultImage);\n const [image, setImage] = useState(defaultImage?.attachment_url);\n\n useEffect(() => {\n setFile(defaultImage);\n }, [defaultImage]);\n\n /**\n * Check if image is selected\n */\n const hasImage = (): boolean => {\n return FileUploadLib.hasFile(file);\n };\n\n /**\n * Callback triggered when the user has ended its selection of a file (or when the selection has been cancelled).\n */\n function onFileSelected (event: React.ChangeEvent) {\n const f = event.target?.files[0];\n if (f) {\n const reader = new FileReader();\n reader.onload = (): void => {\n setImage(reader.result);\n };\n reader.readAsDataURL(f);\n setFile({\n ...file,\n attachment_name: f.name\n });\n setValue(\n `${id}.attachment_name` as Path,\n f.name as UnpackNestedValue>>\n );\n setValue(\n `${id}._destroy` as Path,\n false as UnpackNestedValue>>\n );\n if (typeof onFileChange === 'function') {\n onFileChange({ attachment_name: f.name });\n }\n }\n }\n\n /**\n * Callback triggered when the user clicks on the delete button.\n */\n function onRemoveFile () {\n FileUploadLib.onRemoveFile(file, id, setFile, setValue, onFileRemove);\n }\n\n /**\n * Returns placeholder text\n */\n const placeholder = (): string => hasImage() ? t('app.shared.form_image_upload.edit') : t('app.shared.form_image_upload.browse');\n\n // Compose classnames from props\n const classNames = [\n `${className || ''}`\n ].join(' ');\n\n return (\n
\n
\n {file?.attachment_name {\n currentTarget.onerror = null;\n currentTarget.src = noImage;\n }} />\n
\n
\n {mainOption &&\n \n }\n \n {hasImage() && } className=\"is-main\" />}\n
\n
\n );\n};\n\nFormImageUpload.defaultProps = {\n size: 'medium'\n};\n","import { ReactNode, useCallback, useState } from 'react';\nimport * as React from 'react';\nimport { FieldPathValue } from 'react-hook-form';\nimport { debounce as _debounce } from 'lodash';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FieldPath } from 'react-hook-form/dist/types/path';\nimport { FormComponent } from '../../models/form-component';\nimport { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';\n\ntype FormInputProps = FormComponent & AbstractFormItemProps & {\n icon?: ReactNode,\n addOn?: ReactNode,\n addOnAction?: (event: React.MouseEvent) => void,\n addOnClassName?: string,\n addOnAriaLabel?: string,\n debounce?: number,\n type?: 'text' | 'date' | 'password' | 'url' | 'time' | 'tel' | 'search' | 'number' | 'month' | 'email' | 'datetime-local' | 'week' | 'hidden' | 'file',\n accept?: string,\n defaultValue?: TInputType,\n placeholder?: string,\n step?: number | 'any',\n onChange?: (event: React.ChangeEvent) => void,\n nullable?: boolean,\n ariaLabel?: string,\n maxLength?: number\n}\n\n/**\n * This component is a template for an input component to use within React Hook Form\n */\nexport const FormInput = ({ id, register, label, tooltip, defaultValue, icon, className, rules, disabled, type, addOn, addOnAction, addOnClassName, addOnAriaLabel, placeholder, error, warning, formState, step, onChange, debounce, accept, nullable = false, ariaLabel, maxLength }: FormInputProps) => {\n const [characterCount, setCharacterCount] = useState(0);\n\n /**\n * Debounced (ie. temporised) version of the 'on change' callback.\n */\n const debouncedOnChange = debounce ? useCallback(_debounce(onChange, debounce), [debounce]) : null;\n\n /**\n * Handle the change of content in the input field, and trigger the parent callback, if any\n */\n const handleChange = (e: React.ChangeEvent) => {\n setCharacterCount(e.currentTarget.value.length);\n if (typeof onChange === 'function') {\n if (debouncedOnChange) {\n debouncedOnChange(e);\n } else {\n onChange(e);\n }\n }\n };\n\n /**\n * Parse the inputted value before saving it in the RHF state\n */\n const parseValue = (value: string) => {\n if ([null, ''].includes(value) && nullable) {\n return null;\n } else {\n if (type === 'number') {\n const num: number = parseFloat(value);\n if (Number.isNaN(num) && nullable) {\n return null;\n }\n return num;\n }\n if (type === 'date') {\n const date: Date = new Date(value + 'T00:00:00');\n if (Number.isNaN(date) && nullable) {\n return null;\n }\n return date;\n }\n setCharacterCount(value?.length || 0);\n return value;\n }\n };\n\n // Compose classnames from props\n const classNames = [\n `${className || ''}`,\n `${type === 'hidden' ? 'is-hidden' : ''}`\n ].join(' ');\n\n return (\n \n {icon && {icon}}\n , {\n ...rules,\n setValueAs: parseValue,\n value: defaultValue as FieldPathValue>,\n onChange: (e) => { handleChange(e); }\n })}\n type={type}\n step={step}\n disabled={typeof disabled === 'function' ? disabled(id) : disabled}\n placeholder={placeholder}\n accept={accept}\n maxLength={maxLength} />\n {(type === 'file' && placeholder) && {placeholder}}\n {maxLength && {characterCount} / {maxLength}}\n {addOn && addOnAction && }\n {addOn && !addOnAction && {addOn}}\n \n );\n};\n","import { ReactNode } from 'react';\nimport { FormFileUpload } from './form-file-upload';\nimport { FabButton } from '../base/fab-button';\nimport { Plus } from 'phosphor-react';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FormComponent, FormControlledComponent } from '../../models/form-component';\nimport { AbstractFormItemProps } from './abstract-form-item';\nimport { UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { ArrayPath, FieldArray, Path, useFieldArray, useWatch } from 'react-hook-form';\nimport { FileType } from '../../models/file';\nimport { UnpackNestedValue } from 'react-hook-form/dist/types';\nimport { FieldPathValue } from 'react-hook-form/dist/types/path';\n\ntype FormMultiFileUploadProps = FormComponent & FormControlledComponent & AbstractFormItemProps & {\n setValue: UseFormSetValue,\n addButtonLabel: ReactNode,\n accept: string\n}\n\n/**\n * This component allows to upload multiple files, in forms managed by react-hook-form.\n */\nexport const FormMultiFileUpload = ({ id, className, register, control, setValue, formState, addButtonLabel, accept }: FormMultiFileUploadProps) => {\n const { append } = useFieldArray({ control, name: id as ArrayPath });\n const output = useWatch({ control, name: id as Path });\n\n /**\n * Remove an file\n */\n const handleRemoveFile = (file: FileType, index: number) => {\n return () => {\n setValue(\n `${id}.${index}._destroy` as Path,\n true as UnpackNestedValue>>\n );\n };\n };\n\n return (\n
\n
\n {output?.map((field: FileType, index) => (\n handleRemoveFile(field, index)}/>\n ))}\n
\n append({ _destroy: false } as UnpackNestedValue>>)}\n className='is-secondary'\n icon={}>\n {addButtonLabel}\n \n
\n );\n};\n","import { ReactNode } from 'react';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FormComponent, FormControlledComponent } from '../../models/form-component';\nimport { AbstractFormItemProps } from './abstract-form-item';\nimport { UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { ArrayPath, FieldArray, Path, useFieldArray, useWatch } from 'react-hook-form';\nimport { FormImageUpload } from './form-image-upload';\nimport { FabButton } from '../base/fab-button';\nimport { Plus } from 'phosphor-react';\nimport { ImageType } from '../../models/file';\nimport { UnpackNestedValue } from 'react-hook-form/dist/types';\nimport { FieldPathValue } from 'react-hook-form/dist/types/path';\n\ntype FormMultiImageUploadProps = FormComponent & FormControlledComponent & AbstractFormItemProps & {\n setValue: UseFormSetValue,\n addButtonLabel: ReactNode\n}\n\n/**\n * This component allows to upload multiple images, in forms managed by react-hook-form.\n */\nexport const FormMultiImageUpload = ({ id, className, register, control, setValue, formState, addButtonLabel }: FormMultiImageUploadProps) => {\n const { append } = useFieldArray({ control, name: id as ArrayPath });\n const output = useWatch({ control, name: id as Path });\n\n /**\n * Add new image, set as main if it is the first\n */\n const addImage = () => {\n append({\n is_main: output.filter((i: ImageType) => i.is_main).length === 0,\n _destroy: false\n } as UnpackNestedValue>>);\n };\n\n /**\n * Remove an image and set the first image as the new main image if the provided was main\n */\n const handleRemoveImage = (image: ImageType, index: number) => {\n return () => {\n if (image.is_main && output.length > 1) {\n setValue(\n `${id}.${index === 0 ? 1 : 0}.is_main` as Path,\n true as UnpackNestedValue>>\n );\n }\n setValue(\n `${id}.${index}._destroy` as Path,\n true as UnpackNestedValue>>\n );\n };\n };\n\n /**\n * Set the image at the given index as the new main image, and unset the current main image\n */\n const handleSetMainImage = (index: number) => {\n return (setNewImageValue: (isMain: boolean) => void) => {\n const mainImageIndex = output.findIndex((i: ImageType, idx) => i.is_main && idx !== index);\n if (mainImageIndex > -1) {\n setValue(\n `${id}.${mainImageIndex}.is_main` as Path,\n false as UnpackNestedValue>>\n );\n }\n setNewImageValue(true);\n };\n };\n\n return (\n
\n
\n {output.map((field: ImageType, index) => (\n \n ))}\n
\n }>\n {addButtonLabel}\n \n
\n );\n};\n","import { useState, useEffect } from 'react';\nimport AsyncSelect from 'react-select/async';\nimport Select from 'react-select';\nimport AsyncCreatableSelect from 'react-select/async-creatable';\nimport CreatableSelect from 'react-select/creatable';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FieldPath } from 'react-hook-form/dist/types/path';\nimport { FormControlledComponent } from '../../models/form-component';\nimport { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';\nimport { useTranslation } from 'react-i18next';\nimport { Controller, FieldPathValue, Path } from 'react-hook-form';\nimport { UnpackNestedValue } from 'react-hook-form/dist/types/form';\n\ntype CommonProps = FormControlledComponent & AbstractFormItemProps & {\n valuesDefault?: Array,\n onChange?: (values: Array) => void,\n placeholder?: string,\n creatable?: boolean,\n selectKey?: string,\n}\n\n// we should provide either an array of options or a function that returns a promise, but not both\ntype OptionsProps =\n { options: Array>, loadOptions?: never } |\n { options?: never, loadOptions: (inputValue: string, callback: (options: Array>) => void) => void };\n\ntype FormSelectProps = CommonProps & OptionsProps;\n\n/**\n * Option format, expected by react-select\n * @see https://github.com/JedWatson/react-select\n */\ntype selectOption = { value: TOptionValue, label: string, select?: boolean };\n\n/**\n * This component is a wrapper around react-select to use with react-hook-form.\n * It is a multi-select component.\n */\nexport const FormMultiSelect = ({ id, label, tooltip, className, control, placeholder, options, valuesDefault, error, rules, disabled, onChange, formState, warning, loadOptions, creatable, selectKey }: FormSelectProps) => {\n const { t } = useTranslation('shared');\n\n const [isDisabled, setIsDisabled] = useState(false);\n const [allOptions, setAllOptions] = useState>>(options || []);\n\n useEffect(() => {\n if (typeof disabled === 'function') {\n setIsDisabled(disabled(id));\n } else {\n setIsDisabled(disabled);\n }\n }, [disabled]);\n\n useEffect(() => {\n if (typeof loadOptions === 'function') {\n loadOptions('', options => {\n setTimeout(() => setAllOptions(options), 1);\n });\n }\n }, [loadOptions]);\n\n /**\n * The following callback will set the new selected options in the component state.\n */\n const onChangeCb = (newValues: Array, rhfOnChange: (values: Array) => void): void => {\n if (typeof onChange === 'function') {\n onChange(newValues);\n }\n if (typeof rhfOnChange === 'function') {\n rhfOnChange(newValues);\n }\n };\n\n /**\n * This function will return the currently selected options, according to the selectedOptions state.\n */\n const getCurrentValues = (value: Array): Array> => {\n return allOptions?.filter(c => value?.includes(c.value));\n };\n\n /**\n * When the select is 'creatable', this callback handle the creation and the selection of a new option.\n */\n const handleCreate = (inputValue: string, currentSelection: Array, rhfOnChange: (values: Array) => void) => {\n // add the new value to the list of options\n const newValue = inputValue as unknown as TOptionValue;\n const newOption = { value: newValue, label: inputValue };\n setAllOptions([...allOptions, newOption]);\n if (typeof rhfOnChange === 'function') {\n rhfOnChange([...currentSelection, newValue]);\n }\n };\n\n /**\n * Translate the label for a new item when the select is \"creatable\"\n */\n const formatCreateLabel = (inputValue: string): string => {\n return t('app.shared.form_multi_select.create_label', { VALUE: inputValue });\n };\n\n // if the user can create new options, and/or load the options through a promise need to use different components\n const AbstractSelect = loadOptions\n ? creatable\n ? AsyncCreatableSelect\n : AsyncSelect\n : creatable\n ? CreatableSelect\n : Select;\n\n return (\n \n }\n control={control}\n defaultValue={valuesDefault as UnpackNestedValue>>}\n rules={rules}\n render={({ field: { onChange: rhfOnChange, value, ref } }) => {\n const selectProps = {\n classNamePrefix: 'rs',\n className: 'rs',\n ref,\n key: selectKey,\n value: getCurrentValues(value),\n placeholder,\n isDisabled,\n isMulti: true,\n onChange: val => onChangeCb(val?.map(c => c.value), rhfOnChange),\n options: allOptions\n };\n\n if (loadOptions) {\n Object.assign(selectProps, { loadOptions, defaultOptions: true, cacheOptions: true });\n }\n\n if (creatable) {\n Object.assign(selectProps, {\n formatCreateLabel,\n onCreateOption: inputValue => handleCreate(inputValue, value || [], rhfOnChange)\n });\n }\n\n return ();\n }}\n />\n \n );\n};\n\nFormMultiSelect.defaultProps = {\n creatable: false,\n disabled: false\n};\n","import { useEffect } from 'react';\nimport * as React from 'react';\nimport { FormControlledComponent } from '../../models/form-component';\nimport { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport FabTextEditor, { FabTextEditorRef } from '../base/text-editor/fab-text-editor';\nimport { Controller, Path } from 'react-hook-form';\nimport { FieldPath } from 'react-hook-form/dist/types/path';\nimport { FieldPathValue, UnpackNestedValue } from 'react-hook-form/dist/types';\n\ntype FormRichTextProps = FormControlledComponent & AbstractFormItemProps & {\n valueDefault?: string,\n limit?: number,\n heading?: boolean,\n bulletList?: boolean,\n blockquote?: boolean,\n link?: boolean,\n video?: boolean,\n image?: boolean,\n ariaLabel?: string,\n}\n\n/**\n * This component is a rich-text editor to use with react-hook-form.\n */\nexport const FormRichText = ({ id, label, tooltip, className, control, valueDefault, error, warning, rules, disabled = false, formState, limit, heading, bulletList, blockquote, video, image, link, ariaLabel }: FormRichTextProps) => {\n const textEditorRef = React.useRef();\n const [isDisabled, setIsDisabled] = React.useState(false);\n\n useEffect(() => {\n if (typeof disabled === 'function') {\n setIsDisabled(disabled(id));\n } else {\n setIsDisabled(disabled);\n }\n }, [disabled]);\n\n /**\n * Callback triggered when the user clicks to get the focus on the editor.\n * We do not want the default behavior (focus the first child, which is the Bold button)\n * but we want to focus the text edition area.\n */\n function focusTextEditor (event: React.MouseEvent) {\n event.preventDefault();\n textEditorRef.current.focus();\n }\n\n return (\n \n }\n control={control}\n defaultValue={valueDefault as UnpackNestedValue>>}\n rules={rules}\n render={({ field: { onChange, value } }) =>\n \n } />\n \n );\n};\n","import { useState, useEffect } from 'react';\nimport Select from 'react-select';\nimport CreatableSelect from 'react-select/creatable';\nimport { Controller, Path } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FieldPath } from 'react-hook-form/dist/types/path';\nimport { FieldPathValue, UnpackNestedValue } from 'react-hook-form/dist/types';\nimport { FormControlledComponent } from '../../models/form-component';\nimport { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';\nimport { SelectOption } from '../../models/select';\n\ntype FormSelectProps = FormControlledComponent & AbstractFormItemProps & {\n options: Array>,\n valueDefault?: TOptionValue,\n onChange?: (value: TOptionValue) => void,\n placeholder?: string,\n clearable?: boolean,\n creatable?: boolean,\n}\n\n/**\n * This component is a wrapper for react-select to use with react-hook-form\n */\nexport const FormSelect = ({ id, label, tooltip, className, control, placeholder, options, valueDefault, error, warning, rules, disabled = false, onChange, clearable = false, formState, creatable = false }: FormSelectProps) => {\n const [isDisabled, setIsDisabled] = useState(false);\n\n useEffect(() => {\n if (typeof disabled === 'function') {\n setIsDisabled(disabled(id));\n } else {\n setIsDisabled(disabled);\n }\n }, [disabled]);\n\n /**\n * The following callback will trigger the onChange callback, if it was passed to this component,\n * when the selected option changes.\n */\n const onChangeCb = (newValue: TOptionValue): void => {\n if (typeof onChange === 'function') {\n onChange(newValue);\n }\n };\n\n // if the user can create new options, we need to use a different component\n const AbstractSelect = creatable ? CreatableSelect : Select;\n\n return (\n \n }\n control={control}\n defaultValue={valueDefault as UnpackNestedValue>>}\n rules={rules}\n render={({ field: { onChange, value, ref } }) =>\n c.value === value)}\n onChange={val => {\n onChangeCb(val?.value);\n onChange(val?.value);\n }}\n placeholder={placeholder}\n isDisabled={isDisabled}\n isClearable={clearable}\n options={options}\n isOptionDisabled={(option) => option.disabled}/>\n } />\n \n );\n};\n","import { FormControlledComponent } from '../../models/form-component';\nimport { FieldPath } from 'react-hook-form/dist/types/path';\nimport { FieldPathValue, UnpackNestedValue } from 'react-hook-form/dist/types';\nimport { Controller, Path } from 'react-hook-form';\nimport Switch from 'react-switch';\nimport { AbstractFormItem, AbstractFormItemProps } from './abstract-form-item';\n\ntype FormSwitchProps = FormControlledComponent & AbstractFormItemProps & {\n defaultValue?: boolean,\n onChange?: (value: boolean) => void,\n}\n\n/**\n * This component is a wrapper for react-switch, to use with react-hook-form.\n */\nexport const FormSwitch = ({ id, label, tooltip, className, error, rules, disabled, control, defaultValue, formState, warning, onChange }: FormSwitchProps) => {\n /**\n * The following callback will trigger the onChange callback, if it was passed to this component,\n * when the selected option changes.\n */\n const onChangeCb = (newValue: boolean): void => {\n if (typeof onChange === 'function') {\n onChange(newValue);\n }\n };\n\n return (\n \n }\n control={control}\n defaultValue={defaultValue as UnpackNestedValue>>}\n rules={rules}\n render={({ field: { onChange, value, ref } }) =>\n {\n onChange(val);\n onChangeCb(val);\n }}\n checked={value as boolean || false}\n width={40}\n height={19}\n uncheckedIcon={false}\n checkedIcon={false}\n handleDiameter={15}\n ref={ref}\n disabled={typeof disabled === 'function' ? disabled(id) : disabled} />\n } />\n \n );\n};\n","import { FieldArrayWithId } from 'react-hook-form/dist/types/fieldArray';\nimport { UseFormRegister } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport React, { ReactNode } from 'react';\nimport { X } from 'phosphor-react';\nimport { FormInput } from './form-input';\nimport { FieldArrayPath } from 'react-hook-form/dist/types/path';\n\ninterface FormUnsavedListProps, TKeyName extends string> {\n fields: Array>,\n onRemove: (index: number) => void,\n register: UseFormRegister,\n className?: string,\n title: string,\n shouldRenderField?: (field: FieldArrayWithId) => boolean,\n renderField: (field: FieldArrayWithId) => ReactNode,\n formAttributeName: `${string}_attributes`,\n formAttributes: Array>,\n saveReminderLabel?: string | ReactNode,\n cancelLabel?: string | ReactNode\n}\n\n/**\n * This component render a list of unsaved attributes, created elsewhere than in the form (e.g. in a modal dialog)\n * and pending for the form to be saved.\n *\n * The `renderField` attribute should return a JSX element composed like the following example:\n * ```\n * <> \n *
\n * Attribute 1 \n *

{item.attr1}

\n *
\n *
\n * ...\n *
\n * \n * ```\n */\nexport const FormUnsavedList = = FieldArrayPath, TKeyName extends string = 'id'>({ fields, onRemove, register, className, title, shouldRenderField = () => true, renderField, formAttributeName, formAttributes, saveReminderLabel, cancelLabel }: FormUnsavedListProps) => {\n const { t } = useTranslation('shared');\n\n /**\n * Render an unsaved field\n */\n const renderUnsavedField = (field: FieldArrayWithId, index: number): ReactNode => {\n return (\n
\n {renderField(field)}\n

onRemove(index)}>\n {cancelLabel || t('app.shared.form_unsaved_list.cancel')}\n \n

\n {formAttributes.map((attribute, attrIndex) => (\n \n ))}\n
\n );\n };\n\n if (fields.filter(shouldRenderField).length === 0) return null;\n\n return (\n
\n {title}\n {saveReminderLabel || t('app.shared.form_unsaved_list.save_reminder')}\n {fields.map((field, index) => {\n if (!shouldRenderField(field)) return false;\n return renderUnsavedField(field, index);\n }).filter(Boolean)}\n
\n );\n};\n","import { PropsWithChildren, useCallback, useEffect, useState } from 'react';\nimport { UIRouter } from '@uirouter/angularjs';\nimport { FormState } from 'react-hook-form/dist/types/form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FabModal } from '../base/fab-modal';\nimport Deferred from '../../lib/deferred';\nimport { useTranslation } from 'react-i18next';\n\ninterface UnsavedFormAlertProps {\n uiRouter: UIRouter,\n formState: FormState,\n}\n\n/**\n * Alert the user about unsaved changes in the given form, before leaving the current page.\n * This component is highly dependent of these external libraries:\n * - [react-hook-form](https://react-hook-form.com/)\n * - [ui-router](https://ui-router.github.io/)\n */\nexport const UnsavedFormAlert = ({ uiRouter, formState, children }: PropsWithChildren>) => {\n const { t } = useTranslation('shared');\n\n const [showAlertModal, setShowAlertModal] = useState(false);\n const [promise, setPromise] = useState>(null);\n const [dirty, setDirty] = useState(formState.isDirty);\n\n useEffect(() => {\n const submitStatus = (!formState.isSubmitting && (!formState.isSubmitted || !formState.isSubmitSuccessful));\n setDirty(submitStatus && Object.keys(formState.dirtyFields).length > 0);\n }, [formState]);\n\n /**\n * Check if the current form is dirty. If so, show the confirmation modal and return a promise\n */\n const alertOnDirtyForm = (isDirty: boolean): Promise|void => {\n if (isDirty) {\n toggleAlertModal();\n const userChoicePromise = new Deferred();\n setPromise(userChoicePromise);\n return userChoicePromise.promise;\n }\n };\n\n // memoised version of the alertOnDirtyForm function, will be updated only when the form becames dirty\n const alertDirty = useCallback<() => Promise|void>(() => alertOnDirtyForm(dirty), [dirty]);\n\n // we should place this useEffect after the useCallback declaration (because it's a scoped variable)\n useEffect(() => {\n const { transitionService, globals: { current } } = uiRouter;\n const deregisters = transitionService.onBefore({ from: current.name }, alertDirty);\n return () => {\n deregisters();\n };\n }, [alertDirty]);\n\n /**\n * When the user tries to close the current page (tab/window), we alert him about unsaved changes\n */\n const alertOnExit = (event: BeforeUnloadEvent, isDirty: boolean) => {\n if (isDirty) {\n event.preventDefault();\n event.returnValue = '';\n }\n };\n\n // memoised version of the alertOnExit function, will be updated only when the form becames dirty\n const alertExit = useCallback<(event: BeforeUnloadEvent) => void>((event) => alertOnExit(event, dirty), [dirty]);\n\n // we should place this useEffect after the useCallback declaration (because it's a scoped variable)\n useEffect(() => {\n window.addEventListener('beforeunload', alertExit);\n return () => {\n window.removeEventListener('beforeunload', alertExit);\n };\n }, [alertExit]);\n\n /**\n * Hide/show the alert modal \"you have some unsaved content, are you sure you want to leave?\"\n */\n const toggleAlertModal = () => {\n setShowAlertModal(!showAlertModal);\n };\n\n /**\n * Callback triggered when the user has choosen: continue and exit\n */\n const handleConfirmation = () => {\n promise.resolve(true);\n };\n\n /**\n * Callback triggered when the user has choosen: cancel and stay\n */\n const handleCancel = () => {\n promise.resolve(false);\n };\n\n return (\n
\n {children}\n \n {t('app.shared.unsaved_form_alert.confirmation_message')}\n \n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { User } from '../../models/user';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { Group } from '../../models/group';\nimport GroupAPI from '../../api/group';\nimport { FabButton } from '../base/fab-button';\nimport { useTranslation } from 'react-i18next';\nimport { useForm } from 'react-hook-form';\nimport { FormSelect } from '../form/form-select';\nimport MemberAPI from '../../api/member';\nimport SettingAPI from '../../api/setting';\nimport UserLib from '../../lib/user';\nimport { SelectOption } from '../../models/select';\n\ndeclare const Application: IApplication;\n\ninterface ChangeGroupProps {\n user: User,\n onSuccess: (message: string, user: User) => void,\n onError: (message: string) => void,\n allowChange?: boolean,\n className?: string,\n}\n\n/**\n * Component to display the group of the provided user, and allow him to change his group.\n */\nexport const ChangeGroup: React.FC = ({ user, onSuccess, onError, allowChange, className }) => {\n const { t } = useTranslation('shared');\n\n const [groups, setGroups] = useState>([]);\n const [changeRequested, setChangeRequested] = useState(false);\n const [operator, setOperator] = useState(null);\n const [allowedUserChangeGoup, setAllowedUserChangeGoup] = useState(false);\n\n const { handleSubmit, control } = useForm();\n\n useEffect(() => {\n GroupAPI.index({ disabled: false }).then(setGroups).catch(onError);\n MemberAPI.current().then(setOperator).catch(onError);\n SettingAPI.get('user_change_group').then((setting) => {\n setAllowedUserChangeGoup(setting.value === 'true');\n }).catch(onError);\n }, []);\n\n useEffect(() => {\n setChangeRequested(false);\n }, [user, allowChange]);\n\n /**\n * Displays or hide the form to change the group.\n */\n const toggleChangeRequest = () => {\n setChangeRequested(!changeRequested);\n };\n\n /**\n * Check if the group changing is currently allowed.\n */\n const canChangeGroup = (): boolean => {\n const userLib = new UserLib(operator);\n return allowChange && (allowedUserChangeGoup || userLib.isPrivileged(user));\n };\n\n /**\n * Convert the provided array of items to the react-select format\n */\n const buildGroupsOptions = (): Array> => {\n return groups?.map(t => {\n return { value: t.id, label: t.name };\n });\n };\n\n /**\n * Callback triggered when the group changing form is submitted.\n */\n const onSubmit = (data: { group_id: number }) => {\n MemberAPI.update({ id: user.id, group_id: data.group_id } as User).then(res => {\n toggleChangeRequest();\n onSuccess(t('app.shared.change_group.success'), res);\n }).catch(onError);\n };\n\n // do not render the component if no user were provided (we cannot change th group of nobody)\n if (!user) return null;\n\n return (\n
\n

{t('app.shared.change_group.title', { OPERATOR: operator?.id === user.id ? 'self' : 'admin' })}

\n {!changeRequested &&
\n
\n {groups.find(group => group.id === user.group_id)?.name}\n
\n {canChangeGroup() && \n {t('app.shared.change_group.change', { OPERATOR: operator?.id === user.id ? 'self' : 'admin' })}\n }\n
}\n {changeRequested &&
\n \n
\n {t('app.shared.change_group.cancel')}\n {t('app.shared.change_group.validate')}\n
\n }\n
\n );\n};\n\nChangeGroup.defaultProps = {\n allowChange: true\n};\n\nconst ChangeGroupWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('changeGroup', react2angular(ChangeGroupWrapper, ['user', 'onSuccess', 'onError', 'allowChange', 'className']));\n","import { IApplication } from '../../models/application';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport { SettingName, SettingValue } from '../../models/setting';\nimport { useEffect } from 'react';\nimport SettingAPI from '../../api/setting';\nimport SettingLib from '../../lib/setting';\nimport { FabAlert } from '../base/fab-alert';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { FormSwitch } from '../form/form-switch';\nimport { FabButton } from '../base/fab-button';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport FormatLib from '../../lib/format';\nimport { FormInput } from '../form/form-input';\nimport { UnsavedFormAlert } from '../form/unsaved-form-alert';\nimport type { UIRouter } from '@uirouter/angularjs';\n\ndeclare const Application: IApplication;\n\nconst invoiceSettings: SettingName[] = ['invoice_prefix', 'payment_schedule_prefix', 'prevent_invoices_zero'];\n\ninterface InvoicesSettingsPanelProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n uiRouter: UIRouter\n}\n\n/**\n * Invoices settings display and edition\n */\nexport const InvoicesSettingsPanel: React.FC = ({ onError, onSuccess, uiRouter }) => {\n const { t } = useTranslation('admin');\n const { control, register, handleSubmit, reset, formState } = useForm>();\n const invoicePrefix = useWatch({ control, name: 'invoice_prefix' });\n const schedulePrefix = useWatch({ control, name: 'payment_schedule_prefix' });\n\n const example = {\n id: Math.ceil(Math.random() * 100),\n idSchedule: Math.ceil(Math.random() * 100),\n date: FormatLib.dateFilename(new Date())\n };\n\n useEffect(() => {\n SettingAPI.query(invoiceSettings)\n .then(settings => {\n const data = SettingLib.bulkMapToObject(settings);\n reset(data);\n })\n .catch(onError);\n }, []);\n\n /**\n * Callback triggered when the form is submitted: save the settings\n */\n const onSubmit: SubmitHandler> = (data) => {\n SettingAPI.bulkUpdate(SettingLib.objectToBulkMap(data)).then(() => {\n onSuccess(t('app.admin.invoices_settings_panel.update_success'));\n }, reason => {\n onError(reason);\n });\n };\n\n return (\n
\n
\n \n
\n

{t('app.admin.invoices_settings_panel.disable_invoices_zero')}

\n \n
\n
\n

{t('app.admin.invoices_settings_panel.filename')}

\n \n \n \n \n
\n {t('app.admin.invoices_settings_panel.example')}\n

\n {invoicePrefix}-{example.id}_{example.date}\n

\n
\n
\n
\n

{t('app.admin.invoices_settings_panel.schedule_filename')}

\n \n \n \n \n
\n {t('app.admin.invoices_settings_panel.example')}\n

\n {schedulePrefix}-{example.idSchedule}_{example.date}\n

\n
\n
\n
\n {t('app.admin.invoices_settings_panel.save')}\n
\n \n
\n );\n};\n\nconst InvoicesSettingspanelWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('invoicesSettingsPanel', react2angular(InvoicesSettingspanelWrapper, ['onError', 'onSuccess', 'uiRouter']));\n","import React, { useEffect, useState } from 'react';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport SettingAPI from '../../api/setting';\nimport { SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport { SettingName, SettingValue } from '../../models/setting';\nimport { useTranslation } from 'react-i18next';\nimport SettingLib from '../../lib/setting';\nimport { FormSwitch } from '../form/form-switch';\nimport { FormInput } from '../form/form-input';\nimport { FabButton } from '../base/fab-button';\nimport { FabAlert } from '../base/fab-alert';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { SettingHistoryModal } from '../settings/setting-history-modal';\nimport { useImmer } from 'use-immer';\nimport { enableMapSet } from 'immer';\nimport { ClockCounterClockwise } from 'phosphor-react';\n\ndeclare const Application: IApplication;\n\nconst vatSettings: SettingName[] = ['invoice_VAT-rate', 'invoice_VAT-active', 'invoice_VAT-name', 'invoice_VAT-rate_Product', 'invoice_VAT-rate_Event',\n 'invoice_VAT-rate_Machine', 'invoice_VAT-rate_Subscription', 'invoice_VAT-rate_Space', 'invoice_VAT-rate_Training'];\n\ninterface VatSettingsModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\nenableMapSet();\n\n/**\n * Modal dialog to configure VAT settings\n */\nexport const VatSettingsModal: React.FC = ({ isOpen, toggleModal, onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n\n const { handleSubmit, reset, control, register, formState } = useForm>();\n const isActive = useWatch({ control, name: 'invoice_VAT-active' });\n const generalRate = useWatch({ control, name: 'invoice_VAT-rate' });\n\n const [modalWidth, setModalWidth] = useState(ModalSize.small);\n const [advancedLabel, setAdvancedLabel] = useState(t('app.admin.vat_settings_modal.advanced'));\n const [histories, setHistories] = useImmer>(new Map());\n\n useEffect(() => {\n SettingAPI.query(vatSettings)\n .then(settings => {\n const data = SettingLib.bulkMapToObject(settings);\n reset(data);\n })\n .catch(onError);\n }, [isOpen]);\n\n /**\n * Callback triggered when the form is submitted: save the settings\n */\n const onSubmit: SubmitHandler> = (data) => {\n SettingAPI.bulkUpdate(SettingLib.objectToBulkMap(data, { stripNaN: true })).then(() => {\n onSuccess(t('app.admin.vat_settings_modal.update_success'));\n toggleModal();\n }, reason => {\n onError(reason);\n });\n };\n\n /**\n * Show the panel allowing to configure a rate per resource type\n */\n const toggleAdvancedRates = () => {\n if (modalWidth === ModalSize.small) {\n setModalWidth(ModalSize.large);\n setAdvancedLabel(t('app.admin.vat_settings_modal.hide_advanced'));\n } else {\n setModalWidth(ModalSize.small);\n setAdvancedLabel(t('app.admin.vat_settings_modal.advanced'));\n }\n };\n\n /**\n * Open/closes the modal dialog showing the changes history for the given paramater name\n */\n const toggleHistoryModal = (name: SettingName) => {\n return () => {\n setHistories(draft => {\n draft.set(name, !draft.get(name));\n });\n };\n };\n\n return (\n \n
\n
\n
\n \n {isActive && <>\n \n }\n addOnAriaLabel={t('app.admin.vat_settings_modal.show_history')}\n addOnAction={toggleHistoryModal('invoice_VAT-rate')} />\n \n }\n {modalWidth === ModalSize.large && \n \n }\n
\n {modalWidth === ModalSize.large &&
\n }\n addOnAriaLabel={t('app.admin.vat_settings_modal.show_history')}\n addOnAction={toggleHistoryModal('invoice_VAT-rate_Product')} />\n \n }\n addOnAriaLabel={t('app.admin.vat_settings_modal.show_history')}\n addOnAction={toggleHistoryModal('invoice_VAT-rate_Event')} />\n \n }\n addOnAriaLabel={t('app.admin.vat_settings_modal.show_history')}\n addOnAction={toggleHistoryModal('invoice_VAT-rate_Machine')} />\n \n }\n addOnAriaLabel={t('app.admin.vat_settings_modal.show_history')}\n addOnAction={toggleHistoryModal('invoice_VAT-rate_Subscription')} />\n \n }\n addOnAriaLabel={t('app.admin.vat_settings_modal.show_history')}\n addOnAction={toggleHistoryModal('invoice_VAT-rate_Space')} />\n \n }\n addOnAriaLabel={t('app.admin.vat_settings_modal.show_history')}\n addOnAction={toggleHistoryModal('invoice_VAT-rate_Training')} />\n \n
}\n
\n
\n {isActive && {advancedLabel}}\n {t('app.admin.vat_settings_modal.save')}\n
\n
\n
\n );\n};\n\nconst VatSettingsModalWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('vatSettingsModal', react2angular(VatSettingsModalWrapper, ['isOpen', 'toggleModal', 'onError', 'onSuccess']));\n","import { ReactNode, useState } from 'react';\nimport * as React from 'react';\nimport { Machine } from '../../models/machine';\nimport { useTranslation } from 'react-i18next';\nimport { Loader } from '../base/loader';\nimport { ReserveButton } from './reserve-button';\nimport { User } from '../../models/user';\n\ninterface MachineCardProps {\n user?: User,\n machine: Machine,\n onShowMachine: (machine: Machine) => void,\n onReserveMachine: (machine: Machine) => void,\n onLoginRequested: () => Promise,\n onEnrollRequested: (trainingId: number) => void,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n canProposePacks: boolean,\n}\n\n/**\n * This component is a box showing the picture of the given machine and two buttons: one to start the reservation process\n * and another to redirect the user to the machine description page.\n */\nconst MachineCard: React.FC = ({ user, machine, onShowMachine, onReserveMachine, onError, onSuccess, onLoginRequested, onEnrollRequested, canProposePacks }) => {\n const { t } = useTranslation('public');\n\n // shall we display a loader to prevent double-clicking, while the machine details are loading?\n const [loading, setLoading] = useState(false);\n\n /**\n * Callback triggered when the user clicks on the 'reserve' button and has passed all the verifications\n */\n const handleReserveMachine = (): void => {\n onReserveMachine(machine);\n };\n /**\n * Callback triggered when the user clicks on the 'view' button\n */\n const handleShowMachine = (): void => {\n onShowMachine(machine);\n };\n\n /**\n * Return the machine's picture or a placeholder\n */\n const machinePicture = (): ReactNode => {\n if (!machine.machine_image_attributes?.attachment_url) {\n return
;\n }\n\n return (\n
\n );\n };\n\n return (\n
\n {machinePicture()}\n
\n {machine.name}\n
\n
\n {!machine.disabled && machine.reservable && setLoading(true)}\n onLoadingEnd={() => setLoading(false)}\n onError={onError}\n onSuccess={onSuccess}\n onReserveMachine={handleReserveMachine}\n onLoginRequested={onLoginRequested}\n onEnrollRequested={onEnrollRequested}\n canProposePacks={canProposePacks}\n className=\"reserve-button\">\n \n {t('app.public.machine_card.book')}\n }\n \n \n \n
\n
\n );\n};\n\nconst MachineCardWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { MachineCardWrapper as MachineCard };\n","import React, { useEffect, useState } from 'react';\nimport { MachineCategory } from '../../models/machine-category';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport MachineCategoryAPI from '../../api/machine-category';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../base/fab-button';\nimport { MachineCategoryModal } from './machine-category-modal';\nimport { EditDestroyButtons } from '../base/edit-destroy-buttons';\n\ndeclare const Application: IApplication;\n\ninterface MachineCategoriesListProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\n/**\n * This component shows a list of all machines and allows filtering on that list.\n */\nexport const MachineCategoriesList: React.FC = ({ onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n\n // shown machine categories\n const [machineCategories, setMachineCategories] = useState>([]);\n // creation/edition modal\n const [modalIsOpen, setModalIsOpen] = useState(false);\n // currently added/edited category\n const [machineCategory, setMachineCategory] = useState(null);\n\n // retrieve the full list of machine categories on component mount\n useEffect(() => {\n MachineCategoryAPI.index()\n .then(setMachineCategories)\n .catch(onError);\n }, []);\n\n /**\n * Toggle the modal dialog to create/edit a machine category\n */\n const toggleCreateAndEditModal = (): void => {\n setModalIsOpen(!modalIsOpen);\n };\n\n /**\n * Callback triggred when the current machine category was successfully saved\n */\n const onSaveTypeSuccess = (message: string): void => {\n setModalIsOpen(false);\n MachineCategoryAPI.index().then(data => {\n setMachineCategories(data);\n onSuccess(message);\n }).catch((error) => {\n onError('Unable to load machine categories' + error);\n });\n };\n\n /**\n * Init the process of creating a new machine category\n */\n const addMachineCategory = (): void => {\n setMachineCategory({} as MachineCategory);\n setModalIsOpen(true);\n };\n\n /**\n * Init the process of editing the given machine category\n */\n const editMachineCategory = (category: MachineCategory): () => void => {\n return (): void => {\n setMachineCategory(category);\n setModalIsOpen(true);\n };\n };\n\n /**\n * Callback triggred when the current machine category was successfully deleted\n */\n const onDestroySuccess = (message: string): void => {\n MachineCategoryAPI.index().then(data => {\n setMachineCategories(data);\n onSuccess(message);\n }).catch((error) => {\n onError('Unable to load machine categories' + error);\n });\n };\n\n return (\n
\n
\n

{t('app.admin.machine_categories_list.machine_categories')}

\n
\n {t('app.admin.machine_categories_list.add_a_machine_category')}\n
\n
\n \n \n \n \n \n \n \n \n \n \n {machineCategories.map(category => {\n return (\n \n \n \n \n \n );\n })}\n \n
{t('app.admin.machine_categories_list.name')}{t('app.admin.machine_categories_list.machines_number')}
\n {category.name}\n \n {category.machine_ids.length}\n \n
\n \n
\n
\n
\n );\n};\n\nconst MachineCategoriesListWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('machineCategoriesList', react2angular(MachineCategoriesListWrapper, ['onError', 'onSuccess']));\n","import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { SubmitHandler, useForm } from 'react-hook-form';\nimport { FormInput } from '../form/form-input';\nimport { FormChecklist } from '../form/form-checklist';\nimport { MachineCategory } from '../../models/machine-category';\nimport { FabButton } from '../base/fab-button';\nimport { Machine } from '../../models/machine';\nimport { SelectOption } from '../../models/select';\n\ninterface MachineCategoryFormProps {\n machines: Array,\n machineCategory?: MachineCategory,\n saveMachineCategory: (data: MachineCategory) => void,\n}\n\n/**\n * Form to set create/edit machine category\n */\nexport const MachineCategoryForm: React.FC = ({ machines, machineCategory, saveMachineCategory }) => {\n const { t } = useTranslation('admin');\n\n const { handleSubmit, register, control, formState } = useForm({ defaultValues: { ...machineCategory } });\n\n /**\n * Convert all machines to the checklist format\n */\n const buildOptions = (): Array> => {\n return machines.map(t => {\n return { value: t.id, label: t.name };\n });\n };\n\n /**\n * Callback triggered when the form is submitted: process with the machine category creation or update.\n */\n const onSubmit: SubmitHandler = (data: MachineCategory) => {\n saveMachineCategory(data);\n };\n\n return (\n
\n
\n \n
\n

{t('app.admin.machine_category_form.assigning_machines')}

\n \n
\n
\n \n {t('app.admin.machine_category_form.save')}\n \n
\n \n
\n );\n};\n","import React, { useEffect, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { MachineCategory } from '../../models/machine-category';\nimport { Machine } from '../../models/machine';\nimport MachineCategoryAPI from '../../api/machine-category';\nimport { MachineCategoryForm } from './machine-category-form';\nimport MachineAPI from '../../api/machine';\n\ninterface MachineCategoryModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n machineCategory?: MachineCategory,\n}\n\n/**\n * Modal dialog to create/edit a machine category\n */\nexport const MachineCategoryModal: React.FC = ({ isOpen, toggleModal, onSuccess, onError, machineCategory }) => {\n const { t } = useTranslation('admin');\n // all machines, to assign to the category\n const [machines, setMachines] = useState>([]);\n\n // retrieve the full list of machines on component mount\n useEffect(() => {\n if (!isOpen) return;\n\n MachineAPI.index({ category: [machineCategory?.id, 'none'] })\n .then(setMachines)\n .catch(onError);\n }, [isOpen]);\n\n /**\n * Save the current machine category to the API\n */\n const handleSaveMachineCategory = async (data: MachineCategory): Promise => {\n try {\n if (machineCategory?.id) {\n await MachineCategoryAPI.update(data);\n onSuccess(t('app.admin.machine_category_modal.successfully_updated'));\n } else {\n await MachineCategoryAPI.create(data);\n onSuccess(t('app.admin.machine_category_modal.successfully_created'));\n }\n } catch (e) {\n if (machineCategory?.id) {\n onError(t('app.admin.machine_category_modal.unable_to_update') + e);\n } else {\n onError(t('app.admin.machine_category_modal.unable_to_create') + e);\n }\n }\n };\n\n return (\n \n \n \n );\n};\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport { Machine } from '../../models/machine';\nimport MachineAPI from '../../api/machine';\nimport { useTranslation } from 'react-i18next';\nimport { FormInput } from '../form/form-input';\nimport { FormImageUpload } from '../form/form-image-upload';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { ErrorBoundary } from '../base/error-boundary';\nimport { FormRichText } from '../form/form-rich-text';\nimport { FormSwitch } from '../form/form-switch';\nimport { FormMultiFileUpload } from '../form/form-multi-file-upload';\nimport { FabButton } from '../base/fab-button';\nimport { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';\nimport { FormSelect } from '../form/form-select';\nimport { SelectOption } from '../../models/select';\nimport MachineCategoryAPI from '../../api/machine-category';\nimport SettingAPI from '../../api/setting';\nimport { MachineCategory } from '../../models/machine-category';\nimport { FabAlert } from '../base/fab-alert';\n\ndeclare const Application: IApplication;\n\ninterface MachineFormProps {\n action: 'create' | 'update',\n machine?: Machine,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\n/**\n * Form to edit or create machines\n */\nexport const MachineForm: React.FC = ({ action, machine, onError, onSuccess }) => {\n const { handleSubmit, register, control, setValue, formState } = useForm({ defaultValues: { ...machine } });\n const output = useWatch({ control });\n const { t } = useTranslation('admin');\n\n const [machineCategories, setMachineCategories] = useState>([]);\n const [isActiveAccounting, setIsActiveAccounting] = useState(false);\n\n // retrieve the full list of machine categories on component mount\n // check advanced accounting activation\n useEffect(() => {\n MachineCategoryAPI.index()\n .then(data => setMachineCategories(data))\n .catch(e => onError(e));\n SettingAPI.get('advanced_accounting').then(res => setIsActiveAccounting(res.value === 'true')).catch(onError);\n }, []);\n\n /**\n * Callback triggered when the user validates the machine form: handle create or update\n */\n const onSubmit: SubmitHandler = (data: Machine) => {\n MachineAPI[action](data).then((res) => {\n onSuccess(t(`app.admin.machine_form.${action}_success`));\n window.location.href = `/#!/machines/${res.slug}`;\n }).catch(error => {\n onError(error);\n });\n };\n\n /**\n * Callack triggered when the user changes the 'reservable' status of the machine:\n * A reservable machine cannot be disabled\n */\n const onReservableToggled = (reservable: boolean) => {\n if (reservable) {\n setValue('disabled', false);\n }\n };\n\n /**\n * Callack triggered when the user changes the 'disabled' status of the machine:\n * A disabled machine cannot be reservable\n */\n const onDisabledToggled = (disabled: boolean) => {\n if (disabled) {\n setValue('reservable', false);\n }\n };\n\n /**\n * Convert all machine categories to the select format\n */\n const buildOptions = (): Array> => {\n return machineCategories.map(t => {\n return { value: t.id, label: t.name };\n });\n };\n\n return (\n
\n
\n

{t('app.admin.machine_form.ACTION_title', { ACTION: action })}

\n \n {t('app.admin.machine_form.save')}\n \n
\n
\n {action === 'create' &&\n \n {t('app.admin.machine_form.watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions')} {t('app.admin.machine_form.consider_changing_them_before_creating_any_reservation_slot')}\n \n }\n
\n
\n

{t('app.admin.machine_form.description')}

\n
\n
\n \n \n \n \n \n
\n
\n\n
\n
\n

{t('app.admin.machine_form.attachments')}

\n
\n
\n
\n

{t('app.admin.machine_form.attached_files_pdf')}

\n
\n \n
\n
\n\n
\n
\n

{t('app.admin.machine_form.settings')}

\n
\n
\n \n \n
\n
\n\n {isActiveAccounting &&\n
\n \n
\n }\n
\n
\n );\n};\n\nconst MachineFormWrapper: React.FC = (props) => {\n return (\n \n \n \n \n \n );\n};\n\nApplication.Components.component('machineForm', react2angular(MachineFormWrapper, ['action', 'machine', 'onError', 'onSuccess']));\n","import { useEffect, useState } from 'react';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { EditorialBlock } from '../editorial-block/editorial-block';\nimport SettingAPI from '../../api/setting';\nimport SettingLib from '../../lib/setting';\nimport { SettingValue, machinesSettings } from '../../models/setting';\n\ndeclare const Application: IApplication;\n\ninterface MachinesEditorialBlockProps {\n onError: (message: string) => void\n}\n\n/**\n * This component displays to Users the editorial block (banner) associated to machines.\n */\nexport const MachinesEditorialBlock: React.FC = ({ onError }) => {\n // Store Banner retrieved from API\n const [banner, setBanner] = useState>({});\n\n // Retrieve the settings related to the Machines Banner from the API\n useEffect(() => {\n SettingAPI.query(machinesSettings)\n .then(settings => {\n setBanner({ ...SettingLib.bulkMapToObject(settings) });\n })\n .catch(onError);\n }, []);\n\n return (\n <>\n {banner.machines_banner_active &&\n \n }\n \n );\n};\n\nconst MachinesEditorialBlockWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('machinesEditorialBlock', react2angular(MachinesEditorialBlockWrapper, ['onError']));\n","import * as React from 'react';\nimport Select from 'react-select';\nimport { useTranslation } from 'react-i18next';\nimport { SelectOption } from '../../models/select';\nimport { MachineCategory } from '../../models/machine-category';\n\ninterface MachinesFiltersProps {\n onFilterChangedBy: (type: string, value: number | boolean | void) => void,\n machineCategories: Array,\n}\n\n/**\n * Allows filtering on machines list\n */\nexport const MachinesFilters: React.FC = ({ onFilterChangedBy, machineCategories }) => {\n const { t } = useTranslation('public');\n\n const defaultValue = { value: false, label: t('app.public.machines_filters.status_enabled') };\n const categoryDefaultValue = { value: null, label: t('app.public.machines_filters.all_machines') };\n\n // Styles the React-select component\n const customStyles = {\n control: base => ({\n ...base,\n width: '20ch',\n border: 'none',\n backgroundColor: 'transparent'\n }),\n indicatorSeparator: () => ({\n display: 'none'\n })\n };\n\n /**\n * Provides boolean options in the react-select format (yes/no/all)\n */\n const buildBooleanOptions = (): Array> => {\n return [\n defaultValue,\n { value: true, label: t('app.public.machines_filters.status_disabled') },\n { value: null, label: t('app.public.machines_filters.status_all') }\n ];\n };\n\n /**\n * Provides categories options in the react-select format\n */\n const buildCategoriesOptions = (): Array> => {\n const options = machineCategories.map(c => {\n return { value: c.id, label: c.name };\n });\n return [categoryDefaultValue].concat(options);\n };\n\n /**\n * Callback triggered when the user selects a machine status in the dropdown list\n */\n const handleStatusSelected = (option: SelectOption): void => {\n onFilterChangedBy('disabled', option.value);\n };\n\n /**\n * Callback triggered when the user selects a machine category in the dropdown list\n */\n const handleCategorySelected = (option: SelectOption): void => {\n onFilterChangedBy('category', option.value);\n };\n\n return (\n
\n
\n

{t('app.public.machines_filters.show_machines')}

\n \n
\n }\n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { Machine, MachineIndexFilter } from '../../models/machine';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport MachineAPI from '../../api/machine';\nimport MachineCategoryAPI from '../../api/machine-category';\nimport { MachineCategory } from '../../models/machine-category';\nimport { MachineCard } from './machine-card';\nimport { MachinesFilters } from './machines-filters';\nimport { User } from '../../models/user';\n\ndeclare const Application: IApplication;\n\ninterface MachinesListProps {\n user?: User,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n onShowMachine: (machine: Machine) => void,\n onReserveMachine: (machine: Machine) => void,\n onLoginRequested: () => Promise,\n onEnrollRequested: (trainingId: number) => void,\n canProposePacks: boolean,\n}\n\n/**\n * This component shows a list of all machines and allows filtering on that list.\n */\nexport const MachinesList: React.FC = ({ onError, onSuccess, onShowMachine, onReserveMachine, onLoginRequested, onEnrollRequested, user, canProposePacks }) => {\n // shown machines\n const [machines, setMachines] = useState>(null);\n // shown machine categories\n const [machineCategories, setMachineCategories] = useState>([]);\n // machine list filter\n const [filters, setFilters] = useState({\n disabled: false,\n category: null\n });\n\n // retrieve the full list of machines on component mount\n useEffect(() => {\n MachineAPI.index(filters)\n .then(data => setMachines(data))\n .catch(e => onError(e));\n MachineCategoryAPI.index()\n .then(data => setMachineCategories(data))\n .catch(e => onError(e));\n }, []);\n\n // refetch the machines when the filters change\n useEffect(() => {\n MachineAPI.index(filters)\n .then(data => setMachines(data))\n .catch(e => onError(e));\n }, [filters]);\n\n /**\n * Callback triggered when the user changes the filter.\n * @param type, status, category\n * @param value, status and category value\n */\n const handleFilterChangedBy = (type: string, value: number | boolean | void) => {\n setFilters({\n ...filters,\n [type]: value\n });\n };\n\n return (\n
\n \n
\n {machines && machines.map(machine => {\n return ;\n })}\n
\n
\n );\n};\n\nconst MachinesListWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('machinesList', react2angular(MachinesListWrapper, ['user', 'onError', 'onSuccess', 'onShowMachine', 'onReserveMachine', 'onLoginRequested', 'onEnrollRequested', 'canProposePacks']));\n","import React, { useEffect } from 'react';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { ErrorBoundary } from '../base/error-boundary';\nimport { useTranslation } from 'react-i18next';\nimport { useForm, SubmitHandler } from 'react-hook-form';\nimport { FabButton } from '../base/fab-button';\nimport { EditorialKeys, EditorialBlockForm } from '../editorial-block/editorial-block-form';\nimport SettingAPI from '../../api/setting';\nimport SettingLib from '../../lib/setting';\nimport { SettingName, SettingValue, machinesSettings } from '../../models/setting';\nimport { UnsavedFormAlert } from '../form/unsaved-form-alert';\nimport { UIRouter } from '@uirouter/angularjs';\n\ndeclare const Application: IApplication;\n\ninterface MachinesSettingsProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n beforeSubmit?: (data: Record) => void,\n uiRouter?: UIRouter\n}\n\n/**\n * Machines settings\n */\nexport const MachinesSettings: React.FC = ({ onError, onSuccess, beforeSubmit, uiRouter }) => {\n const { t } = useTranslation('admin');\n const { register, control, formState, handleSubmit, reset } = useForm>();\n\n /** Link Machines Banner Setting Names to generic keys expected by the Editorial Form */\n const bannerKeys: Record = {\n active_text_block: 'machines_banner_active',\n text_block: 'machines_banner_text',\n active_cta: 'machines_banner_cta_active',\n cta_label: 'machines_banner_cta_label',\n cta_url: 'machines_banner_cta_url'\n };\n\n /** Callback triggered when the form is submitted: save the settings */\n const onSubmit: SubmitHandler> = (data) => {\n if (typeof beforeSubmit === 'function') beforeSubmit(data);\n SettingAPI.bulkUpdate(SettingLib.objectToBulkMap(data)).then(() => {\n onSuccess(t('app.admin.machines_settings.successfully_saved'));\n }, reason => {\n onError(reason);\n });\n };\n\n /** On component mount, fetch existing Machines Banner Settings from API, and populate form with these values. */\n useEffect(() => {\n SettingAPI.query(machinesSettings)\n .then(settings => reset(SettingLib.bulkMapToObject(settings)))\n .catch(onError);\n }, []);\n\n return (\n
\n
\n

{t('app.admin.machines_settings.title')}

\n {t('app.admin.machines_settings.save')}\n
\n
\n {uiRouter && }\n
\n \n
\n \n
\n );\n};\n\nconst MachinesSettingsWrapper: React.FC = (props) => {\n return (\n \n \n \n \n \n );\n};\n\nApplication.Components.component('machinesSettings', react2angular(MachinesSettingsWrapper, ['onError', 'onSuccess', 'beforeSubmit', 'uiRouter']));\n","import * as React from 'react';\nimport { FabModal } from '../base/fab-modal';\nimport { useTranslation } from 'react-i18next';\nimport { HtmlTranslate } from '../base/html-translate';\nimport FormatLib from '../../lib/format';\nimport { TDateISO } from '../../typings/date-iso';\n\ninterface PendingTrainingModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n nextReservation: TDateISO,\n}\n\n/**\n * Modal dialog shown if the current user has registered for a training but this training isn't validated\n * when the user tries to book a machine.\n */\nexport const PendingTrainingModal: React.FC = ({ isOpen, toggleModal, nextReservation }) => {\n const { t } = useTranslation('logged');\n\n /**\n * Return the formatted localized date for the given date\n */\n const formatDateTime = (date: TDateISO): string => {\n return t('app.logged.pending_training_modal.DATE_TIME', { DATE: FormatLib.date(date), TIME: FormatLib.time(date) });\n };\n\n return (\n \n

{t('app.logged.pending_training_modal.wait_for_validated')}

\n

\n
\n );\n};\n","import { ReactNode } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabModal } from '../base/fab-modal';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { Machine } from '../../models/machine';\nimport { User } from '../../models/user';\nimport { Avatar } from '../user/avatar';\nimport { FabButton } from '../base/fab-button';\n\ninterface RequiredTrainingModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n user?: User,\n machine?: Machine,\n onEnrollRequested: (trainingId: number) => void,\n}\n/**\n * Modal dialog shown if the current user does not have the required training to book the given machine\n */\nexport const RequiredTrainingModal: React.FC = ({ isOpen, toggleModal, user, machine, onEnrollRequested }) => {\n const { t } = useTranslation('logged');\n\n /**\n * Properly format the list of allowed trainings\n */\n const formatTrainings = (): string => {\n if (!machine) return '';\n\n return machine.trainings.map(t => t.name).join(t('app.logged.required_training_modal.training_or_training_html'));\n };\n\n /**\n * Callback triggered when the user has clicked on the \"enroll\" button\n */\n const handleEnroll = (): void => {\n onEnrollRequested(machine.trainings[0].id);\n };\n\n /**\n * Custom header of the dialog: we display the username and avatar\n */\n const header = (): ReactNode => {\n return (\n
\n \n {user?.name}\n
\n );\n };\n\n /**\n * Custom footer of the dialog: we display a user-friendly message to close the dialog\n */\n const footer = (): ReactNode => {\n return (\n
\n

{t('app.logged.required_training_modal.no_enroll_for_now')}

\n {t('app.logged.required_training_modal.close')}\n
\n );\n };\n\n return (\n \n
\n

\n \n

\n
\n {t('app.logged.required_training_modal.enroll_now')}\n
\n
\n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { PendingTrainingModal } from './pending-training-modal';\nimport { RequiredTrainingModal } from './required-training-modal';\nimport { Loader } from '../base/loader';\nimport { ProposePacksModal } from '../prepaid-packs/propose-packs-modal';\nimport MachineAPI from '../../api/machine';\nimport { Machine } from '../../models/machine';\nimport { User } from '../../models/user';\nimport { IApplication } from '../../models/application';\nimport SettingAPI from '../../api/setting';\n\ndeclare const Application: IApplication;\n\ninterface ReserveButtonProps {\n currentUser?: User,\n machineId: number,\n onLoadingStart?: () => void,\n onLoadingEnd?: () => void,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n onReserveMachine: (machine: Machine) => void,\n onLoginRequested: () => Promise,\n onEnrollRequested: (trainingId: number) => void,\n className?: string,\n canProposePacks: boolean,\n}\n\n/**\n * Button component that makes the training verification before redirecting the user to the reservation calendar\n */\nconst ReserveButton: React.FC = ({ currentUser, machineId, onLoginRequested, onLoadingStart, onLoadingEnd, onError, onSuccess, onReserveMachine, onEnrollRequested, className, children, canProposePacks }) => {\n const { t } = useTranslation('shared');\n\n const [machine, setMachine] = useState(null);\n const [user, setUser] = useState(currentUser);\n const [pendingTraining, setPendingTraining] = useState(false);\n const [trainingRequired, setTrainingRequired] = useState(false);\n const [proposePacks, setProposePacks] = useState(false);\n const [isPackOnlyForSubscription, setIsPackOnlyForSubscription] = useState(true);\n\n // handle login from an external process\n useEffect(() => setUser(currentUser), [currentUser]);\n // check the trainings after we retrieved the machine data\n useEffect(() => checkTraining(), [machine]);\n useEffect(() => {\n SettingAPI.get('pack_only_for_subscription')\n .then(data => setIsPackOnlyForSubscription(data.value === 'true'))\n .catch(error => onError(error));\n }, []);\n\n /**\n * Callback triggered when the user clicks on the 'reserve' button.\n */\n const handleClick = (): void => {\n getMachine();\n };\n\n /**\n * We load the full machine data, including data on the current user status for this machine.\n * Then we check if the user has passed the training for it (if it's needed)\n */\n const getMachine = (): void => {\n if (onLoadingStart) onLoadingStart();\n\n MachineAPI.get(machineId)\n .then(data => {\n setMachine(data);\n if (onLoadingEnd) onLoadingEnd();\n })\n .catch(error => {\n onError(error);\n if (onLoadingEnd) onLoadingEnd();\n });\n };\n\n /**\n * Open/closes the alert modal informing the user about his pending training\n */\n const togglePendingTrainingModal = (): void => {\n setPendingTraining(!pendingTraining);\n };\n\n /**\n * Open/closes the alert modal informing the user about his pending training\n */\n const toggleRequiredTrainingModal = (): void => {\n setTrainingRequired(!trainingRequired);\n };\n\n /**\n * Open/closes the modal dialog inviting the user to buy a prepaid-pack\n */\n const toggleProposePacksModal = (): void => {\n setProposePacks(!proposePacks);\n };\n\n /**\n * Callback triggered when the user has successfully bought a pre-paid pack.\n * Display the success message and redirect him to the booking page.\n */\n const handlePackBought = (message: string, machine: Machine): void => {\n onSuccess(message);\n onReserveMachine(machine);\n };\n\n /**\n * Check that the current user has passed the required training before allowing him to book\n */\n const checkTraining = (): void => {\n // do nothing if the machine is still not loaded\n if (!machine) return;\n\n // if there's no user currently logged, trigger the logging process\n if (!user) {\n onLoginRequested()\n .then(() => getMachine())\n .catch(error => onError(error));\n return;\n }\n\n // if the currently logged user has completed the training for this machine, or this machine does not require\n // a prior training, move forward to the prepaid-packs verification.\n // Moreover, if there's no enabled associated trainings, also move to the next step.\n if (machine.current_user_is_trained || machine.trainings.length === 0 ||\n machine.trainings.map(t => t.disabled).reduce((acc, val) => acc && val, true)) {\n return checkPrepaidPack();\n }\n\n // if the currently logged user booked a training for this machine, tell him that he must wait\n // for an admin to validate the training before he can book the reservation\n if (machine.current_user_next_training_reservation) {\n return setPendingTraining(true);\n }\n\n // if the currently logged user doesn't have booked the required training, tell him to register\n // for a training session first\n setTrainingRequired(true);\n };\n\n /**\n * Once the training condition has been verified, we check if there are prepaid-packs to propose to the customer.\n */\n const checkPrepaidPack = (): void => {\n // if the customer has already bought a pack or if there's no active packs for this machine,\n // or customer has not any subscription if admin active pack only for subscription option\n // let the customer reserve\n if (machine.current_user_has_packs || !machine.has_prepaid_packs_for_current_user || (isPackOnlyForSubscription && !user.subscribed_plan) || !canProposePacks) {\n return onReserveMachine(machine);\n }\n\n // otherwise, we show a dialog modal to propose the customer to buy an available pack\n setProposePacks(true);\n };\n\n return (\n \n \n \n \n {machine && user && }\n \n\n );\n};\n\nconst ReserveButtonWrapper: React.FC = (props) => {\n return (\n \n \n {props.children}\n \n \n );\n};\n\nexport { ReserveButtonWrapper as ReserveButton };\n\nApplication.Components.component('reserveButton', react2angular(ReserveButtonWrapper, ['currentUser', 'machineId', 'onLoadingStart', 'onLoadingEnd', 'onError', 'onSuccess', 'onReserveMachine', 'onLoginRequested', 'onEnrollRequested', 'className', 'canProposePacks']));\n","import { useEffect } from 'react';\nimport { Loader } from '../base/loader';\nimport { useTranslation } from 'react-i18next';\nimport { NotificationPreference } from '../../models/notification-preference';\nimport { useForm } from 'react-hook-form';\nimport { FormSwitch } from '../form/form-switch';\nimport NotificationPreferencesAPI from '../../api/notification_preference';\n\ninterface NotificationFormProps {\n onError: (message: string) => void,\n preference: NotificationPreference\n}\n\n/**\n * Displays the list of notifications\n */\nconst NotificationForm: React.FC = ({ preference, onError }) => {\n const { t } = useTranslation('logged');\n const { handleSubmit, formState, control, reset } = useForm({ defaultValues: { ...preference } });\n\n // Create or Update (if id exists) a Notification Preference\n const onSubmit = (updatedPreference: NotificationPreference) => NotificationPreferencesAPI.update(updatedPreference).catch(onError);\n\n // Calls submit handler on every change of a Form Switch\n const handleChange = () => handleSubmit(onSubmit)();\n\n // Resets form on component mount, and if preference changes (happens when bulk updating a category)\n useEffect(() => {\n reset(preference);\n }, [preference]);\n\n return (\n
\n

{t(`app.logged.notification_form.${preference.notification_type}`)}

\n
\n \n \n
\n
\n );\n};\n\nconst NotificationFormWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { NotificationFormWrapper as NotificationForm };\n","import { Loader } from '../base/loader';\nimport { Notification } from '../../models/notification';\nimport FormatLib from '../../lib/format';\nimport { FabButton } from '../base/fab-button';\nimport { useTranslation } from 'react-i18next';\n\ninterface NotificationInlineProps {\n notification: Notification,\n onUpdate?: (Notification) => void\n}\n\n/**\n * Displays one notification\n */\nconst NotificationInline: React.FC = ({ notification, onUpdate }) => {\n const { t } = useTranslation('logged');\n const createdAt = new Date(notification.created_at);\n\n // Call a parent component method to update the notification\n const update = () => onUpdate(notification);\n\n return (\n
\n
{ FormatLib.date(createdAt) } { FormatLib.time(createdAt) }
\n
\n {onUpdate && { t('app.logged.notification_inline.mark_as_read') }}\n
\n );\n};\n\nconst NotificationInlineWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { NotificationInlineWrapper as NotificationInline };\n","import { Loader } from '../base/loader';\nimport { useTranslation } from 'react-i18next';\nimport { NotificationPreference } from '../../models/notification-preference';\nimport { NotificationForm } from './notification-form';\nimport { FabButton } from '../base/fab-button';\nimport NotificationPreferencesAPI from '../../api/notification_preference';\n\ninterface NotificationsCategoryProps {\n onError: (message: string) => void,\n refreshSettings: () => void,\n categoryName: string,\n preferences: Array\n}\n\n/**\n * Displays the list of notifications\n */\nconst NotificationsCategory: React.FC = ({ onError, categoryName, preferences, refreshSettings }) => {\n const { t } = useTranslation('logged');\n // Triggers a general update to enable all notifications for this category\n const enableAll = () => updateAll(true);\n\n // Triggers a general update to disable all notifications for this category\n const disableAll = () => updateAll(false);\n\n // Update all notifications for this category with a bulk_update.\n // This triggers a refresh of all the forms.\n const updateAll = async (value: boolean) => {\n const updatedPreferences: Array = preferences.map(preference => {\n return { id: preference.id, notification_type: preference.notification_type, in_system: value, email: value };\n });\n await NotificationPreferencesAPI.bulk_update(updatedPreferences).catch(onError);\n refreshSettings();\n };\n\n return (\n <>\n {(preferences.length > 0) &&\n
\n

{`${t(`app.logged.notifications_category.${categoryName}`)}, ${t('app.logged.notifications_category.notify_me_when')}`}

\n
\n
\n {t('app.logged.notifications_category.enable_all')}\n {t('app.logged.notifications_category.disable_all')}\n
\n {preferences.map(preference => )}\n
\n
\n }\n \n );\n};\n\nconst NotificationsCategoryWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { NotificationsCategoryWrapper as NotificationsCategory };\n","import { useState, useEffect } from 'react';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { FabTabs } from '../base/fab-tabs';\nimport { NotificationsList } from './notifications-list';\nimport { NotificationsSettings } from './notifications-settings';\nimport { useTranslation } from 'react-i18next';\nimport MemberAPI from '../../api/member';\nimport { UserRole } from '../../models/user';\n\ndeclare const Application: IApplication;\n\ninterface NotificationsCenterProps {\n onError: (message: string) => void\n}\n\n/**\n * This Admin component groups two tabs : a list of notifications and the notifications settings\n */\nexport const NotificationsCenter: React.FC = ({ onError }) => {\n const { t } = useTranslation('logged');\n const [role, setRole] = useState();\n\n useEffect(() => {\n MemberAPI.current()\n .then(data => setRole(data.role))\n .catch(onError);\n }, []);\n\n return (\n <>\n {role === 'admin' && \n },\n {\n id: 'notifications-list',\n title: t('app.logged.notifications_center.notifications_list'),\n content: \n }\n ]} />}\n {role !== 'admin' && }\n \n );\n};\n\nconst NotificationsCenterWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('notificationsCenter', react2angular(NotificationsCenterWrapper, ['onError']));\n","import { useEffect, useState } from 'react';\nimport { Loader } from '../base/loader';\nimport { Notification, NotificationsTotals } from '../../models/notification';\nimport NotificationAPI from '../../api/notification';\nimport { useTranslation } from 'react-i18next';\nimport { NotificationInline } from './notification-inline';\nimport { FabButton } from '../base/fab-button';\n\ninterface NotificationsListProps {\n onError: (message: string) => void\n}\n\n/**\n * Displays the list of notifications\n */\nconst NotificationsList: React.FC = ({ onError }) => {\n const { t } = useTranslation('logged');\n\n const [notifications, setNotifications] = useState>([]);\n const [totals, setTotals] = useState({ total: 0, unread: 0 });\n const [page, setPage] = useState(1);\n\n const newNotifications = notifications.filter(notification => notification.is_read === false);\n const pastNotifications = notifications.filter(notification => notification.is_read === true);\n\n // Fetch Notification and Notification Totals from API\n const fetchNotifications = () => {\n NotificationAPI.index()\n .then(data => {\n setTotals(data.totals);\n setNotifications(data.notifications);\n })\n .catch(onError);\n };\n\n // Fetch Notifications and Notification Totals on component mount\n useEffect(() => {\n fetchNotifications();\n }, []);\n\n // Call Notifications API to set one notification as read, and fetch the updated Notifications & Totals\n const markAsRead = async (notification: Notification) => {\n await NotificationAPI.update(notification);\n fetchNotifications();\n };\n\n // Call Notifications API to set all notifications as read, and fetch the updated Notifications & Totals\n const markAllAsRead = async () => {\n await NotificationAPI.update_all();\n fetchNotifications();\n };\n\n // Calculate if they are notifications that are not yet displayed\n // If true, allows user to display more notifications\n const isMoreNotifications = (totals.total - notifications.length) > 0;\n\n // Call API to Load More Notifications\n const loadMoreNotifications = () => {\n if (isMoreNotifications) {\n const nextPage = page + 1;\n NotificationAPI.index(nextPage)\n .then(data => {\n setNotifications(prevState => [...prevState, ...data.notifications]);\n setPage(nextPage);\n })\n .catch(onError);\n }\n };\n\n return (\n
\n
\n

{t('app.logged.notifications_list.notifications')}

\n {totals.unread > 0 &&\n \n { t('app.logged.notifications_list.mark_all_as_read')} ({totals.unread})\n }\n
\n {totals.unread === 0 &&

{ t('app.logged.notifications_list.no_new_notifications') }

}\n
\n {newNotifications.map(notification => )}\n
\n {pastNotifications.length > 0 &&\n
\n

{ t('app.logged.notifications_list.archives') }

\n {pastNotifications.length === 0\n ?

{ t('app.logged.notifications_list.no_archived_notifications') }

\n : pastNotifications.map(notification => )\n }\n
\n }\n {isMoreNotifications &&\n \n { t('app.logged.notifications_list.load_the_next_notifications') }\n \n }\n
\n );\n};\n\nconst NotificationsListWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { NotificationsListWrapper as NotificationsList };\n","import { Loader } from '../base/loader';\nimport { useEffect, useState } from 'react';\nimport NotificationPreferencesAPI from '../../api/notification_preference';\nimport { NotificationPreference, NotificationPreferencesByCategories } from '../../models/notification-preference';\nimport { NotificationCategoryNames } from '../../models/notification-type';\nimport { NotificationsCategory } from './notifications-category';\nimport NotificationTypesAPI from '../../api/notification_types';\n\ninterface NotificationsSettingsProps {\n onError: (message: string) => void\n}\n\n/**\n * Displays the list of notifications\n */\nconst NotificationsSettings: React.FC = ({ onError }) => {\n const [preferencesByCategories, setPreferencesCategories] = useState({});\n\n // From a default pattern of categories, and existing preferences and types retrieved from API,\n // this function builds an object with Notification Preferences sorted by categories.\n const fetchNotificationPreferences = async () => {\n let notificationPreferences: Array;\n\n await NotificationPreferencesAPI.index()\n .then(userNotificationPreferences => {\n notificationPreferences = userNotificationPreferences;\n })\n .catch(onError);\n\n NotificationTypesAPI.index({ is_configurable: true })\n .then(notificationTypes => {\n // Initialize an object with every category as keys\n const newPreferencesByCategories: NotificationPreferencesByCategories = {};\n for (const categoryName of NotificationCategoryNames) {\n newPreferencesByCategories[categoryName] = [];\n }\n\n // For every notification type, we check if a notification preference already exists.\n // If there is none, we create one with default values.\n // Each Notification Preference is then placed in the right category.\n notificationTypes.forEach((notificationType) => {\n const existingPreference = notificationPreferences.find((notificationPreference) => {\n return notificationPreference.notification_type === notificationType.name;\n });\n newPreferencesByCategories[notificationType.category].push(\n existingPreference ||\n {\n notification_type: notificationType.name,\n in_system: true,\n email: true\n }\n );\n });\n setPreferencesCategories(newPreferencesByCategories);\n })\n .catch(onError);\n };\n\n // Triggers the fetch Notification Preferences on component mount\n useEffect(() => {\n fetchNotificationPreferences();\n }, []);\n\n return (\n
\n {Object.entries(preferencesByCategories).map((notificationPreferencesCategory) => (\n \n ))\n }\n
\n );\n};\n\nconst NotificationsSettingsWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { NotificationsSettingsWrapper as NotificationsSettings };\n","import {\n PaymentMethod,\n PaymentSchedule,\n PaymentScheduleItem\n} from '../../models/payment-schedule';\nimport { ReactElement, useState } from 'react';\nimport * as React from 'react';\nimport { FabButton } from '../base/fab-button';\nimport { useTranslation } from 'react-i18next';\nimport { User } from '../../models/user';\nimport PaymentScheduleAPI from '../../api/payment-schedule';\nimport { FabModal } from '../base/fab-modal';\nimport FormatLib from '../../lib/format';\nimport { StripeConfirmModal } from '../payment/stripe/stripe-confirm-modal';\nimport { UpdateCardModal } from '../payment/update-card-modal';\nimport { UpdatePaymentMeanModal } from './update-payment-mean-modal';\n\n// we want to display some buttons only once. This is the types of buttons it applies to.\nexport type TypeOnce = 'card-update'|'subscription-cancel'|'update-payment-mean';\n\ninterface PaymentScheduleItemActionsProps {\n paymentScheduleItem: PaymentScheduleItem,\n paymentSchedule: PaymentSchedule,\n onError: (message: string) => void,\n onSuccess: () => void,\n onCardUpdateSuccess: () => void\n operator: User,\n displayOnceMap: Map>,\n show: boolean,\n}\n\n/**\n * This component is responsible for rendering the actions buttons for a payment schedule item.\n */\nexport const PaymentScheduleItemActions: React.FC = ({ paymentScheduleItem, paymentSchedule, onError, onSuccess, onCardUpdateSuccess, displayOnceMap, operator, show }) => {\n const { t } = useTranslation('shared');\n\n // is open, the modal dialog to cancel the associated subscription?\n const [showCancelSubscription, setShowCancelSubscription] = useState(false);\n // is open, the modal dialog to confirm the cashing of a check?\n const [showConfirmCashing, setShowConfirmCashing] = useState(false);\n // is open, the modal dialog to confirm a back transfer?\n const [showConfirmTransfer, setShowConfirmTransfer] = useState(false);\n // is open, the modal dialog the resolve a pending card payment?\n const [showResolveAction, setShowResolveAction] = useState(false);\n // is open, the modal dialog to update the card details\n const [showUpdateCard, setShowUpdateCard] = useState(false);\n // is open, the modal dialog to update the payment mean\n const [showUpdatePaymentMean, setShowUpdatePaymentMean] = useState(false);\n // the user cannot confirm the action modal (3D secure), unless he has resolved the pending action\n const [isConfirmActionDisabled, setConfirmActionDisabled] = useState(true);\n\n /**\n * Check if the current operator has administrative rights or is a normal member\n */\n const isPrivileged = (): boolean => {\n return (operator.role === 'admin' || operator.role === 'manager');\n };\n\n /**\n * Return a button to download a PDF invoice file\n */\n const downloadInvoiceButton = (id: number): JSX.Element => {\n const link = `api/invoices/${id}/download`;\n return (\n \n \n {t('app.shared.payment_schedule_item_actions.download')}\n \n );\n };\n\n /**\n * Return a button to cancel the given subscription, if the user is privileged enough\n */\n const cancelSubscriptionButton = (): ReactElement => {\n const displayOnceStatus = displayOnceMap.get('subscription-cancel').get(paymentSchedule.id);\n if (isPrivileged() && (!displayOnceStatus || displayOnceStatus === paymentScheduleItem.id)) {\n displayOnceMap.get('subscription-cancel').set(paymentSchedule.id, paymentScheduleItem.id);\n return (\n }>\n {t('app.shared.payment_schedule_item_actions.cancel_subscription')}\n \n );\n }\n };\n\n /**\n * Return a button to confirm the receipt of the bank transfer, if the user is privileged enough\n */\n const confirmTransferButton = (): ReactElement => {\n if (isPrivileged()) {\n return (\n }>\n {t('app.shared.payment_schedule_item_actions.confirm_payment')}\n \n );\n }\n };\n\n /**\n * Return a button to confirm the cashing of the check, if the user is privileged enough\n */\n const confirmCheckButton = (): ReactElement => {\n if (isPrivileged()) {\n return (\n }>\n {t('app.shared.payment_schedule_item_actions.confirm_check')}\n \n );\n }\n };\n\n /**\n * Return a button to resolve the 3DS security check\n */\n const solveActionButton = (): ReactElement => {\n return (\n }>\n {t('app.shared.payment_schedule_item_actions.resolve_action')}\n \n );\n };\n\n /**\n * Return a button to update the default payment mean for the current payment schedule\n */\n const updatePaymentMeanButton = (): ReactElement => {\n const displayOnceStatus = displayOnceMap.get('update-payment-mean').get(paymentSchedule.id);\n if (isPrivileged() && (!displayOnceStatus || displayOnceStatus === paymentScheduleItem.id)) {\n displayOnceMap.get('update-payment-mean').set(paymentSchedule.id, paymentScheduleItem.id);\n return (\n }>\n {t('app.shared.payment_schedule_item_actions.update_payment_mean')}\n \n );\n }\n };\n\n /**\n * Return a button to update the credit card associated with the payment schedule\n */\n const updateCardButton = (): ReactElement => {\n const displayOnceStatus = displayOnceMap.get('card-update').get(paymentSchedule.id);\n if (!displayOnceStatus || displayOnceStatus === paymentScheduleItem.id) {\n displayOnceMap.get('card-update').set(paymentSchedule.id, paymentScheduleItem.id);\n return (\n }>\n {t('app.shared.payment_schedule_item_actions.update_card')}\n \n );\n }\n };\n\n /**\n * Return the actions button(s) for current paymentScheduleItem with state Pending\n */\n const pendingActions = (): ReactElement => {\n if (isPrivileged()) {\n if (paymentSchedule.payment_method === PaymentMethod.Transfer) {\n return confirmTransferButton();\n }\n if (paymentSchedule.payment_method === PaymentMethod.Check) {\n return confirmCheckButton();\n }\n } else {\n return {t('app.shared.payment_schedule_item_actions.please_ask_reception')};\n }\n };\n\n /**\n * Return the actions button(s) for current paymentScheduleItem with state Error or GatewayCanceled\n */\n const errorActions = (): ReactElement[] => {\n // if the payment schedule is canceled/in error, the schedule is over, and we can't update the card\n displayOnceMap.get('card-update').set(paymentSchedule.id, paymentScheduleItem.id);\n\n const buttons = [];\n if (isPrivileged()) {\n buttons.push(cancelSubscriptionButton());\n buttons.push(updatePaymentMeanButton());\n } else {\n buttons.push({t('app.shared.payment_schedule_item_actions.please_ask_reception')});\n }\n return buttons;\n };\n\n /**\n * Return the actions button(s) for current paymentScheduleItem with state New\n */\n const newActions = (): Array => {\n const buttons = [];\n if (paymentSchedule.payment_method === PaymentMethod.Card) {\n buttons.push(updateCardButton());\n }\n if (isPrivileged()) {\n buttons.push(cancelSubscriptionButton());\n }\n return buttons;\n };\n\n /**\n * Show/hide the modal dialog to cancel the current subscription\n */\n const toggleCancelSubscriptionModal = (): void => {\n setShowCancelSubscription(!showCancelSubscription);\n };\n\n /**\n * Show/hide the modal dialog that enable to confirm the cashing of the check for a given deadline.\n */\n const toggleConfirmCashingModal = (): void => {\n setShowConfirmCashing(!showConfirmCashing);\n };\n\n /**\n * Show/hide the modal dialog that enable to confirm the bank transfer for a given deadline.\n */\n const toggleConfirmTransferModal = (): void => {\n setShowConfirmTransfer(!showConfirmTransfer);\n };\n\n /**\n * Show/hide the modal dialog that trigger the card \"action\".\n */\n const toggleResolveActionModal = (): void => {\n setShowResolveAction(!showResolveAction);\n };\n\n /**\n * Enable/disable the confirm button of the \"action\" modal\n */\n const toggleConfirmActionButton = (): void => {\n setConfirmActionDisabled(!isConfirmActionDisabled);\n };\n\n /**\n * Show/hide the modal dialog to update the bank card details\n */\n const toggleUpdateCardModal = (): void => {\n setShowUpdateCard(!showUpdateCard);\n };\n\n /**\n * Show/hide the modal dialog to update the payment mean\n */\n const toggleUpdatePaymentMeanModal = (): void => {\n setShowUpdatePaymentMean(!showUpdatePaymentMean);\n };\n\n /**\n * After the user has confirmed that he wants to cash the check, update the API, refresh the list and close the modal.\n */\n const onCheckCashingConfirmed = (): void => {\n PaymentScheduleAPI.cashCheck(paymentScheduleItem.id).then((res) => {\n if (res.state === 'paid') {\n onSuccess();\n toggleConfirmCashingModal();\n }\n });\n };\n\n /**\n * After the user has confirmed that he validates the transfer, update the API, refresh the list and close the modal.\n */\n const onTransferConfirmed = (): void => {\n PaymentScheduleAPI.confirmTransfer(paymentScheduleItem.id).then((res) => {\n if (res.state === 'paid') {\n onSuccess();\n toggleConfirmTransferModal();\n }\n });\n };\n\n /**\n * When the card was successfully updated, pay the invoice (using the new payment method) and close the modal\n */\n const handleCardUpdateSuccess = (): void => {\n if (paymentScheduleItem.state === 'requires_payment_method') {\n PaymentScheduleAPI.payItem(paymentScheduleItem.id).then(() => {\n onSuccess();\n onCardUpdateSuccess();\n toggleUpdateCardModal();\n }).catch((err) => {\n onError(err);\n });\n } else {\n // the user is updating his card number in a pro-active way, we don't need to trigger the payment\n onCardUpdateSuccess();\n toggleUpdateCardModal();\n }\n };\n\n /**\n * When the user has confirmed the cancellation, we transfer the request to the API\n */\n const onCancelSubscriptionConfirmed = (): void => {\n PaymentScheduleAPI.cancel(paymentSchedule.id).then(() => {\n onSuccess();\n toggleCancelSubscriptionModal();\n });\n };\n\n /**\n * After the 3DS confirmation was done (successfully or not), ask the API to refresh the item status,\n * then refresh the list and close the modal\n */\n const afterConfirmAction = (): void => {\n toggleConfirmActionButton();\n PaymentScheduleAPI.refreshItem(paymentScheduleItem.id).then(() => {\n onSuccess();\n toggleResolveActionModal();\n });\n };\n\n /**\n * When the update of the payment mean was successful, refresh the list and close the modal\n */\n const onPaymentMeanUpdateSuccess = (): void => {\n onSuccess();\n toggleUpdatePaymentMeanModal();\n };\n\n if (!show) return null;\n\n return (\n \n {paymentScheduleItem.state === 'paid' && downloadInvoiceButton(paymentScheduleItem.invoice_id)}\n {paymentScheduleItem.state === 'pending' && pendingActions()}\n {paymentScheduleItem.state === 'requires_action' && solveActionButton()}\n {paymentScheduleItem.state === 'requires_payment_method' && updateCardButton()}\n {paymentScheduleItem.state === 'error' && errorActions()}\n {paymentScheduleItem.state === 'gateway_canceled' && errorActions()}\n {paymentScheduleItem.state === 'new' && newActions()}\n
\n {/* Confirm the cashing of the current deadline by check */}\n \n \n {t('app.shared.payment_schedule_item_actions.confirm_check_cashing_body', {\n AMOUNT: FormatLib.price(paymentScheduleItem.amount),\n DATE: FormatLib.date(paymentScheduleItem.due_date)\n })}\n \n \n {/* Confirm the bank transfer for the current deadline */}\n \n \n {t('app.shared.payment_schedule_item_actions.confirm_bank_transfer_body', {\n AMOUNT: FormatLib.price(paymentScheduleItem.amount),\n DATE: FormatLib.date(paymentScheduleItem.due_date)\n })}\n \n \n {/* Cancel the subscription */}\n \n {t('app.shared.payment_schedule_item_actions.confirm_cancel_subscription')}\n \n {/* 3D secure confirmation */}\n \n {/* Update credit card */}\n \n \n {/* Update the payment mean */}\n \n
\n
\n );\n};\n\nPaymentScheduleItemActions.defaultProps = { show: false };\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport '../../lib/i18n';\nimport { Loader } from '../base/loader';\nimport { FabModal } from '../base/fab-modal';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport { IApplication } from '../../models/application';\nimport FormatLib from '../../lib/format';\n\ndeclare const Application: IApplication;\n\ninterface PaymentScheduleSummaryProps {\n schedule: PaymentSchedule\n}\n\n/**\n * This component displays a summary of the monthly payment schedule for the current cart, with a subscription\n */\nexport const PaymentScheduleSummary: React.FC = ({ schedule }) => {\n const { t } = useTranslation('shared');\n\n // is open, the modal dialog showing the full details of the payment schedule?\n const [modal, setModal] = useState(false);\n\n /**\n * Test if all payment deadlines have the same amount\n */\n const hasEqualDeadlines = (): boolean => {\n const prices = schedule.items.map(i => i.amount);\n return prices.every(p => p === prices[0]);\n };\n /**\n * Open or closes the modal dialog showing the full payment schedule\n */\n const toggleFullScheduleModal = (): void => {\n setModal(!modal);\n };\n\n return (\n
\n
\n

{ t('app.shared.payment_schedule_summary.your_payment_schedule') }

\n {hasEqualDeadlines() &&
    \n
  • \n \n {t('app.shared.payment_schedule_summary.NUMBER_monthly_payment_of_AMOUNT', { NUMBER: schedule.items.length, AMOUNT: FormatLib.price(schedule.items[0].amount) })}\n \n {t('app.shared.payment_schedule_summary.first_debit')}\n
  • \n
}\n {!hasEqualDeadlines() &&
    \n
  • \n {t('app.shared.payment_schedule_summary.monthly_payment_NUMBER', { NUMBER: 1 })}\n {FormatLib.price(schedule.items[0].amount)}\n {t('app.shared.payment_schedule_summary.debit')}\n
  • \n
  • \n \n {t('app.shared.payment_schedule_summary.NUMBER_monthly_payment_of_AMOUNT', { NUMBER: schedule.items.length - 1, AMOUNT: FormatLib.price(schedule.items[1].amount) })}\n \n
  • \n
}\n \n \n
    \n {schedule.items.map(item => (\n
  • \n {FormatLib.date(item.due_date)}\n \n {FormatLib.price(item.amount)}\n
  • \n ))}\n
\n
\n
\n
\n );\n};\n\nconst PaymentScheduleSummaryWrapper: React.FC = ({ schedule }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('paymentScheduleSummary', react2angular(PaymentScheduleSummaryWrapper, ['schedule']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { PaymentSchedulesTable } from './payment-schedules-table';\nimport { FabButton } from '../base/fab-button';\nimport { Loader } from '../base/loader';\nimport { User } from '../../models/user';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport { IApplication } from '../../models/application';\nimport PaymentScheduleAPI from '../../api/payment-schedule';\n\ndeclare const Application: IApplication;\n\ninterface PaymentSchedulesDashboardProps {\n currentUser: User,\n onError: (message: string) => void,\n onCardUpdateSuccess: (message: string) => void,\n}\n\n// how many payment schedules should we display for each page?\nconst PAGE_SIZE = 20;\n\n/**\n * This component shows a list of all payment schedules with their associated deadlines (aka. PaymentScheduleItem) and invoices\n * for the currentUser\n */\nexport const PaymentSchedulesDashboard: React.FC = ({ currentUser, onError, onCardUpdateSuccess }) => {\n const { t } = useTranslation('logged');\n\n // list of displayed payment schedules\n const [paymentSchedules, setPaymentSchedules] = useState>([]);\n // current page\n const [pageNumber, setPageNumber] = useState(1);\n\n /**\n * When the component is loaded first, refresh the list of schedules to fill the first page.\n */\n useEffect(() => {\n handleRefreshList();\n }, []);\n\n /**\n * Fetch from the API the next payment schedules to display, for the current filters, and append them to the current results table.\n */\n const handleLoadMore = (): void => {\n setPageNumber(pageNumber + 1);\n\n PaymentScheduleAPI.index({ query: { page: pageNumber + 1, size: PAGE_SIZE } }).then((res) => {\n const list = paymentSchedules.concat(res);\n setPaymentSchedules(list);\n }).catch((error) => onError(error.message));\n };\n\n /**\n * Reload from te API all the currently displayed payment schedules\n */\n const handleRefreshList = (): void => {\n PaymentScheduleAPI.index({ query: { page: 1, size: PAGE_SIZE * pageNumber } }).then((res) => {\n setPaymentSchedules(res);\n }).catch((err) => {\n onError(err.message);\n });\n };\n\n /**\n * after a successful card update, provide a success message to the end-user\n */\n const handleCardUpdateSuccess = (): void => {\n onCardUpdateSuccess(t('app.logged.dashboard.payment_schedules_dashboard.card_updated_success'));\n };\n\n /**\n * Check if the current collection of payment schedules is empty or not.\n */\n const hasSchedules = (): boolean => {\n return paymentSchedules.length > 0;\n };\n\n /**\n * Check if there are some results for the current filters that aren't currently shown.\n */\n const hasMoreSchedules = (): boolean => {\n return hasSchedules() && paymentSchedules.length < paymentSchedules[0].max_length;\n };\n\n return (\n
\n {!hasSchedules() &&
{t('app.logged.dashboard.payment_schedules_dashboard.no_payment_schedules')}
}\n {hasSchedules() &&
\n \n {hasMoreSchedules() && {t('app.logged.dashboard.payment_schedules_dashboard.load_more')}}\n
}\n
\n );\n};\n\nconst PaymentSchedulesDashboardWrapper: React.FC = ({ currentUser, onError, onCardUpdateSuccess }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('paymentSchedulesDashboard', react2angular(PaymentSchedulesDashboardWrapper, ['currentUser', 'onError', 'onCardUpdateSuccess']));\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { DocumentFilters } from '../document-filters';\nimport { PaymentSchedulesTable } from './payment-schedules-table';\nimport { FabButton } from '../base/fab-button';\nimport { Loader } from '../base/loader';\nimport { User } from '../../models/user';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport { IApplication } from '../../models/application';\nimport PaymentScheduleAPI from '../../api/payment-schedule';\nimport { TDateISODate } from '../../typings/date-iso';\n\ndeclare const Application: IApplication;\n\ninterface PaymentSchedulesListProps {\n currentUser: User,\n onError: (message: string) => void,\n onCardUpdateSuccess: (message: string) => void,\n}\n\n// how many payment schedules should we display for each page?\nconst PAGE_SIZE = 20;\n\n/**\n * This component shows a list of all payment schedules with their associated deadlines (aka. PaymentScheduleItem) and invoices\n */\nexport const PaymentSchedulesList: React.FC = ({ currentUser, onError, onCardUpdateSuccess }) => {\n const { t } = useTranslation('admin');\n\n // list of displayed payment schedules\n const [paymentSchedules, setPaymentSchedules] = useState>([]);\n // current page\n const [pageNumber, setPageNumber] = useState(1);\n // current filter, by reference, for the schedules\n const [referenceFilter, setReferenceFilter] = useState(null);\n // current filter, by customer's name, for the schedules\n const [customerFilter, setCustomerFilter] = useState(null);\n // current filter, by date, for the schedules and the deadlines\n const [dateFilter, setDateFilter] = useState(null);\n\n /**\n * Fetch from the API the payments schedules matching the given filters and reset the results table with the new schedules.\n */\n const handleFiltersChange = ({ reference, customer, date }): void => {\n setReferenceFilter(reference);\n setCustomerFilter(customer);\n setDateFilter(date);\n\n PaymentScheduleAPI.list({ query: { reference, customer, date, page: 1, size: PAGE_SIZE } }).then((res) => {\n setPaymentSchedules(res);\n }).catch((error) => onError(error.message));\n };\n\n /**\n * Fetch from the API the next payment schedules to display, for the current filters, and append them to the current results table.\n */\n const handleLoadMore = (): void => {\n setPageNumber(pageNumber + 1);\n\n PaymentScheduleAPI.list({ query: { reference: referenceFilter, customer: customerFilter, date: dateFilter, page: pageNumber + 1, size: PAGE_SIZE } }).then((res) => {\n const list = paymentSchedules.concat(res);\n setPaymentSchedules(list);\n }).catch((error) => onError(error.message));\n };\n\n /**\n * Reload from te API all the currently displayed payment schedules\n */\n const handleRefreshList = (): void => {\n PaymentScheduleAPI.list({ query: { reference: referenceFilter, customer: customerFilter, date: dateFilter, page: 1, size: PAGE_SIZE * pageNumber } }).then((res) => {\n setPaymentSchedules(res);\n }).catch((err) => {\n onError(err.message);\n });\n };\n\n /**\n * Check if the current collection of payment schedules is empty or not.\n */\n const hasSchedules = (): boolean => {\n return paymentSchedules.length > 0;\n };\n\n /**\n * Check if there are some results for the current filters that aren't currently shown.\n */\n const hasMoreSchedules = (): boolean => {\n return hasSchedules() && paymentSchedules.length < paymentSchedules[0].max_length;\n };\n\n /**\n * after a successful card update, provide a success message to the operator\n */\n const handleCardUpdateSuccess = (): void => {\n onCardUpdateSuccess(t('app.admin.invoices.payment_schedules_list.card_updated_success'));\n };\n\n return (\n
\n

\n \n {t('app.admin.invoices.payment_schedules_list.filter_schedules')}\n

\n
\n \n
\n {!hasSchedules() &&
{t('app.admin.invoices.payment_schedules_list.no_payment_schedules')}
}\n {hasSchedules() &&
\n \n {hasMoreSchedules() && {t('app.admin.invoices.payment_schedules_list.load_more')}}\n
}\n
\n );\n};\n\nconst PaymentSchedulesListWrapper: React.FC = ({ currentUser, onError, onCardUpdateSuccess }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('paymentSchedulesList', react2angular(PaymentSchedulesListWrapper, ['currentUser', 'onError', 'onCardUpdateSuccess']));\n","import { ReactEventHandler, useState, useEffect, ReactElement } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Loader } from '../base/loader';\nimport _ from 'lodash';\nimport { User } from '../../models/user';\nimport type { PaymentSchedule, PaymentScheduleItem } from '../../models/payment-schedule';\nimport FormatLib from '../../lib/format';\nimport { PaymentScheduleItemActions, TypeOnce } from './payment-schedule-item-actions';\nimport { StripeElements } from '../payment/stripe/stripe-elements';\nimport SettingAPI from '../../api/setting';\nimport { Setting } from '../../models/setting';\n\ninterface PaymentSchedulesTableProps {\n paymentSchedules: Array,\n showCustomer?: boolean,\n refreshList: () => void,\n operator: User,\n onError: (message: string) => void,\n onCardUpdateSuccess: () => void\n}\n\n/**\n * This component shows a list of all payment schedules with their associated deadlines (aka. PaymentScheduleItem) and invoices\n */\nconst PaymentSchedulesTable: React.FC = ({ paymentSchedules, showCustomer, refreshList, operator, onError, onCardUpdateSuccess }) => {\n const { t } = useTranslation('shared');\n\n // for each payment schedule: are the details (all deadlines) shown or hidden?\n const [showExpanded, setShowExpanded] = useState>(new Map());\n // we want to display some buttons only once. This map keep track of the buttons that have been displayed.\n const [displayOnceMap] = useState>>(new Map([\n ['subscription-cancel', new Map()],\n ['card-update', new Map()],\n ['update-payment-mean', new Map()]\n ]));\n const [gateway, setGateway] = useState(null);\n\n useEffect(() => {\n SettingAPI.get('payment_gateway')\n .then(setting => setGateway(setting))\n .catch(error => onError(error));\n }, []);\n\n /**\n * Check if the requested payment schedule is displayed with its deadlines (PaymentScheduleItem) or without them\n */\n const isExpanded = (paymentScheduleId: number): boolean => {\n return showExpanded.get(paymentScheduleId);\n };\n\n /**\n * Return the value for the CSS property 'display', for the payment schedule deadlines\n */\n const statusDisplay = (paymentScheduleId: number): string => {\n if (isExpanded(paymentScheduleId)) {\n return 'table-row';\n } else {\n return 'none';\n }\n };\n\n /**\n * Return the action icon for showing/hiding the deadlines\n */\n const expandCollapseIcon = (paymentScheduleId: number): JSX.Element => {\n if (isExpanded(paymentScheduleId)) {\n // eslint-disable-next-line fabmanager/component-class-named-as-component\n return ;\n } else {\n // eslint-disable-next-line fabmanager/component-class-named-as-component\n return ;\n }\n };\n\n /**\n * Show or hide the deadlines for the provided payment schedule, inverting their current status\n */\n const togglePaymentScheduleDetails = (paymentScheduleId: number): ReactEventHandler => {\n return (): void => {\n if (isExpanded(paymentScheduleId)) {\n setShowExpanded((prev) => new Map(prev).set(paymentScheduleId, false));\n } else {\n setShowExpanded((prev) => new Map(prev).set(paymentScheduleId, true));\n }\n };\n };\n\n /**\n * Return a button to download a PDF file, may be an invoice, or a payment schedule, depending or the provided parameters\n */\n const downloadScheduleButton = (id: number): JSX.Element => {\n const link = `api/payment_schedules/${id}/download`;\n return (\n // eslint-disable-next-line fabmanager/component-class-named-as-component\n \n \n {t('app.shared.payment_schedules_table.download')}\n \n );\n };\n\n /**\n * Return the human-readable string for the status of the provided deadline.\n */\n const formatState = (item: PaymentScheduleItem, schedule: PaymentSchedule): JSX.Element => {\n let res = t(`app.shared.payment_schedules_table.state_${item.state}${item.state === 'pending' ? '_' + schedule.payment_method : ''}`);\n if (item.state === 'paid') {\n const key = `app.shared.payment_schedules_table.method_${item.payment_method}`;\n res += ` (${t(key)})`;\n }\n // eslint-disable-next-line fabmanager/component-class-named-as-component\n return {res};\n };\n\n /**\n * Refresh all payment schedules in the table\n */\n const refreshSchedulesTable = (): void => {\n refreshList();\n };\n\n /**\n * Return the JSX table element that list all payment schedules and allows to perform actions on them.\n */\n const renderPaymentSchedulesTable = (): ReactElement => {\n return (\n \n \n \n \n \n \n {showCustomer && }\n \n \n \n {paymentSchedules.map(p => \n \n )}\n \n
\n {t('app.shared.payment_schedules_table.schedule_num')}{t('app.shared.payment_schedules_table.date')}{t('app.shared.payment_schedules_table.price')}{t('app.shared.payment_schedules_table.customer')}\n
\n \n \n \n \n \n \n \n {showCustomer && }\n \n \n \n \n \n \n
{expandCollapseIcon(p.id)}{p.reference}{FormatLib.date(_.minBy(p.items, 'due_date').due_date)}{FormatLib.price(p.total)}{p.user.name}{downloadScheduleButton(p.id)}
\n \n
\n \n \n \n \n \n \n \n \n \n {_.orderBy(p.items, 'due_date').map(item => \n \n \n \n \n )}\n \n
{t('app.shared.payment_schedules_table.deadline')}{t('app.shared.payment_schedules_table.amount')}{t('app.shared.payment_schedules_table.state')}\n
{FormatLib.date(item.due_date)}{FormatLib.price(item.amount)}{formatState(item, p)}\n \n
\n
\n
\n
\n );\n };\n\n /**\n * Determine which gateway is enabled and return the appropriate payment schedules\n */\n if (gateway === null) return
;\n\n switch (gateway.value) {\n case 'stripe':\n return (\n \n {renderPaymentSchedulesTable()}\n \n );\n case 'payzen':\n case null:\n return (\n
\n {renderPaymentSchedulesTable()}\n
\n );\n default:\n console.error(`[PaymentSchedulesTable] Unimplemented gateway: ${gateway.value}`);\n return
;\n }\n};\nPaymentSchedulesTable.defaultProps = { showCustomer: false };\n\nconst PaymentSchedulesTableWrapper: React.FC = ({ paymentSchedules, showCustomer, refreshList, operator, onError, onCardUpdateSuccess }) => {\n return (\n \n \n \n );\n};\n\nexport { PaymentSchedulesTableWrapper as PaymentSchedulesTable };\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport Switch from 'react-switch';\nimport '../../lib/i18n';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\n\ndeclare const Application: IApplication;\n\ninterface SelectScheduleProps {\n show: boolean,\n selected: boolean,\n onChange: (selected: boolean) => void,\n className?: string,\n}\n\n/**\n * This component is a switch enabling the users to choose if they want to pay by monthly schedule\n * or with a one time payment\n */\nexport const SelectSchedule: React.FC = ({ show, selected, onChange, className }) => {\n const { t } = useTranslation('shared');\n\n return (\n
\n {show &&
\n \n \n
}\n
\n );\n};\n\nconst SelectScheduleWrapper: React.FC = ({ show, selected, onChange, className }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('selectSchedule', react2angular(SelectScheduleWrapper, ['show', 'selected', 'onChange', 'className']));\n","import * as React from 'react';\nimport Select from 'react-select';\nimport { useTranslation } from 'react-i18next';\nimport { FabModal } from '../base/fab-modal';\nimport { PaymentMethod, PaymentSchedule } from '../../models/payment-schedule';\nimport PaymentScheduleAPI from '../../api/payment-schedule';\nimport { SelectOption } from '../../models/select';\n\ninterface UpdatePaymentMeanModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onError: (message: string) => void,\n afterSuccess: () => void,\n paymentSchedule: PaymentSchedule\n}\n\n/**\n * Component to allow the member to change his payment mean for the given payment schedule (e.g. from card to transfer)\n */\nexport const UpdatePaymentMeanModal: React.FC = ({ isOpen, toggleModal, onError, afterSuccess, paymentSchedule }) => {\n const { t } = useTranslation('admin');\n\n const [paymentMean, setPaymentMean] = React.useState();\n\n /**\n * Convert all payment means to the react-select format\n */\n const buildOptions = (): Array> => {\n return Object.keys(PaymentMethod).filter(pm => PaymentMethod[pm] !== PaymentMethod.Card).map(pm => {\n return { value: PaymentMethod[pm], label: t(`app.admin.update_payment_mean_modal.method_${pm}`) };\n });\n };\n\n /**\n * When the payment mean is changed in the select, update the state\n */\n const handleMeanSelected = (option: SelectOption): void => {\n setPaymentMean(option.value);\n };\n\n /**\n * When the user clicks on the update button, update the default payment mean for the given payment schedule\n */\n const handlePaymentMeanUpdate = (): void => {\n PaymentScheduleAPI.update({\n id: paymentSchedule.id,\n payment_method: paymentMean\n }).then(() => {\n afterSuccess();\n }).catch(error => {\n onError(error.message);\n });\n };\n\n return (\n \n {t('app.admin.update_payment_mean_modal.update_info')}\n \n \n );\n};\n","import { FunctionComponent, ReactNode, useEffect, useRef, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport WalletLib from '../../lib/wallet';\nimport { WalletInfo } from './wallet-info';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { CustomAsset, CustomAssetName } from '../../models/custom-asset';\nimport { ShoppingCart } from '../../models/payment';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport { User } from '../../models/user';\nimport CustomAssetAPI from '../../api/custom-asset';\nimport PriceAPI from '../../api/price';\nimport WalletAPI from '../../api/wallet';\nimport { Invoice } from '../../models/invoice';\nimport SettingAPI from '../../api/setting';\nimport { GoogleTagManager } from '../../models/gtm';\nimport { ComputePriceResult } from '../../models/price';\nimport { Wallet } from '../../models/wallet';\nimport FormatLib from '../../lib/format';\nimport { Order } from '../../models/order';\nimport { computePriceWithCoupon } from '../../lib/coupon';\n\nexport interface GatewayFormProps {\n onSubmit: () => void,\n onSuccess: (result: Invoice|PaymentSchedule|Order) => void,\n onError: (message: string) => void,\n customer: User,\n operator: User,\n className?: string,\n paymentSchedule?: PaymentSchedule,\n cart?: ShoppingCart,\n order?: Order,\n updateCart?: (cart: ShoppingCart) => void,\n formId: string,\n}\n\ninterface AbstractPaymentModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n afterSuccess: (result: Invoice|PaymentSchedule|Order) => void,\n onError: (message: string) => void,\n cart: ShoppingCart,\n order?: Order,\n updateCart?: (cart: ShoppingCart) => void,\n currentUser: User,\n schedule?: PaymentSchedule,\n customer: User,\n logoFooter: ReactNode,\n GatewayForm: FunctionComponent,\n formId: string,\n className?: string,\n formClassName?: string,\n title?: string,\n preventCgv?: boolean,\n preventScheduleInfo?: boolean,\n modalSize?: ModalSize,\n}\n\ndeclare const GTM: GoogleTagManager;\n\n/**\n * This component is an abstract modal that must be extended by each payment gateway to include its payment form.\n *\n * This component must not be called directly but must be extended for each implemented payment gateway.\n * @see https://reactjs.org/docs/composition-vs-inheritance.html\n */\nexport const AbstractPaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, updateCart, currentUser, schedule, customer, logoFooter, GatewayForm, formId, className, formClassName, title, preventCgv, preventScheduleInfo, modalSize, order }) => {\n // customer's wallet\n const [wallet, setWallet] = useState(null);\n // server-computed price with all details\n const [price, setPrice] = useState(null);\n // remaining price = total price - wallet amount\n const [remainingPrice, setRemainingPrice] = useState(0);\n // is the component ready to display?\n const [ready, setReady] = useState(false);\n // errors to display in the UI (gateway errors mainly)\n const [errors, setErrors] = useState(null);\n // are we currently processing the payment (ie. the form was submit, but the process is still running)?\n const [submitState, setSubmitState] = useState(false);\n // did the user accepts the terms of services (CGV)?\n const [tos, setTos] = useState(false);\n // currently active payment gateway\n const [gateway, setGateway] = useState(null);\n // the sales conditions\n const [cgv, setCgv] = useState(null);\n // is the component mounted\n const mounted = useRef(false);\n\n const { t } = useTranslation('shared');\n\n /**\n * When the component loads first, get the name of the currently active payment modal\n */\n useEffect(() => {\n mounted.current = true;\n CustomAssetAPI.get(CustomAssetName.CgvFile).then(asset => setCgv(asset));\n SettingAPI.get('payment_gateway').then((setting) => {\n // we capitalize the first letter of the name\n if (setting.value) {\n setGateway(setting.value.replace(/^\\w/, (c) => c.toUpperCase()));\n }\n });\n\n return () => { mounted.current = false; };\n }, []);\n\n /**\n * On each display:\n * - Refresh the wallet\n * - Refresh the price\n * - Refresh the remaining price\n */\n useEffect(() => {\n if (order && order?.user?.id) {\n WalletAPI.getByUser(order.user.id).then((wallet) => {\n setWallet(wallet);\n const p = { price: computePriceWithCoupon(order.total, order.coupon), price_without_coupon: order.total };\n setPrice(p);\n setRemainingPrice(new WalletLib(wallet).computeRemainingPrice(p.price));\n setReady(true);\n });\n } else if (cart && cart.customer_id) {\n WalletAPI.getByUser(cart.customer_id).then((wallet) => {\n setWallet(wallet);\n PriceAPI.compute(cart).then((res) => {\n setPrice(res);\n setRemainingPrice(new WalletLib(wallet).computeRemainingPrice(res.price));\n setReady(true);\n });\n });\n }\n }, [cart, order]);\n\n /**\n * Check if there is currently an error to display\n */\n const hasErrors = (): boolean => {\n return errors !== null;\n };\n\n /**\n * Check if the user accepts the Terms of Sales document\n */\n const hasCgv = (): boolean => {\n return cgv != null && !preventCgv;\n };\n\n /**\n * Triggered when the user accepts or declines the Terms of Sales\n */\n const toggleTos = (): void => {\n setTos(!tos);\n };\n\n /**\n * Check if we must display the info box about the payment schedule\n */\n const hasPaymentScheduleInfo = (): boolean => {\n return schedule !== undefined && !preventScheduleInfo;\n };\n\n /**\n * Set the component as 'currently submitting'\n */\n const handleSubmit = (): void => {\n setSubmitState(true);\n };\n\n /**\n * After sending the form with success, process the resulting payment method\n */\n const handleFormSuccess = async (result: Invoice|PaymentSchedule|Order): Promise => {\n setSubmitState(false);\n GTM.trackPurchase(result.id, result.total);\n afterSuccess(result);\n };\n\n /**\n * When the payment form raises an error, it is handled by this callback which display it in the modal.\n */\n const handleFormError = (message: string): void => {\n if (mounted.current) {\n setSubmitState(false);\n setErrors(message);\n } else {\n onError(message);\n }\n };\n\n /**\n * Check the form can be submitted.\n * => We're not currently already submitting the form, and, if the terms of service are enabled, the user must agree with them.\n */\n const canSubmit = (): boolean => {\n let terms = true;\n if (hasCgv()) { terms = tos; }\n return !submitState && terms;\n };\n\n /**\n * Build the modal title. If the provided title is a shared translation key, interpolate it through the\n * translation service. Otherwise, just display the provided string.\n */\n const getTitle = (): string => {\n if (title.match(/^app\\.shared\\./)) {\n return t(title);\n }\n return title;\n };\n\n return (\n \n {ready &&
\n \n \n {hasErrors() &&
\n {errors}\n
}\n {hasPaymentScheduleInfo() &&
\n \n
}\n {hasCgv() &&
\n \n \n
}\n
\n {!submitState && }\n {submitState &&
\n
\n \n
\n
}\n
}\n
\n );\n};\n\nAbstractPaymentModal.defaultProps = {\n title: 'app.shared.abstract_payment_modal.online_payment',\n preventCgv: false,\n preventScheduleInfo: false,\n modalSize: ModalSize.medium\n};\n","import { ReactElement, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { StripeModal } from './stripe/stripe-modal';\nimport { PayzenModal } from './payzen/payzen-modal';\nimport { PagseguroModal } from './pagseguro/pagseguro-modal';\nimport { IApplication } from '../../models/application';\nimport { ShoppingCart } from '../../models/payment';\nimport { User } from '../../models/user';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport { Setting } from '../../models/setting';\nimport { Invoice } from '../../models/invoice';\nimport SettingAPI from '../../api/setting';\nimport { useTranslation } from 'react-i18next';\nimport { Order } from '../../models/order';\nimport { GetnetModal } from './getnet/getnet-modal';\n\ndeclare const Application: IApplication;\n\ninterface CardPaymentModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n afterSuccess: (result: Invoice|PaymentSchedule|Order) => void,\n onError: (message: string) => void,\n cart: ShoppingCart,\n order?: Order,\n currentUser: User,\n schedule?: PaymentSchedule,\n customer: User\n}\n\n/**\n * This component open a modal dialog for the configured payment gateway, allowing the user to input his card data\n * to process an online payment.\n */\nconst CardPaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, currentUser, schedule, cart, customer, order }) => {\n const { t } = useTranslation('shared');\n\n const [gateway, setGateway] = useState(null);\n\n useEffect(() => {\n SettingAPI.get('payment_gateway')\n .then(setting => setGateway(setting))\n .catch(error => onError(error));\n }, []);\n\n /**\n * Render the Stripe payment modal\n */\n const renderStripeModal = (): ReactElement => {\n return ;\n };\n\n /**\n * Render the PayZen payment modal\n */\n const renderPayZenModal = (): ReactElement => {\n return ;\n };\n\n /**\n * Render the PagSeguro payment modal\n */\n const renderPagSeguroModal = (): ReactElement => {\n return ;\n };\n\n /**\n * Render the Getnet payment modal\n */\n const renderGetnetModal = (): ReactElement => {\n return ;\n };\n\n /**\n * Determine which gateway is enabled and return the appropriate payment modal\n */\n if (gateway === null || !isOpen) return
;\n\n switch (gateway.value) {\n case 'stripe':\n return renderStripeModal();\n case 'payzen':\n return renderPayZenModal();\n case 'pagseguro':\n return renderPagSeguroModal();\n case 'getnet':\n return renderGetnetModal();\n case null:\n case undefined:\n onError(t('app.shared.card_payment_modal.online_payment_disabled'));\n return
;\n default:\n onError(t('app.shared.card_payment_modal.unexpected_error'));\n console.error(`[PaymentModal] Unimplemented gateway: ${gateway.value}`);\n return
;\n }\n};\n\nconst CardPaymentModalWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { CardPaymentModalWrapper as CardPaymentModal };\n\nApplication.Components.component('cardPaymentModal', react2angular(CardPaymentModalWrapper, ['isOpen', 'toggleModal', 'afterSuccess', 'onError', 'currentUser', 'schedule', 'cart', 'customer', 'order']));\n","import { FunctionComponent, useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { GatewayFormProps } from '../abstract-payment-modal';\nimport { useForm } from 'react-hook-form';\nimport { FormInput } from '../../form/form-input';\nimport Inputmask from 'inputmask';\nimport ValidationLib from '../../../lib/validation';\nimport GetnetAPI from '../../../api/getnet';\nimport { Card, CreatePaymentResponse } from '../../../models/getnet';\nimport CheckoutAPI from '../../../api/checkout';\nimport { Invoice } from '../../../models/invoice';\nimport { Order } from '../../../models/order';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\nimport { ShoppingCart } from '../../../models/payment';\nimport { User } from '../../../models/user';\n\n// we use these two additional parameters to update the card, if provided\ninterface GetnetFormProps extends GatewayFormProps {\n updateCard?: boolean,\n}\n\n/**\n * A form component to collect the credit card details and to create the payment method on Stripe.\n * The form validation button must be created elsewhere, using the attribute form={formId}.\n */\nexport const GetnetForm: React.FC = ({ onSubmit, onSuccess, onError, children, updateCard = false, className, paymentSchedule, cart, customer, formId, order }) => {\n const [loadingClass, setLoadingClass] = useState<'hidden' | 'loader' | 'loader-overlay'>('hidden');\n const { register, formState, handleSubmit } = useForm();\n\n useEffect(() => {\n Inputmask({ mask: '99/99', clearMaskOnLostFocus: true }).mask('[id=\"expiration\"]');\n Inputmask({ mask: '9999 9999 9999 99[9][9]', clearMaskOnLostFocus: true }).mask('[id=\"number\"]');\n Inputmask({ mask: '999[9]', clearMaskOnLostFocus: true }).mask('[id=\"cvv\"]');\n }, []);\n\n /**\n * Handle the submission of the form.\n */\n const submitForm = async (card: Card): Promise => {\n onSubmit();\n try {\n const token = await crateCardToken(card);\n createPayment(cardData(card, token), cart, customer).then((payment) => {\n if (payment.result.status === 'APPROVED') {\n confirmPayment(payment).then((confirmation) => {\n onSuccess(confirmation);\n }).catch(e => onError(e));\n } else if (payment.result.message === 'DENY') {\n onError('Transação negada por regra de segurança do sistema de Antifraude.');\n } else {\n if (payment.result.details.length === 0) {\n onError('Erro ao realizar pagamento. Confira os dados do cartão e tente novamente.');\n } else {\n onError(payment.result.details[0].description);\n }\n }\n }).catch(e => onError(e));\n } catch (err) {\n // catch api errors\n onError(err);\n } finally {\n setLoadingClass('hidden');\n }\n };\n\n /**\n * Make a request for tokenize card number\n * @param card\n * @returns\n */\n const crateCardToken = async (card: Card): Promise => {\n const res = await GetnetAPI.tokenCard(card.number, customer);\n if (!res.token) {\n throw new Error(' Número de cartão inválido');\n }\n return res.token;\n };\n\n /**\n * Create a card object for payment\n * @param card\n * @param token\n * @returns\n */\n const cardData = (card: Card, token: string): Card => {\n return {\n token,\n name: card.name,\n expiration: card.expiration,\n cvv: card.cvv\n } as Card;\n };\n\n /**\n * Ask the API to create the form token.\n * Depending on the current transaction (schedule or not), a PayZen Token or Payment may be created.\n */\n const createPayment = async (card: Card, cart: ShoppingCart, customer: User): Promise => {\n if (updateCard) {\n throw new Error('Atualização de cartão não implementada');\n } else if (paymentSchedule) {\n throw new Error('Pagamento recorrente não implementado');\n } else if (order) {\n const res = await CheckoutAPI.payment(order);\n return res.payment as CreatePaymentResponse;\n } else {\n return await GetnetAPI.createPayment(card, cart, customer);\n }\n };\n\n /**\n * Confirm the payment, depending on the current type of payment (single shot or recurring)\n */\n const confirmPayment = async (payment: CreatePaymentResponse): Promise => {\n if (paymentSchedule) {\n throw new Error('Pagamento recorrente não implementado');\n } else if (order) {\n const res = await CheckoutAPI.confirmPayment(order, payment.orderId);\n return res.order;\n } else {\n return await GetnetAPI.confirm(payment.orderId, cart);\n }\n };\n\n /**\n * Return a loader\n */\n const Loader: FunctionComponent = () => {\n return (\n
\n \n
\n );\n };\n\n return (\n
\n \n
\n
\n \n }\n type=\"tel\"\n register={register}\n rules={{\n pattern: {\n value: ValidationLib.cardNumberRegex,\n message: 'Cartão inválido'\n },\n required: true\n }}\n formState={formState}\n />\n
\n
\n \n }\n type=\"text\"\n register={register}\n rules={{ required: true }}\n formState={formState}\n />\n
\n
\n
\n \n }\n type=\"tel\"\n placeholder='DD/MM'\n register={register}\n rules={{\n pattern: {\n value: ValidationLib.expirationCardRegex,\n message: 'Data inválida'\n },\n required: true\n }}\n formState={formState}\n />\n
\n
\n \n }\n type=\"tel\"\n register={register}\n rules={{\n pattern: {\n value: ValidationLib.cvvRegex,\n message: 'CVV inválido'\n },\n required: true\n }}\n formState={formState}\n />\n
\n
\n
\n {children}\n \n );\n};\n","import { ReactNode, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { enableMapSet } from 'immer';\nimport { useImmer } from 'use-immer';\nimport { HtmlTranslate } from '../../base/html-translate';\nimport { FabInput } from '../../base/fab-input';\nimport { Loader } from '../../base/loader';\nimport { SettingName } from '../../../models/setting';\nimport SettingAPI from '../../../api/setting';\nimport GetnetAPI from '../../../api/getnet';\n\nenableMapSet();\n\ninterface GetnetKeysFormProps {\n onValidKeys: (getnetSettings: Map) => void,\n onInvalidKeys: () => void,\n}\n\n// all settings related to Getnet that are requested by this form\nconst getnetSettings: Array = ['getnet_seller_id', 'getnet_client_id', 'getnet_client_secret', 'getnet_endpoint'];\n// settings related to the Getnet REST API (server side)\nconst restApiSettings: Array = ['getnet_seller_id', 'getnet_client_id', 'getnet_client_secret', 'getnet_endpoint'];\n\n// Prevent multiples call to the getnet keys validation endpoint.\n// this cannot be handled by a React state because of their asynchronous nature\nlet pendingKeysValidation = false;\n\n/**\n * Form to set the Getnet's username, password and public key\n */\nconst GetnetKeysForm: React.FC = ({ onValidKeys, onInvalidKeys }) => {\n const { t } = useTranslation('admin');\n\n // values of the Getnet settings\n const [settings, updateSettings] = useImmer>(new Map(getnetSettings.map(name => [name, ''])));\n // Icon of the fieldset for the Getnet's keys concerning the REST API. Used to display if the key is valid.\n const [keysAddOn, setKeysAddOn] = useState(null);\n // Style class for the add-on icon, for the REST API\n const [keysAddOnClassName, setKeysAddOnClassName] = useState<'key-invalid' | 'key-valid' | ''>('');\n\n /**\n * When the component loads for the first time, initialize the keys with the values fetched from the API (if any)\n */\n useEffect(() => {\n SettingAPI.query(getnetSettings).then(getnetKeys => {\n updateSettings(new Map(getnetKeys));\n }).catch(error => console.error(error));\n }, []);\n\n /**\n * When the style class for the public key, and the REST API are updated, check if they indicate valid keys.\n * If both are valid, run the 'onValidKeys' callback, else run 'onInvalidKeys'\n */\n useEffect(() => {\n const validClassName = 'key-valid';\n if (keysAddOnClassName === validClassName) {\n onValidKeys(settings);\n } else {\n onInvalidKeys();\n }\n }, [keysAddOnClassName, settings]);\n\n useEffect(() => {\n testRestApi();\n }, [settings]);\n\n /**\n * Send a test call to the payZen REST API to check if the inputted settings key are valid.\n * Depending on the test result, assign an add-on icon and a style to notify the user.\n */\n const testRestApi = () => {\n const valid: boolean = restApiSettings.map(s => !!settings.get(s))\n .reduce((acc, val) => acc && val, true);\n\n if (valid && !pendingKeysValidation) {\n pendingKeysValidation = true;\n GetnetAPI.sdkTest(\n settings.get('getnet_endpoint'),\n settings.get('getnet_seller_id'),\n settings.get('getnet_client_id'),\n settings.get('getnet_client_secret')\n ).then(result => {\n pendingKeysValidation = false;\n\n if (result.success) {\n setKeysAddOn();\n setKeysAddOnClassName('key-valid');\n } else {\n setKeysAddOn();\n setKeysAddOnClassName('key-invalid');\n }\n }, () => {\n pendingKeysValidation = false;\n\n setKeysAddOn();\n setKeysAddOnClassName('key-invalid');\n });\n }\n if (!valid) {\n setKeysAddOn();\n setKeysAddOnClassName('key-invalid');\n }\n };\n\n /**\n * Assign the inputted key to the given settings\n */\n const setApiKey = (setting: typeof restApiSettings[number]) => {\n return (key: string) => {\n updateSettings(draft => draft.set(setting, key));\n };\n };\n\n return (\n
\n
\n \n
\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n
\n
\n );\n};\n\nconst GetnetKeysFormWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { GetnetKeysFormWrapper as GetnetKeysForm };\n","import { FunctionComponent, ReactNode } from 'react';\nimport * as React from 'react';\nimport { GatewayFormProps, AbstractPaymentModal } from '../abstract-payment-modal';\nimport { ShoppingCart } from '../../../models/payment';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\nimport { User } from '../../../models/user';\nimport { Invoice } from '../../../models/invoice';\n\nimport securitySite from '../../../../../images/security-site.png';\nimport getnet from '../../../../../images/getnet.png';\nimport { GetnetForm } from './getnet-form';\nimport { Order } from '../../../models/order';\n\ninterface GetnetModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n afterSuccess: (result: Invoice|PaymentSchedule|Order) => void,\n onError: (message: string) => void,\n cart: ShoppingCart,\n order?: Order,\n currentUser: User,\n schedule?: PaymentSchedule,\n customer: User\n}\n\n/**\n * This component enables the user to input his card data or process payments, using the PayZen gateway.\n * Supports Strong-Customer Authentication (SCA).\n *\n * This component should not be called directly. Prefer using which can handle the configuration\n * of a different payment gateway.\n */\nexport const GetnetModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, currentUser, schedule, customer, order }) => {\n /**\n * Return the logos, shown in the modal footer.\n */\n const logoFooter = (): ReactNode => {\n return (\n
\n Getnet\n \"powered\n
\n );\n };\n\n /**\n * Integrates the PayzenForm into the parent PaymentModal\n */\n const renderForm: FunctionComponent = ({ onSubmit, onSuccess, onError, operator, className, formId, cart, customer, paymentSchedule, children, order }) => {\n return (\n \n {children}\n \n );\n };\n\n return (\n \n );\n};\n","import * as React from 'react';\nimport { FormEvent, useEffect, useState } from 'react';\nimport Select from 'react-select';\nimport { useTranslation } from 'react-i18next';\nimport { GatewayFormProps } from '../abstract-payment-modal';\nimport LocalPaymentAPI from '../../../api/local-payment';\nimport FormatLib from '../../../lib/format';\nimport SettingAPI from '../../../api/setting';\nimport { CardPaymentModal } from '../card-payment-modal';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\nimport { HtmlTranslate } from '../../base/html-translate';\nimport CheckoutAPI from '../../../api/checkout';\nimport { SelectOption } from '../../../models/select';\nimport { PaymentMethod } from '../../../models/payment';\n\nconst ALL_SCHEDULE_METHODS = ['card', 'check', 'transfer'] as const;\ntype scheduleMethod = typeof ALL_SCHEDULE_METHODS[number];\n\n/**\n * A form component to ask for confirmation before cashing a payment directly at the FabLab's reception.\n * This is intended for use by privileged users.\n * The form validation button must be created elsewhere, using the attribute form={formId}.\n */\nexport const LocalPaymentForm: React.FC = ({ onSubmit, onSuccess, onError, children, className, paymentSchedule, cart, updateCart, customer, operator, formId, order }) => {\n const { t } = useTranslation('admin');\n\n const [method, setMethod] = useState('check');\n const [onlinePaymentModal, setOnlinePaymentModal] = useState(false);\n\n useEffect(() => {\n setMethod(cart.payment_method || 'check');\n if (cart.payment_method === '') {\n cart.payment_method = PaymentMethod.Check;\n }\n }, [cart]);\n\n /**\n * Open/closes the online payment modal, used to collect card credentials when paying the payment schedule by card.\n */\n const toggleOnlinePaymentModal = (): void => {\n setOnlinePaymentModal(!onlinePaymentModal);\n };\n\n /**\n * Convert all payement methods for schedules to the react-select format\n */\n const buildMethodOptions = (): Array> => {\n return ALL_SCHEDULE_METHODS.map(i => methodToOption(i));\n };\n\n /**\n * Convert the given payment-method to the react-select format\n */\n const methodToOption = (value: scheduleMethod): SelectOption => {\n if (!value) return { value, label: '' };\n\n return { value, label: t(`app.admin.local_payment_form.method_${value}`) };\n };\n\n /**\n * Callback triggered when the user selects a payment method for the current payment schedule.\n */\n const handleUpdateMethod = (option: SelectOption) => {\n updateCart(Object.assign({}, cart, { payment_method: option.value }));\n setMethod(option.value);\n };\n\n /**\n * Handle the submission of the form. It will process the local payment.\n */\n const handleSubmit = async (event: FormEvent): Promise => {\n event.preventDefault();\n onSubmit();\n\n if (paymentSchedule && method === 'card') {\n // check that the online payment is active\n try {\n const online = await SettingAPI.get('online_payment_module');\n if (online.value !== 'true') {\n return onError(t('app.admin.local_payment_form.online_payment_disabled'));\n }\n return toggleOnlinePaymentModal();\n } catch (e) {\n onError(e);\n }\n }\n\n try {\n let res;\n if (order) {\n res = await CheckoutAPI.payment(order);\n res = res.order;\n } else {\n res = await LocalPaymentAPI.confirmPayment(cart);\n }\n onSuccess(res);\n } catch (e) {\n onError(e);\n }\n };\n\n /**\n * Callback triggered after a successful payment by online card for a schedule.\n */\n const afterCreatePaymentSchedule = (document: PaymentSchedule) => {\n toggleOnlinePaymentModal();\n onSuccess(document);\n };\n\n /**\n * Generally, this form component is only shown to admins or to managers when they book for someone else.\n * If this is not the case, then it is shown to validate a free (or prepaid by wallet) cart.\n * This function will return `true` in the later case.\n */\n const isFreeOfCharge = (): boolean => {\n return (customer.id === operator.id);\n };\n\n /**\n * Get the type of the main item in the cart compile\n */\n const mainItemType = (): string => {\n if (order) {\n return '';\n }\n return Object.keys(cart.items[0])[0];\n };\n\n return (\n
\n {!paymentSchedule && !isFreeOfCharge() &&

{t('app.admin.local_payment_form.about_to_cash')}

}\n {!paymentSchedule && isFreeOfCharge() &&

{t('app.admin.local_payment_form.about_to_confirm', { ITEM: mainItemType() })}

}\n {paymentSchedule &&
\n
\n \n \n \n \n \n \n \n {selectedGateway === Gateway.Stripe && }\n {selectedGateway === Gateway.PayZen && }\n {selectedGateway === Gateway.PagSeguro && }\n {selectedGateway === Gateway.Getnet && }\n \n );\n};\n\nconst SelectGatewayModalWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('selectGatewayModal', react2angular(SelectGatewayModalWrapper, ['isOpen', 'toggleModal', 'currentUser', 'onSuccess', 'onError']));\n","import { Invoice } from '../../../models/invoice';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\nimport { ShoppingCart } from '../../../models/payment';\nimport { User } from '../../../models/user';\nimport { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport WalletAPI from '../../../api/wallet';\nimport { Wallet } from '../../../models/wallet';\nimport WalletLib from '../../../lib/wallet';\nimport UserLib from '../../../lib/user';\nimport { LocalPaymentModal } from '../local-payment/local-payment-modal';\nimport { CardPaymentModal } from '../card-payment-modal';\nimport PriceAPI from '../../../api/price';\nimport { ComputePriceResult } from '../../../models/price';\nimport { Order } from '../../../models/order';\nimport { computePriceWithCoupon } from '../../../lib/coupon';\n\ninterface PaymentModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n afterSuccess: (result: Invoice|PaymentSchedule|Order) => void,\n onError: (message: string) => void,\n cart: ShoppingCart,\n order?: Order,\n updateCart: (cart: ShoppingCart) => void,\n operator: User,\n schedule?: PaymentSchedule,\n customer: User\n}\n\n/**\n * This component is responsible for rendering the payment modal.\n */\nexport const PaymentModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, updateCart, operator, schedule, customer, order }) => {\n // the user's wallet\n const [wallet, setWallet] = useState(null);\n // the price of the cart\n const [price, setPrice] = useState(null);\n // the remaining price to pay, after the wallet was changed\n const [remainingPrice, setRemainingPrice] = useState(null);\n\n // refresh the wallet when the customer changes\n useEffect(() => {\n WalletAPI.getByUser(customer.id).then(wallet => {\n setWallet(wallet);\n });\n }, [customer]);\n\n // refresh the price when the cart changes\n useEffect(() => {\n if (order) {\n setPrice({ price: computePriceWithCoupon(order.total, order.coupon), price_without_coupon: order.total });\n } else {\n PriceAPI.compute(cart).then(price => {\n setPrice(price);\n });\n }\n }, [cart, order]);\n\n // refresh the remaining price when the cart price was computed and the wallet was retrieved\n useEffect(() => {\n if (price && wallet) {\n setRemainingPrice(new WalletLib(wallet).computeRemainingPrice(price?.price));\n }\n }, [price, wallet]);\n\n /**\n * Check the conditions for the local payment\n */\n const isLocalPayment = (): boolean => {\n return (new UserLib(operator).isPrivileged(customer) || remainingPrice === 0);\n };\n\n // do not render the modal until the real remaining price is computed\n if (remainingPrice === null) return null;\n\n if (isLocalPayment()) {\n return (\n \n );\n } else {\n return (\n \n );\n }\n};\n","import { ReactNode, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabModal } from '../../base/fab-modal';\nimport { StripeCardUpdate } from './stripe-card-update';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\nimport { User } from '../../../models/user';\nimport stripeLogo from '../../../../../images/powered_by_stripe.png';\nimport mastercardLogo from '../../../../../images/mastercard.png';\nimport visaLogo from '../../../../../images/visa.png';\n\ninterface StripeCardUpdateModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onSuccess: () => void,\n schedule: PaymentSchedule,\n operator: User\n}\n\n/**\n * Modal dialog to allow the member to update his payment card for a payment schedule, when the Stripe gateway is used\n */\nexport const StripeCardUpdateModal: React.FC = ({ isOpen, toggleModal, onSuccess, schedule, operator }) => {\n const { t } = useTranslation('shared');\n\n // prevent submitting the form to update the card details, until the user has filled correctly all required fields\n const [canSubmitUpdateCard, setCanSubmitUpdateCard] = useState(true);\n // we save errors here, if any, for display purposes.\n const [errors, setErrors] = useState(null);\n\n /**\n * Return the logos, shown in the modal footer.\n */\n const logoFooter = (): ReactNode => {\n return (\n
\n \n \"powered\n \"mastercard\"\n \"visa\"\n
\n );\n };\n\n /**\n * When the user clicks the submit button, we disable it to prevent double form submission\n */\n const handleCardUpdateSubmit = (): void => {\n setCanSubmitUpdateCard(false);\n };\n\n /**\n * When the card was not updated, show the error\n */\n const handleCardUpdateError = (error): void => {\n setErrors(error);\n setCanSubmitUpdateCard(true);\n };\n\n return (\n \n {schedule && \n {errors &&
\n {errors}\n
}\n
}\n
\n {canSubmitUpdateCard && }\n {!canSubmitUpdateCard &&
\n
\n \n
\n
}\n
\n
\n );\n};\n","import { FormEvent } from 'react';\nimport * as React from 'react';\nimport { CardElement, useElements, useStripe } from '@stripe/react-stripe-js';\nimport { User } from '../../../models/user';\nimport StripeAPI from '../../../api/stripe';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\n\ninterface StripeCardUpdateProps {\n onSubmit: () => void,\n onSuccess: () => void,\n onError: (message: string) => void,\n schedule: PaymentSchedule\n operator: User,\n className?: string,\n}\n\n/**\n * A simple form component to collect and update the credit card details, for Stripe.\n *\n * The form validation button must be created elsewhere, using the attribute form=\"stripe-card\".\n */\nexport const StripeCardUpdate: React.FC = ({ onSubmit, onSuccess, onError, className, schedule, operator, children }) => {\n const stripe = useStripe();\n const elements = useElements();\n\n /**\n * Handle the submission of the form. Depending on the configuration, it will create the payment method on Stripe,\n * or it will process a payment with the inputted card.\n */\n const handleSubmit = async (event: FormEvent): Promise => {\n event.preventDefault();\n onSubmit();\n\n // Stripe.js has not loaded yet\n if (!stripe || !elements) { return; }\n\n const cardElement = elements.getElement(CardElement);\n const { error, paymentMethod } = await stripe.createPaymentMethod({\n type: 'card',\n card: cardElement\n });\n\n if (error) {\n // stripe error\n onError(error.message);\n } else {\n try {\n // we start by associating the payment method with the user\n const intent = await StripeAPI.setupIntent(schedule.user.id);\n const { error } = await stripe.confirmCardSetup(intent.client_secret, {\n payment_method: paymentMethod.id,\n mandate_data: {\n customer_acceptance: {\n type: 'online',\n online: {\n ip_address: operator.ip_address,\n user_agent: navigator.userAgent\n }\n }\n }\n });\n if (error) {\n onError(error.message);\n } else {\n // then we update the default payment method\n const res = await StripeAPI.updateCard(schedule.user.id, paymentMethod.id, schedule.id);\n if (res.updated) {\n onSuccess();\n } else {\n onError(res.error);\n }\n }\n } catch (err) {\n // catch api errors\n onError(err);\n }\n }\n };\n\n /**\n * Options for the Stripe's card input\n */\n const cardOptions = {\n style: {\n base: {\n fontSize: '16px',\n color: '#424770',\n '::placeholder': { color: '#aab7c4' }\n },\n invalid: {\n color: '#9e2146',\n iconColor: '#9e2146'\n }\n },\n hidePostalCode: true\n };\n\n return (\n \n \n {children}\n \n );\n};\n","import { StripeConfirm } from './stripe-confirm';\nimport { FabModal } from '../../base/fab-modal';\nimport { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport PaymentScheduleAPI from '../../../api/payment-schedule';\nimport { PaymentScheduleItem } from '../../../models/payment-schedule';\nimport { useTranslation } from 'react-i18next';\n\ninterface StripeConfirmModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onSuccess: () => void,\n paymentScheduleItemId: number,\n}\n\n/**\n * Modal dialog that trigger a 3D secure confirmation for the given payment schedule item (deadline for a payment schedule).\n */\nexport const StripeConfirmModal: React.FC = ({ isOpen, toggleModal, onSuccess, paymentScheduleItemId }) => {\n const { t } = useTranslation('shared');\n\n const [item, setItem] = useState(null);\n const [isPending, setIsPending] = useState(false);\n\n useEffect(() => {\n PaymentScheduleAPI.getItem(paymentScheduleItemId).then(data => {\n setItem(data);\n });\n }, [paymentScheduleItemId]);\n\n /**\n * Callback triggered when the confirm button was clicked in the modal.\n */\n const onConfirmed = (): void => {\n togglePending();\n onSuccess();\n };\n\n /**\n * Enable/disable the confirm button of the \"action\" modal\n */\n const togglePending = (): void => {\n setIsPending(!isPending);\n };\n\n return (\n \n {item && }\n \n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useStripe } from '@stripe/react-stripe-js';\nimport { useTranslation } from 'react-i18next';\n\ninterface StripeConfirmProps {\n clientSecret: string,\n onResponse: () => void,\n}\n\n/**\n * This component runs a 3D secure confirmation for the given Stripe payment (identified by clientSecret).\n * A message is shown, depending on the result of the confirmation.\n * In case of success, a callback \"onResponse\" is also run.\n */\nexport const StripeConfirm: React.FC = ({ clientSecret, onResponse }) => {\n const stripe = useStripe();\n const { t } = useTranslation('shared');\n\n // the message displayed to the user\n const [message, setMessage] = useState(t('app.shared.stripe_confirm.pending'));\n // the style class of the message\n const [type, setType] = useState('info');\n\n /**\n * When the component is mounted, run the 3DS confirmation.\n */\n useEffect(() => {\n stripe.confirmCardPayment(clientSecret).then(function (result) {\n onResponse();\n if (result.error) {\n // Display error.message in your UI.\n setType('error');\n setMessage(result.error.message);\n } else {\n // The setup has succeeded. Display a success message.\n setType('success');\n setMessage(t('app.shared.stripe_confirm.success'));\n }\n });\n }, []);\n\n return
\n
{message}
\n
;\n};\n","import { memo, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { Elements } from '@stripe/react-stripe-js';\nimport { loadStripe, Stripe } from '@stripe/stripe-js';\nimport SettingAPI from '../../../api/setting';\n\n/**\n * This component initializes the stripe's Elements tag with the API key\n */\nexport const StripeElements: React.FC = memo(({ children }) => {\n const [stripe, setStripe] = useState>(undefined);\n\n /**\n * When this component is mounted, we initialize the tag with the Stripe's public key\n */\n useEffect(() => {\n SettingAPI.get('stripe_public_key').then(key => {\n if (key?.value) {\n const promise = loadStripe(key.value);\n setStripe(promise);\n }\n });\n }, []);\n\n return (\n
\n {stripe && \n {children}\n }\n
\n );\n});\n\nStripeElements.displayName = 'StripeElements';\n","import { FormEvent } from 'react';\nimport * as React from 'react';\nimport { CardElement, useElements, useStripe } from '@stripe/react-stripe-js';\nimport { useTranslation } from 'react-i18next';\nimport { GatewayFormProps } from '../abstract-payment-modal';\nimport { PaymentConfirmation } from '../../../models/payment';\nimport StripeAPI from '../../../api/stripe';\nimport { Invoice } from '../../../models/invoice';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\nimport CheckoutAPI from '../../../api/checkout';\nimport { Order } from '../../../models/order';\n\n/**\n * A form component to collect the credit card details and to create the payment method on Stripe.\n * The form validation button must be created elsewhere, using the attribute form={formId}.\n */\nexport const StripeForm: React.FC = ({ onSubmit, onSuccess, onError, children, className, paymentSchedule = false, cart, formId, order }) => {\n const { t } = useTranslation('shared');\n\n const stripe = useStripe();\n const elements = useElements();\n\n /**\n * Handle the submission of the form. Depending on the configuration, it will create the payment method on Stripe,\n * or it will process a payment with the inputted card.\n */\n const handleSubmit = async (event: FormEvent): Promise => {\n event.preventDefault();\n event.stopPropagation();\n onSubmit();\n\n // Stripe.js has not loaded yet\n if (!stripe || !elements) { return; }\n\n const cardElement = elements.getElement(CardElement);\n const { error, paymentMethod } = await stripe.createPaymentMethod({\n type: 'card',\n card: cardElement\n });\n\n if (error) {\n // stripe error\n onError(error.message);\n } else {\n try {\n if (!paymentSchedule) {\n if (order) {\n const res = await CheckoutAPI.payment(order, paymentMethod.id);\n if (res.payment) {\n await handleServerConfirmation(res.payment as PaymentConfirmation);\n } else {\n await handleServerConfirmation(res.order);\n }\n } else {\n // process the normal payment pipeline, including SCA validation\n const res = await StripeAPI.confirmMethod(paymentMethod.id, cart);\n await handleServerConfirmation(res);\n }\n } else {\n const res = await StripeAPI.setupSubscription(paymentMethod.id, cart);\n await handleServerConfirmation(res, paymentMethod.id);\n }\n } catch (err) {\n // catch api errors\n onError(err);\n }\n }\n };\n\n /**\n * Process the server response about the Strong-customer authentication (SCA)\n * @param response can be a PaymentConfirmation, or an Invoice/PaymentSchedule (if the payment succeeded)\n * @param paymentMethodId ID of the payment method, required only when confirming a payment schedule\n * @see app/controllers/api/stripe_controller.rb#confirm_payment\n */\n const handleServerConfirmation = async (response: PaymentConfirmation|Invoice|PaymentSchedule|Order, paymentMethodId?: string) => {\n if ('error' in response) {\n if (response.error.statusText) {\n onError(response.error.statusText);\n } else {\n onError(`${t('app.shared.stripe_form.payment_card_error')} ${response.error}`);\n }\n } else if ('requires_action' in response) {\n if (response.type === 'payment') {\n // Use Stripe.js to handle required card action\n const result = await stripe.handleCardAction(response.payment_intent_client_secret);\n if (result.error) {\n onError(result.error.message);\n } else {\n // The card action has been handled\n // The PaymentIntent can be confirmed again on the server\n try {\n if (order) {\n const confirmation = await CheckoutAPI.confirmPayment(order, result.paymentIntent.id);\n await handleServerConfirmation(confirmation.order);\n } else {\n const confirmation = await StripeAPI.confirmIntent(result.paymentIntent.id, cart);\n await handleServerConfirmation(confirmation);\n }\n } catch (e) {\n onError(e);\n }\n }\n } else if (response.type === 'subscription') {\n const result = await stripe.confirmCardPayment(response.payment_intent_client_secret, {\n payment_method: paymentMethodId\n });\n if (result.error) {\n onError(result.error.message);\n } else {\n try {\n const confirmation = await StripeAPI.confirmSubscription(response.subscription_id, cart);\n await handleServerConfirmation(confirmation);\n } catch (e) {\n onError(e);\n }\n }\n }\n } else if ('id' in response) {\n onSuccess(response);\n } else {\n console.error(`[StripeForm] unknown response received: ${response}`);\n }\n };\n\n /**\n * Options for the Stripe's card input\n */\n const cardOptions = {\n style: {\n base: {\n fontSize: '16px',\n color: '#424770',\n '::placeholder': { color: '#aab7c4' }\n },\n invalid: {\n color: '#9e2146',\n iconColor: '#9e2146'\n }\n },\n hidePostalCode: true\n };\n\n return (\n
\n \n {children}\n \n );\n};\n","import { ReactNode, useEffect, useRef, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { HtmlTranslate } from '../../base/html-translate';\nimport { FabInput } from '../../base/fab-input';\nimport { Loader } from '../../base/loader';\nimport StripeAPI from '../../../api/external/stripe';\nimport SettingAPI from '../../../api/setting';\n\ninterface StripeKeysFormProps {\n onValidKeys: (stripePublic: string, stripeSecret:string) => void,\n onInvalidKeys: () => void,\n}\n\n/**\n * Form to set the stripe's public and private keys\n */\nconst StripeKeysForm: React.FC = ({ onValidKeys, onInvalidKeys }) => {\n const { t } = useTranslation('admin');\n\n // used to prevent promises from resolving if the component was unmounted\n const mounted = useRef(false);\n\n // Stripe's public key\n const [publicKey, setPublicKey] = useState('');\n // Icon of the input field for the Stripe's public key. Used to display if the key is valid.\n const [publicKeyAddOn, setPublicKeyAddOn] = useState(null);\n // Style class for the add-on icon, for the public key\n const [publicKeyAddOnClassName, setPublicKeyAddOnClassName] = useState<'key-invalid' | 'key-valid' | ''>('');\n // Stripe's secret key\n const [secretKey, setSecretKey] = useState('');\n // Icon of the input field for the Stripe's secret key. Used to display if the key is valid.\n const [secretKeyAddOn, setSecretKeyAddOn] = useState(null);\n // Style class for the add-on icon, for the public key\n const [secretKeyAddOnClassName, setSecretKeyAddOnClassName] = useState<'key-invalid' | 'key-valid' | ''>('');\n\n /**\n * When the component loads for the first time:\n * - mark it as mounted\n * - initialize the keys with the values fetched from the API (if any)\n */\n useEffect(() => {\n mounted.current = true;\n\n SettingAPI.query(['stripe_public_key', 'stripe_secret_key']).then(stripeKeys => {\n setPublicKey(stripeKeys.get('stripe_public_key'));\n setSecretKey(stripeKeys.get('stripe_secret_key'));\n }).catch(error => console.error(error));\n\n // when the component unmounts, mark it as unmounted\n return () => {\n mounted.current = false;\n };\n }, []);\n\n /**\n * When the style class for the public and private key are updated, check if they indicate valid keys.\n * If both are valid, run the 'onValidKeys' callback\n */\n useEffect(() => {\n const validClassName = 'key-valid';\n if (publicKeyAddOnClassName === validClassName && secretKeyAddOnClassName === validClassName) {\n onValidKeys(publicKey, secretKey);\n } else {\n onInvalidKeys();\n }\n }, [publicKeyAddOnClassName, secretKeyAddOnClassName]);\n\n /**\n * Send a test call to the Stripe API to check if the inputted public key is valid\n */\n const testPublicKey = (key: string) => {\n setPublicKeyAddOnClassName('');\n\n if (!key.match(/^pk_/)) {\n setPublicKeyAddOn();\n setPublicKeyAddOnClassName('key-invalid');\n return;\n }\n StripeAPI.createPIIToken(key, 'test').then(() => {\n if (!mounted.current) return;\n\n setPublicKey(key);\n setPublicKeyAddOn();\n setPublicKeyAddOnClassName('key-valid');\n }, reason => {\n if (!mounted.current) return;\n\n if (reason.response.status === 401) {\n setPublicKeyAddOn();\n setPublicKeyAddOnClassName('key-invalid');\n }\n });\n };\n\n /**\n * Send a test call to the Stripe API to check if the inputted secret key is valid\n */\n const testSecretKey = (key: string) => {\n setSecretKeyAddOnClassName('');\n\n if (!key.match(/^sk_/)) {\n setSecretKeyAddOn();\n setSecretKeyAddOnClassName('key-invalid');\n return;\n }\n StripeAPI.listAllCharges(key).then(() => {\n if (!mounted.current) return;\n\n setSecretKey(key);\n setSecretKeyAddOn();\n setSecretKeyAddOnClassName('key-valid');\n }, reason => {\n if (!mounted.current) return;\n\n if (reason.response?.status === 401) {\n setSecretKeyAddOn();\n setSecretKeyAddOnClassName('key-invalid');\n }\n });\n };\n\n return (\n
\n
\n \n
\n
\n
\n \n }\n defaultValue={publicKey}\n onChange={testPublicKey}\n addOn={publicKeyAddOn}\n addOnClassName={publicKeyAddOnClassName}\n debounce={200}\n required />\n
\n
\n \n }\n defaultValue={secretKey}\n onChange={testSecretKey}\n addOn={secretKeyAddOn}\n addOnClassName={secretKeyAddOnClassName}\n debounce={200}\n required/>\n
\n
\n
\n );\n};\n\nconst StripeKeysFormWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { StripeKeysFormWrapper as StripeKeysForm };\n","import { FunctionComponent, ReactNode } from 'react';\nimport * as React from 'react';\nimport { StripeElements } from './stripe-elements';\nimport { StripeForm } from './stripe-form';\nimport { GatewayFormProps, AbstractPaymentModal } from '../abstract-payment-modal';\nimport { ShoppingCart } from '../../../models/payment';\nimport { PaymentSchedule } from '../../../models/payment-schedule';\nimport { User } from '../../../models/user';\n\nimport stripeLogo from '../../../../../images/powered_by_stripe.png';\nimport mastercardLogo from '../../../../../images/mastercard.png';\nimport visaLogo from '../../../../../images/visa.png';\nimport { Invoice } from '../../../models/invoice';\nimport { Order } from '../../../models/order';\n\ninterface StripeModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n afterSuccess: (result: Invoice|PaymentSchedule|Order) => void,\n onError: (message: string) => void,\n cart: ShoppingCart,\n order?: Order,\n currentUser: User,\n schedule?: PaymentSchedule,\n customer: User\n}\n\n/**\n * This component enables the user to input his card data or process payments, using the Stripe gateway.\n * Supports Strong-Customer Authentication (SCA).\n *\n * This component should not be called directly. Prefer using which can handle the configuration\n * of a different payment gateway.\n */\nexport const StripeModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, cart, currentUser, schedule, customer, order }) => {\n /**\n * Return the logos, shown in the modal footer.\n */\n const logoFooter = (): ReactNode => {\n return (\n
\n \n \"powered\n \"mastercard\"\n \"visa\"\n
\n );\n };\n\n /**\n * Integrates the StripeForm into the parent PaymentModal\n */\n const renderForm: FunctionComponent = ({ onSubmit, onSuccess, onError, operator, className, formId, cart, customer, paymentSchedule, children, order }) => {\n return (\n \n \n {children}\n \n \n );\n };\n\n return (\n \n );\n};\n","import { ReactElement, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { Loader } from '../base/loader';\nimport { StripeCardUpdateModal } from './stripe/stripe-card-update-modal';\nimport { PayzenCardUpdateModal } from './payzen/payzen-card-update-modal';\nimport { User } from '../../models/user';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport { useTranslation } from 'react-i18next';\n\ninterface UpdateCardModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n afterSuccess: () => void,\n onError: (message: string) => void,\n schedule: PaymentSchedule,\n operator: User\n}\n\n/**\n * This component open a modal dialog for the configured payment gateway, allowing the user to input his card data\n * to process an online payment.\n */\nconst UpdateCardModal: React.FC = ({ isOpen, toggleModal, afterSuccess, onError, operator, schedule }) => {\n const { t } = useTranslation('shared');\n const [gateway, setGateway] = useState('');\n\n useEffect(() => {\n setGateway(schedule.gateway);\n }, [schedule]);\n\n /**\n * Render the Stripe update-card modal\n */\n const renderStripeModal = (): ReactElement => {\n return ;\n };\n\n /**\n * Render the PayZen update-card modal\n */\n const renderPayZenModal = (): ReactElement => {\n return ;\n };\n\n /**\n * Determine which gateway is in use with the current schedule and return the appropriate modal\n */\n\n switch (gateway) {\n case 'Stripe':\n return renderStripeModal();\n case 'PayZen':\n return renderPayZenModal();\n case '':\n case undefined:\n return
;\n default:\n onError(t('app.shared.update_card_modal.unexpected_error'));\n console.error(`[UpdateCardModal] unexpected gateway: ${schedule.gateway} for schedule ${schedule.id}`);\n return
;\n }\n};\n\nconst UpdateCardModalWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { UpdateCardModalWrapper as UpdateCardModal };\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport '../../lib/i18n';\nimport { Loader } from '../base/loader';\nimport { User } from '../../models/user';\nimport { Wallet } from '../../models/wallet';\nimport WalletLib from '../../lib/wallet';\nimport { ShoppingCart } from '../../models/payment';\nimport FormatLib from '../../lib/format';\n\ndeclare const Application: IApplication;\n\ninterface WalletInfoProps {\n cart: ShoppingCart,\n currentUser: User,\n wallet: Wallet,\n price: number,\n}\n\n/**\n * This component displays a summary of the amount paid with the virtual wallet, for the current transaction\n */\nexport const WalletInfo: React.FC = ({ cart, currentUser, wallet, price }) => {\n const { t } = useTranslation('shared');\n const [remainingPrice, setRemainingPrice] = useState(0);\n\n /**\n * Refresh the remaining price on each display\n */\n useEffect(() => {\n const wLib = new WalletLib(wallet);\n setRemainingPrice(wLib.computeRemainingPrice(price));\n });\n\n /**\n * Check if the currently connected used is also the person making the reservation.\n * If the currently connected user (i.e. the operator), is an admin or a manager, he may book the reservation for someone else.\n */\n const isOperatorAndClient = (): boolean => {\n return currentUser.id === cart.customer_id;\n };\n /**\n * If the client has some money in his wallet & the price is not zero, then we should display this component.\n */\n const shouldBeShown = (): boolean => {\n return wallet.amount > 0 && price > 0;\n };\n /**\n * If the amount in the wallet is not enough to cover the whole price, then the user must pay the remaining price\n * using another payment mean.\n */\n const hasRemainingPrice = (): boolean => {\n return remainingPrice > 0;\n };\n /**\n * Does the current cart contains a payment schedule?\n */\n const isPaymentSchedule = (): boolean => {\n return cart.items.find(i => 'subscription' in i) && cart.payment_schedule;\n };\n /**\n * Return the human-readable name of the item currently bought with the wallet\n */\n const getPriceItem = (): string => {\n let item = 'other';\n if (cart.items.find(i => 'reservation' in i)) {\n item = 'reservation';\n } else if (cart.items.find(i => 'subscription' in i)) {\n if (cart.payment_schedule) {\n item = 'first_deadline';\n } else item = 'subscription';\n }\n\n return t(`app.shared.wallet.wallet_info.item_${item}`);\n };\n\n return (\n
\n {shouldBeShown() &&
\n {isOperatorAndClient() &&
\n

{t('app.shared.wallet.wallet_info.you_have_AMOUNT_in_wallet', { AMOUNT: FormatLib.price(wallet.amount) })}

\n {!hasRemainingPrice() &&

\n {t('app.shared.wallet.wallet_info.wallet_pay_ITEM', { ITEM: getPriceItem() })}\n

}\n {hasRemainingPrice() &&

\n {t('app.shared.wallet.wallet_info.credit_AMOUNT_for_pay_ITEM', {\n AMOUNT: FormatLib.price(remainingPrice),\n ITEM: getPriceItem()\n })}\n

}\n
}\n {!isOperatorAndClient() &&
\n

{t('app.shared.wallet.wallet_info.client_have_AMOUNT_in_wallet', { AMOUNT: FormatLib.price(wallet.amount) })}

\n {!hasRemainingPrice() &&

\n {t('app.shared.wallet.wallet_info.client_wallet_pay_ITEM', { ITEM: getPriceItem() })}\n

}\n {hasRemainingPrice() &&

\n {t('app.shared.wallet.wallet_info.client_credit_AMOUNT_for_pay_ITEM', {\n AMOUNT: FormatLib.price(remainingPrice),\n ITEM: getPriceItem()\n })}\n

}\n
}\n {!hasRemainingPrice() && isPaymentSchedule() &&

\n \n {t('app.shared.wallet.wallet_info.other_deadlines_no_wallet')}\n

}\n
}\n
\n );\n};\n\nconst WalletInfoWrapper: React.FC = ({ currentUser, cart, price, wallet }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('walletInfo', react2angular(WalletInfoWrapper, ['currentUser', 'price', 'cart', 'wallet']));\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport PlanCategoryAPI from '../../api/plan-category';\nimport { PlanCategory } from '../../models/plan-category';\nimport { FabButton } from '../base/fab-button';\nimport { FabModal } from '../base/fab-modal';\nimport { Loader } from '../base/loader';\n\ninterface DeletePlanCategoryProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n category: PlanCategory,\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog to ask the user for confirmation about the deletion of the provided plan-category.\n */\nconst DeletePlanCategory: React.FC = ({ onSuccess, onError, category }) => {\n const { t } = useTranslation('admin');\n\n const [deletionModal, setDeletionModal] = useState(false);\n\n /**\n * Opens/closes the deletion modal\n */\n const toggleDeletionModal = (): void => {\n setDeletionModal(!deletionModal);\n };\n\n /**\n * The deletion has been confirmed by the user.\n * Call the API to trigger the deletion of the temporary set plan-category\n */\n const onDeleteConfirmed = (): void => {\n PlanCategoryAPI.destroy(category.id).then(() => {\n onSuccess(t('app.admin.delete_plan_category.success'));\n }).catch((error) => {\n onError(t('app.admin.delete_plan_category.error') + error);\n });\n toggleDeletionModal();\n };\n\n return (\n
\n } onClick={toggleDeletionModal} />\n \n {t('app.admin.delete_plan_category.confirm')}\n \n
\n );\n};\n\nconst DeletePlanCategoryWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { DeletePlanCategoryWrapper as DeletePlanCategory };\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { PlanCategory } from '../../models/plan-category';\nimport { FabButton } from '../base/fab-button';\nimport { FabModal } from '../base/fab-modal';\nimport { Loader } from '../base/loader';\nimport { PlanCategoryForm } from './plan-category-form';\n\ninterface ManagePlanCategoryProps {\n category?: PlanCategory,\n action: 'create' | 'update',\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog allowing to fill the parameters of a plan-category (create new or update existing).\n */\nconst ManagePlanCategory: React.FC = ({ category, action, onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n // is the creation modal open?\n const [isOpen, setIsOpen] = useState(false);\n // when editing, we store the category here, until the edition is over\n const [tempCategory, setTempCategory] = useState(category);\n\n /**\n * Opens/closes the new plan-category (creation) modal\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * Initialize a new plan-category for creation\n * or refresh plan-category data for update\n */\n const initCategoryCreation = () => {\n if (action === 'create') {\n setTempCategory({ name: '', description: '', weight: 0 });\n } else {\n setTempCategory(category);\n }\n };\n\n /**\n * Close the modal if the form submission was successful\n */\n const handleSuccess = (message) => {\n setIsOpen(false);\n onSuccess(message);\n };\n\n /**\n * Render the appropriate button depending on the action type\n */\n const toggleBtn = () => {\n switch (action) {\n case 'create':\n return (\n }\n className=\"create-button\"\n onClick={toggleModal}>\n {t('app.admin.manage_plan_category.create')}\n \n );\n case 'update':\n return (}\n className=\"edit-button\"\n onClick={toggleModal} />);\n }\n };\n\n return (\n
\n { toggleBtn() }\n \n\n {tempCategory && }\n\n \n
\n );\n};\n\nconst ManagePlanCategoryWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { ManagePlanCategoryWrapper as ManagePlanCategory };\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport PlanCategoryAPI from '../../api/plan-category';\nimport { PlanCategory } from '../../models/plan-category';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { ManagePlanCategory } from './manage-plan-category';\nimport { DeletePlanCategory } from './delete-plan-category';\n\ndeclare const Application: IApplication;\n\ninterface PlanCategoriesListProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows a list of all plan-categories and offer to manager them by deleting, modifying\n * and reordering each plan-categories.\n */\nexport const PlanCategoriesList: React.FC = ({ onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n // list of all categories\n const [categories, setCategories] = useState>(null);\n\n // load the categories list on component mount\n useEffect(() => {\n refreshCategories();\n }, []);\n\n /**\n * The creation/edition/deletion was successful.\n * Show the provided message and refresh the list\n */\n const handleSuccess = (message: string): void => {\n onSuccess(message);\n refreshCategories();\n };\n\n /**\n * Refresh the list of categories\n */\n const refreshCategories = () => {\n PlanCategoryAPI.index().then((data) => {\n setCategories(data);\n }).catch((error) => onError(error));\n };\n\n return (\n
\n \n

{t('app.admin.plan_categories_list.categories_list')}

\n {categories && categories.length === 0 && {t('app.admin.plan_categories_list.no_categories')}}\n {categories && categories.length > 0 && \n \n \n \n \n \n \n \n \n {categories.map(c =>\n \n \n \n \n )}\n \n
{t('app.admin.plan_categories_list.name')}{t('app.admin.plan_categories_list.significance')}
{c.name}{c.weight}\n \n \n
}\n
\n );\n};\n\nconst PlanCategoriesListWrapper: React.FC = ({ onSuccess, onError }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('planCategoriesList', react2angular(PlanCategoriesListWrapper, ['onSuccess', 'onError']));\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport PlanCategoryAPI from '../../api/plan-category';\nimport { PlanCategory } from '../../models/plan-category';\nimport { Loader } from '../base/loader';\nimport { useForm, SubmitHandler } from 'react-hook-form';\nimport { FormInput } from '../form/form-input';\nimport { FabAlert } from '../base/fab-alert';\nimport { FabButton } from '../base/fab-button';\nimport { FormRichText } from '../form/form-rich-text';\n\ninterface PlanCategoryFormProps {\n action: 'create' | 'update',\n category: PlanCategory,\n onSuccess: (message: string) => void,\n onError: (message: string) => void\n}\n\n/**\n * Form to create/edit a plan category\n */\nconst PlanCategoryForm: React.FC = ({ action, category, onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n const { register, control, handleSubmit, formState } = useForm({ defaultValues: { ...category } });\n /**\n * The action has been confirmed by the user.\n * Push the created/updated plan-category to the API.\n */\n const onSubmit: SubmitHandler = (data: PlanCategory) => {\n switch (action) {\n case 'create':\n PlanCategoryAPI.create(data).then(() => {\n onSuccess(t('app.admin.plan_category_form.create.success'));\n }).catch((error) => {\n onError(t('app.admin.plan_category_form.create.error') + error);\n });\n break;\n case 'update':\n PlanCategoryAPI.update(data).then(() => {\n onSuccess(t('app.admin.plan_category_form.update.success'));\n }).catch((error) => {\n onError(t('app.admin.plan_category_form.update.error') + error);\n });\n break;\n }\n };\n\n return (\n
\n \n\n \n\n \n \n {t('app.admin.plan_category_form.info')}\n \n {t(`app.admin.plan_category_form.${action}.cta`)}\n \n );\n};\n\nconst PlanCategoryFormWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { PlanCategoryFormWrapper as PlanCategoryForm };\n","import * as React from 'react';\nimport { FabModal } from '../base/fab-modal';\nimport { useTranslation } from 'react-i18next';\nimport { SubmitHandler, useForm } from 'react-hook-form';\nimport { Partner } from '../../models/plan';\nimport UserAPI from '../../api/user';\nimport { User } from '../../models/user';\nimport { FormInput } from '../form/form-input';\n\ninterface PartnerModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onError: (message: string) => void,\n onPartnerCreated: (partner: User) => void,\n}\n\n/**\n * Modal dialog to add o new user with role 'partner'\n */\nexport const PartnerModal: React.FC = ({ isOpen, toggleModal, onError, onPartnerCreated }) => {\n const { t } = useTranslation('admin');\n const { handleSubmit, register, formState } = useForm();\n\n /**\n * Callback triggered when the user validates the partner form: create the partner on the API\n */\n const onSubmit: SubmitHandler = (data: Partner) => {\n UserAPI.create(data, 'partner').then(onPartnerCreated).catch(onError);\n };\n\n return (\n \n
\n \n \n \n \n
\n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport moment from 'moment';\nimport _ from 'lodash';\nimport { Plan } from '../../models/plan';\nimport { User } from '../../models/user';\nimport { Loader } from '../base/loader';\nimport '../../lib/i18n';\nimport FormatLib from '../../lib/format';\n\ninterface PlanCardProps {\n plan: Plan,\n userId?: number,\n subscribedPlanId?: number,\n operator: User,\n isSelected: boolean,\n canSelectPlan: boolean,\n onSelectPlan: (plan: Plan) => void,\n onLoginRequested: () => void,\n}\n\n/**\n * This component is a \"card\" (visually), publicly presenting the details of a plan and allowing a user to subscribe.\n */\nconst PlanCard: React.FC = ({ plan, userId, subscribedPlanId, operator, onSelectPlan, isSelected, onLoginRequested, canSelectPlan }) => {\n const { t } = useTranslation('public');\n /**\n * Return the formatted localized amount of the given plan (eg. 20.5 => \"20,50 €\")\n */\n const amount = () : string => {\n return FormatLib.price(plan.amount);\n };\n /**\n * Return the formatted localized amount, divided by the number of months (eg. 120 => \"10,00 € / month\")\n */\n const monthlyAmount = (): string => {\n const monthly = plan.amount / moment.duration(plan.interval_count, plan.interval).asMonths();\n return FormatLib.price(monthly);\n };\n /**\n * Return the formatted localized duration of te given plan (eg. Month/3 => \"3 mois\")\n */\n const duration = (): string => {\n return moment.duration(plan.interval_count, plan.interval).humanize();\n };\n /**\n * Check if no users are currently logged-in\n */\n const mustLogin = (): boolean => {\n return _.isNil(operator);\n };\n /**\n * Check if the user can subscribe to the current plan, for himself\n */\n const canSubscribeForMe = (): boolean => {\n return operator?.role === 'member' || (operator?.role === 'manager' && userId === operator?.id);\n };\n /**\n * Check if the user can subscribe to the current plan, for someone else\n */\n const canSubscribeForOther = (): boolean => {\n return operator?.role === 'admin' || (operator?.role === 'manager' && userId !== operator?.id);\n };\n /**\n * Check it the user has subscribed to this plan or not\n */\n const hasSubscribedToThisPlan = (): boolean => {\n return subscribedPlanId === plan.id;\n };\n /**\n * Check if the plan has an attached file\n */\n const hasAttachment = (): boolean => {\n return !!plan.plan_file_url;\n };\n /**\n * Check if the plan has a description\n */\n const hasDescription = (): boolean => {\n return !!plan.description;\n };\n /**\n * Check if the plan is allowing a monthly payment schedule\n */\n const canBeScheduled = (): boolean => {\n return plan.monthly_payment;\n };\n /**\n * Callback triggered when the user select the plan\n */\n const handleSelectPlan = (): void => {\n if (canSelectPlan) {\n onSelectPlan(plan);\n }\n };\n /**\n * Callback triggered when a visitor (not logged-in user) select a plan\n */\n const handleLoginRequest = (): void => {\n onLoginRequested();\n };\n return (\n
\n

{plan.base_name}

\n
\n {canBeScheduled() &&
\n
\n
{t('app.public.plan_card.AMOUNT_per_month', { AMOUNT: monthlyAmount() })}
\n {duration()}\n
\n
}\n {!canBeScheduled() &&
\n
\n
{amount()}
\n {duration()}\n
\n
}\n
\n
\n {hasDescription() &&
}\n {hasAttachment() && { t('app.public.plan_card.more_information') }}\n {mustLogin() &&
\n \n
}\n {canSubscribeForMe() &&
\n {!hasSubscribedToThisPlan() && }\n {hasSubscribedToThisPlan() && }\n
}\n {canSubscribeForOther() &&
\n \n
}\n
\n
\n );\n};\n\nconst PlanCardWrapper: React.FC = ({ plan, userId, subscribedPlanId, operator, onSelectPlan, isSelected, onLoginRequested, canSelectPlan }) => {\n return (\n \n \n \n );\n};\n\nexport { PlanCardWrapper as PlanCard };\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport { Interval, Plan } from '../../models/plan';\nimport { useTranslation } from 'react-i18next';\nimport { FormInput } from '../form/form-input';\nimport PlanAPI from '../../api/plan';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { ErrorBoundary } from '../base/error-boundary';\nimport GroupAPI from '../../api/group';\nimport { SelectOption } from '../../models/select';\nimport { FormSelect } from '../form/form-select';\nimport { FormSwitch } from '../form/form-switch';\nimport PlanCategoryAPI from '../../api/plan-category';\nimport FormatLib from '../../lib/format';\nimport { FabAlert } from '../base/fab-alert';\nimport { FormRichText } from '../form/form-rich-text';\nimport { FormFileUpload } from '../form/form-file-upload';\nimport UserAPI from '../../api/user';\nimport { FabButton } from '../base/fab-button';\nimport { UserPlus } from 'phosphor-react';\nimport { PartnerModal } from './partner-modal';\nimport { PlanPricingForm } from './plan-pricing-form';\nimport { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';\nimport { FabTabs } from '../base/fab-tabs';\nimport { PlanLimitForm } from './plan-limit-form';\nimport { UnsavedFormAlert } from '../form/unsaved-form-alert';\nimport { UIRouter } from '@uirouter/angularjs';\n\ndeclare const Application: IApplication;\n\ninterface PlanFormProps {\n action: 'create' | 'update',\n plan?: Plan,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n beforeSubmit?: (data: Plan) => void,\n uiRouter: UIRouter\n}\n\n/**\n * Form to edit or create subscription plans\n */\nexport const PlanForm: React.FC = ({ action, plan, onError, onSuccess, beforeSubmit, uiRouter }) => {\n const { handleSubmit, register, control, formState, setValue, getValues, resetField } = useForm({ defaultValues: { ...plan } });\n const output = useWatch({ control }); // eslint-disable-line\n const { t } = useTranslation('admin');\n\n const [groups, setGroups] = useState>>(null);\n const [categories, setCategories] = useState>>(null);\n const [allGroups, setAllGroups] = useState(false);\n const [partners, setPartners] = useState>>(null);\n const [isOpenPartnerModal, setIsOpenPartnerModal] = useState(false);\n\n useEffect(() => {\n GroupAPI.index({ disabled: false })\n .then(res => setGroups(res.map(g => {\n return { value: g.id, label: g.name };\n })))\n .catch(onError);\n PlanCategoryAPI.index()\n .then(res => setCategories(res.map(c => {\n return { value: c.id, label: c.name };\n })))\n .catch(onError);\n UserAPI.index({ role: 'partner' })\n .then(res => setPartners(res.map(p => {\n return { value: p.id, label: p.name };\n })))\n .catch(onError);\n }, []);\n\n /**\n * Callback triggered when the user validates the plan form: handle create or update\n */\n const onSubmit: SubmitHandler = (data: Plan) => {\n if (typeof beforeSubmit === 'function') beforeSubmit(data);\n PlanAPI[action](data).then(() => {\n onSuccess(t(`app.admin.plan_form.${action}_success`));\n window.location.href = '/#!/admin/pricing';\n }).catch(error => {\n onError(error);\n });\n };\n\n /**\n * Callback triggered when the user switches the 'all group' button.\n */\n const handleAllGroupsChange = (checked: boolean) => {\n setAllGroups(checked);\n if (checked) {\n setValue('group_id', 'all');\n } else {\n setValue('group_id', null);\n }\n };\n\n /**\n * Callback triggere when the user switches the 'partner plan' button.\n */\n const handlePartnershipChange = (checked: boolean) => {\n if (checked) {\n setValue('type', 'PartnerPlan');\n } else {\n setValue('type', 'Plan');\n }\n };\n\n /**\n * Return the available options for the plan period\n */\n const buildPeriodsOptions = (): Array> => {\n return ['week', 'month', 'year'].map(d => {\n return { value: d, label: t(`app.admin.plan_form.${d}`) };\n });\n };\n\n /**\n * Callback triggered when the user changes the period of the current plan\n */\n const handlePeriodUpdate = (period: Interval) => {\n if (period === 'week') {\n setValue('monthly_payment', false);\n }\n };\n\n /**\n * Open/closes the partner creation modal\n */\n const tooglePartnerModal = () => {\n setIsOpenPartnerModal(!isOpenPartnerModal);\n };\n\n /**\n * Callback triggered when a user with role partner was created in the dedicated modal form\n */\n const handleNewPartner = (user) => {\n tooglePartnerModal();\n onSuccess(t('app.admin.plan_form.partner_created'));\n partners.push({ value: user.id, label: user.name });\n setValue('partner_id', user.id);\n };\n\n /**\n * Render the content of the 'subscriptions settings' tab\n */\n const renderSettingsTab = () => (\n
\n
\n
\n

{t('app.admin.plan_form.description')}

\n
\n
\n \n \n \n
\n
\n\n
\n
\n

{t('app.admin.plan_form.general_settings')}

\n

{t('app.admin.plan_form.general_settings_info')}

\n
\n
\n {action === 'create' && }\n {!allGroups && groups && }\n
\n \n \n
\n {action === 'update' && \n {t('app.admin.plan_form.edit_amount_info')}\n }\n \n
\n
\n\n
\n
\n

{t('app.admin.plan_form.activation_and_payment')}

\n
\n
\n \n \n \n
\n
\n\n
\n
\n

{t('app.admin.plan_form.partnership')}

\n

{t('app.admin.plan_form.partner_plan_help')}

\n
\n
\n \n \n {output.type === 'PartnerPlan' &&
\n {partners && }\n } onClick={tooglePartnerModal}>\n {t('app.admin.plan_form.new_user')}\n \n
}\n
\n
\n\n
\n
\n

{t('app.admin.plan_form.slots_visibility')}

\n

{t('app.admin.plan_form.slots_visibility_help')}

\n
\n
\n { return (v === null || v >= 7 || t('app.admin.plan_form.visibility_minimum') as string); } }}\n type=\"number\"\n label={t('app.admin.plan_form.machines_visibility')} />\n
\n
\n\n
\n
\n

{t('app.admin.plan_form.display')}

\n
\n
\n {categories?.length > 0 && }\n \n
\n
\n\n
\n \n
\n\n {action === 'update' && }\n
\n );\n\n return (\n
\n
\n

{t('app.admin.plan_form.ACTION_title', { ACTION: action })}

\n
\n \n {t('app.admin.plan_form.save')}\n \n
\n
\n\n
\n \n \n }\n ]} />\n \n\n \n
\n );\n};\n\nconst PlanFormWrapper: React.FC = (props) => {\n return (\n \n \n \n \n \n );\n};\nApplication.Components.component('planForm', react2angular(PlanFormWrapper, ['action', 'plan', 'onError', 'onSuccess', 'uiRouter']));\n","import React, { ReactNode, useEffect, useState } from 'react';\nimport { Control, FormState, UseFormGetValues, UseFormResetField } from 'react-hook-form/dist/types/form';\nimport { FormSwitch } from '../form/form-switch';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../base/fab-button';\nimport { PlanLimitModal } from './plan-limit-modal';\nimport { Plan, PlanLimitation } from '../../models/plan';\nimport { useFieldArray, UseFormRegister, useWatch } from 'react-hook-form';\nimport { Machine } from '../../models/machine';\nimport { MachineCategory } from '../../models/machine-category';\nimport MachineAPI from '../../api/machine';\nimport MachineCategoryAPI from '../../api/machine-category';\nimport { FormUnsavedList } from '../form/form-unsaved-list';\nimport { EditDestroyButtons } from '../base/edit-destroy-buttons';\nimport { X } from 'phosphor-react';\n\ninterface PlanLimitFormProps {\n register: UseFormRegister,\n control: Control,\n formState: FormState,\n onError: (message: string) => void,\n getValues: UseFormGetValues,\n resetField: UseFormResetField\n}\n\n/**\n * Form tab to manage a subscription's usage limit\n */\nexport const PlanLimitForm = ({ register, control, formState, onError, getValues, resetField }: PlanLimitFormProps) => {\n const { t } = useTranslation('admin');\n const { fields, append, remove, update } = useFieldArray({ control, name: 'plan_limitations_attributes' });\n const limiting = useWatch({ control, name: 'limiting' });\n\n const [isOpen, setIsOpen] = useState(false);\n const [machines, setMachines] = useState>([]);\n const [categories, setCategories] = useState>([]);\n const [edited, setEdited] = useState<{index: number, limitation: PlanLimitation}>(null);\n\n useEffect(() => {\n MachineAPI.index({ disabled: false })\n .then(setMachines)\n .catch(onError);\n MachineCategoryAPI.index()\n .then(setCategories)\n .catch(onError);\n }, []);\n\n /**\n * Opens/closes the product stock edition modal\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * Triggered when the user clicks on 'add a limitation'\n */\n const onAddLimitation = (): void => {\n setEdited(null);\n toggleModal();\n };\n /**\n * Triggered when a new limit was added or an existing limit was modified\n */\n const onLimitationSuccess = (limitation: PlanLimitation): void => {\n const id = getValues(`plan_limitations_attributes.${edited?.index}.id`);\n if (id) {\n update(edited.index, { ...limitation, id });\n setEdited(null);\n } else {\n append({ ...limitation, id });\n }\n };\n\n /**\n * Triggered when an unsaved limit was removed from the \"pending\" list.\n */\n const onRemoveUnsaved = (index: number): void => {\n const id = getValues(`plan_limitations_attributes.${index}.id`);\n if (id) {\n // will reset the field to its default values\n resetField(`plan_limitations_attributes.${index}`);\n // unmount and remount the field\n update(index, getValues(`plan_limitations_attributes.${index}`));\n } else {\n remove(index);\n }\n };\n\n /**\n * Callback triggered when a saved limitation is requested to be deleted\n */\n const handleLimitationDelete = (index: number): () => Promise => {\n return () => {\n return new Promise((resolve) => {\n update(index, { ...getValues(`plan_limitations_attributes.${index}`), _destroy: true });\n resolve();\n });\n };\n };\n\n /**\n * Triggered when the user clicks on \"cancel\" for a limitated previsouly marked as deleted\n */\n const cancelDeletion = (index: number): (event: React.MouseEvent) => void => {\n return (event) => {\n event.preventDefault();\n update(index, { ...getValues(`plan_limitations_attributes.${index}`), _destroy: false });\n };\n };\n\n /**\n * Callback triggered when the user wants to modify a limitation. Return a callback\n */\n const onEditLimitation = (limitation: PlanLimitation, index: number): () => void => {\n return () => {\n setEdited({ index, limitation });\n toggleModal();\n };\n };\n\n /**\n * Render an unsaved limitation of use\n */\n const renderOngoingLimit = (limit: PlanLimitation): ReactNode => (\n <>\n {(limit.limitable_type === 'MachineCategory' &&
\n {t('app.admin.plan_limit_form.category')}\n

{categories?.find(c => c.id === limit.limitable_id)?.name}

\n
) ||\n
\n {t('app.admin.plan_limit_form.machine')}\n

{machines?.find(m => m.id === limit.limitable_id)?.name}

\n
}\n
\n {t('app.admin.plan_limit_form.max_hours_per_day')}\n

{limit.limit}

\n
\n \n );\n\n return (\n
\n
\n
\n

{t('app.admin.plan_limit_form.usage_limitation')}

\n

{t('app.admin.plan_limit_form.usage_limitation_info')}

\n
\n
\n \n
\n
\n\n {limiting &&
\n
\n

{t('app.admin.plan_limit_form.all_limitations')}

\n
\n \n {t('app.admin.plan_limit_form.new_usage_limitation')}\n \n
\n
\n limit._modified}\n formAttributeName=\"plan_limitations_attributes\"\n formAttributes={['id', 'limitable_type', 'limitable_id', 'limit']}\n renderField={renderOngoingLimit}\n cancelLabel={t('app.admin.plan_limit_form.cancel')} />\n\n {fields.filter(f => f._modified).length > 0 &&\n

{t('app.admin.plan_limit_form.saved_limitations')}

\n }\n\n {fields.filter(f => f.limitable_type === 'MachineCategory' && !f._modified).length > 0 &&\n
\n

{t('app.admin.plan_limit_form.by_category')}

\n {fields.map((limitation, index) => {\n if (limitation.limitable_type !== 'MachineCategory' || limitation._modified) return false;\n\n return (\n
\n
\n
\n {t('app.admin.plan_limit_form.category')}\n

{categories.find(c => c.id === limitation.limitable_id)?.name}

\n
\n
\n {t('app.admin.plan_limit_form.max_hours_per_day')}\n

{limitation.limit}

\n
\n
\n\n
\n \n
\n
\n );\n }).filter(Boolean)}\n
\n }\n\n {fields.filter(f => f.limitable_type === 'Machine' && !f._modified).length > 0 &&\n
\n

{t('app.admin.plan_limit_form.by_machine')}

\n {fields.map((limitation, index) => {\n if (limitation.limitable_type !== 'Machine' || limitation._modified) return false;\n\n return (\n
\n
\n
\n {t('app.admin.plan_limit_form.machine')}\n

{machines.find(m => m.id === limitation.limitable_id)?.name}

\n
\n
\n {t('app.admin.plan_limit_form.max_hours_per_day')}\n

{limitation.limit}

\n
\n {limitation._destroy &&
{t('app.admin.plan_limit_form.ongoing_deletion')}
}\n
\n\n
\n {(limitation._destroy &&\n

\n {t('app.admin.plan_limit_form.cancel_deletion')}\n \n

) ||\n }\n
\n
\n );\n }).filter(Boolean)}\n
\n }\n
}\n\n \n
\n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabAlert } from '../base/fab-alert';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { useForm, useWatch } from 'react-hook-form';\nimport { FormSelect } from '../form/form-select';\nimport { FormInput } from '../form/form-input';\nimport { LimitableType, PlanLimitation } from '../../models/plan';\nimport { Machine } from '../../models/machine';\nimport { MachineCategory } from '../../models/machine-category';\nimport { SelectOption } from '../../models/select';\nimport { FabButton } from '../base/fab-button';\nimport { useEffect } from 'react';\n\ninterface PlanLimitModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onSuccess: (limit: PlanLimitation) => void,\n machines: Array\n categories: Array,\n limitation?: PlanLimitation,\n existingLimitations: Array;\n}\n\n/**\n * Form to manage subscriptions limitations of use\n */\nexport const PlanLimitModal: React.FC = ({ isOpen, toggleModal, machines, categories, onSuccess, limitation, existingLimitations = [] }) => {\n const { t } = useTranslation('admin');\n\n const { register, control, formState, setValue, handleSubmit, reset } = useForm({ defaultValues: limitation || { limitable_type: 'MachineCategory' } });\n const limitType = useWatch({ control, name: 'limitable_type' });\n\n useEffect(() => {\n reset(limitation);\n }, [limitation]);\n\n /**\n * Toggle the form between 'categories' and 'machine'\n */\n const toggleLimitType = (evt: React.MouseEvent, type: LimitableType) => {\n evt.preventDefault();\n setValue('limitable_type', type);\n setValue('limitable_id', null);\n };\n\n /**\n * Callback triggered when the user validates the new limit.\n * We do not use handleSubmit() directly to prevent the propagaion of the \"submit\" event to the parent form\n */\n const onSubmit = (event: React.FormEvent) => {\n if (event) {\n event.stopPropagation();\n event.preventDefault();\n }\n return handleSubmit((data: PlanLimitation) => {\n onSuccess({ ...data, _modified: true });\n reset({ limitable_type: 'MachineCategory', limitable_id: null, limit: null });\n toggleModal();\n })(event);\n };\n /**\n * Creates options to the react-select format\n */\n const buildOptions = (): Array> => {\n if (limitType === 'MachineCategory') {\n return categories\n .filter(c => limitation || !existingLimitations.filter(l => l.limitable_type === 'MachineCategory').map(l => l.limitable_id).includes(c.id))\n .map(cat => {\n return { value: cat.id, label: cat.name };\n });\n } else {\n return machines\n .filter(m => limitation || !existingLimitations.filter(l => l.limitable_type === 'Machine').map(l => l.limitable_id).includes(m.id))\n .map(machine => {\n return { value: machine.id, label: machine.name };\n });\n }\n };\n\n return (\n reset({ limitable_type: 'MachineCategory' })}\n closeButton>\n
\n

{t('app.admin.plan_limit_modal.limit_reservations')}

\n
\n \n \n
\n {limitType === 'Machine' ? t('app.admin.plan_limit_modal.machine_info') : t('app.admin.plan_limit_modal.categories_info')}\n \n \n \n \n {t('app.admin.plan_limit_modal.confirm')}\n \n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useFieldArray, UseFormRegister } from 'react-hook-form';\nimport { Control, FormState, UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { Plan } from '../../models/plan';\nimport { FormInput } from '../form/form-input';\nimport { Machine } from '../../models/machine';\nimport { Space } from '../../models/space';\nimport SettingAPI from '../../api/setting';\nimport { SettingName } from '../../models/setting';\nimport MachineAPI from '../../api/machine';\nimport SpaceAPI from '../../api/space';\nimport { Price } from '../../models/price';\nimport FormatLib from '../../lib/format';\nimport { FabTabs } from '../base/fab-tabs';\nimport PlanAPI from '../../api/plan';\nimport { FormSelect } from '../form/form-select';\nimport { SelectOption } from '../../models/select';\n\ninterface PlanPricingFormProps {\n register: UseFormRegister,\n control: Control\n formState: FormState,\n setValue: UseFormSetValue,\n onError: (message: string) => void,\n}\n\n/**\n * Sub-form to define prices for machines and spaces, for the current plan\n */\nexport const PlanPricingForm = ({ register, control, formState, setValue, onError }: PlanPricingFormProps) => {\n const { t } = useTranslation('admin');\n const { fields } = useFieldArray({ control, name: 'prices_attributes' });\n\n const [machines, setMachines] = useState>(null);\n const [spaces, setSpaces] = useState>(null);\n const [settings, setSettings] = useState>(null);\n const [plans, setPlans] = useState>>(null);\n\n useEffect(() => {\n SettingAPI.query(['spaces_module', 'machines_module']).then(setSettings).catch(onError);\n PlanAPI.index()\n .then(res => setPlans(res.map(p => { return { value: p.id, label: p.name }; })))\n .catch(onError);\n }, []);\n\n useEffect(() => {\n if (settings?.get('machines_module') === 'true') {\n MachineAPI.index().then(setMachines).catch(onError);\n }\n if (settings?.get('spaces_module') === 'true') {\n SpaceAPI.index().then(setSpaces).catch(onError);\n }\n }, [settings]);\n\n /**\n * Copy prices from the selected plan\n */\n const handleCopyPrices = (planId: number) => {\n PlanAPI.get(planId).then(parent => {\n parent.prices_attributes.forEach(price => {\n const index = fields.findIndex(p => p.priceable_type === price.priceable_type && p.priceable_id === price.priceable_id);\n setValue(`prices_attributes.${index}.amount`, price.amount);\n });\n }).catch(onError);\n };\n\n /**\n * Render the form element for the given price\n */\n const renderPriceElement = (price: Price, index: number) => {\n const item: Space | Machine = (price.priceable_type === 'Machine' && machines?.find(m => m.id === price.priceable_id)) ||\n (price.priceable_type === 'Space' && spaces?.find(s => s.id === price.priceable_id));\n if (!item?.disabled) {\n return (\n
\n \n \n
\n );\n }\n };\n\n return (\n
\n
\n

{t('app.admin.plan_pricing_form.prices')}

\n

{t('app.admin.plan_pricing_form.about_prices')}

\n
\n
\n {plans && }\n { {\n if (price.priceable_type !== 'Machine') return false;\n return renderPriceElement(price, index);\n }).filter(Boolean)\n },\n spaces && {\n id: 'spaces',\n title: t('app.admin.plan_pricing_form.spaces'),\n content: fields.map((price, index) => {\n if (price.priceable_type !== 'Space') return false;\n return renderPriceElement(price, index);\n }).filter(Boolean)\n }\n ]} />}\n
\n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport Select from 'react-select';\nimport { useTranslation } from 'react-i18next';\nimport { Group } from '../../models/group';\nimport { User } from '../../models/user';\nimport PlanAPI from '../../api/plan';\nimport { PlansDuration } from '../../models/plan';\nimport { SelectOption } from '../../models/select';\n\ninterface PlansFilterProps {\n user?: User,\n groups: Array,\n onGroupSelected: (groupId: number) => void,\n onError: (message: string) => void,\n onDurationSelected: (plansIds: Array) => void,\n}\n\n/**\n * Allows filtering on plans list\n */\nexport const PlansFilter: React.FC = ({ user, groups, onGroupSelected, onError, onDurationSelected }) => {\n const { t } = useTranslation('public');\n\n const [durations, setDurations] = useState>(null);\n\n // get the plans durations on component load\n useEffect(() => {\n PlanAPI.durations().then(data => {\n setDurations(data);\n }).catch(error => onError(error));\n }, []);\n\n /**\n * Convert all groups to the react-select format\n */\n const buildGroupOptions = (): Array> => {\n return groups.filter(g => !g.disabled).map(g => {\n return { value: g.id, label: g.name };\n });\n };\n\n /**\n * Convert all durations to the react-select format\n */\n const buildDurationOptions = (): Array> => {\n const options = durations.map((d, index) => {\n return { value: index, label: d.name };\n });\n options.unshift({ value: null, label: t('app.public.plans_filter.all_durations') });\n return options;\n };\n\n /**\n * Callback triggered when the user selects a group in the dropdown list\n */\n const handleGroupSelected = (option: SelectOption): void => {\n onGroupSelected(option.value);\n };\n\n /**\n * Callback triggered when the user selects a duration in the dropdown list\n */\n const handleDurationSelected = (option: SelectOption): void => {\n onDurationSelected(durations[option.value]?.plans_ids);\n };\n\n return (\n
\n {!user &&
\n \n \n
}\n
\n );\n};\n","import { ReactNode, useEffect, useState } from 'react';\nimport * as React from 'react';\nimport _ from 'lodash';\nimport PlanAPI from '../../api/plan';\nimport { Plan } from '../../models/plan';\nimport { PlanCategory } from '../../models/plan-category';\nimport PlanCategoryAPI from '../../api/plan-category';\nimport { User } from '../../models/user';\nimport { Group } from '../../models/group';\nimport GroupAPI from '../../api/group';\nimport { PlanCard } from './plan-card';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport { PlansFilter } from './plans-filter';\n\ndeclare const Application: IApplication;\n\ninterface PlansListProps {\n onError: (message: string) => void,\n onPlanSelection: (plan: Plan) => void,\n onLoginRequest: () => void,\n operator?: User,\n customer?: User,\n subscribedPlanId?: number,\n canSelectPlan: boolean,\n}\n\n// A list of plans, organized by group ID - then organized by plan-category ID (or NaN if the plan has no category)\ntype PlansTree = Map>>;\n\n/**\n * This component display an organized list of plans to allow the end-user to select one and subscribe online\n */\nexport const PlansList: React.FC = ({ onError, onPlanSelection, onLoginRequest, operator, customer, subscribedPlanId, canSelectPlan }) => {\n // all plans\n const [plans, setPlans] = useState(null);\n // all plan-categories, ordered by weight\n const [planCategories, setPlanCategories] = useState>(null);\n // all groups\n const [groups, setGroups] = useState>(null);\n // currently selected plan\n const [selectedPlan, setSelectedPlan] = useState(null);\n // filtering shown plans by only one group\n const [groupFilter, setGroupFilter] = useState(null);\n // filtering shown plans by ids\n const [plansFilter, setPlansFilter] = useState>(null);\n\n // fetch data on component mounted\n useEffect(() => {\n PlanCategoryAPI.index()\n .then(data => setPlanCategories(data))\n .catch(error => onError(error));\n GroupAPI.index()\n .then(groupsData => {\n setGroups(groupsData);\n PlanAPI.index()\n .then(data => setPlans(sortPlans(data, groupsData)))\n .catch(error => onError(error));\n })\n .catch(error => onError(error));\n }, []);\n\n // reset the selected plan when the user changes\n useEffect(() => {\n setSelectedPlan(null);\n setGroupFilter(null);\n }, [customer, operator]);\n\n /**\n * Group a flat array of plans and return a collection of the same plans, grouped by the given property\n */\n const groupBy = (plans: Array, criteria: string): Map> => {\n const grouped = _.groupBy(plans, criteria);\n\n const map = new Map>();\n for (const criteriaId in grouped) {\n if (Object.prototype.hasOwnProperty.call(grouped, criteriaId)) {\n const enabled = grouped[criteriaId].filter(plan => !plan.disabled);\n // null ids will be converted to NaN\n map.set(Number(criteriaId), enabled);\n }\n }\n return map;\n };\n\n /**\n * Sort the plans, by group and by category and return the corresponding map\n */\n const sortPlans = (plans: Array, groups: Array): PlansTree => {\n const byGroup = groupBy(plans, 'group_id');\n\n const res = new Map>>();\n for (const [groupId, plansByGroup] of byGroup) {\n const group = groups.find(g => g.id === groupId);\n if (group && !group.disabled) {\n res.set(groupId, groupBy(plansByGroup, 'plan_category_id'));\n }\n }\n return res;\n };\n\n /**\n * Filter the plans to display, depending on the connected/selected user and on the selected group filter (if any)\n */\n const filteredPlans = (): PlansTree => {\n if (_.isEmpty(customer) && !groupFilter) return plans;\n if (groupFilter) return new Map([[groupFilter, plans.get(groupFilter)]]);\n\n return new Map([[customer.group_id, plans.get(customer.group_id)]]);\n };\n\n /**\n * When called with a group ID, returns the name of the requested group\n */\n const groupName = (groupId: number): string => {\n return groups.find(g => g.id === groupId)?.name;\n };\n\n /**\n * When called with a category ID, returns the requested plan-category\n */\n const findCategory = (categoryId: number): PlanCategory => {\n return planCategories?.find(c => c.id === categoryId);\n };\n\n /**\n * Check if the currently selected plan matched the provided one\n */\n const isSelectedPlan = (plan: Plan): boolean => {\n return (plan === selectedPlan);\n };\n\n /**\n * Callback for sorting plans by weight\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort\n */\n const comparePlans = (plan1: Plan, plan2: Plan): number => {\n return (plan2.ui_weight - plan1.ui_weight);\n };\n\n /**\n * Callback for sorting categories by weight\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort\n */\n const compareCategories = (category1: [number, Array], category2: [number, Array]): number => {\n if (isNaN(category1[0])) return -1;\n if (isNaN(category2[0])) return 1;\n\n const categoryObject1 = planCategories.find(c => c.id === category1[0]);\n const categoryObject2 = planCategories.find(c => c.id === category2[0]);\n return (categoryObject2.weight - categoryObject1.weight);\n };\n\n /**\n * Callback triggered when the user chooses a plan to subscribe\n */\n const handlePlanSelection = (plan: Plan): void => {\n setSelectedPlan(plan);\n onPlanSelection(plan);\n };\n\n /**\n * Callback triggered when the user selects a group to filter the current list\n */\n const handleFilterByGroup = (groupId: number): void => {\n setGroupFilter(groupId);\n };\n\n /**\n * Callback triggered when the user selects a duration to filter the current list\n */\n const handleFilterByDuration = (plansIds: Array): void => {\n setPlansFilter(plansIds);\n };\n\n /**\n * Callback for filtering plans to display, depending on the filter-by-plans-ids selection\n * @see https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Array/filter\n */\n const filterPlan = (plan: Plan): boolean => {\n if (!plansFilter) return true;\n\n return plansFilter.includes(plan.id);\n };\n\n /**\n * Render the provided list of categories, with each associated plans\n */\n const renderPlansByCategory = (plans: Map>): ReactNode => {\n if (!plans) {\n return null;\n }\n return (\n
\n {Array.from(plans).sort(compareCategories).map(([categoryId, plansByCategory]) => {\n const category = findCategory(categoryId);\n const categoryPlans = plansByCategory.filter(filterPlan);\n const isShown = !!category && categoryPlans.length > 0;\n return (\n
\n {isShown &&

{ category.name }

}\n {isShown &&

}\n {renderPlans(categoryPlans)}\n

\n );\n })}\n
\n );\n };\n\n /**\n * Render the provided list of plans, ordered by ui_weight.\n */\n const renderPlans = (categoryPlans: Array): ReactNode => {\n return (\n
\n {categoryPlans.length > 0 && categoryPlans.sort(comparePlans).map(plan => (\n \n ))}\n
\n );\n };\n\n return (\n
\n {groups && }\n {plans && Array.from(filteredPlans()).map(([groupId, plansByGroup]) => {\n return (\n
\n {plansByGroup?.size > 0 &&

{ groupName(groupId) }

}\n {plansByGroup && renderPlansByCategory(plansByGroup)}\n
\n );\n })}\n
\n );\n};\n\nconst PlansListWrapper: React.FC = ({ customer, onError, onPlanSelection, onLoginRequest, operator, subscribedPlanId, canSelectPlan }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('plansList', react2angular(PlansListWrapper, ['customer', 'onError', 'onPlanSelection', 'onLoginRequest', 'operator', 'subscribedPlanId', 'canSelectPlan']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport _ from 'lodash';\nimport { Machine } from '../../models/machine';\nimport { User } from '../../models/user';\nimport { UserPack } from '../../models/user-pack';\nimport UserPackAPI from '../../api/user-pack';\nimport SettingAPI from '../../api/setting';\nimport { FabButton } from '../base/fab-button';\nimport { useTranslation } from 'react-i18next';\nimport { ProposePacksModal } from './propose-packs-modal';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport { PrepaidPack } from '../../models/prepaid-pack';\nimport PrepaidPackAPI from '../../api/prepaid-pack';\nimport { FabAlert } from '../base/fab-alert';\n\ndeclare const Application: IApplication;\n\ntype PackableItem = Machine;\n\ninterface PacksSummaryProps {\n item: PackableItem,\n itemType: 'Machine',\n customer?: User,\n operator: User,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n refresh?: Promise\n}\n\n/**\n * Display a short summary of the prepaid-packs already bought by the provider customer, for the given item.\n * May also allows members to buy directly some new prepaid-packs.\n */\nconst PacksSummary: React.FC = ({ item, itemType, customer, operator, onError, onSuccess, refresh }) => {\n const { t } = useTranslation('logged');\n\n const [packs, setPacks] = useState>(null);\n const [userPacks, setUserPacks] = useState>(null);\n const [threshold, setThreshold] = useState(null);\n const [packsModal, setPacksModal] = useState(false);\n const [isPackOnlyForSubscription, setIsPackOnlyForSubscription] = useState(true);\n\n useEffect(() => {\n SettingAPI.get('renew_pack_threshold')\n .then(data => setThreshold(parseFloat(data.value)))\n .catch(error => onError(error));\n SettingAPI.get('pack_only_for_subscription')\n .then(data => setIsPackOnlyForSubscription(data.value === 'true'))\n .catch(error => onError(error));\n }, []);\n\n useEffect(() => {\n getUserPacksData();\n }, [customer, item, itemType]);\n\n useEffect(() => {\n if (refresh instanceof Promise) {\n refresh.then(getUserPacksData);\n }\n }, [refresh]);\n\n /**\n * Fetch the user packs data from the API\n */\n const getUserPacksData = (): void => {\n if (_.isEmpty(customer)) return;\n\n UserPackAPI.index({ user_id: customer.id, priceable_type: itemType, priceable_id: item.id })\n .then(data => setUserPacks(data))\n .catch(error => onError(error));\n PrepaidPackAPI.index({ priceable_id: item.id, priceable_type: itemType, group_id: customer.group_id, disabled: false })\n .then(data => setPacks(data))\n .catch(error => onError(error));\n };\n\n /**\n * Total of minutes used by the customer\n */\n const totalUsed = (): number => {\n if (!userPacks) return 0;\n\n return userPacks.map(up => up.minutes_used).reduce((acc, curr) => acc + curr, 0);\n };\n\n /**\n * Total of minutes available is the packs bought by the customer\n */\n const totalAvailable = (): number => {\n if (!userPacks) return 0;\n\n return userPacks.map(up => up.prepaid_pack.minutes).reduce((acc, curr) => acc + curr, 0);\n };\n\n /**\n * Total prepaid hours remaining for the current customer\n */\n const totalHours = (): number => {\n return (totalAvailable() - totalUsed()) / 60;\n };\n\n /**\n * Do we need to display the \"buy new pack\" button?\n */\n const shouldDisplayButton = (): boolean => {\n if (!packs?.length) return false;\n\n if (threshold < 1) {\n return totalAvailable() - totalUsed() <= totalAvailable() * threshold;\n }\n\n return totalAvailable() - totalUsed() <= threshold * 60;\n };\n\n /**\n * Open/closes the prepaid-pack buying modal\n */\n const togglePacksModal = (): void => {\n setPacksModal(!packsModal);\n };\n\n /**\n * Callback triggered when the customer has successfully bought a prepaid-pack\n */\n const handlePackBoughtSuccess = (message: string): void => {\n onSuccess(message);\n togglePacksModal();\n UserPackAPI.index({ user_id: customer.id, priceable_type: itemType, priceable_id: item.id })\n .then(data => setUserPacks(data))\n .catch(error => onError(error));\n };\n\n // prevent component rendering if no customer selected\n if (_.isEmpty(customer)) return
;\n // prevent component rendering if ths customer have no packs and there are no packs available\n if (totalHours() === 0 && packs?.length === 0) return
;\n // render remaining hours and a warning if customer has not any subscription if admin active pack only for subscription option\n if (totalHours() > 0) {\n return (\n
\n

{t('app.logged.packs_summary.prepaid_hours')}

\n
\n \n {t('app.logged.packs_summary.remaining_HOURS', { HOURS: totalHours(), ITEM: itemType })}\n {isPackOnlyForSubscription && !customer.subscribed_plan &&\n \n {t('app.logged.packs_summary.unable_to_use_pack_for_subsription_is_expired')}\n \n }\n \n
\n
\n );\n }\n // prevent component rendering buy pack button if customer has not any subscription if admin active pack only for subscription option\n if (isPackOnlyForSubscription && !customer.subscribed_plan) return
;\n\n return (\n
\n

{t('app.logged.packs_summary.prepaid_hours')}

\n
\n \n {totalHours() === 0 && t('app.logged.packs_summary.no_hours', { ITEM: itemType })}\n \n {shouldDisplayButton() &&
\n }>\n {t('app.logged.packs_summary.buy_a_new_pack')}\n \n \n
}\n
\n
\n );\n};\n\nconst PacksSummaryWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nexport { PacksSummaryWrapper as PacksSummary };\n\nApplication.Components.component('packsSummary', react2angular(PacksSummaryWrapper, ['item', 'itemType', 'customer', 'operator', 'onError', 'onSuccess', 'refresh']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { Machine } from '../../models/machine';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport PrepaidPackAPI from '../../api/prepaid-pack';\nimport { User } from '../../models/user';\nimport { PrepaidPack } from '../../models/prepaid-pack';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../base/fab-button';\nimport PriceAPI from '../../api/price';\nimport { Price } from '../../models/price';\nimport { PaymentMethod, ShoppingCart } from '../../models/payment';\nimport FormatLib from '../../lib/format';\nimport { PaymentModal } from '../payment/stripe/payment-modal';\n\ntype PackableItem = Machine;\n\ninterface ProposePacksModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n item: PackableItem,\n itemType: 'Machine',\n customer: User,\n operator: User,\n onError: (message: string) => void,\n onDecline: (item: PackableItem) => void,\n onSuccess: (message:string, item: PackableItem) => void,\n}\n\n/**\n * Modal dialog shown to offer prepaid-packs for purchase, to the current user.\n */\nexport const ProposePacksModal: React.FC = ({ isOpen, toggleModal, item, itemType, customer, operator, onError, onDecline, onSuccess }) => {\n const { t } = useTranslation('logged');\n\n const [price, setPrice] = useState(null);\n const [packs, setPacks] = useState>(null);\n const [cart, setCart] = useState(null);\n const [paymentModal, setPaymentModal] = useState(false);\n\n useEffect(() => {\n PrepaidPackAPI.index({ priceable_id: item.id, priceable_type: itemType, group_id: customer.group_id, disabled: false })\n .then(data => setPacks(data))\n .catch(error => onError(error));\n PriceAPI.index({ priceable_id: item.id, priceable_type: itemType, group_id: customer.group_id, plan_id: null })\n .then(data => setPrice(data[0]))\n .catch(error => onError(error));\n }, [item]);\n\n /**\n * Open/closes the payment modal\n */\n const togglePaymentModal = (): void => {\n setPaymentModal(!paymentModal);\n };\n\n /**\n * Convert the hourly-based price of the given prive, to a total price, based on the duration of the given pack\n */\n const hourlyPriceToTotal = (price: Price, pack: PrepaidPack): number => {\n const hours = pack.minutes / 60;\n return price.amount * hours;\n };\n\n /**\n * Return the number of hours, user-friendly formatted\n */\n const formatDuration = (minutes: number): string => {\n return t('app.logged.propose_packs_modal.pack_DURATION', { DURATION: minutes / 60 });\n };\n\n /**\n * Return a user-friendly string for the validity of the provided pack\n */\n const formatValidity = (pack: PrepaidPack): string => {\n if (!pack.validity_interval) return null;\n\n const period = t(`app.logged.propose_packs_modal.period.${pack.validity_interval}`, { COUNT: pack.validity_count });\n return t('app.logged.propose_packs_modal.validity', { COUNT: pack.validity_count, PERIODS: period });\n };\n\n /**\n * The user has declined to buy a pack\n */\n const handlePacksRefused = (): void => {\n onDecline(item);\n };\n\n /**\n * The user has accepted to buy the provided pack, process with the payment\n */\n const handleBuyPack = (pack: PrepaidPack) => {\n return (): void => {\n setCart({\n customer_id: customer.id,\n payment_method: PaymentMethod.Card,\n items: [\n { prepaid_pack: { id: pack.id } }\n ]\n });\n togglePaymentModal();\n };\n };\n\n /**\n * Callback triggered when the user has bought the pack with a successful payment\n */\n const handlePackBought = (): void => {\n onSuccess(t('app.logged.propose_packs_modal.pack_bought_success'), item);\n };\n\n /**\n * Render the given prepaid-pack\n */\n const renderPack = (pack: PrepaidPack) => {\n if (!price) return;\n\n const normalPrice = hourlyPriceToTotal(price, pack);\n return (\n
\n {formatDuration(pack.minutes)}\n {FormatLib.price(pack.amount)}\n {pack.amount < normalPrice && {FormatLib.price(normalPrice)}}\n {formatValidity(pack)}\n }>\n {t('app.logged.propose_packs_modal.buy_this_pack')}\n \n
\n );\n };\n\n return (\n \n

{t('app.logged.propose_packs_modal.packs_proposed')}

\n
\n {packs?.map(p => renderPack(p))}\n
\n {cart &&
\n \n
}\n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { IFablab } from '../../models/fablab';\nimport { FabInput } from '../base/fab-input';\nimport { FabButton } from '../base/fab-button';\nimport { Price } from '../../models/price';\nimport FormatLib from '../../lib/format';\n\ndeclare let Fablab: IFablab;\n\ninterface EditablePriceProps {\n price: Price,\n onSave: (price: Price) => void,\n}\n\n/**\n * Display the given price.\n * When the user clics on the price, switch to the edition mode to allow him modifying the price.\n */\nexport const EditablePrice: React.FC = ({ price, onSave }) => {\n const [edit, setEdit] = useState(false);\n const [tempPrice, setTempPrice] = useState(`${price.amount}`);\n\n /**\n * Saves the new price\n */\n const handleValidateEdit = (): void => {\n const newPrice: Price = Object.assign({}, price);\n newPrice.amount = parseFloat(tempPrice);\n onSave(newPrice);\n toggleEdit();\n };\n\n /**\n * Callback triggered when the user input a new price\n */\n const handleChangePrice = (value: string): void => {\n setTempPrice(value);\n };\n\n /**\n * Enable or disable the edit mode\n */\n const toggleEdit = (): void => {\n setEdit(!edit);\n };\n\n return (\n \n {!edit && {FormatLib.price(price.amount)}}\n {edit && \n \n } className=\"approve-button\" onClick={handleValidateEdit} />\n } className=\"cancel-button\" onClick={toggleEdit} />\n }\n \n );\n};\n","import { ReactNode, useState } from 'react';\nimport * as React from 'react';\nimport { PrepaidPack } from '../../../models/prepaid-pack';\nimport { useTranslation } from 'react-i18next';\nimport { FabPopover } from '../../base/fab-popover';\nimport { CreatePack } from './create-pack';\nimport PrepaidPackAPI from '../../../api/prepaid-pack';\nimport FormatLib from '../../../lib/format';\nimport { EditDestroyButtons } from '../../base/edit-destroy-buttons';\nimport { FabModal } from '../../base/fab-modal';\nimport { PackForm } from './pack-form';\n\ninterface ConfigurePacksButtonProps {\n packsData: Array,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n groupId: number,\n priceableId: number,\n priceableType: string,\n}\n\n/**\n * This component is a button that shows the list of prepaid-packs when moving the mouse over it.\n * It also triggers modal dialogs to configure (add/delete/edit/remove) prepaid-packs.\n */\nexport const ConfigurePacksButton: React.FC = ({ packsData, onError, onSuccess, groupId, priceableId, priceableType }) => {\n const { t } = useTranslation('admin');\n\n const [packs, setPacks] = useState>(packsData);\n const [showList, setShowList] = useState(false);\n const [isOpen, setIsOpen] = useState(false);\n const [packData, setPackData] = useState(null);\n\n /**\n * Return the number of hours, user-friendly formatted\n */\n const formatDuration = (minutes: number): string => {\n return t('app.admin.configure_packs_button.pack_DURATION', { DURATION: minutes / 60 });\n };\n\n /**\n * Open/closes the popover listing the existing packs\n */\n const toggleShowList = (): void => {\n setShowList(!showList);\n };\n\n /**\n * Callback triggered when the PrepaidPack was successfully created/deleted/updated.\n * We refresh the list of packs for the current tooltip to display the new data.\n */\n const handleSuccess = (message: string) => {\n onSuccess(message);\n PrepaidPackAPI.index({ group_id: groupId, priceable_id: priceableId, priceable_type: priceableType })\n .then(data => setPacks(data))\n .catch(error => onError(error));\n };\n\n /**\n * Render the button used to trigger the \"new pack\" modal\n */\n const renderAddButton = (): ReactNode => {\n return ;\n };\n\n /**\n * Open/closes the \"edit pack\" modal dialog\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * When the user clicks on the edition button, query the full data of the current pack from the API, then open the edition modal\n */\n const handleRequestEdit = (pack: PrepaidPack): void => {\n PrepaidPackAPI.get(pack.id)\n .then(data => {\n setPackData(data);\n toggleModal();\n })\n .catch(error => onError(error));\n };\n\n /**\n * Callback triggered when the user has validated the changes of the PrepaidPack\n */\n const handleUpdate = (pack: PrepaidPack): void => {\n PrepaidPackAPI.update(pack)\n .then(() => {\n handleSuccess(t('app.admin.configure_packs_button.pack_successfully_updated'));\n toggleModal();\n })\n .catch(error => onError(error));\n };\n\n return (\n
\n \n {showList && \n
    \n {packs?.map(p =>\n
  • \n {formatDuration(p.minutes)} - {FormatLib.price(p.amount)}\n handleRequestEdit(p)}\n itemId={p.id}\n itemType={t('app.admin.configure_packs_button.pack')}\n destroy={PrepaidPackAPI.destroy}/>\n \n {packData && }\n \n
  • )}\n
\n {packs?.length === 0 && {t('app.admin.configure_packs_button.no_packs')}}\n
}\n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { FabModal } from '../../base/fab-modal';\nimport { PackForm } from './pack-form';\nimport { PrepaidPack } from '../../../models/prepaid-pack';\nimport PrepaidPackAPI from '../../../api/prepaid-pack';\nimport { useTranslation } from 'react-i18next';\nimport { FabAlert } from '../../base/fab-alert';\n\ninterface CreatePackProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n groupId: number,\n priceableId: number,\n priceableType: string,\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog handing the process of creating a new PrepaidPack\n */\nexport const CreatePack: React.FC = ({ onSuccess, onError, groupId, priceableId, priceableType }) => {\n const { t } = useTranslation('admin');\n\n const [isOpen, setIsOpen] = useState(false);\n\n /**\n * Open/closes the \"new pack\" modal dialog\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * Callback triggered when the user has validated the creation of the new PrepaidPack\n */\n const handleSubmit = (pack: PrepaidPack): void => {\n // set the already-known attributes of the new pack\n const newPack = Object.assign({} as PrepaidPack, pack);\n newPack.group_id = groupId;\n newPack.priceable_id = priceableId;\n newPack.priceable_type = priceableType;\n\n // create it on the API\n PrepaidPackAPI.create(newPack)\n .then(() => {\n onSuccess(t('app.admin.create_pack.pack_successfully_created'));\n toggleModal();\n })\n .catch(error => onError(error));\n };\n\n return (\n
\n \n \n \n {t('app.admin.create_pack.new_pack_info', { TYPE: priceableType })}\n \n \n \n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { FabModal } from '../../base/fab-modal';\nimport { PackForm } from './pack-form';\nimport { PrepaidPack } from '../../../models/prepaid-pack';\nimport PrepaidPackAPI from '../../../api/prepaid-pack';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../../base/fab-button';\n\ninterface EditPackProps {\n pack: PrepaidPack,\n onSuccess: (message: string) => void,\n onError: (message: string) => void\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog handing the process of creating a new PrepaidPack\n */\nexport const EditPack: React.FC = ({ pack, onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n const [isOpen, setIsOpen] = useState(false);\n const [packData, setPackData] = useState(null);\n\n /**\n * Open/closes the \"edit pack\" modal dialog\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * When the user clicks on the edition button, query the full data of the current pack from the API, then open te edition modal\n */\n const handleRequestEdit = (): void => {\n PrepaidPackAPI.get(pack.id)\n .then(data => {\n setPackData(data);\n toggleModal();\n })\n .catch(error => onError(error));\n };\n\n /**\n * Callback triggered when the user has validated the changes of the PrepaidPack\n */\n const handleUpdate = (pack: PrepaidPack): void => {\n PrepaidPackAPI.update(pack)\n .then(() => {\n onSuccess(t('app.admin.edit_pack.pack_successfully_updated'));\n toggleModal();\n })\n .catch(error => onError(error));\n };\n\n return (\n
\n } onClick={handleRequestEdit} />\n \n {packData && }\n \n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../../base/loader';\nimport { FabAlert } from '../../base/fab-alert';\nimport { HtmlTranslate } from '../../base/html-translate';\nimport MachineAPI from '../../../api/machine';\nimport GroupAPI from '../../../api/group';\nimport { Machine } from '../../../models/machine';\nimport { Group } from '../../../models/group';\nimport { IApplication } from '../../../models/application';\nimport { EditablePrice } from '../editable-price';\nimport { ConfigurePacksButton } from './configure-packs-button';\nimport PriceAPI from '../../../api/price';\nimport { Price } from '../../../models/price';\nimport PrepaidPackAPI from '../../../api/prepaid-pack';\nimport { PrepaidPack } from '../../../models/prepaid-pack';\nimport { useImmer } from 'use-immer';\nimport FormatLib from '../../../lib/format';\n\ndeclare const Application: IApplication;\n\ninterface MachinesPricingProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\n/**\n * Interface to set and edit the prices of machines-hours, per group\n */\nexport const MachinesPricing: React.FC = ({ onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n\n const [machines, setMachines] = useState>(null);\n const [groups, setGroups] = useState>(null);\n const [prices, updatePrices] = useImmer>(null);\n const [packs, setPacks] = useState>(null);\n\n // retrieve the initial data\n useEffect(() => {\n MachineAPI.index({ disabled: false })\n .then(data => setMachines(data))\n .catch(error => onError(error));\n GroupAPI.index({ disabled: false })\n .then(data => setGroups(data))\n .catch(error => onError(error));\n PriceAPI.index({ priceable_type: 'Machine', plan_id: null })\n .then(data => updatePrices(data))\n .catch(error => onError(error));\n PrepaidPackAPI.index()\n .then(data => setPacks(data))\n .catch(error => onError(error));\n }, []);\n\n // duration of the example slot\n const EXEMPLE_DURATION = 20;\n\n /**\n * Return the exemple price, formatted\n */\n const examplePrice = (type: 'hourly_rate' | 'final_price'): string => {\n const hourlyRate = 10;\n\n if (type === 'hourly_rate') {\n return FormatLib.price(hourlyRate);\n }\n\n const price = (hourlyRate / 60) * EXEMPLE_DURATION;\n return FormatLib.price(price);\n };\n\n /**\n * Find the price matching the given criterion\n */\n const findPriceBy = (machineId, groupId): Price => {\n return prices.find(price => price.priceable_id === machineId && price.group_id === groupId);\n };\n\n /**\n * Filter the packs matching the given criterion\n */\n const filterPacksBy = (machineId, groupId): Array => {\n return packs.filter(pack => pack.priceable_id === machineId && pack.group_id === groupId);\n };\n\n /**\n * Update the given price in the internal state\n */\n const updatePrice = (price: Price): void => {\n updatePrices(draft => {\n const index = draft.findIndex(p => p.id === price.id);\n draft[index] = price;\n return draft;\n });\n };\n\n /**\n * Callback triggered when the user has confirmed to update a price\n */\n const handleUpdatePrice = (price: Price): void => {\n PriceAPI.update(price)\n .then(() => {\n onSuccess(t('app.admin.machines_pricing.price_updated'));\n updatePrice(price);\n })\n .catch(error => onError(error));\n };\n\n return (\n
\n \n

\n

\n

{t('app.admin.machines_pricing.you_can_override')}

\n
\n \n \n \n \n {groups?.map(group => )}\n \n \n \n {machines?.map(machine => \n \n {groups?.map(group => )}\n )}\n \n
{t('app.admin.machines_pricing.machines')}{group.name}
{machine.name}\n {prices && }\n {packs && }\n
\n
\n );\n};\n\nconst MachinesPricingWrapper: React.FC = ({ onError, onSuccess }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('machinesPricing', react2angular(MachinesPricingWrapper, ['onError', 'onSuccess']));\n","import { useEffect, useState } from 'react';\nimport { Controller, SubmitHandler, useForm } from 'react-hook-form';\nimport { PrepaidPack } from '../../../models/prepaid-pack';\nimport { useTranslation } from 'react-i18next';\nimport { IFablab } from '../../../models/fablab';\nimport { SelectOption } from '../../../models/select';\nimport { FormInput } from '../../form/form-input';\nimport { FormSelect } from '../../form/form-select';\nimport { FormSwitch } from '../../form/form-switch';\nimport { FabInput } from '../../base/fab-input';\n\ndeclare let Fablab: IFablab;\n\ninterface PackFormProps {\n formId: string,\n onSubmit: (pack: PrepaidPack) => void,\n pack?: PrepaidPack,\n}\n\nconst ALL_INTERVALS = ['day', 'week', 'month', 'year'] as const;\ntype interval = typeof ALL_INTERVALS[number];\n\n/**\n * A form component to create/edit a PrepaidPack.\n * The form validation must be created elsewhere, using the attribute form={formId}.\n */\nexport const PackForm: React.FC = ({ formId, onSubmit, pack }) => {\n const { t } = useTranslation('admin');\n\n const { handleSubmit, register, control, formState, setValue } = useForm({ defaultValues: { ...pack } });\n\n const [formattedDuration, setFormattedDuration] = useState(pack?.minutes || 60);\n /**\n * Callback triggered when the user validates the form\n */\n const submitForm: SubmitHandler = (data:PrepaidPack) => {\n onSubmit(data);\n };\n\n /**\n * Convert all validity-intervals to the react-select format\n */\n const buildOptions = (): Array> => {\n return ALL_INTERVALS.map(i => intervalToOption(i));\n };\n\n /**\n * Convert the given validity-interval to the react-select format\n */\n const intervalToOption = (value: interval): SelectOption => {\n if (!value) return { value, label: '' };\n return { value, label: t(`app.admin.pack_form.intervals.${value}`, { COUNT: pack?.validity_count || 0 }) };\n };\n\n /**\n * Changes hours into minutes\n */\n const formatDuration = (value) => {\n setFormattedDuration(value * 60);\n };\n useEffect(() => {\n setValue('minutes', formattedDuration);\n }, [formattedDuration]);\n\n return (\n
\n
\n \n (\n }\n onChange={formatDuration}\n defaultValue={formattedDuration / 60} />\n )} />\n
\n\n }\n addOn={Fablab.intl_currency}\n rules={{ required: true, min: 0 }}\n label={t('app.admin.pack_form.amount')} />\n\n \n
\n }\n rules={{ min: 0 }}/>\n \n
\n\n \n \n );\n};\n","import { ReactNode, useState } from 'react';\nimport * as React from 'react';\nimport { Price } from '../../../models/price';\nimport { useTranslation } from 'react-i18next';\nimport { FabPopover } from '../../base/fab-popover';\nimport { CreateExtendedPrice } from './create-extended-price';\nimport PriceAPI from '../../../api/price';\nimport FormatLib from '../../../lib/format';\nimport { EditExtendedPrice } from './edit-extended-price';\nimport { DeleteExtendedPrice } from './delete-extended-price';\n\ninterface ConfigureExtendedPricesButtonProps {\n prices: Array,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n groupId: number,\n priceableId: number,\n priceableType: string,\n}\n\n/**\n * This component is a button that shows the list of extendedPrices.\n * It also triggers modal dialogs to configure (add/edit/remove) extendedPrices.\n */\nexport const ConfigureExtendedPricesButton: React.FC = ({ prices, onError, onSuccess, groupId, priceableId, priceableType }) => {\n const { t } = useTranslation('admin');\n\n const [extendedPrices, setExtendedPrices] = useState>(prices);\n const [showList, setShowList] = useState(false);\n\n /**\n * Return the number of hours, user-friendly formatted\n */\n const formatDuration = (minutes: number): string => {\n return t('app.admin.configure_extended_prices_button.extended_price_DURATION', { DURATION: minutes / 60 });\n };\n\n /**\n * Open/closes the popover listing the existing packs\n */\n const toggleShowList = (): void => {\n setShowList(!showList);\n };\n\n /**\n * Callback triggered when the extendedPrice was successfully created/deleted/updated.\n * We refresh the list of extendedPrices.\n */\n const handleSuccess = (message: string) => {\n onSuccess(message);\n PriceAPI.index({ group_id: groupId, priceable_id: priceableId, priceable_type: priceableType })\n .then(data => setExtendedPrices(data.filter(p => p.duration !== 60)))\n .catch(error => onError(error));\n };\n\n /**\n * Render the button used to trigger the \"new extended price\" modal\n */\n const renderAddButton = (): ReactNode => {\n return ;\n };\n\n return (\n
\n \n {showList && \n
    \n {extendedPrices?.map(extendedPrice =>\n
  • \n {formatDuration(extendedPrice.duration)} - {FormatLib.price(extendedPrice.amount)}\n \n \n \n \n
  • )}\n
\n {extendedPrices?.length === 0 && {t('app.admin.configure_extended_prices_button.no_extended_prices')}}\n
}\n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { FabModal } from '../../base/fab-modal';\nimport { ExtendedPriceForm } from './extended-price-form';\nimport { Price } from '../../../models/price';\nimport PriceAPI from '../../../api/price';\nimport { useTranslation } from 'react-i18next';\nimport { FabAlert } from '../../base/fab-alert';\n\ninterface CreateExtendedPriceProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n groupId: number,\n priceableId: number,\n priceableType: string,\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog handing the process of creating a new extended price\n */\nexport const CreateExtendedPrice: React.FC = ({ onSuccess, onError, groupId, priceableId, priceableType }) => {\n const { t } = useTranslation('admin');\n\n const [isOpen, setIsOpen] = useState(false);\n\n /**\n * Open/closes the \"new extended price\" modal dialog\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * Callback triggered when the user has validated the creation of the new extended price\n */\n const handleSubmit = (extendedPrice: Price): void => {\n // set the already-known attributes of the new extended price\n const newExtendedPrice = Object.assign({} as Price, extendedPrice);\n newExtendedPrice.group_id = groupId;\n newExtendedPrice.priceable_id = priceableId;\n newExtendedPrice.priceable_type = priceableType;\n\n // create it on the API\n PriceAPI.create(newExtendedPrice)\n .then(() => {\n onSuccess(t('app.admin.create_extended_price.extended_price_successfully_created'));\n toggleModal();\n })\n .catch(error => onError(error));\n };\n\n return (\n
\n \n \n \n {t('app.admin.create_extended_price.new_extended_price_info', { TYPE: priceableType })}\n \n \n \n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../../base/fab-button';\nimport { FabModal } from '../../base/fab-modal';\nimport { Price } from '../../../models/price';\nimport PriceAPI from '../../../api/price';\n\ninterface DeleteExtendedPriceProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n price: Price,\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog to ask the user for confirmation about the deletion of the provided extended price.\n */\nexport const DeleteExtendedPrice: React.FC = ({ onSuccess, onError, price }) => {\n const { t } = useTranslation('admin');\n\n const [deletionModal, setDeletionModal] = useState(false);\n\n /**\n * Opens/closes the deletion modal\n */\n const toggleDeletionModal = (): void => {\n setDeletionModal(!deletionModal);\n };\n\n /**\n * The deletion has been confirmed by the user.\n * Call the API to trigger the deletion of the temporary set extended price\n */\n const onDeleteConfirmed = (): void => {\n PriceAPI.destroy(price.id).then(() => {\n onSuccess(t('app.admin.delete_extended_price.extended_price_deleted'));\n }).catch((error) => {\n onError(t('app.admin.delete_extended_price.unable_to_delete') + error);\n });\n toggleDeletionModal();\n };\n\n return (\n
\n } onClick={toggleDeletionModal} />\n \n {t('app.admin.delete_extended_price.delete_confirmation')}\n \n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { FabModal } from '../../base/fab-modal';\nimport { ExtendedPriceForm } from './extended-price-form';\nimport { Price } from '../../../models/price';\nimport PriceAPI from '../../../api/price';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../../base/fab-button';\n\ninterface EditExtendedPriceProps {\n price: Price,\n onSuccess: (message: string) => void,\n onError: (message: string) => void\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog handing the process of creating a new extended price\n */\nexport const EditExtendedPrice: React.FC = ({ price, onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n const [isOpen, setIsOpen] = useState(false);\n const [extendedPriceData, setExtendedPriceData] = useState(price);\n\n /**\n * Open/closes the \"edit extended price\" modal dialog\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * When the user clicks on the edition button open te edition modal\n */\n const handleRequestEdit = (): void => {\n toggleModal();\n };\n\n /**\n * Callback triggered when the user has validated the changes of the extended price\n */\n const handleUpdate = (price: Price): void => {\n PriceAPI.update(price)\n .then(() => {\n onSuccess(t('app.admin.edit_extended_price.extended_price_successfully_updated'));\n setExtendedPriceData(price);\n toggleModal();\n })\n .catch(error => onError(error));\n };\n\n return (\n
\n } onClick={handleRequestEdit} />\n \n {extendedPriceData && }\n \n
\n );\n};\n","import { BaseSyntheticEvent } from 'react';\nimport * as React from 'react';\nimport { Price } from '../../../models/price';\nimport { useTranslation } from 'react-i18next';\nimport { useImmer } from 'use-immer';\nimport { FabInput } from '../../base/fab-input';\nimport { IFablab } from '../../../models/fablab';\n\ndeclare let Fablab: IFablab;\n\ninterface ExtendedPriceFormProps {\n formId: string,\n onSubmit: (price: Price) => void,\n price?: Price,\n}\n\n/**\n * A form component to create/edit an extended price.\n * The form validation must be created elsewhere, using the attribute form={formId}.\n */\nexport const ExtendedPriceForm: React.FC = ({ formId, onSubmit, price }) => {\n const [extendedPriceData, updateExtendedPriceData] = useImmer(price || {} as Price);\n\n const { t } = useTranslation('admin');\n\n /**\n * Callback triggered when the user sends the form.\n */\n const handleSubmit = (event: BaseSyntheticEvent): void => {\n event.preventDefault();\n onSubmit(extendedPriceData);\n };\n\n /**\n * Callback triggered when the user inputs an amount for the current extended price.\n */\n const handleUpdateAmount = (amount: string) => {\n updateExtendedPriceData(draft => {\n draft.amount = parseFloat(amount);\n });\n };\n\n /**\n * Callback triggered when the user inputs a number of hours for the current extended price.\n */\n const handleUpdateHours = (minutes: string) => {\n updateExtendedPriceData(draft => {\n draft.duration = parseFloat(minutes) * 60;\n });\n };\n\n return (\n
\n \n }\n required />\n \n }\n addOn={Fablab.intl_currency}\n required />\n \n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../../base/loader';\nimport { FabAlert } from '../../base/fab-alert';\nimport { HtmlTranslate } from '../../base/html-translate';\nimport SpaceAPI from '../../../api/space';\nimport GroupAPI from '../../../api/group';\nimport { Group } from '../../../models/group';\nimport { IApplication } from '../../../models/application';\nimport { Space } from '../../../models/space';\nimport { EditablePrice } from '../editable-price';\nimport { ConfigureExtendedPricesButton } from './configure-extended-prices-button';\nimport PriceAPI from '../../../api/price';\nimport { Price } from '../../../models/price';\nimport { useImmer } from 'use-immer';\nimport FormatLib from '../../../lib/format';\n\ndeclare const Application: IApplication;\n\ninterface SpacesPricingProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\n/**\n * Interface to set and edit the prices of spaces-hours, per group\n */\nexport const SpacesPricing: React.FC = ({ onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n\n const [spaces, setSpaces] = useState>(null);\n const [groups, setGroups] = useState>(null);\n const [prices, updatePrices] = useImmer>([]);\n\n // retrieve the initial data\n useEffect(() => {\n SpaceAPI.index()\n .then(data => setSpaces(data))\n .catch(error => onError(error));\n GroupAPI.index({ disabled: false })\n .then(data => setGroups(data))\n .catch(error => onError(error));\n PriceAPI.index({ priceable_type: 'Space', plan_id: null })\n .then(data => updatePrices(data))\n .catch(error => onError(error));\n }, []);\n\n // duration of the example slot\n const EXEMPLE_DURATION = 20;\n\n /**\n * Return the exemple price, formatted\n */\n const examplePrice = (type: 'hourly_rate' | 'final_price'): string => {\n const hourlyRate = 10;\n\n if (type === 'hourly_rate') {\n return FormatLib.price(hourlyRate);\n }\n\n const price = (hourlyRate / 60) * EXEMPLE_DURATION;\n return FormatLib.price(price);\n };\n\n /**\n * Find the default price (hourly rate) matching the given criterion\n */\n const findPriceBy = (spaceId, groupId): Price => {\n return prices.find(price => price.priceable_id === spaceId && price.group_id === groupId && price.duration === 60);\n };\n\n /**\n * Find prices matching the given criterion, except the default hourly rate\n */\n const findExtendedPricesBy = (spaceId, groupId): Array => {\n return prices.filter(price => price.priceable_id === spaceId && price.group_id === groupId && price.duration !== 60);\n };\n\n /**\n * Update the given price in the internal state\n */\n const updatePrice = (price: Price): void => {\n updatePrices(draft => {\n const index = draft.findIndex(p => p.id === price.id);\n draft[index] = price;\n return draft;\n });\n };\n\n /**\n * Callback triggered when the user has confirmed to update a price\n */\n const handleUpdatePrice = (price: Price): void => {\n PriceAPI.update(price)\n .then(() => {\n onSuccess(t('app.admin.spaces_pricing.price_updated'));\n updatePrice(price);\n })\n .catch(error => onError(error));\n };\n\n return (\n
\n \n

\n

\n

{t('app.admin.spaces_pricing.you_can_override')}

\n

{t('app.admin.spaces_pricing.extended_prices')}

\n
\n \n \n \n \n {groups?.map(group => )}\n \n \n \n {spaces?.map(space => \n \n {groups?.map(group => )}\n )}\n \n
{t('app.admin.spaces_pricing.spaces')}{group.name}
{space.name}\n {prices.length && }\n \n
\n
\n );\n};\n\nconst SpacesPricingWrapper: React.FC = ({ onError, onSuccess }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('spacesPricing', react2angular(SpacesPricingWrapper, ['onError', 'onSuccess']));\n","import { useEffect } from 'react';\nimport * as React from 'react';\nimport { ActiveProviderResponse } from '../../models/authentication-provider';\nimport { useTranslation } from 'react-i18next';\nimport { User } from '../../models/user';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport SettingAPI from '../../api/setting';\nimport { SettingName, titleSettings } from '../../models/setting';\nimport UserLib from '../../lib/user';\n\ndeclare const Application: IApplication;\n\ninterface CompletionHeaderInfoProps {\n user: User,\n activeProvider: ActiveProviderResponse,\n onError: (message: string) => void,\n}\n\n/**\n * This component will show an information message, on the profile completion page.\n */\nexport const CompletionHeaderInfo: React.FC = ({ user, activeProvider, onError }) => {\n const { t } = useTranslation('logged');\n const [settings, setSettings] = React.useState>(null);\n\n const userLib = new UserLib(user);\n\n useEffect(() => {\n SettingAPI.query(titleSettings).then(setSettings).catch(onError);\n }, []);\n\n return (\n
\n {activeProvider?.providable_type === 'DatabaseProvider' &&
\n

{t('app.logged.profile_completion.completion_header_info.rules_changed')}

\n
}\n {activeProvider?.providable_type !== 'DatabaseProvider' &&
\n

\n \n {t('app.logged.profile_completion.completion_header_info.sso_intro', {\n GENDER: settings?.get('name_genre'),\n NAME: settings?.get('fablab_name')\n })}\n \n \n {activeProvider?.name}\n {userLib.ssoEmail() && ({ userLib.ssoEmail() })}\n \n

\n {userLib.hasDuplicate() &&

\n {t('app.logged.profile_completion.completion_header_info.duplicate_email_info')}\n

}\n {!userLib.hasDuplicate() &&

\n {t('app.logged.profile_completion.completion_header_info.details_needed_info')}\n

}\n
}\n
\n );\n};\n\nconst CompletionHeaderInfoWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('completionHeaderInfo', react2angular(CompletionHeaderInfoWrapper, ['user', 'activeProvider', 'onError']));\n","import * as React from 'react';\nimport { User } from '../../models/user';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { ActiveProviderResponse } from '../../models/authentication-provider';\nimport { useTranslation } from 'react-i18next';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { UserProfileForm } from '../user/user-profile-form';\nimport UserLib from '../../lib/user';\nimport { FabButton } from '../base/fab-button';\nimport Authentication from '../../api/authentication';\n\ndeclare const Application: IApplication;\n\ninterface ProfileFormOptionProps {\n user: User,\n operator: User,\n activeProvider: ActiveProviderResponse,\n onError: (message: string) => void,\n onSuccess: (user: User) => void,\n}\n\n/**\n * After first logged-in from an SSO, the user has two options:\n * - complete his profile (*) ;\n * - bind his profile to his existing account ;\n * (*) This component handle the first case.\n * It also deals with duplicate email addresses in database\n */\nexport const ProfileFormOption: React.FC = ({ user, operator, activeProvider, onError, onSuccess }) => {\n const { t } = useTranslation('logged');\n\n const userLib = new UserLib(user);\n\n /**\n * Route the current user to the interface provided by the authentication provider, to update his profile.\n */\n const redirectToSsoProfile = (): void => {\n window.open(activeProvider.link_to_sso_profile, '_blank');\n };\n\n /**\n * Disconnect and re-connect the user to the SSO to force the synchronisation of the profile's data\n */\n function syncProfile () {\n Authentication.logout().then(() => {\n window.location.href = activeProvider.link_to_sso_connect;\n }).catch(onError);\n }\n\n return (\n
\n

{t('app.logged.profile_completion.profile_form_option.title')}

\n {!userLib.hasDuplicate() &&
\n

{t('app.logged.profile_completion.profile_form_option.please_fill')}

\n

{t('app.logged.profile_completion.profile_form_option.disabled_data_from_sso', { NAME: activeProvider?.name })}

\n

\n \n

\n \n
}\n {userLib.hasDuplicate() &&
\n

\n \n

\n }>\n {t('app.logged.profile_completion.profile_form_option.edit_profile')}\n \n

\n \n

\n }>\n {t('app.logged.profile_completion.profile_form_option.sync_profile')}\n \n
}\n
\n );\n};\n\nconst ProfileFormOptionWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('profileFormOption', react2angular(ProfileFormOptionWrapper, ['user', 'activeProvider', 'onError', 'onSuccess']));\n","import { useState, useEffect, BaseSyntheticEvent } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport Switch from 'react-switch';\nimport _ from 'lodash';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { ProfileCustomField } from '../../models/profile-custom-field';\nimport ProfileCustomFieldAPI from '../../api/profile-custom-field';\nimport { FabButton } from '../base/fab-button';\n\ndeclare const Application: IApplication;\n\ninterface ProfileCustomFieldsListProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows a list of all profile custom fields\n */\nexport const ProfileCustomFieldsList: React.FC = ({ onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n const [profileCustomFields, setProfileCustomFields] = useState>([]);\n const [profileCustomFieldToEdit, setProfileCustomFieldToEdit] = useState(null);\n\n // get profile custom fields\n useEffect(() => {\n ProfileCustomFieldAPI.index().then(pData => {\n setProfileCustomFields(pData);\n });\n }, []);\n\n /**\n * Save the new state of the given custom field to the API\n */\n const saveProfileCustomField = (profileCustomField: ProfileCustomField) => {\n ProfileCustomFieldAPI.update(profileCustomField).then(data => {\n const newFields = profileCustomFields.map(f => {\n if (f.id === data.id) {\n return data;\n }\n return f;\n });\n setProfileCustomFields(newFields);\n if (profileCustomFieldToEdit) {\n setProfileCustomFieldToEdit(null);\n }\n onSuccess(t('app.admin.settings.account.profile_custom_fields_list.field_successfully_updated'));\n }).catch(err => {\n onError(t('app.admin.settings.account.profile_custom_fields_list.unable_to_update') + err);\n });\n };\n\n /**\n * Callback triggered when the 'switch' is changed.\n */\n const handleSwitchChanged = (profileCustomField: ProfileCustomField, field: string) => {\n return (value: boolean) => {\n const _profileCustomField = _.clone(profileCustomField);\n _profileCustomField[field] = value;\n if (field === 'actived' && !value) {\n _profileCustomField.required = false;\n }\n saveProfileCustomField(_profileCustomField);\n };\n };\n\n /**\n * Callback triggered when the user clicks on the 'edit field' button.\n * Opens the edition form for the given custom field\n */\n const editProfileCustomFieldLabel = (profileCustomField: ProfileCustomField) => {\n return () => {\n setProfileCustomFieldToEdit(_.clone(profileCustomField));\n };\n };\n\n /**\n * Callback triggered when the input \"label\" is changed: updates the according state\n */\n const onChangeProfileCustomFieldLabel = (e: BaseSyntheticEvent) => {\n const { value } = e.target;\n setProfileCustomFieldToEdit({\n ...profileCustomFieldToEdit,\n label: value\n });\n };\n\n /**\n * Save the currently edited custom field\n */\n const saveProfileCustomFieldLabel = () => {\n saveProfileCustomField(profileCustomFieldToEdit);\n };\n\n /**\n * Closes the edition form for the currently edited custom field\n */\n const cancelEditProfileCustomFieldLabel = () => {\n setProfileCustomFieldToEdit(null);\n };\n\n return (\n \n \n \n \n \n \n \n \n \n {profileCustomFields.map(field => {\n return (\n \n \n \n \n \n );\n })}\n \n
\n {profileCustomFieldToEdit?.id !== field.id && field.label}\n {profileCustomFieldToEdit?.id !== field.id && (\n \n \n \n )}\n {profileCustomFieldToEdit?.id === field.id && (\n
\n \n \n \n \n \n \n \n \n \n
\n )}\n
\n \n \n \n \n \n
\n );\n};\n\nconst ProfileCustomFieldsListWrapper: React.FC = ({ onSuccess, onError }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('profileCustomFieldsList', react2angular(ProfileCustomFieldsListWrapper, ['onSuccess', 'onError']));\n","import React, { useState, useRef } from 'react';\nimport { FabButton } from '../base/fab-button';\nimport { ProjectSettingOption } from '../../models/project-setting-option';\nimport { Check, X } from 'phosphor-react';\nimport { useTranslation } from 'react-i18next';\n\ninterface ProjectsSettingOptionFormProps {\n hasDescription?: boolean,\n handleSave: (option: ProjectSettingOption) => void,\n handleExit: () => void,\n option?: ProjectSettingOption\n}\n\n/**\n* Provides a inline form for a Projects Setting Option\n**/\nexport const ProjectsSettingOptionForm: React.FC = ({ option = { name: '', description: '' }, handleSave, handleExit, hasDescription }) => {\n const { t } = useTranslation('admin');\n\n const enteredOptionName = useRef(null);\n const enteredOptionDescription = useRef(null);\n\n const [errorMessage, setErrorMessage] = useState('');\n\n /**\n * Builds up new or updated option based on User input and provides it to parent component.\n * The option property :name should not be blank and triggers an error message for the user.\n **/\n const saveOption = () => {\n if (enteredOptionName.current.value === '') {\n setErrorMessage(t('app.admin.projects_setting_option_form.name_cannot_be_blank'));\n return;\n } else if (hasDescription) {\n handleSave({\n id: option.id,\n name: enteredOptionName.current.value,\n description: enteredOptionDescription.current.value\n });\n } else {\n handleSave({ id: option.id, name: enteredOptionName.current.value });\n }\n setErrorMessage('');\n handleExit();\n };\n\n return (\n \n \n \n {errorMessage &&

{errorMessage}

}\n \n \n {hasDescription && }\n \n \n \n \n \n \n \n \n \n \n );\n};\n","import React, { Fragment, useState } from 'react';\nimport { FabButton } from '../base/fab-button';\nimport { Pencil, Trash } from 'phosphor-react';\nimport { useTranslation } from 'react-i18next';\nimport { ProjectSettingOption } from '../../models/project-setting-option';\nimport { ProjectsSettingOptionForm } from './projects-setting-option-form';\n\ninterface ProjectsSettingOptionProps {\n hasDescription?: boolean,\n handleDelete: (id: number) => void,\n handleUpdate: (option: ProjectSettingOption) => void,\n option: ProjectSettingOption\n}\n\n/**\n * This component is used by the component ProjectsSetting\n * It provides the display of each option and the update/delete features, all inline.\n*/\nexport const ProjectsSettingOption: React.FC = ({ option, handleDelete, handleUpdate, hasDescription }) => {\n const { t } = useTranslation('admin');\n\n const [isEditing, setIsEditing] = useState(false);\n\n // If option is in display mode, sets it in editing mode, and vice-versa.\n const toggleIsEditing = () => setIsEditing(prevState => !prevState);\n\n // Provides the id of the deleted option to parent component, ProjectSetting.\n const deleteOptionLine = () => { handleDelete(option.id); };\n\n // Provides the updated option to parent component, ProjectSetting.\n const updateOptionLine = (option) => { handleUpdate(option); };\n\n // UI for displaying an option, when editing mode is off.\n const displayingOptionLine = (\n \n {option.name}\n {hasDescription && option.description}\n \n \n \n {t('app.admin.projects_setting_option.edit')}\n \n \n \n \n \n \n );\n\n return (\n \n {!isEditing && displayingOptionLine}\n {isEditing &&\n }\n \n );\n};\n","import React, { useState } from 'react';\nimport { FabButton } from '../base/fab-button';\nimport { ProjectsSettingOption } from './projects-setting-option';\nimport { useTranslation } from 'react-i18next';\nimport { ProjectSettingOption } from '../../models/project-setting-option';\nimport { ProjectsSettingOptionForm } from './projects-setting-option-form';\n\ninterface ProjectsSettingProps {\n hasDescription?: boolean,\n handleAdd: (option: ProjectSettingOption) => void,\n handleDelete: (id: number) => void,\n handleUpdate: (option: ProjectSettingOption) => void,\n optionType: string,\n options: ProjectSettingOption[]\n}\n\n/**\n * This component is used in Projects Settings (admin part)\n * It provides add / update / delete features for any setting of a project (status, themes, licences...)\n * If a Setting has a description property, this component should be called with the prop hasDescription={true}\n*/\nexport const ProjectsSetting: React.FC = ({ hasDescription = false, handleAdd, handleUpdate, handleDelete, options, optionType }) => {\n const { t } = useTranslation('admin');\n const [isAdding, setIsAdding] = useState(false);\n\n // Shows form to add an option if it's not already here. Else, removes it.\n const toggleIsAdding = () => setIsAdding((prevState) => !prevState);\n\n // Pass on the newly created option to parent component.\n const addOption = (option) => { handleAdd(option); };\n\n return (\n
\n \n {`${t('app.admin.projects_setting.add')} a ${optionType}`}\n \n \n \n \n \n {hasDescription &&\n \n }\n {!hasDescription &&\n \n }\n \n \n \n \n {options.map((option) => {\n return (\n \n );\n })}\n {isAdding &&\n \n }\n \n
{t('app.admin.projects_setting.name')}{t('app.admin.projects_setting.description')}
\n
\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport { react2angular } from 'react2angular';\nimport Select from 'react-select';\nimport { useTranslation } from 'react-i18next';\nimport StatusAPI from '../../../api/status';\nimport { IApplication } from '../../../models/application';\nimport { SelectOption } from '../../../models/select';\nimport { Loader } from '../../base/loader';\nimport { Status } from '../../../models/status';\n\ndeclare const Application: IApplication;\n\ninterface StatusFilterProps {\n currentStatusIndex: number,\n onFilterChange: (status: Status) => void,\n onError: (message: string) => void\n}\n\n/**\n * Implement filtering projects by their status\n*/\nexport const StatusFilter: React.FC = ({ currentStatusIndex, onError, onFilterChange }) => {\n const { t } = useTranslation('public');\n const defaultValue = { value: null, label: t('app.public.status_filter.all_statuses') };\n const [statusesList, setStatusesList] = useState>([]);\n const [currentOption, setCurrentOption] = useState>(defaultValue);\n\n /**\n * From the statusesList (retrieved from API) and a default Value, generates an Array of options conform to react-select\n */\n const buildOptions = (): Array> => {\n const apiStatusesList = statusesList.map(status => {\n return { value: status.id, label: status.name };\n });\n return [defaultValue, ...apiStatusesList];\n };\n\n /**\n * On component mount, asynchronously load the full list of statuses\n * Converts name property into label property, since a SelectOption needs a label\n */\n useEffect(() => {\n StatusAPI.index()\n .then((data) => {\n setStatusesList(data);\n }).catch(onError);\n }, []);\n\n // If currentStatusIndex is provided and match a status, set currentOption accordingly\n useEffect(() => {\n const selectedStatus = statusesList.find((status) => status.id === currentStatusIndex);\n if (selectedStatus) {\n setCurrentOption({ value: selectedStatus.id, label: selectedStatus.name });\n }\n }, [currentStatusIndex, statusesList]);\n\n /**\n * Callback triggered when the admin selects a status in the dropdown list\n */\n const handleStatusSelected = (option: SelectOption): void => {\n onFilterChange({ id: option.value, name: option.label });\n setCurrentOption(option);\n };\n\n const selectStyles = {\n control: (baseStyles, state) => ({\n ...baseStyles,\n boxShadow: state.isFocused ? 'inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(253, 222, 63, 0.6);' : 'grey',\n border: state.isFocused ? '1px solid #fdde3f' : '1px solid #c4c4c4',\n color: '#555555',\n '&:hover': {\n borderColor: state.isFocused ? '#fdde3f' : '#c4c4c4'\n }\n }),\n singleValue: (baseStyles) => ({\n ...baseStyles,\n color: '#555555'\n })\n };\n\n return (\n
\n {statusesList.length !== 0 &&\n \n \n
)}\n {!hideSave && {t('app.admin.check_list_setting.save')}}\n
\n );\n};\n\nconst CheckListSettingWrapper: React.FC = ({ availableOptions, onSuccess, onError, label, className, name, hideSave, defaultValue, onChange }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('checkListSetting', react2angular(CheckListSettingWrapper, ['className', 'name', 'label', 'availableOptions', 'onSuccess', 'onError']));\n","import type { Setting, SettingName } from '../../models/setting';\nimport React, { useEffect, useState } from 'react';\nimport { sortBy as _sortBy } from 'lodash';\nimport SettingAPI from '../../api/setting';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport FormatLib from '../../lib/format';\nimport { useTranslation } from 'react-i18next';\nimport { useImmer } from 'use-immer';\nimport { HistoryValue } from '../../models/history-value';\n\ninterface CommonProps {\n isOpen: boolean,\n toggleModal: () => void,\n onError: (error: string) => void,\n}\n\ntype SettingsProps =\n { setting: SettingName, settings?: never } |\n { setting?: never, settings: Array }\n\ntype SettingHistoryModalProps = CommonProps & SettingsProps;\n\n/**\n * Shows the history of the changes for the provided setting.\n * Support for a cross history of several settings.\n */\nexport const SettingHistoryModal: React.FC = ({ isOpen, toggleModal, setting, settings, onError }) => {\n const { t } = useTranslation('admin');\n\n const [settingData, setSettingData] = useImmer>(new Map());\n const [history, setHistory] = useState>([]);\n\n useEffect(() => {\n if (isOpen) {\n settings?.forEach((setting) => {\n SettingAPI.get(setting, { history: true }).then(res => {\n setSettingData(draft => {\n draft.set(setting, res);\n });\n }).catch(onError);\n });\n if (setting) {\n SettingAPI.get(setting, { history: true }).then(res => {\n setSettingData(draft => {\n draft.set(setting, res);\n });\n }).catch(onError);\n }\n }\n }, [isOpen]);\n\n useEffect(() => {\n setHistory(buildHistory());\n }, [settingData]);\n\n /**\n * Build the cross history for all the given settings\n */\n const buildHistory = () => {\n let history = [];\n for (const stng of settingData.keys()) {\n history = _sortBy(history.concat(settingData.get(stng as SettingName)?.history?.map(hv => {\n return {\n ...hv,\n setting: stng\n };\n })), 'created_at');\n }\n return history;\n };\n\n return (\n \n {history.length === 0 &&
\n {t('app.admin.setting_history_modal.no_history')}\n
}\n {history.length > 0 && \n \n \n \n \n \n \n \n \n \n {history.map(hv => \n \n \n \n \n )}\n \n
{t('app.admin.setting_history_modal.setting')}{t('app.admin.setting_history_modal.value')}{t('app.admin.setting_history_modal.date')}{t('app.admin.setting_history_modal.operator')}
{settingData.get(hv.setting).localized}{hv.value}{FormatLib.date(hv.created_at)}{hv.user.name}
}\n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { SettingName } from '../../models/setting';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport SettingAPI from '../../api/setting';\nimport { Loader } from '../base/loader';\nimport { FabButton } from '../base/fab-button';\nimport { BooleanSetting } from './boolean-setting';\nimport { CheckListSetting } from './check-list-setting';\nimport { FabAlert } from '../base/fab-alert';\n\ndeclare const Application: IApplication;\n\ninterface UserValidationSettingProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component allows an admin to configure the settings related to the user account validation.\n */\nexport const UserValidationSetting: React.FC = ({ onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n const [userValidationRequired, setUserValidationRequired] = useState('false');\n const userValidationRequiredListDefault = ['subscription', 'machine', 'event', 'space', 'training', 'pack'];\n const [userValidationRequiredList, setUserValidationRequiredList] = useState(null);\n const userValidationRequiredOptions = userValidationRequiredListDefault.map(l => {\n return [l, t(`app.admin.settings.account.user_validation_setting.user_validation_required_list.${l}`)];\n });\n\n /**\n * Save the built string to the Setting API\n */\n const updateSetting = (name: SettingName, value: string) => {\n SettingAPI.update(name, value)\n .then(() => {\n if (name === 'user_validation_required') {\n onSuccess(t('app.admin.settings.account.user_validation_setting.customization_of_SETTING_successfully_saved', {\n SETTING: t(`app.admin.settings.account.${name}`) // eslint-disable-line fabmanager/scoped-translation\n }));\n }\n }).catch(err => {\n if (err.status === 304) return;\n\n if (err.status === 423) {\n if (name === 'user_validation_required') {\n onError(t('app.admin.settings.account.user_validation_setting.error_SETTING_locked', {\n SETTING: t(`app.admin.settings.account.${name}`) // eslint-disable-line fabmanager/scoped-translation\n }));\n }\n return;\n }\n\n console.log(err);\n onError(t('app.admin.settings.account.user_validation_setting.an_error_occurred_saving_the_setting'));\n });\n };\n\n /**\n * Callback triggered when the 'save' button is clicked.\n */\n const handleSave = () => {\n updateSetting('user_validation_required', userValidationRequired);\n if (userValidationRequiredList !== null) {\n if (userValidationRequired === 'true') {\n updateSetting('user_validation_required_list', userValidationRequiredList);\n } else {\n updateSetting('user_validation_required_list', null);\n }\n }\n };\n\n return (\n
\n \n \n {userValidationRequired === 'true' &&\n
\n

{t('app.admin.settings.account.user_validation_setting.user_validation_required_list_title')}

\n

\n {t('app.admin.settings.account.user_validation_setting.user_validation_required_list_info')}\n

\n \n {t('app.admin.settings.account.user_validation_setting.user_validation_required_list_other_info')}\n \n \n \n
\n }\n {t('app.admin.settings.account.user_validation_setting.save')}\n
\n );\n};\n\nconst UserValidationSettingWrapper: React.FC = ({ onSuccess, onError }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('userValidationSetting', react2angular(UserValidationSettingWrapper, ['onSuccess', 'onError']));\n","import { useState, useReducer } from 'react';\nimport { FormState, UseFormRegister, UseFormSetValue } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { User } from '../../models/user';\nimport { SocialNetwork } from '../../models/social-network';\nimport Icons from '../../../../images/social-icons.svg';\nimport { FormInput } from '../form/form-input';\nimport { Trash } from 'phosphor-react';\nimport { useTranslation } from 'react-i18next';\nimport ValidationLib from '../../lib/validation';\n\ninterface EditSocialsProps {\n register: UseFormRegister,\n setValue: UseFormSetValue,\n networks: SocialNetwork[],\n formState: FormState,\n disabled: boolean|((id: string) => boolean),\n}\n\n/**\n * Allow a user to edit its personnal social networks\n */\nexport const EditSocials = ({ register, setValue, networks, formState, disabled }: EditSocialsProps) => {\n const { t } = useTranslation('shared');\n\n const initSelectedNetworks = networks.filter(el => !['', null, undefined].includes(el.url));\n const [selectedNetworks, setSelectedNetworks] = useState(initSelectedNetworks);\n\n /**\n * Callback triggered when the user adds a network, from the list of available networks, to the editable networks.\n */\n const selectNetwork = (network) => {\n setSelectedNetworks([...selectedNetworks, network]);\n };\n\n /**\n * Return a derivated state of the selected networks list, depending on the given action.\n */\n const reducer = (state, action) => {\n switch (action.type) {\n case 'delete':\n setSelectedNetworks(selectedNetworks.filter(el => el !== action.payload.network));\n setValue(action.payload.field, '');\n return state.map(el => el === action.payload.network\n ? { ...el, url: '' }\n : el);\n case 'update':\n return state.map(el => el === action.payload\n ? { ...el, url: action.payload.url }\n : el);\n default:\n return state;\n }\n };\n const [userNetworks, dispatch] = useReducer(reducer, networks);\n\n return (\n <>\n
\n {userNetworks.map((network, index) =>\n !selectedNetworks.includes(network) && selectNetwork(network)} viewBox=\"0 0 24 24\" >\n \n \n )}\n
\n {selectNetwork.length &&
\n {userNetworks.map((network, index) =>\n selectedNetworks.includes(network) &&\n }\n addOn={}\n addOnAction={() => dispatch({ type: 'delete', payload: { network, field: `profile_attributes.${network.name}` } })} />\n )}\n
}\n \n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useForm } from 'react-hook-form';\nimport { FormInput } from '../form/form-input';\nimport SettingAPI from '../../api/setting';\nimport { supportedNetworks } from '../../models/social-network';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { SettingName } from '../../models/setting';\nimport Icons from '../../../../images/social-icons.svg';\nimport { Trash } from 'phosphor-react';\nimport { useTranslation } from 'react-i18next';\nimport { FabButton } from '../base/fab-button';\nimport ValidationLib from '../../lib/validation';\n\ndeclare const Application: IApplication;\n\ninterface FabSocialsProps {\n show: boolean,\n onError: (message: string) => void,\n onSuccess: (message: string) => void\n}\n\n/**\n * Allows the Fablab to edit its corporate social networks, or to display them read-only to the end users (show=true)\n */\nexport const FabSocials: React.FC = ({ show = false, onError, onSuccess }) => {\n const { t } = useTranslation('shared');\n\n const { handleSubmit, register, setValue, formState } = useForm();\n\n const settingsList = supportedNetworks.map(el => el as SettingName);\n\n const [fabNetworks, setFabNetworks] = useState([]);\n const [selectedNetworks, setSelectedNetworks] = useState([]);\n\n useEffect(() => {\n SettingAPI.query(settingsList).then(res => {\n setFabNetworks(Array.from(res, ([name, url]) => ({ name, url })));\n }).catch(error => console.error(error));\n }, []);\n\n useEffect(() => {\n setSelectedNetworks(fabNetworks.filter(el => el.url !== ''));\n }, [fabNetworks]);\n\n /**\n * Callback triggered when the social networks are saved\n */\n const onSubmit = (data) => {\n const updatedNetworks = new Map();\n Object.keys(data).forEach(key => updatedNetworks.set(key as SettingName, data[key]));\n SettingAPI.bulkUpdate(updatedNetworks).then(res => {\n const errorResults = Array.from(res.values()).filter(item => !item.status);\n if (errorResults.length > 0) {\n onError(t('app.shared.fab_socials.networks_update_error'));\n } else {\n onSuccess(t('app.shared.fab_socials.networks_update_success'));\n }\n });\n };\n\n /**\n * Callback triggered when the user adds a network, from the list of available networks, to the editable networks.\n */\n const selectNetwork = (network) => {\n setSelectedNetworks([...selectedNetworks, network]);\n };\n\n /**\n * Callback triggered when the user removes a network, from the list of editables networks, add put it back to the\n * list of avaiable networks.\n */\n const remove = (network) => {\n setSelectedNetworks(selectedNetworks.filter(el => el !== network));\n setValue(network.name, '');\n };\n\n return (\n
{show\n ? (selectedNetworks.length > 0) && <>\n

{t('app.shared.fab_socials.follow_us')}

\n
\n {fabNetworks.map((network, index) =>\n selectedNetworks.includes(network) &&\n \n \n \n )}\n
\n \n\n :
\n
\n {fabNetworks.map((network, index) =>\n !selectedNetworks.includes(network) &&\n selectNetwork(network)}>\n \n \n )}\n
\n {selectNetwork.length &&
\n {fabNetworks.map((network, index) =>\n selectedNetworks.includes(network) &&\n }\n addOn={}\n addOnAction={() => remove(network)} />\n )}\n
}\n \n {t('app.shared.fab_socials.save')}\n \n
\n }
\n );\n};\n\nconst FabSocialsWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\nApplication.Components.component('fabSocials', react2angular(FabSocialsWrapper, ['show', 'onError', 'onSuccess']));\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport SpaceAPI from '../../api/space';\nimport { useTranslation } from 'react-i18next';\nimport { FormInput } from '../form/form-input';\nimport { FormImageUpload } from '../form/form-image-upload';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { ErrorBoundary } from '../base/error-boundary';\nimport { FormRichText } from '../form/form-rich-text';\nimport { FormSwitch } from '../form/form-switch';\nimport { FormMultiFileUpload } from '../form/form-multi-file-upload';\nimport { FabButton } from '../base/fab-button';\nimport { Space } from '../../models/space';\nimport { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';\nimport SettingAPI from '../../api/setting';\nimport { FabAlert } from '../base/fab-alert';\n\ndeclare const Application: IApplication;\n\ninterface SpaceFormProps {\n action: 'create' | 'update',\n space?: Space,\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n}\n\n/**\n * Form to edit or create spaces\n */\nexport const SpaceForm: React.FC = ({ action, space, onError, onSuccess }) => {\n const { handleSubmit, register, control, setValue, formState } = useForm({ defaultValues: { ...space } });\n const output = useWatch({ control });\n const { t } = useTranslation('admin');\n\n const [isActiveAccounting, setIsActiveAccounting] = useState(false);\n\n useEffect(() => {\n SettingAPI.get('advanced_accounting').then(res => setIsActiveAccounting(res.value === 'true')).catch(onError);\n }, []);\n\n /**\n * Callback triggered when the user validates the machine form: handle create or update\n */\n const onSubmit: SubmitHandler = (data: Space) => {\n SpaceAPI[action](data).then((res) => {\n onSuccess(t(`app.admin.space_form.${action}_success`));\n window.location.href = `/#!/spaces/${res.slug}`;\n }).catch(error => {\n onError(error);\n });\n };\n\n return (\n
\n
\n

{t('app.admin.space_form.ACTION_title', { ACTION: action })}

\n \n {t('app.admin.space_form.save')}\n \n
\n
\n {action === 'create' &&\n \n {t('app.admin.space_form.watch_out_when_creating_a_new_space_its_prices_are_initialized_at_0_for_all_subscriptions')} {t('app.admin.space_form.consider_changing_its_prices_before_creating_any_reservation_slot')}\n \n }\n
\n
\n

{t('app.admin.space_form.description')}

\n
\n
\n \n \n \n \n \n
\n
\n\n
\n
\n

{t('app.admin.space_form.attachments')}

\n
\n
\n
\n

{t('app.admin.space_form.attached_files_pdf')}

\n
\n \n
\n
\n\n
\n
\n

{t('app.admin.space_form.settings')}

\n
\n
\n \n
\n
\n\n {isActiveAccounting &&\n
\n \n
\n }\n
\n
\n );\n};\n\nconst SpaceFormWrapper: React.FC = (props) => {\n return (\n \n \n \n \n \n );\n};\n\nApplication.Components.component('spaceForm', react2angular(SpaceFormWrapper, ['action', 'space', 'onError', 'onSuccess']));\n","import { PencilSimple, Trash } from 'phosphor-react';\nimport { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { ProductCategory } from '../../../models/product-category';\nimport { FabButton } from '../../base/fab-button';\nimport { FabModal, ModalSize } from '../../base/fab-modal';\nimport { ProductCategoryForm } from './product-category-form';\n\ninterface ManageProductCategoryProps {\n action: 'create' | 'update' | 'delete',\n productCategories: Array,\n productCategory?: ProductCategory,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows a button.\n * When clicked, we show a modal dialog allowing to fill the parameters of a product category.\n */\nexport const ManageProductCategory: React.FC = ({ productCategories, productCategory, action, onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n // is the modal open?\n const [isOpen, setIsOpen] = useState(false);\n\n /**\n * Opens/closes the product category modal\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * Close the modal if the form submission was successful\n */\n const handleSuccess = (message) => {\n setIsOpen(false);\n onSuccess(message);\n };\n\n /**\n * Render the appropriate button depending on the action type\n */\n const toggleBtn = () => {\n switch (action) {\n case 'create':\n return (\n \n {t('app.admin.store.manage_product_category.create')}\n \n );\n case 'update':\n return (}\n className=\"edit-btn\"\n onClick={toggleModal} />);\n case 'delete':\n return (}\n className=\"delete-btn\"\n onClick={toggleModal} />);\n }\n };\n\n return (\n
\n { toggleBtn() }\n \n { action === 'update' &&

{productCategory.name}

}\n \n
\n
\n );\n};\n","import * as React from 'react';\nimport { ProductCategory } from '../../../models/product-category';\nimport { useSortable } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport { ManageProductCategory } from './manage-product-category';\nimport { ArrowElbowDownRight, ArrowLeft, CaretDown, DotsSixVertical } from 'phosphor-react';\n\ninterface ProductCategoriesItemProps {\n productCategories: Array,\n category: ProductCategory,\n offset: 'up' | 'down' | null,\n collapsed?: boolean,\n handleCollapse?: (id: number) => void,\n status: 'child' | 'single' | 'parent',\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * Renders a draggable category item\n */\nexport const ProductCategoriesItem: React.FC = ({ productCategories, category, offset, collapsed, handleCollapse, status, onSuccess, onError }) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging\n } = useSortable({ id: category.id });\n\n const style = {\n transition,\n transform: CSS.Transform.toString(transform)\n };\n\n return (\n
\n {((isDragging && offset) || status === 'child') &&\n
\n {(offset === 'down') && }\n {(offset === 'up') && }\n
\n }\n
\n
\n {status === 'parent' &&
\n \n
}\n

{category.name}

\n \n
\n
\n {!isDragging &&\n
\n \n \n
\n }\n
\n \n
\n
\n
\n
\n );\n};\n","import { useEffect } from 'react';\nimport * as React from 'react';\nimport { useImmer } from 'use-immer';\nimport { ProductCategory } from '../../../models/product-category';\nimport { DndContext, KeyboardSensor, PointerSensor, useSensor, useSensors, closestCenter, DragMoveEvent } from '@dnd-kit/core';\nimport { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable';\nimport { restrictToWindowEdges } from '@dnd-kit/modifiers';\nimport { ProductCategoriesItem } from './product-categories-item';\n\ninterface ProductCategoriesTreeProps {\n productCategories: Array,\n onDnd: (list: Array, activeCategory: ProductCategory, position: number) => void,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows a tree list of all Product's Categories\n */\nexport const ProductCategoriesTree: React.FC = ({ productCategories, onDnd, onSuccess, onError }) => {\n const [categoriesList, setCategoriesList] = useImmer(productCategories);\n const [activeData, setActiveData] = useImmer(initActiveData);\n const [extractedChildren, setExtractedChildren] = useImmer({});\n const [collapsed, setCollapsed] = useImmer([]);\n\n // Initialize state from props\n useEffect(() => {\n setCategoriesList(productCategories);\n }, [productCategories]);\n\n // @dnd-kit config\n const sensors = useSensors(\n useSensor(PointerSensor),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates\n })\n );\n\n /**\n * On drag start\n * Collect dragged items' data\n * Extract children from list\n */\n const handleDragStart = ({ active }: DragMoveEvent) => {\n const activeIndex = active.data.current.sortable.index;\n const children = getChildren(active.id);\n\n setActiveData(draft => {\n draft.index = activeIndex;\n draft.category = getCategory(active.id);\n draft.status = getStatus(active.id);\n draft.children = children?.length ? children : null;\n });\n\n setExtractedChildren(draft => { draft[active.id] = children; });\n hideChildren(active.id, activeIndex);\n };\n\n /**\n * On drag move\n */\n const handleDragMove = ({ delta, active, over }: DragMoveEvent) => {\n const activeStatus = getStatus(active.id);\n if (activeStatus === 'single') {\n if (Math.ceil(delta.x) > 32 && getStatus(over.id) !== 'child') {\n setActiveData(draft => {\n return { ...draft, offset: 'down' };\n });\n } else if (Math.ceil(delta.x) < -32 && getStatus(over.id) === 'child') {\n setActiveData(draft => {\n return { ...draft, offset: 'up' };\n });\n } else {\n setActiveData(draft => {\n return { ...draft, offset: null };\n });\n }\n }\n if (activeStatus === 'child') {\n if (Math.ceil(delta.x) > 32 && getStatus(over.id) !== 'child') {\n setActiveData(draft => {\n return { ...draft, offset: 'down' };\n });\n } else if (Math.ceil(delta.x) < -32 && getStatus(over.id) === 'child') {\n setActiveData(draft => {\n return { ...draft, offset: 'up' };\n });\n } else {\n setActiveData(draft => {\n return { ...draft, offset: null };\n });\n }\n }\n };\n\n /**\n * On drag End\n * Insert children back in list\n */\n const handleDragEnd = ({ active, over }: DragMoveEvent) => {\n let newOrder = [...categoriesList];\n const currentIdsOrder = over?.data.current.sortable.items;\n let newIndex = over.data.current.sortable.index;\n let droppedItem = getCategory(active.id);\n const activeStatus = getStatus(active.id);\n const overStatus = getStatus(over.id);\n let newPosition = getCategory(over.id).position;\n\n // [A]:Single dropped over [B]:Single\n if (activeStatus === 'single' && overStatus === 'single') {\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => {\n let category = getCategory(sortedId);\n if (activeData.offset === 'down' && sortedId === active.id && activeData.index < newIndex && active.id !== over.id) {\n category = { ...category, parent_id: Number(over.id) };\n droppedItem = category;\n newPosition = 1;\n } else if (activeData.offset === 'down' && sortedId === active.id && (activeData.index > newIndex || active.id === over.id)) {\n const adopter = getPreviousAdopter(over.id);\n const siblingsLength = getChildren(adopter)?.length | 0;\n category = { ...category, parent_id: adopter };\n droppedItem = category;\n newPosition = siblingsLength + 1;\n }\n return category;\n });\n }\n\n // [A]:Child dropped over [B]:Single\n if ((activeStatus === 'child') && overStatus === 'single') {\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => {\n let category = getCategory(sortedId);\n if (activeData.offset === 'down' && sortedId === active.id && activeData.index < newIndex) {\n category = { ...category, parent_id: Number(over.id) };\n droppedItem = category;\n newPosition = 1;\n } else if (activeData.offset === 'down' && sortedId === active.id && activeData.index > newIndex) {\n category = { ...category, parent_id: getPreviousAdopter(over.id) };\n droppedItem = category;\n newPosition = getChildren(getPreviousAdopter(over.id))?.length || 1;\n } else if (sortedId === active.id) {\n category = { ...category, parent_id: null };\n droppedItem = category;\n newPosition = getCategory(over.id).position + 1;\n }\n return category;\n });\n }\n\n // [A]:Single || [A]:Child dropped over…\n if (activeStatus === 'single' || activeStatus === 'child') {\n // [B]:Parent\n if (overStatus === 'parent') {\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n if (activeData.index < newIndex) {\n newOrder = newIdsOrder.map(sortedId => {\n let category = getCategory(sortedId);\n if (sortedId === active.id) {\n category = { ...category, parent_id: Number(over.id) };\n droppedItem = category;\n newPosition = 1;\n }\n return category;\n });\n } else if (activeData.index > newIndex) {\n newOrder = newIdsOrder.map(sortedId => {\n let category = getCategory(sortedId);\n if (sortedId === active.id && !activeData.offset) {\n category = { ...category, parent_id: null };\n droppedItem = category;\n } else if (sortedId === active.id && activeData.offset === 'down') {\n category = { ...category, parent_id: getPreviousAdopter(over.id) };\n droppedItem = category;\n newPosition = getChildren(getPreviousAdopter(over.id))?.length || 1;\n }\n return category;\n });\n }\n }\n // [B]:Child\n if (overStatus === 'child') {\n if (activeData.offset === 'up') {\n const lastChildIndex = newOrder.findIndex(c => c.id === getChildren(getCategory(over.id).parent_id).pop().id);\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, lastChildIndex);\n newOrder = newIdsOrder.map(sortedId => {\n let category = getCategory(sortedId);\n if (sortedId === active.id) {\n category = { ...category, parent_id: null };\n droppedItem = category;\n newPosition = getCategory(getCategory(over.id).parent_id).position + 1;\n }\n return category;\n });\n } else {\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => {\n let category = getCategory(sortedId);\n if (sortedId === active.id) {\n category = { ...category, parent_id: getCategory(over.id).parent_id };\n droppedItem = category;\n }\n return category;\n });\n }\n }\n }\n\n // [A]:Parent dropped over…\n if (activeStatus === 'parent') {\n // [B]:Single\n if (overStatus === 'single') {\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => getCategory(sortedId));\n }\n // [B]:Parent\n if (overStatus === 'parent') {\n if (activeData.index < newIndex) {\n newIndex = newOrder.findIndex(c => c.id === getChildren(over.id).pop().id);\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => getCategory(sortedId));\n } else {\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => getCategory(sortedId));\n }\n }\n // [B]:Child\n if (overStatus === 'child') {\n const parent = newOrder.find(c => c.id === getCategory(over.id).parent_id);\n if (activeData.index < newIndex) {\n newIndex = newOrder.findIndex(c => c.id === getChildren(parent.id).pop().id);\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => getCategory(sortedId));\n newPosition = parent.position;\n } else {\n newIndex = currentIdsOrder.indexOf(getCategory(over.id).parent_id);\n const newIdsOrder = arrayMove(currentIdsOrder, activeData.index, newIndex);\n newOrder = newIdsOrder.map(sortedId => getCategory(sortedId));\n newPosition = parent.position;\n }\n }\n // insert children back\n newOrder = showChildren(active.id, newOrder, newIndex);\n }\n\n setActiveData(initActiveData);\n onDnd(newOrder, droppedItem, newPosition);\n };\n\n /**\n * On drag cancel\n * Reset states\n */\n const handleDragCancel = ({ active }: DragMoveEvent) => {\n setCategoriesList(productCategories);\n setActiveData(initActiveData);\n setExtractedChildren({ ...extractedChildren, [active.id]: null });\n };\n\n /**\n * Get a category by its id\n */\n const getCategory = (id) => {\n return categoriesList.find(c => c.id === id);\n };\n\n /**\n * Get the children categories of a parent category by its id\n */\n const getChildren = (id) => {\n const displayedChildren = categoriesList.filter(c => c.parent_id === id);\n if (displayedChildren.length) {\n return displayedChildren;\n }\n return extractedChildren[id];\n };\n\n /**\n * Get previous category that can have children\n */\n const getPreviousAdopter = (overId) => {\n const reversedList = [...categoriesList].reverse();\n const dropIndex = reversedList.findIndex(c => c.id === overId);\n const adopter = reversedList.find((c, index) => index > dropIndex && !c.parent_id)?.id;\n return adopter || null;\n };\n\n /**\n * Get category's status by its id\n * child | single | parent\n */\n const getStatus = (id) => {\n const c = getCategory(id);\n return !c.parent_id\n ? getChildren(id)?.length\n ? 'parent'\n : 'single'\n : 'child';\n };\n\n /**\n * Extract children from the list by their parent's id\n */\n const hideChildren = (parentId, parentIndex) => {\n const children = getChildren(parentId);\n if (children?.length) {\n const shortenList = [...categoriesList];\n shortenList.splice(parentIndex + 1, children.length);\n setCategoriesList(shortenList);\n }\n };\n\n /**\n * Insert children back in the list by their parent's id\n */\n const showChildren = (parentId, currentList, insertIndex) => {\n if (extractedChildren[parentId]?.length) {\n currentList.splice(insertIndex + 1, 0, ...extractedChildren[parentId]);\n setExtractedChildren({ ...extractedChildren, [parentId]: null });\n }\n return currentList;\n };\n\n /**\n * Toggle parent category by hiding/showing its children\n */\n const handleCollapse = (id) => {\n const i = collapsed.findIndex(el => el === id);\n if (i === -1) {\n setCollapsed([...collapsed, id]);\n } else {\n const copy = [...collapsed];\n copy.splice(i, 1);\n setCollapsed(copy);\n }\n };\n\n return (\n \n \n
\n {categoriesList\n .map((category) => (\n \n ))}\n
\n
\n \n );\n};\n\ninterface ActiveData {\n index: number,\n category: ProductCategory,\n status: 'child' | 'single' | 'parent',\n children: ProductCategory[],\n offset: 'up' | 'down' | null\n}\nconst initActiveData: ActiveData = {\n index: null,\n category: null,\n status: null,\n children: [],\n offset: null\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { ProductCategory } from '../../../models/product-category';\nimport ProductCategoryAPI from '../../../api/product-category';\nimport { ManageProductCategory } from './manage-product-category';\nimport { ProductCategoriesTree } from './product-categories-tree';\nimport { FabAlert } from '../../base/fab-alert';\nimport { IApplication } from '../../../models/application';\nimport { Loader } from '../../base/loader';\nimport { react2angular } from 'react2angular';\nimport ProductLib from '../../../lib/product';\n\ndeclare const Application: IApplication;\n\ninterface ProductCategoriesProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows a tree list of all product categories and offer to manager them\n * by creating, deleting, modifying and reordering each product categories.\n */\nconst ProductCategories: React.FC = ({ onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n // List of all products' categories\n const [productCategories, setProductCategories] = useState>([]);\n\n // load the categories list on component mount\n useEffect(() => {\n refreshCategories();\n }, []);\n\n /**\n * The creation/edition/deletion was successful.\n * Show the provided message and refresh the list\n */\n const handleSuccess = (message: string): void => {\n onSuccess(message);\n refreshCategories();\n };\n\n /**\n * Update state after drop\n */\n const handleDnd = (list: ProductCategory[], activeCategory: ProductCategory, position: number) => {\n setProductCategories(list);\n ProductCategoryAPI\n .update(activeCategory)\n .then(c => {\n ProductCategoryAPI\n .updatePosition(c, position)\n .then(refreshCategories)\n .catch(error => onError(error));\n })\n .catch(error => onError(error));\n };\n\n /**\n * Refresh the list of categories\n */\n const refreshCategories = () => {\n ProductCategoryAPI.index().then(data => {\n setProductCategories(ProductLib.sortCategories(data));\n }).catch((error) => onError(error));\n };\n\n return (\n
\n
\n

{t('app.admin.store.product_categories.title')}

\n
\n \n
\n
\n \n {t('app.admin.store.product_categories.info')}\n \n \n
\n );\n};\n\nconst ProductCategoriesWrapper: React.FC = ({ onSuccess, onError }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('productCategories', react2angular(ProductCategoriesWrapper, ['onSuccess', 'onError']));\n","import { useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useForm, SubmitHandler } from 'react-hook-form';\nimport slugify from 'slugify';\nimport { FormInput } from '../../form/form-input';\nimport { FormSelect } from '../../form/form-select';\nimport { ProductCategory } from '../../../models/product-category';\nimport { FabButton } from '../../base/fab-button';\nimport ProductCategoryAPI from '../../../api/product-category';\nimport { HtmlTranslate } from '../../base/html-translate';\nimport { SelectOption } from '../../../models/select';\n\ninterface ProductCategoryFormProps {\n action: 'create' | 'update' | 'delete',\n productCategories: Array,\n productCategory?: ProductCategory,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * Form to create/edit/delete a product category\n */\nexport const ProductCategoryForm: React.FC = ({ action, productCategories, productCategory, onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n const { register, watch, setValue, control, handleSubmit, formState } = useForm({ defaultValues: { ...productCategory } });\n\n // filter all first level product categorie\n let parents = productCategories.filter(c => !c.parent_id);\n if (action === 'update') {\n parents = parents.filter(c => c.id !== productCategory.id);\n }\n\n /**\n * Convert all parents to the react-select format\n */\n const buildOptions = (): Array> => {\n const options = parents.map(t => {\n return { value: t.id, label: t.name };\n });\n if (action === 'update') {\n options.unshift({ value: null, label: t('app.admin.store.product_category_form.no_parent') });\n }\n return options;\n };\n\n // Create slug from category's name\n useEffect(() => {\n const subscription = watch((value, { name }) => {\n if (name === 'name') {\n const _slug = slugify(value.name, { lower: true, strict: true });\n setValue('slug', _slug);\n }\n });\n return () => subscription.unsubscribe();\n }, [watch]);\n // Check slug pattern\n // Only lowercase alphanumeric groups of characters separated by an hyphen\n const slugPattern = /^[a-z\\d]+(?:-[a-z\\d]+)*$/g;\n\n // Form submit\n const onSubmit: SubmitHandler = (category: ProductCategory) => {\n switch (action) {\n case 'create':\n ProductCategoryAPI.create(category).then(() => {\n onSuccess(t('app.admin.store.product_category_form.create.success'));\n }).catch((error) => {\n onError(t('app.admin.store.product_category_form.create.error') + error);\n });\n break;\n case 'update':\n ProductCategoryAPI.update(category).then(() => {\n onSuccess(t('app.admin.store.product_category_form.update.success'));\n }).catch((error) => {\n onError(t('app.admin.store.product_category_form.update.error') + error);\n });\n break;\n case 'delete':\n ProductCategoryAPI.destroy(category.id).then(() => {\n onSuccess(t('app.admin.store.product_category_form.delete.success'));\n }).catch((error) => {\n onError(t('app.admin.store.product_category_form.delete.error') + error);\n });\n break;\n }\n };\n\n return (\n
\n { action === 'delete'\n ? <>\n \n {t('app.admin.store.product_category_form.delete.save')}\n \n : <>\n \n \n \n {t('app.admin.store.product_category_form.save')}\n \n }\n \n );\n};\n","import * as React from 'react';\nimport { SubmitHandler, useForm } from 'react-hook-form';\nimport { FormInput } from '../form/form-input';\nimport { FormSwitch } from '../form/form-switch';\nimport { useTranslation } from 'react-i18next';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { Product } from '../../models/product';\nimport ProductAPI from '../../api/product';\n\ninterface CloneProductModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onSuccess: (product: Product) => void,\n onError: (message: string) => void,\n product: Product,\n}\n\n/**\n * Modal dialog to clone a product\n */\nexport const CloneProductModal: React.FC = ({ isOpen, toggleModal, onSuccess, onError, product }) => {\n const { t } = useTranslation('admin');\n const { handleSubmit, register, control, formState, reset } = useForm({\n defaultValues: {\n name: product.name,\n sku: product.sku,\n is_active: false\n }\n });\n\n /**\n * Call product clone api\n */\n const handleClone: SubmitHandler = (data: Product) => {\n ProductAPI.clone(product, data).then((res) => {\n reset(res);\n onSuccess(res);\n }).catch(onError);\n };\n\n return (\n \n
\n \n \n {product.is_active &&\n \n }\n \n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { ProductForm } from './product-form';\nimport { Product } from '../../models/product';\nimport ProductAPI from '../../api/product';\nimport { UIRouter } from '@uirouter/angularjs';\n\ndeclare const Application: IApplication;\n\ninterface EditProductProps {\n productId: number,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n uiRouter: UIRouter\n}\n\n/**\n * This component show edit product form\n */\nconst EditProduct: React.FC = ({ productId, onSuccess, onError, uiRouter }) => {\n const { t } = useTranslation('admin');\n\n const [product, setProduct] = useState();\n\n useEffect(() => {\n ProductAPI.get(productId).then(data => {\n setProduct(data);\n }).catch(onError);\n }, []);\n\n /**\n * Success to save product and return to product list\n * or\n * Success to clone product and return to new product\n */\n const saveProductSuccess = (data: Product) => {\n if (data.id === product.id) {\n onSuccess(t('app.admin.store.edit_product.successfully_updated'));\n window.location.href = '/#!/admin/store/products';\n } else {\n onSuccess(t('app.admin.store.edit_product.successfully_cloned'));\n window.location.href = `/#!/admin/store/products/${data.id}/edit`;\n }\n };\n\n if (product) {\n return (\n
\n \n
\n );\n }\n return null;\n};\n\nconst EditProductWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('editProduct', react2angular(EditProductWrapper, ['productId', 'onSuccess', 'onError', 'uiRouter']));\n","import * as React from 'react';\nimport _ from 'lodash';\nimport { ProductIndexFilter } from '../../../models/product';\nimport { X } from 'phosphor-react';\nimport { ProductCategory } from '../../../models/product-category';\nimport { Machine } from '../../../models/machine';\nimport { useTranslation } from 'react-i18next';\n\ninterface ActiveFiltersTagsProps {\n filters: ProductIndexFilter,\n displayCategories?: boolean,\n onRemoveCategory?: (category: ProductCategory) => void,\n onRemoveMachine: (machine: Machine) => void,\n onRemoveKeyword: () => void,\n onRemoveStock?: () => void,\n}\n\n/**\n * Some tags listing the currently actives filters for a product list\n */\nexport const ActiveFiltersTags: React.FC = ({ filters, displayCategories = true, onRemoveCategory, onRemoveMachine, onRemoveKeyword, onRemoveStock }) => {\n const { t } = useTranslation('shared');\n return (\n <>\n {displayCategories && filters.categories.map(c => (\n
\n

{c.name}

\n \n
\n ))}\n {filters.machines.map(m => (\n
\n

{m.name}

\n \n
\n ))}\n {filters.keywords[0] &&
\n

{t('app.shared.active_filters_tags.keyword', { KEYWORD: filters.keywords[0] })}

\n \n
}\n {(!_.isNil(filters.stock_to) && (filters.stock_to !== 0 || filters.stock_from !== 0)) &&
\n

{t(`app.shared.active_filters_tags.stock_${filters.stock_type}`)} [{filters.stock_from || '…'} ⟶ {filters.stock_to || '…'}]

\n \n
}\n \n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport _ from 'lodash';\nimport ProductLib from '../../../lib/product';\nimport { ProductCategory } from '../../../models/product-category';\nimport { FabButton } from '../../base/fab-button';\nimport { AccordionItem } from '../../base/accordion-item';\nimport { useTranslation } from 'react-i18next';\n\ninterface CategoriesFilterProps {\n productCategories: Array,\n onApplyFilters: (categories: Array) => void,\n currentFilters: Array,\n openDefault?: boolean,\n instantUpdate?: boolean,\n}\n\n/**\n * Component to filter the products list by categories\n */\nexport const CategoriesFilter: React.FC = ({ productCategories, onApplyFilters, currentFilters, openDefault = false, instantUpdate = false }) => {\n const { t } = useTranslation('admin');\n\n const [openedAccordion, setOpenedAccordion] = useState(openDefault);\n const [selectedCategories, setSelectedCategories] = useState(currentFilters || []);\n\n useEffect(() => {\n if (currentFilters && !_.isEqual(currentFilters, selectedCategories)) {\n setSelectedCategories(currentFilters);\n }\n }, [currentFilters]);\n\n /**\n * Open/close the accordion item\n */\n const handleAccordion = (id, state: boolean) => {\n setOpenedAccordion(state);\n };\n\n /**\n * Callback triggered when a category filter is selected or unselected.\n * This may cause other categories to be selected or unselected accordingly.\n */\n const handleSelectCategory = (currentCategory: ProductCategory, checked: boolean) => {\n const list = ProductLib.categoriesSelectionTree(productCategories, selectedCategories, currentCategory, checked ? 'add' : 'remove');\n\n setSelectedCategories(list);\n if (instantUpdate) {\n onApplyFilters(list);\n }\n };\n\n return (\n <>\n \n
\n
\n {productCategories.map(pc => (\n \n ))}\n
\n onApplyFilters(selectedCategories)} className=\"is-secondary\">{t('app.admin.store.categories_filter.filter_apply')}\n
\n
\n \n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { FabButton } from '../../base/fab-button';\nimport { AccordionItem } from '../../base/accordion-item';\nimport { useTranslation } from 'react-i18next';\nimport _ from 'lodash';\n\ninterface KeywordFilterProps {\n onApplyFilters: (keywork: string) => void,\n currentFilters?: string,\n openDefault?: boolean,\n instantUpdate?: boolean,\n}\n\n/**\n * Component to filter the products list by keyword or product reference\n */\nexport const KeywordFilter: React.FC = ({ onApplyFilters, currentFilters = '', openDefault = false, instantUpdate = false }) => {\n const { t } = useTranslation('admin');\n\n const [openedAccordion, setOpenedAccordion] = useState(openDefault);\n const [keyword, setKeyword] = useState(currentFilters || '');\n\n useEffect(() => {\n if (!_.isEqual(currentFilters, keyword)) {\n setKeyword(currentFilters);\n }\n }, [currentFilters]);\n\n /**\n * Open/close the accordion item\n */\n const handleAccordion = (id, state: boolean) => {\n setOpenedAccordion(state);\n };\n\n /**\n * Callback triggered when the user types anything in the input\n */\n const handleKeywordTyping = (evt: React.ChangeEvent) => {\n setKeyword(evt.target.value);\n\n if (instantUpdate) {\n onApplyFilters(evt.target.value);\n }\n };\n\n return (\n <>\n \n
\n
\n handleKeywordTyping(event)} value={keyword} />\n onApplyFilters(keyword || undefined)} className=\"is-secondary\">{t('app.admin.store.keyword_filter.filter_apply')}\n
\n
\n
\n \n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { FabButton } from '../../base/fab-button';\nimport { AccordionItem } from '../../base/accordion-item';\nimport { useTranslation } from 'react-i18next';\nimport { Machine } from '../../../models/machine';\nimport MachineAPI from '../../../api/machine';\nimport _ from 'lodash';\n\ninterface MachinesFilterProps {\n allMachines?: Array,\n onError: (message: string) => void,\n onApplyFilters: (categories: Array) => void,\n currentFilters: Array,\n openDefault?: boolean,\n instantUpdate?: boolean\n}\n\n/**\n * Component to filter the products list by associated machine\n */\nexport const MachinesFilter: React.FC = ({ allMachines, onError, onApplyFilters, currentFilters, openDefault = false, instantUpdate = false }) => {\n const { t } = useTranslation('admin');\n\n const [machines, setMachines] = useState(allMachines || []);\n const [openedAccordion, setOpenedAccordion] = useState(openDefault);\n const [selectedMachines, setSelectedMachines] = useState(currentFilters || []);\n\n useEffect(() => {\n if (_.isEmpty(allMachines)) {\n MachineAPI.index({ disabled: false }).then(data => {\n setMachines(data);\n }).catch(onError);\n }\n }, []);\n\n useEffect(() => {\n if (currentFilters && !_.isEqual(currentFilters, selectedMachines)) {\n setSelectedMachines(currentFilters);\n }\n }, [currentFilters]);\n\n /**\n * Open/close the accordion item\n */\n const handleAccordion = (id, state: boolean) => {\n setOpenedAccordion(state);\n };\n\n /**\n * Callback triggered when a machine filter is seleced or unselected.\n */\n const handleSelectMachine = (currentMachine: Machine, checked: boolean) => {\n const list = [...selectedMachines];\n checked\n ? list.push(currentMachine)\n : list.splice(list.indexOf(currentMachine), 1);\n\n setSelectedMachines(list);\n if (instantUpdate) {\n onApplyFilters(list);\n }\n };\n\n return (\n <>\n \n
\n
\n {machines.map(m => (\n \n ))}\n
\n onApplyFilters(selectedMachines)} className=\"is-secondary\">{t('app.admin.store.machines_filter.filter_apply')}\n
\n
\n \n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { FabButton } from '../../base/fab-button';\nimport { AccordionItem } from '../../base/accordion-item';\nimport { useTranslation } from 'react-i18next';\nimport { ProductIndexFilter, StockType } from '../../../models/product';\nimport { FormSelect } from '../../form/form-select';\nimport { FormInput } from '../../form/form-input';\nimport { useForm } from 'react-hook-form';\nimport _ from 'lodash';\nimport { SelectOption } from '../../../models/select';\n\ninterface StockFilterProps {\n onApplyFilters: (filters: ProductIndexFilter) => void,\n currentFilters: ProductIndexFilter,\n openDefault?: boolean\n}\n\n/**\n * Component to filter the products list by stock\n */\nexport const StockFilter: React.FC = ({ onApplyFilters, currentFilters, openDefault = false }) => {\n const { t } = useTranslation('admin');\n\n const [openedAccordion, setOpenedAccordion] = useState(openDefault);\n\n const { register, control, handleSubmit, getValues, reset } = useForm({ defaultValues: { ...currentFilters } });\n\n useEffect(() => {\n if (currentFilters && !_.isEqual(currentFilters, getValues())) {\n reset(currentFilters);\n }\n }, [currentFilters]);\n\n /**\n * Open/close the accordion item\n */\n const handleAccordion = (id, state: boolean) => {\n setOpenedAccordion(state);\n };\n\n /**\n * Callback triggered when the user clicks on \"apply\" to apply teh current filters.\n */\n const onSubmit = (data: ProductIndexFilter) => {\n onApplyFilters(data);\n };\n\n /** Creates sorting options to the react-select format */\n const buildStockOptions = (): Array> => {\n return [\n { value: 'internal', label: t('app.admin.store.stock_filter.stock_internal') },\n { value: 'external', label: t('app.admin.store.stock_filter.stock_external') }\n ];\n };\n\n return (\n <>\n \n
\n
\n \n
\n \n \n
\n {t('app.admin.store.stock_filter.filter_apply')}\n
\n
\n
\n \n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { ProductForm } from './product-form';\nimport { UIRouter } from '@uirouter/angularjs';\n\ndeclare const Application: IApplication;\n\ninterface NewProductProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n uiRouter: UIRouter,\n}\n\n/**\n * This component show new product form\n */\nconst NewProduct: React.FC = ({ onSuccess, onError, uiRouter }) => {\n const { t } = useTranslation('admin');\n\n const product = {\n id: undefined,\n name: '',\n slug: '',\n sku: '',\n description: '',\n is_active: false,\n quantity_min: 1,\n stock: {\n internal: 0,\n external: 0\n },\n low_stock_alert: false,\n machine_ids: [],\n product_files_attributes: [],\n product_images_attributes: []\n };\n\n /**\n * Success to save product and return to product list\n */\n const saveProductSuccess = () => {\n onSuccess(t('app.admin.store.new_product.successfully_created'));\n window.location.href = '/#!/admin/store/products';\n };\n\n return (\n
\n \n
\n );\n};\n\nconst NewProductWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('newProduct', react2angular(NewProductWrapper, ['onSuccess', 'onError', 'uiRouter']));\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport Select from 'react-select';\nimport { FabModal } from '../base/fab-modal';\nimport OrderAPI from '../../api/order';\nimport { Order } from '../../models/order';\nimport FabTextEditor from '../base/text-editor/fab-text-editor';\nimport { HtmlTranslate } from '../base/html-translate';\nimport { SelectOption } from '../../models/select';\n\ninterface OrderActionsProps {\n order: Order,\n onSuccess: (order: Order, message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * Actions for an order\n */\nexport const OrderActions: React.FC = ({ order, onSuccess, onError }) => {\n const { t } = useTranslation('shared');\n const [currentAction, setCurrentAction] = useState>();\n const [modalIsOpen, setModalIsOpen] = useState(false);\n const [readyNote, setReadyNote] = useState('');\n\n // Styles the React-select component\n const customStyles = {\n control: base => ({\n ...base,\n width: '20ch',\n backgroundColor: 'transparent'\n }),\n indicatorSeparator: () => ({\n display: 'none'\n })\n };\n\n /**\n * Close the action confirmation modal\n */\n const closeModal = (): void => {\n setModalIsOpen(false);\n setCurrentAction(null);\n };\n\n /**\n * Creates sorting options to the react-select format\n */\n const buildOptions = (): Array> => {\n let actions = [];\n switch (order.state) {\n case 'paid':\n actions = actions.concat(['in_progress', 'ready', 'delivered', 'canceled', 'refunded']);\n break;\n case 'payment_failed':\n actions = actions.concat(['canceled']);\n break;\n case 'in_progress':\n actions = actions.concat(['ready', 'delivered', 'canceled', 'refunded']);\n break;\n case 'ready':\n actions = actions.concat(['delivered', 'canceled', 'refunded']);\n break;\n case 'canceled':\n actions = actions.concat(['refunded']);\n break;\n default:\n actions = [];\n }\n return actions.map(action => {\n return { value: action, label: t(`app.shared.store.order_actions.state.${action}`) };\n });\n };\n\n /**\n * Callback after selecting an action\n */\n const handleAction = (action: SelectOption) => {\n setCurrentAction(action);\n setModalIsOpen(true);\n };\n\n /**\n * Callback after confirm an action\n */\n const handleActionConfirmation = () => {\n OrderAPI.updateState(order, currentAction.value, readyNote).then(data => {\n onSuccess(data, t(`app.shared.store.order_actions.order_${currentAction.value}_success`));\n setCurrentAction(null);\n setModalIsOpen(false);\n }).catch((e) => {\n onError(e);\n setCurrentAction(null);\n setModalIsOpen(false);\n });\n };\n\n return (\n <>\n {buildOptions().length > 0 &&\n handleAction(option)}\n value={currentAction}\n styles={customStyles}\n />\n }\n \n \n {currentAction?.value === 'ready' &&\n \n }\n \n \n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Order } from '../../models/order';\nimport FormatLib from '../../lib/format';\nimport { FabButton } from '../base/fab-button';\nimport { User } from '../../models/user';\nimport { FabStateLabel } from '../base/fab-state-label';\nimport OrderLib from '../../lib/order';\nimport { PlusCircle } from 'phosphor-react';\n\ninterface OrderItemProps {\n order?: Order,\n currentUser?: User\n}\n\n/**\n * List item for an order\n */\nexport const OrderItem: React.FC = ({ order, currentUser }) => {\n const { t } = useTranslation('shared');\n /**\n * Go to order page\n */\n const showOrder = (order: Order) => {\n isPrivileged()\n ? window.location.href = `/#!/admin/store/orders/${order.id}`\n : window.location.href = `/#!/dashboard/orders/${order.id}`;\n };\n\n /**\n * Check if the current operator has administrative rights or is a normal member\n */\n const isPrivileged = (): boolean => {\n return (currentUser?.role === 'admin' || currentUser?.role === 'manager');\n };\n\n return (\n
\n
{order.reference}
\n \n {t(`app.shared.store.order_item.state.${OrderLib.statusText(order)}`)}\n \n {isPrivileged() &&\n
\n {t('app.shared.store.order_item.client')}\n

{order?.user?.name || ''}

\n
\n }\n
\n {t('app.shared.store.order_item.created_at')}\n
\n

{FormatLib.date(order.created_at)}\n \n \n \n {t('app.shared.store.order_item.last_update')}
\n {FormatLib.date(order.updated_at)}\n
\n
\n

\n
\n
\n
\n {t('app.shared.store.order_item.total')}\n

{FormatLib.price(order.state === 'cart' ? order.total : order.paid_total)}

\n
\n showOrder(order)} icon={} className=\"is-black\" />\n
\n );\n};\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useImmer } from 'use-immer';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { useForm } from 'react-hook-form';\nimport { FabButton } from '../base/fab-button';\nimport { StoreListHeader } from './store-list-header';\nimport { AccordionItem } from '../base/accordion-item';\nimport { OrderItem } from './order-item';\nimport { MemberSelect } from '../user/member-select';\nimport { User } from '../../models/user';\nimport { FormInput } from '../form/form-input';\nimport OrderAPI from '../../api/order';\nimport { Order, OrderIndexFilter, OrderSortOption, OrderState } from '../../models/order';\nimport { FabPagination } from '../base/fab-pagination';\nimport { CaretDoubleUp, X } from 'phosphor-react';\nimport { ChecklistOption, SelectOption } from '../../models/select';\n\ndeclare const Application: IApplication;\n\ninterface OrdersProps {\n currentUser?: User,\n onError: (message: string) => void,\n}\n\nconst initFilters: OrderIndexFilter = {\n reference: '',\n states: [],\n page: 1,\n sort: 'created_at-desc'\n};\n\nconst FablabOrdersFilters = 'FablabOrdersFilters';\n\n/**\n * Admin list of orders\n */\nconst Orders: React.FC = ({ currentUser, onError }) => {\n const { t } = useTranslation('admin');\n\n const { register, setValue } = useForm();\n\n const [orders, setOrders] = useState>([]);\n const [filters, setFilters] = useImmer(window[FablabOrdersFilters] || initFilters);\n const [accordion, setAccordion] = useState({});\n const [filtersPanel, setFiltersPanel] = useState(true);\n const [pageCount, setPageCount] = useState(0);\n const [totalCount, setTotalCount] = useState(0);\n const [reference, setReference] = useState(filters.reference);\n const [states, setStates] = useState>(filters.states);\n const [user, setUser] = useState<{ id: number, name?: string }>(filters.user);\n const [periodFrom, setPeriodFrom] = useState(filters.period_from);\n const [periodTo, setPeriodTo] = useState(filters.period_to);\n\n useEffect(() => {\n window[FablabOrdersFilters] = filters;\n OrderAPI.index(filters).then(res => {\n setPageCount(res.total_pages);\n setTotalCount(res.total_count);\n setOrders(res.data);\n }).catch(onError);\n }, [filters]);\n\n const statusOptions: ChecklistOption[] = [\n { value: 'cart', label: t('app.admin.store.orders.state.cart') },\n { value: 'paid', label: t('app.admin.store.orders.state.paid') },\n { value: 'payment_failed', label: t('app.admin.store.orders.state.payment_failed') },\n { value: 'in_progress', label: t('app.admin.store.orders.state.in_progress') },\n { value: 'ready', label: t('app.admin.store.orders.state.ready') },\n { value: 'canceled', label: t('app.admin.store.orders.state.canceled') }\n ];\n\n /**\n * Apply filters\n */\n const applyFilters = (filterType: string) => {\n return () => {\n setFilters(draft => {\n switch (filterType) {\n case 'reference':\n draft.reference = reference;\n break;\n case 'states':\n draft.states = states;\n break;\n case 'user':\n draft.user_id = user.id;\n draft.user = user;\n break;\n case 'period':\n if (periodFrom && periodTo) {\n draft.period_from = periodFrom;\n draft.period_to = periodTo;\n } else {\n draft.period_from = '';\n draft.period_to = '';\n }\n break;\n default:\n }\n });\n };\n };\n\n /**\n * Clear filter by type\n */\n const removeFilter = (filterType: string, state?: OrderState) => {\n return () => {\n setFilters(draft => {\n draft.page = 1;\n draft.sort = 'created_at-desc';\n switch (filterType) {\n case 'reference':\n draft.reference = '';\n setReference('');\n break;\n case 'states': {\n const s = [...draft.states];\n s.splice(states.indexOf(state), 1);\n setStates(s);\n draft.states = s;\n break;\n }\n case 'user':\n delete draft.user_id;\n delete draft.user;\n setUser(null);\n break;\n case 'period':\n draft.period_from = '';\n draft.period_to = '';\n setPeriodFrom(null);\n setPeriodTo(null);\n break;\n default:\n }\n });\n };\n };\n\n /**\n * Clear filters\n */\n const clearAllFilters = () => {\n setFilters(initFilters);\n setReference('');\n setStates([]);\n setUser(null);\n setPeriodFrom(null);\n setPeriodTo(null);\n setValue('period_from', '');\n setValue('period_to', '');\n };\n\n /**\n * Creates sorting options to the react-select format\n */\n const buildOptions = (): Array> => {\n return [\n { value: 'created_at-desc', label: t('app.admin.store.orders.sort.newest') },\n { value: 'created_at-asc', label: t('app.admin.store.orders.sort.oldest') }\n ];\n };\n\n /**\n * Display option: sorting\n */\n const handleSorting = (option: SelectOption) => {\n setFilters(draft => {\n draft.sort = option.value;\n });\n };\n\n /**\n * Filter: by reference\n */\n const handleReferenceChanged = (value: string) => {\n setReference(value);\n };\n\n /**\n * Filter: by status\n */\n const handleSelectStatus = (s: ChecklistOption, checked: boolean) => {\n const list = [...states];\n checked\n ? list.push(s.value)\n : list.splice(list.indexOf(s.value), 1);\n setStates(list);\n };\n\n /**\n * Filter: by member\n */\n const handleSelectMember = (user: User) => {\n setUser(user);\n };\n\n /**\n * Filter: by period\n */\n const handlePeriodChanged = (period: string) => {\n return (event: React.ChangeEvent) => {\n const value = event.target.value;\n if (period === 'period_from') {\n setPeriodFrom(value);\n }\n if (period === 'period_to') {\n setPeriodTo(value);\n }\n };\n };\n\n /**\n * Open/close accordion items\n */\n const handleAccordion = (id, state) => {\n setAccordion({ ...accordion, [id]: state });\n };\n\n /**\n * Handle orders pagination\n */\n const handlePagination = (page: number) => {\n setFilters(draft => {\n draft.page = page;\n });\n };\n\n return (\n
\n
\n

{t('app.admin.store.orders.heading')}

\n
\n\n \n\n
\n \n
\n {filters.reference &&
\n

{filters.reference}

\n \n
}\n {filters.states?.map((status, index) => (\n
\n

{t(`app.admin.store.orders.state.${status}`)}

\n \n
\n ))}\n {filters.user_id > 0 &&
\n

{user?.name}

\n \n
}\n {filters.period_from &&
\n

{filters.period_from} {'>'} {filters.period_to}

\n \n
}\n
\n\n
\n {orders.map(order => (\n \n ))}\n
\n {pageCount > 1 &&\n \n }\n
\n
\n );\n};\n\nconst OrdersWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('orders', react2angular(OrdersWrapper, ['currentUser', 'onError']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { SubmitHandler, useForm, useWatch } from 'react-hook-form';\nimport { useTranslation } from 'react-i18next';\nimport slugify from 'slugify';\nimport _ from 'lodash';\nimport { Product } from '../../models/product';\nimport { FormInput } from '../form/form-input';\nimport { FormSwitch } from '../form/form-switch';\nimport { FormSelect } from '../form/form-select';\nimport { FormChecklist } from '../form/form-checklist';\nimport { FormRichText } from '../form/form-rich-text';\nimport { FabButton } from '../base/fab-button';\nimport ProductCategoryAPI from '../../api/product-category';\nimport MachineAPI from '../../api/machine';\nimport ProductAPI from '../../api/product';\nimport { ProductStockForm } from './product-stock-form';\nimport { CloneProductModal } from './clone-product-modal';\nimport ProductLib from '../../lib/product';\nimport { UnsavedFormAlert } from '../form/unsaved-form-alert';\nimport { UIRouter } from '@uirouter/angularjs';\nimport { SelectOption, ChecklistOption } from '../../models/select';\nimport { FormMultiFileUpload } from '../form/form-multi-file-upload';\nimport { FormMultiImageUpload } from '../form/form-multi-image-upload';\nimport { AdvancedAccountingForm } from '../accounting/advanced-accounting-form';\nimport { FabTabs } from '../base/fab-tabs';\nimport { HtmlTranslate } from '../base/html-translate';\n\ninterface ProductFormProps {\n product: Product,\n title: string,\n onSuccess: (product: Product) => void,\n onError: (message: string) => void,\n uiRouter: UIRouter\n}\n\n/**\n * Form component to create or update a product\n */\nexport const ProductForm: React.FC = ({ product, title, onSuccess, onError, uiRouter }) => {\n const { t } = useTranslation('admin');\n\n const { handleSubmit, register, control, formState, setValue, reset } = useForm({ defaultValues: { ...product } });\n const output = useWatch({ control });\n const [isActivePrice, setIsActivePrice] = useState(product.id && _.isFinite(product.amount));\n const [productCategories, setProductCategories] = useState[]>([]);\n const [machines, setMachines] = useState[]>([]);\n const [openCloneModal, setOpenCloneModal] = useState(false);\n const [saving, setSaving] = useState(false);\n\n useEffect(() => {\n ProductCategoryAPI.index().then(data => {\n setProductCategories(buildSelectOptions(ProductLib.sortCategories(data)));\n }).catch(onError);\n MachineAPI.index({ disabled: false }).then(data => {\n setMachines(buildChecklistOptions(data));\n }).catch(onError);\n }, []);\n\n /**\n * Convert the provided array of items to the react-select format\n */\n const buildSelectOptions = (items: Array<{ id?: number, name: string, parent_id?: number }>): Array> => {\n return items.map(t => {\n return {\n value: t.id,\n label: t.parent_id\n ? {t.name}\n : t.name\n };\n });\n };\n\n /**\n * Convert the provided array of items to the checklist format\n */\n const buildChecklistOptions = (items: Array<{ id?: number, name: string }>): Array> => {\n return items.map(t => {\n return { value: t.id, label: t.name };\n });\n };\n\n /**\n * Callback triggered when the name has changed.\n */\n const handleNameChange = (event: React.ChangeEvent): void => {\n const name = event.target.value;\n const slug = slugify(name, { lower: true, strict: true });\n setValue('slug', slug);\n };\n\n /**\n * Callback triggered when the user toggles the visibility of the product in the store.\n */\n const handleIsActiveChanged = (value: boolean): void => {\n if (value) {\n setValue('is_active_price', true);\n setIsActivePrice(true);\n }\n };\n\n /**\n * Callback triggered when is active price has changed.\n */\n const toggleIsActivePrice = (value: boolean) => {\n if (!value) {\n setValue('amount', null);\n setValue('is_active', false);\n }\n setIsActivePrice(value);\n };\n\n /**\n * Callback triggered when the form is submitted: process with the product creation or update.\n */\n const onSubmit: SubmitHandler = (data: Product) => {\n saveProduct(data);\n };\n\n /**\n * Call product creation or update api\n */\n const saveProduct = (data: Product) => {\n setSaving(true);\n if (product.id) {\n ProductAPI.update(data).then((res) => {\n reset(res);\n setSaving(false);\n onSuccess(res);\n }).catch(e => {\n setSaving(false);\n onError(e);\n });\n } else {\n ProductAPI.create(data).then((res) => {\n reset(res);\n onSuccess(res);\n }).catch(e => {\n setSaving(false);\n onError(e);\n });\n }\n };\n\n /**\n * Toggle clone product modal\n */\n const toggleCloneModal = () => {\n setOpenCloneModal(!openCloneModal);\n };\n\n /**\n * This function render the content of the 'products settings' tab\n */\n const renderSettingsTab = () => (\n
\n
\n
\n

{t('app.admin.store.product_form.description')}

\n

{t('app.admin.store.product_form.description_info')}

\n
\n
\n \n \n \n \n \n
\n
\n\n
\n
\n

{t('app.admin.store.product_form.product_images')}

\n \n
\n
\n \n
\n
\n\n
\n
\n

{t('app.admin.store.product_form.price_and_rule_of_selling_product')}

\n
\n
\n \n {isActivePrice && <>\n \n \n }\n
\n
\n\n
\n
\n

{t('app.admin.store.product_form.assigning_category')}

\n \n
\n
\n \n
\n
\n\n
\n
\n

{t('app.admin.store.product_form.assigning_machines')}

\n \n
\n
\n \n
\n
\n\n
\n
\n

{t('app.admin.store.product_form.product_files')}

\n \n
\n
\n \n
\n
\n\n
\n \n
\n
\n );\n\n return (\n <>\n
\n

{title}

\n
\n {product.id &&\n <>\n {t('app.admin.store.product_form.clone')}\n \n \n }\n \n {!saving && t('app.admin.store.product_form.save')}\n {saving && }\n \n
\n
\n
\n \n \n }\n ]} />\n \n \n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Product } from '../../models/product';\nimport noImage from '../../../../images/no_image.png';\nimport { FabStateLabel } from '../base/fab-state-label';\nimport { ProductPrice } from './product-price';\nimport { EditDestroyButtons } from '../base/edit-destroy-buttons';\nimport ProductAPI from '../../api/product';\n\ninterface ProductItemProps {\n product: Product,\n onEdit: (product: Product) => void,\n onDelete: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows a product item in the admin view\n */\nexport const ProductItem: React.FC = ({ product, onEdit, onDelete, onError }) => {\n const { t } = useTranslation('admin');\n\n /**\n * Get the main image\n */\n const thumbnail = () => {\n return product.product_images_attributes.find(att => att.is_main);\n };\n /**\n * Init the process of editing the given product\n */\n const editProduct = (product: Product): () => void => {\n return (): void => {\n onEdit(product);\n };\n };\n\n /**\n * Returns CSS class from stock status\n */\n const stockColor = (product: Product, stockType: string) => {\n if (product.stock[stockType] < (product.quantity_min || 1)) {\n return 'out-of-stock';\n }\n if (product.low_stock_threshold && product.stock[stockType] <= product.low_stock_threshold) {\n return 'low';\n }\n return '';\n };\n\n return (\n
\n
\n \n

{product.name}

\n
\n
\n \n {product.is_active\n ? t('app.admin.store.product_item.visible')\n : t('app.admin.store.product_item.hidden')\n }\n \n
\n {t('app.admin.store.product_item.stock.internal')}\n

{product.stock.internal}

\n
\n
\n {t('app.admin.store.product_item.stock.external')}\n

{product.stock.external}

\n
\n \n
\n
\n \n
\n
\n );\n};\n","import * as React from 'react';\nimport { Product } from '../../models/product';\nimport FormatLib from '../../lib/format';\nimport { useTranslation } from 'react-i18next';\n\ninterface ProductPriceProps {\n product: Product;\n className?: string;\n}\n\n/**\n * Render the formatted price for the given product, or \"free\" if the price is 0 or not set\n */\nexport const ProductPrice: React.FC = ({ product, className }) => {\n const { t } = useTranslation('public');\n\n /**\n * Return the formatted price data\n */\n const renderPrice = (product: Product) => {\n if (product.amount === 0) {\n return

{t('app.public.product_price.free')}

;\n }\n if ([null, undefined].includes(product.amount)) {\n return
;\n }\n return <>\n

{FormatLib.price(product.amount)}

\n {t('app.public.product_price.per_unit')}\n ;\n };\n\n return (\n
\n {renderPrice(product)}\n
\n );\n};\n","import { ReactNode, useEffect, useState } from 'react';\nimport Select from 'react-select';\nimport { PencilSimple } from 'phosphor-react';\nimport { useFieldArray, UseFormRegister } from 'react-hook-form';\nimport { Control, FormState, UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { useTranslation } from 'react-i18next';\nimport {\n Product, ProductStockMovement,\n stockMovementAllReasons, StockMovementIndex, StockMovementIndexFilter,\n StockMovementReason,\n StockType\n} from '../../models/product';\nimport { FormSwitch } from '../form/form-switch';\nimport { FormInput } from '../form/form-input';\nimport { FabButton } from '../base/fab-button';\nimport { ProductStockModal } from './product-stock-modal';\nimport { FabStateLabel } from '../base/fab-state-label';\nimport ProductAPI from '../../api/product';\nimport FormatLib from '../../lib/format';\nimport ProductLib from '../../lib/product';\nimport { useImmer } from 'use-immer';\nimport { FabPagination } from '../base/fab-pagination';\nimport { FormUnsavedList } from '../form/form-unsaved-list';\n\ninterface ProductStockFormProps {\n currentFormValues: Product,\n register: UseFormRegister,\n control: Control,\n formState: FormState,\n setValue: UseFormSetValue,\n onSuccess: (product: Product) => void,\n onError: (message: string) => void,\n}\n\nconst DEFAULT_LOW_STOCK_THRESHOLD = 30;\n\n/**\n * Form tab to manage a product's stock\n */\nexport const ProductStockForm = ({ currentFormValues, register, control, formState, setValue, onError }: ProductStockFormProps) => {\n const { t } = useTranslation('admin');\n\n const [activeThreshold, setActiveThreshold] = useState(currentFormValues.low_stock_threshold != null);\n // is the update stock modal open?\n const [isOpen, setIsOpen] = useState(false);\n const [stockMovements, setStockMovements] = useState(null);\n const [filters, setFilters] = useImmer({ page: 1 });\n\n const { fields, append, remove } = useFieldArray({ control, name: 'product_stock_movements_attributes' });\n\n useEffect(() => {\n if (!currentFormValues?.id) return;\n\n ProductAPI.stockMovements(currentFormValues.id, filters).then(setStockMovements).catch(onError);\n }, [filters]);\n\n // Styles the React-select component\n const customStyles = {\n control: base => ({\n ...base,\n width: '20ch',\n border: 'none',\n backgroundColor: 'transparent'\n }),\n indicatorSeparator: () => ({\n display: 'none'\n })\n };\n\n type reasonSelectOption = { value: StockMovementReason, label: string };\n /**\n * Creates sorting options to the react-select format\n */\n const buildReasonsOptions = (): Array => {\n return stockMovementAllReasons.map(key => {\n return { value: key, label: t(ProductLib.stockMovementReasonTrKey(key)) };\n });\n };\n\n type typeSelectOption = { value: StockType, label: string };\n /**\n * Creates sorting options to the react-select format\n */\n const buildStocksOptions = (): Array => {\n return [\n { value: 'internal', label: t('app.admin.store.product_stock_form.internal') },\n { value: 'external', label: t('app.admin.store.product_stock_form.external') },\n { value: 'all', label: t('app.admin.store.product_stock_form.all') }\n ];\n };\n\n /**\n * On stock movement reason filter change\n */\n const eventsOptionsChange = (evt: reasonSelectOption) => {\n setFilters(draft => {\n return {\n ...draft,\n reason: evt.value\n };\n });\n };\n /**\n * On stocks type filter change\n */\n const stocksOptionsChange = (evt: typeSelectOption) => {\n setFilters(draft => {\n return {\n ...draft,\n stock_type: evt.value\n };\n });\n };\n\n /**\n * Callback triggered when the user wants to swich the current page of stock movements\n */\n const handlePagination = (page: number) => {\n setFilters(draft => {\n return {\n ...draft,\n page\n };\n });\n };\n\n /**\n * Toggle stock threshold\n */\n const toggleStockThreshold = (checked: boolean) => {\n setActiveThreshold(checked);\n setValue(\n 'low_stock_threshold',\n (checked ? DEFAULT_LOW_STOCK_THRESHOLD : null)\n );\n };\n\n /**\n * Opens/closes the product stock edition modal\n */\n const toggleModal = (): void => {\n setIsOpen(!isOpen);\n };\n\n /**\n * Triggered when a new product stock movement was added\n */\n const onNewStockMovement = (movement): void => {\n append({ ...movement });\n };\n\n /**\n * Return the data of the update of the stock for the current product\n */\n const lastStockUpdate = () => {\n if (stockMovements?.data[0]) {\n return stockMovements?.data[0].date;\n } else {\n return currentFormValues?.created_at || new Date();\n }\n };\n\n /**\n * Render an attribute of an unsaved stock movement\n */\n const renderOngoingStockMovement = (movement: ProductStockMovement): ReactNode => (\n <>\n
\n

{t(`app.admin.store.product_stock_form.type_${ProductLib.stockMovementType(movement.reason)}`)}

\n
\n
\n {t(`app.admin.store.product_stock_form.${movement.stock_type}`)}\n

{ProductLib.absoluteStockMovement(movement.quantity, movement.reason)}

\n
\n
\n {t('app.admin.store.product_stock_form.reason')}\n

{t(ProductLib.stockMovementReasonTrKey(movement.reason))}

\n
\n \n );\n\n return (\n
\n

{t('app.admin.store.product_stock_form.stock_up_to_date')} \n {t('app.admin.store.product_stock_form.date_time', {\n DATE: FormatLib.date(lastStockUpdate()),\n TIME: FormatLib.time((lastStockUpdate()))\n })}\n

\n
\n
\n

{currentFormValues?.name}

\n
\n {t('app.admin.store.product_stock_form.internal')}\n

{currentFormValues?.stock?.internal}

\n
\n
\n {t('app.admin.store.product_stock_form.external')}\n

{currentFormValues?.stock?.external}

\n
\n } className=\"is-black\">{t('app.admin.store.product_stock_form.edit')}\n
\n\n \n\n
\n\n
\n
\n

{t('app.admin.store.product_stock_form.low_stock_threshold')}

\n

{t('app.admin.store.product_stock_form.stock_threshold_info')}

\n
\n
\n \n {activeThreshold && <>\n {t('app.admin.store.product_stock_form.low_stock')}\n \n \n }\n
\n
\n\n
\n

{t('app.admin.store.product_stock_form.events_history')}

\n
\n
\n

{t('app.admin.store.product_stock_form.event_type')}

\n eventsOptionsChange(evt)}\n styles={customStyles}\n />\n
\n
\n

{t('app.admin.store.product_stock_form.stocks')}

\n stocksOptionsChange(evt)}\n styles={customStyles}\n />\n
\n
\n {stockMovements?.data?.map(movement =>
\n
\n

{currentFormValues.name}

\n

{FormatLib.date(movement.date)}

\n
\n {t(`app.admin.store.product_stock_form.${movement.stock_type}`)}\n

{ProductLib.absoluteStockMovement(movement.quantity, movement.reason)}

\n
\n
\n {t('app.admin.store.product_stock_form.reason')}\n

{t(ProductLib.stockMovementReasonTrKey(movement.reason))}

\n
\n
\n {t('app.admin.store.product_stock_form.remaining_stock')}\n

{movement.remaining_stock}

\n
\n
\n
)}\n {stockMovements?.total_pages > 1 &&\n \n }\n
\n \n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport {\n ProductStockMovement,\n stockMovementInReasons,\n stockMovementOutReasons,\n StockMovementReason,\n StockType\n} from '../../models/product';\nimport { FormSelect } from '../form/form-select';\nimport { FormInput } from '../form/form-input';\nimport { FabButton } from '../base/fab-button';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { useForm } from 'react-hook-form';\nimport ProductLib from '../../lib/product';\n\ntype reasonSelectOption = { value: StockMovementReason, label: string };\ntype typeSelectOption = { value: StockType, label: string };\n\ninterface ProductStockModalProps {\n onSuccess: (movement: ProductStockMovement) => void,\n isOpen: boolean,\n toggleModal: () => void,\n}\n\n/**\n * Form to manage a product's stock movement and quantity\n */\nexport const ProductStockModal: React.FC = ({ onSuccess, isOpen, toggleModal }) => {\n const { t } = useTranslation('admin');\n\n const [movement, setMovement] = useState<'in' | 'out'>('in');\n\n const { handleSubmit, register, control, formState } = useForm();\n\n /**\n * Toggle between adding or removing product from stock\n */\n const toggleMovementType = (evt: React.MouseEvent, type: 'in' | 'out') => {\n evt.preventDefault();\n setMovement(type);\n };\n\n /**\n * Callback triggered when the user validates the new stock movement.\n * We do not use handleSubmit() directly to prevent the propagaion of the \"submit\" event to the parent form\n */\n const onSubmit = (event: React.FormEvent) => {\n if (event) {\n event.stopPropagation();\n event.preventDefault();\n }\n return handleSubmit((data: ProductStockMovement) => {\n onSuccess(data);\n toggleModal();\n })(event);\n };\n\n /**\n * Creates sorting options to the react-select format\n */\n const buildEventsOptions = (): Array => {\n return (movement === 'in' ? stockMovementInReasons : stockMovementOutReasons).map(key => {\n return { value: key, label: t(ProductLib.stockMovementReasonTrKey(key)) };\n });\n };\n /**\n * Creates sorting options to the react-select format\n */\n const buildStocksOptions = (): Array => {\n return [\n { value: 'internal', label: t('app.admin.store.product_stock_modal.internal') },\n { value: 'external', label: t('app.admin.store.product_stock_modal.external') }\n ];\n };\n\n return (\n \n
\n

{t('app.admin.store.product_stock_modal.new_event')}

\n
\n \n \n
\n \n \n \n {t('app.admin.store.product_stock_modal.update_stock')} \n \n
\n );\n};\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useImmer } from 'use-immer';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport {\n initialFilters, initialResources,\n Product,\n ProductIndexFilter,\n ProductResourcesFetching,\n ProductsIndex,\n ProductSortOption\n} from '../../models/product';\nimport { ProductCategory } from '../../models/product-category';\nimport { FabButton } from '../base/fab-button';\nimport { ProductItem } from './product-item';\nimport ProductAPI from '../../api/product';\nimport { StoreListHeader } from './store-list-header';\nimport { FabPagination } from '../base/fab-pagination';\nimport { CategoriesFilter } from './filters/categories-filter';\nimport { Machine } from '../../models/machine';\nimport { MachinesFilter } from './filters/machines-filter';\nimport { KeywordFilter } from './filters/keyword-filter';\nimport { StockFilter } from './filters/stock-filter';\nimport ProductLib from '../../lib/product';\nimport { ActiveFiltersTags } from './filters/active-filters-tags';\nimport SettingAPI from '../../api/setting';\nimport { UIRouter } from '@uirouter/angularjs';\nimport { CaretDoubleUp } from 'phosphor-react';\nimport { SelectOption } from '../../models/select';\n\ndeclare const Application: IApplication;\n\ninterface ProductsProps {\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n uiRouter: UIRouter,\n}\n\n/** This component shows the admin view of the store */\nconst Products: React.FC = ({ onSuccess, onError, uiRouter }) => {\n const { t } = useTranslation('admin');\n\n const [productsList, setProductList] = useState>([]);\n // this includes the resources fetch from the API (machines, categories) and from the URL (filters)\n const [resources, setResources] = useImmer(initialResources);\n const [machinesModule, setMachinesModule] = useState(false);\n const [pageCount, setPageCount] = useState(0);\n const [currentPage, setCurrentPage] = useState(1);\n const [productsCount, setProductsCount] = useState(0);\n const [filtersPanel, setFiltersPanel] = useState(true);\n\n useEffect(() => {\n ProductLib.fetchInitialResources(setResources, onError);\n SettingAPI.get('machines_module').then(data => {\n setMachinesModule(data.value === 'true');\n }).catch(onError);\n }, []);\n\n useEffect(() => {\n if (resources.filters.ready) {\n fetchProducts();\n uiRouter.stateService.transitionTo(uiRouter.globals.current, ProductLib.indexFiltersToRouterParams(resources.filters.data));\n }\n }, [resources.filters]);\n\n useEffect(() => {\n if (resources.machines.ready && resources.categories.ready) {\n setResources(draft => {\n return {\n ...draft,\n filters: {\n data: ProductLib.readFiltersFromUrl(uiRouter.globals.params, resources.machines.data, resources.categories.data),\n ready: true\n }\n };\n });\n }\n }, [resources.machines, resources.categories]);\n\n /**\n * Handle products pagination\n */\n const handlePagination = (page: number) => {\n if (page !== currentPage) {\n ProductLib.updateFilter(setResources, 'page', page);\n }\n };\n\n /**\n * Fetch the products from the API, according to the current filters\n */\n const fetchProducts = async (): Promise => {\n try {\n const data = await ProductAPI.index(resources.filters.data);\n setCurrentPage(data.page);\n setProductList(data.data);\n setPageCount(data.total_pages);\n setProductsCount(data.total_count);\n return data;\n } catch (error) {\n onError(t('app.admin.store.products.unexpected_error_occurred') + error);\n }\n };\n\n /** Goto edit product page */\n const editProduct = (product: Product) => {\n window.location.href = `/#!/admin/store/products/${product.id}/edit`;\n };\n\n /** Delete a product */\n const deleteProduct = async (message: string): Promise => {\n await fetchProducts();\n onSuccess(message);\n };\n\n /** Goto new product page */\n const newProduct = (): void => {\n window.location.href = '/#!/admin/store/products/new';\n };\n\n /** Filter: toggle non-available products visibility */\n const toggleVisible = (checked: boolean) => {\n ProductLib.updateFilter(setResources, 'is_active', checked);\n };\n\n /**\n * Update the list of applied filters with the given categories\n */\n const handleCategoriesFilterUpdate = (categories: Array) => {\n ProductLib.updateFilter(setResources, 'categories', categories);\n };\n\n /**\n * Remove the provided category from the filters selection\n */\n const handleRemoveCategory = (category: ProductCategory) => {\n const list = ProductLib.categoriesSelectionTree(resources.categories.data, resources.filters.data.categories, category, 'remove');\n handleCategoriesFilterUpdate(list);\n };\n\n /**\n * Update the list of applied filters with the given machines\n */\n const handleMachinesFilterUpdate = (machines: Array) => {\n ProductLib.updateFilter(setResources, 'machines', machines);\n };\n\n /**\n * Update the list of applied filters with the given keywords (or reference)\n */\n const handleKeywordFilterUpdate = (keywords: Array) => {\n ProductLib.updateFilter(setResources, 'keywords', keywords);\n };\n\n /** Filter: by stock range */\n const handleStockFilterUpdate = (filters: ProductIndexFilter) => {\n setResources(draft => {\n return { ...draft, filters: { ...draft.filters, data: { ...draft.filters.data, ...filters } } };\n });\n };\n\n /** Display option: sorting */\n const handleSorting = (option: SelectOption) => {\n ProductLib.updateFilter(setResources, 'sort', option.value);\n };\n\n /** Clear filters */\n const clearAllFilters = () => {\n setResources(draft => {\n return { ...draft, filters: { ...draft.filters, data: initialFilters } };\n });\n };\n\n /** Creates sorting options to the react-select format */\n const buildSortOptions = (): Array> => {\n return [\n { value: 'name-asc', label: t('app.admin.store.products.sort.name_az') },\n { value: 'name-desc', label: t('app.admin.store.products.sort.name_za') },\n { value: 'amount-asc', label: t('app.admin.store.products.sort.price_low') },\n { value: 'amount-desc', label: t('app.admin.store.products.sort.price_high') }\n ];\n };\n\n return (\n
\n
\n

{t('app.admin.store.products.all_products')}

\n
\n {t('app.admin.store.products.create_a_product')}\n
\n
\n \n
\n \n
\n handleMachinesFilterUpdate(resources.filters.data.machines.filter(machine => machine !== m))}\n onRemoveKeyword={() => handleKeywordFilterUpdate([])}\n onRemoveStock={() => handleStockFilterUpdate({ stock_type: 'internal', stock_to: 0, stock_from: 0 })} />\n
\n\n
\n {productsList.map((product) => (\n \n ))}\n
\n {pageCount > 1 &&\n \n }\n
\n
\n );\n};\n\nconst ProductsWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('products', react2angular(ProductsWrapper, ['onSuccess', 'onError', 'uiRouter']));\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { IApplication } from '../../models/application';\nimport { User } from '../../models/user';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport noImage from '../../../../images/no_image.png';\nimport { FabStateLabel } from '../base/fab-state-label';\nimport OrderAPI from '../../api/order';\nimport { Order } from '../../models/order';\nimport FormatLib from '../../lib/format';\nimport OrderLib from '../../lib/order';\nimport { OrderActions } from './order-actions';\n\ndeclare const Application: IApplication;\n\ninterface ShowOrderProps {\n orderId: string,\n currentUser?: User,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component shows an order details\n */\nexport const ShowOrder: React.FC = ({ orderId, currentUser, onSuccess, onError }) => {\n const { t } = useTranslation('shared');\n\n const [order, setOrder] = useState();\n const [withdrawalInstructions, setWithdrawalInstructions] = useState(null);\n\n useEffect(() => {\n OrderAPI.get(orderId).then(data => {\n setOrder(data);\n OrderAPI.withdrawalInstructions(data)\n .then(setWithdrawalInstructions)\n .catch(onError);\n }).catch(onError);\n }, []);\n\n /**\n * Check if the current operator has administrative rights or is a normal member\n */\n const isPrivileged = (): boolean => {\n return (currentUser?.role === 'admin' || currentUser?.role === 'manager');\n };\n\n /**\n * Returns order's payment info\n */\n const paymentInfo = (): string => {\n let paymentVerbose = '';\n if (order.payment_method === 'card') {\n paymentVerbose = t('app.shared.store.show_order.payment.settlement_by_debit_card');\n } else if (order.payment_method === 'boleto') {\n paymentVerbose = t('app.shared.store.show_order.payment.settlement_by_boleto');\n } else if (order.payment_method === 'wallet') {\n paymentVerbose = t('app.shared.store.show_order.payment.settlement_by_wallet');\n } else {\n paymentVerbose = t('app.shared.store.show_order.payment.settlement_done_at_the_reception');\n }\n paymentVerbose += ' ' + t('app.shared.store.show_order.payment.on_DATE_at_TIME', {\n DATE: FormatLib.date(order.payment_date),\n TIME: FormatLib.time(order.payment_date)\n });\n if (order.payment_method !== 'wallet') {\n paymentVerbose += ' ' + t('app.shared.store.show_order.payment.for_an_amount_of_AMOUNT', { AMOUNT: FormatLib.price(order.paid_total) });\n }\n if (order.wallet_amount) {\n if (order.payment_method === 'wallet') {\n paymentVerbose += ' ' + t('app.shared.store.show_order.payment.for_an_amount_of_AMOUNT', { AMOUNT: FormatLib.price(order.wallet_amount) });\n } else {\n paymentVerbose += ' ' + t('app.shared.store.show_order.payment.and') + ' ' + t('app.shared.store.show_order.payment.by_wallet') + ' ' +\n t('app.shared.store.show_order.payment.for_an_amount_of_AMOUNT', { AMOUNT: FormatLib.price(order.wallet_amount) });\n }\n }\n return paymentVerbose;\n };\n\n /**\n * Callback after action success\n */\n const handleActionSuccess = (data: Order, message: string) => {\n setOrder(data);\n onSuccess(message);\n };\n\n /**\n * Ruturn item's ordrable url\n */\n const itemOrderableUrl = (item) => {\n if (isPrivileged()) {\n return `/#!/admin/store/products/${item.orderable_id}/edit`;\n }\n return `/#!/store/p/${item.orderable_slug}`;\n };\n\n if (!order) {\n return null;\n }\n\n return (\n
\n
\n

[{order.reference}]

\n
\n {isPrivileged() &&\n \n }\n {order?.invoice_id && (\n \n {t('app.shared.store.show_order.see_invoice')}\n \n )}\n
\n
\n\n
\n \n
\n {isPrivileged() && order.user &&\n
\n {t('app.shared.store.show_order.client')}\n

{order.user.name}

\n
\n }\n
\n {t('app.shared.store.show_order.created_at')}\n

{FormatLib.date(order.created_at)}

\n
\n
\n {t('app.shared.store.show_order.last_update')}\n

{FormatLib.date(order.updated_at)}

\n
\n \n {t(`app.shared.store.show_order.state.${OrderLib.statusText(order)}`)}\n \n
\n
\n\n
\n \n
\n {order.order_items_attributes.map(item => (\n
\n
\n \n
\n
\n {t('app.shared.store.show_order.reference_short')} {item.orderable_ref || ''}\n

{item.orderable_name}

\n
\n
\n
\n

{FormatLib.price(item.amount)}

\n / {t('app.shared.store.show_order.unit')}\n
\n\n {item.quantity}\n\n
\n {t('app.shared.store.show_order.item_total')}\n

{FormatLib.price(OrderLib.itemAmount(item))}

\n
\n
\n
\n ))}\n
\n
\n\n
\n
\n \n {order.invoice_id &&

{paymentInfo()}

}\n
\n
\n \n

{t('app.shared.store.show_order.products_total')}{FormatLib.price(OrderLib.totalBeforeOfferedAmount(order))}

\n {OrderLib.hasOfferedItem(order) &&\n

{t('app.shared.store.show_order.gift_total')}-{FormatLib.price(OrderLib.offeredAmount(order))}

\n }\n {order.coupon &&\n

{t('app.shared.store.show_order.coupon')}-{FormatLib.price(OrderLib.couponAmount(order))}

\n }\n

{t('app.shared.store.show_order.cart_total')} {FormatLib.price(OrderLib.paidTotal(order))}

\n
\n
\n \n

\n

\n
\n
\n );\n};\n\nconst ShowOrderWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('showOrder', react2angular(ShowOrderWrapper, ['orderId', 'currentUser', 'onError', 'onSuccess']));\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport Select from 'react-select';\nimport Switch from 'react-switch';\nimport { SortOption } from '../../models/api';\nimport { SelectOption } from '../../models/select';\n\ninterface StoreListHeaderProps {\n productsCount: number,\n selectOptions: SelectOption[],\n onSelectOptionsChange: (option: SelectOption) => void,\n selectValue?: SortOption,\n switchLabel?: string,\n switchChecked?: boolean,\n onSwitch?: (boolean) => void\n}\n\n/**\n * Renders an accordion item\n */\nexport const StoreListHeader: React.FC = ({ productsCount, selectOptions, onSelectOptionsChange, switchLabel, switchChecked, onSwitch, selectValue }) => {\n const { t } = useTranslation('admin');\n\n // Styles the React-select component\n const customStyles = {\n control: base => ({\n ...base,\n width: '20ch',\n border: 'none',\n backgroundColor: 'transparent'\n }),\n indicatorSeparator: () => ({\n display: 'none'\n })\n };\n\n return (\n
\n
\n

{t('app.admin.store.store_list_header.result_count')}{productsCount}

\n
\n
\n
\n

{t('app.admin.store.store_list_header.sort')}

\n onSelectOptionsChange(evt)}\n value={selectOptions.find(option => option.value === selectValue)}\n styles={customStyles}\n />\n
\n {onSwitch &&\n
\n \n
\n }\n
\n
\n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport _ from 'lodash';\nimport { FabButton } from '../base/fab-button';\nimport { Product } from '../../models/product';\nimport { Order } from '../../models/order';\nimport { FabStateLabel } from '../base/fab-state-label';\nimport CartAPI from '../../api/cart';\nimport noImage from '../../../../images/no_image.png';\nimport { ProductPrice } from './product-price';\nimport ProductLib from '../../lib/product';\n\ninterface StoreProductItemProps {\n product: Product,\n cart: Order,\n onSuccessAddProductToCart: (cart: Order) => void,\n onError: (message: string) => void\n}\n\n/**\n * This component shows a product item \"card\" in the public store list\n */\nexport const StoreProductItem: React.FC = ({ product, cart, onSuccessAddProductToCart, onError }) => {\n const { t } = useTranslation('public');\n\n /**\n * Return main image of Product, if the product has no image, show default image\n */\n const productImageUrl = (product: Product) => {\n const productImage = _.find(product.product_images_attributes, { is_main: true });\n if (productImage) {\n return productImage.attachment_url;\n }\n return noImage;\n };\n\n /**\n * Add the product to cart\n */\n const addProductToCart = (e: React.BaseSyntheticEvent) => {\n e.preventDefault();\n e.stopPropagation();\n CartAPI.addItem(cart, product.id, 'Product', 1).then(onSuccessAddProductToCart).catch(() => {\n onError(t('app.public.store_product_item.stock_limit'));\n });\n };\n\n /**\n * Goto show product page\n */\n const showProduct = (product: Product): void => {\n window.location.href = `/#!/store/p/${product.slug}`;\n };\n\n /**\n * Returns CSS class from stock status\n */\n const statusColor = (product: Product) => {\n if (product.stock.external < (product.quantity_min || 1)) {\n return 'out-of-stock';\n }\n if (product.low_stock_threshold && product.stock.external <= product.low_stock_threshold) {\n return 'low';\n }\n return '';\n };\n\n return (\n
showProduct(product)}>\n
\n \n
\n

{product.name}

\n {product.quantity_min > 1 &&\n {t('app.public.store_product_item.minimum_purchase')}{product.quantity_min}\n }\n \n \n {t(ProductLib.stockStatusTrKey(product))}\n \n {product.stock.external >= (product.quantity_min || 1) &&\n } className=\"main-action-btn\" onClick={addProductToCart}>\n {t('app.public.store_product_item.add')}\n \n }\n
\n );\n};\n","import { useEffect, useState, useRef } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport _ from 'lodash';\nimport { Product } from '../../models/product';\nimport { User } from '../../models/user';\nimport ProductAPI from '../../api/product';\nimport CartAPI from '../../api/cart';\nimport noImage from '../../../../images/no_image.png';\nimport { FabButton } from '../base/fab-button';\nimport useCart from '../../hooks/use-cart';\nimport { FilePdf, Minus, Plus } from 'phosphor-react';\nimport { FabStateLabel } from '../base/fab-state-label';\nimport { ProductPrice } from './product-price';\nimport ProductLib from '../../lib/product';\n\ndeclare const Application: IApplication;\n\ninterface StoreProductProps {\n productSlug: string,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n currentUser?: User\n}\n\n/**\n * This component shows the details of a single product, in full page\n */\nexport const StoreProduct: React.FC = ({ productSlug, currentUser, onSuccess, onError }) => {\n const { t } = useTranslation('public');\n\n const { cart, setCart } = useCart(currentUser);\n const [product, setProduct] = useState();\n const [showImage, setShowImage] = useState(null);\n const [toCartCount, setToCartCount] = useState(0);\n const [displayToggle, setDisplayToggle] = useState(false);\n const [collapseDescription, setCollapseDescription] = useState(true);\n const descContainer = useRef(null);\n\n useEffect(() => {\n ProductAPI.get(productSlug).then(data => {\n setProduct(data);\n const productImage = _.find(data.product_images_attributes, { is_main: true });\n if (productImage) {\n setShowImage(productImage.id as number);\n }\n setToCartCount(data.quantity_min ? data.quantity_min : 1);\n setDisplayToggle(descContainer.current.offsetHeight < descContainer.current.scrollHeight);\n }).catch((e) => {\n onError(t('app.public.store_product.unexpected_error_occurred') + e);\n });\n }, []);\n\n /**\n * Return main image of Product, if the product has no image, show default image\n */\n const productImageUrl = (id: number) => {\n const productImage = _.find(product.product_images_attributes, { id });\n if (productImage) {\n return productImage.attachment_url;\n }\n return noImage;\n };\n\n /**\n * Returns CSS class from stock status\n */\n const statusColor = (product: Product) => {\n if (product.stock.external < (product.quantity_min || 1)) {\n return 'out-of-stock';\n }\n if (product.low_stock_threshold && product.stock.external <= product.low_stock_threshold) {\n return 'low';\n }\n return '';\n };\n\n /**\n * Update product count\n */\n const setCount = (type: 'add' | 'remove') => {\n switch (type) {\n case 'add':\n if (toCartCount < product.stock.external) {\n setToCartCount(toCartCount + 1);\n }\n break;\n case 'remove':\n if (toCartCount > product.quantity_min) {\n setToCartCount(toCartCount - 1);\n }\n break;\n }\n };\n /**\n * Update product count\n */\n const typeCount = (evt: React.ChangeEvent) => {\n evt.preventDefault();\n setToCartCount(Number(evt.target.value));\n };\n\n /**\n * Add product to cart\n */\n const addToCart = () => {\n if (toCartCount <= product.stock.external) {\n CartAPI.addItem(cart, product.id, 'Product', toCartCount).then(data => {\n setCart(data);\n onSuccess(t('app.public.store_product.add_to_cart_success'));\n }).catch(() => {\n onError(t('app.public.store_product.stock_limit'));\n });\n }\n };\n\n if (product) {\n return (\n
\n {product.sku && {t('app.public.store_product.ref', { REF: product.sku })}}\n

{product.name}

\n
\n
\n
\n \n
\n
\n {product.product_images_attributes.length > 1 &&\n
\n {product.product_images_attributes.map(i => (\n
\n setShowImage(i.id as number)} src={i.thumb_attachment_url} />\n
\n ))}\n
\n }\n
\n
\n
\n {displayToggle &&\n \n }\n {product.product_files_attributes.length > 0 &&\n
\n

{t('app.public.store_product.documentation')}

\n
\n {product.product_files_attributes.map(f =>\n \n \n {f.attachment_name}\n \n )}\n
\n
\n }\n
\n\n \n
\n );\n }\n return null;\n};\n\nconst StoreProductWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('storeProduct', react2angular(StoreProductWrapper, ['productSlug', 'currentUser', 'onSuccess', 'onError']));\n","import { useEffect } from 'react';\nimport * as React from 'react';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { useTranslation } from 'react-i18next';\nimport { useForm, SubmitHandler } from 'react-hook-form';\nimport { FormRichText } from '../form/form-rich-text';\nimport { FabButton } from '../base/fab-button';\nimport SettingAPI from '../../api/setting';\nimport SettingLib from '../../lib/setting';\nimport { SettingName, SettingValue, storeSettings } from '../../models/setting';\nimport { FormSwitch } from '../form/form-switch';\n\ndeclare const Application: IApplication;\n\ninterface StoreSettingsProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void\n}\n\n/**\n * Store settings display and edition\n */\nexport const StoreSettings: React.FC = ({ onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n const { control, handleSubmit, reset } = useForm>();\n\n useEffect(() => {\n SettingAPI.query(storeSettings)\n .then(settings => {\n const data = SettingLib.bulkMapToObject(settings);\n reset(data);\n console.log(data);\n })\n .catch(onError);\n }, []);\n\n /**\n * Callback triggered when the form is submitted: save the settings\n */\n const onSubmit: SubmitHandler> = (data) => {\n SettingAPI.bulkUpdate(SettingLib.objectToBulkMap(data)).then(() => {\n onSuccess(t('app.admin.store_settings.update_success'));\n }, reason => {\n onError(reason);\n });\n };\n\n return (\n
\n
\n

{t('app.admin.store_settings.title')}

\n {t('app.admin.store_settings.save')}\n
\n
\n
\n
\n

{t('app.admin.store_settings.withdrawal_instructions')}

\n

{t('app.admin.store_settings.withdrawal_info')}

\n
\n
\n \n
\n
\n
\n
\n

{t('app.admin.store_settings.store_hidden_title')}

\n

{t('app.admin.store_settings.store_hidden_info')}

\n
\n
\n \n
\n
\n
\n
\n );\n};\n\nconst StoreSettingsWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('storeSettings', react2angular(StoreSettingsWrapper, ['onError', 'onSuccess']));\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { react2angular } from 'react2angular';\nimport { Loader } from '../base/loader';\nimport { IApplication } from '../../models/application';\nimport { FabButton } from '../base/fab-button';\nimport {\n initialFilters,\n initialResources,\n Product,\n ProductResourcesFetching,\n ProductsIndex,\n ProductSortOption\n} from '../../models/product';\nimport { ProductCategory } from '../../models/product-category';\nimport ProductAPI from '../../api/product';\nimport { StoreProductItem } from './store-product-item';\nimport useCart from '../../hooks/use-cart';\nimport { User } from '../../models/user';\nimport { Order } from '../../models/order';\nimport { StoreListHeader } from './store-list-header';\nimport { FabPagination } from '../base/fab-pagination';\nimport { MachinesFilter } from './filters/machines-filter';\nimport { useImmer } from 'use-immer';\nimport { Machine } from '../../models/machine';\nimport { KeywordFilter } from './filters/keyword-filter';\nimport { ActiveFiltersTags } from './filters/active-filters-tags';\nimport ProductLib from '../../lib/product';\nimport { UIRouter } from '@uirouter/angularjs';\nimport SettingAPI from '../../api/setting';\nimport { SelectOption } from '../../models/select';\nimport { CaretDoubleUp } from 'phosphor-react';\n\ndeclare const Application: IApplication;\n\nconst storeInitialFilters = {\n ...initialFilters,\n is_active: true\n};\n\nconst storeInitialResources = {\n ...initialResources,\n filters: {\n data: storeInitialFilters,\n ready: false\n }\n};\n\ninterface StoreProps {\n onError: (message: string) => void,\n onSuccess: (message: string) => void,\n currentUser: User,\n uiRouter: UIRouter,\n}\n\n/**\n * This component shows public store\n */\nconst Store: React.FC = ({ onError, onSuccess, currentUser, uiRouter }) => {\n const { t } = useTranslation('public');\n\n const { cart, setCart } = useCart(currentUser);\n\n const [products, setProducts] = useState>([]);\n // this includes the resources fetch from the API (machines, categories) and from the URL (filters)\n const [resources, setResources] = useImmer(storeInitialResources);\n const [machinesModule, setMachinesModule] = useState(false);\n const [categoriesTree, setCategoriesTree] = useState([]);\n const [filtersPanel, setFiltersPanel] = useState(false);\n const [pageCount, setPageCount] = useState(0);\n const [productsCount, setProductsCount] = useState(0);\n const [currentPage, setCurrentPage] = useState(1);\n\n useEffect(() => {\n ProductLib.fetchInitialResources(setResources, onError, formatCategories);\n SettingAPI.get('machines_module').then(data => {\n setMachinesModule(data.value === 'true');\n }).catch(onError);\n }, []);\n\n useEffect(() => {\n if (resources.filters.ready) {\n fetchProducts();\n uiRouter.stateService.transitionTo(uiRouter.globals.current, ProductLib.indexFiltersToRouterParams(resources.filters.data));\n }\n }, [resources.filters]);\n\n useEffect(() => {\n if (resources.machines.ready && resources.categories.ready) {\n setResources(draft => {\n return {\n ...draft,\n filters: {\n data: ProductLib.readFiltersFromUrl(uiRouter.globals.params, resources.machines.data, resources.categories.data, storeInitialFilters),\n ready: true\n }\n };\n });\n }\n }, [resources.machines, resources.categories]);\n\n /**\n * Create categories tree (parent/children)\n */\n const formatCategories = (list: ProductCategory[]) => {\n const tree: Array = [];\n const parents = list.filter(c => !c.parent_id);\n parents.forEach(p => {\n tree.push({\n parent: p,\n children: list.filter(c => c.parent_id === p.id)\n });\n });\n setCategoriesTree(tree);\n };\n\n /**\n * Filter by category: the selected category will always be first\n */\n const filterCategory = (category: ProductCategory) => {\n ProductLib.updateFilter(\n setResources,\n 'categories',\n category\n ? Array.from(new Set([category, ...ProductLib.categoriesSelectionTree(resources.categories.data, [], category, 'add')]))\n : []\n );\n };\n\n /**\n * Update the list of applied filters with the given machines\n */\n const applyMachineFilters = (machines: Array) => {\n ProductLib.updateFilter(setResources, 'machines', machines);\n };\n\n /**\n * Update the list of applied filters with the given keywords (or reference)\n */\n const applyKeywordFilter = (keywords: Array) => {\n ProductLib.updateFilter(setResources, 'keywords', keywords);\n };\n /**\n * Clear filters\n */\n const clearAllFilters = () => {\n setResources(draft => {\n return {\n ...draft,\n filters: {\n ...draft.filters,\n data: {\n ...storeInitialFilters,\n categories: draft.filters.data.categories\n }\n }\n };\n });\n };\n\n /**\n * Creates sorting options to the react-select format\n */\n const buildOptions = (): Array> => {\n return [\n { value: 'name-asc', label: t('app.public.store.products.sort.name_az') },\n { value: 'name-desc', label: t('app.public.store.products.sort.name_za') },\n { value: 'amount-asc', label: t('app.public.store.products.sort.price_low') },\n { value: 'amount-desc', label: t('app.public.store.products.sort.price_high') }\n ];\n };\n /**\n * Display option: sorting\n */\n const handleSorting = (option: SelectOption) => {\n ProductLib.updateFilter(setResources, 'sort', option.value);\n };\n\n /**\n * Filter: toggle non-available products visibility\n */\n const toggleVisible = (checked: boolean) => {\n ProductLib.updateFilter(setResources, 'is_available', checked);\n };\n\n /**\n * Add product to the cart\n */\n const addToCart = (cart: Order) => {\n setCart(cart);\n onSuccess(t('app.public.store.add_to_cart_success'));\n };\n\n /**\n * Handle products pagination\n */\n const handlePagination = (page: number) => {\n if (page !== currentPage) {\n ProductLib.updateFilter(setResources, 'page', page);\n }\n };\n\n /**\n * Fetch the products from the API, according to the current filters\n */\n const fetchProducts = async (): Promise => {\n try {\n const data = await ProductAPI.index(Object.assign({ store: true }, resources.filters.data));\n setCurrentPage(data.page);\n setProducts(data.data);\n setPageCount(data.total_pages);\n setProductsCount(data.total_count);\n return data;\n } catch (error) {\n onError(t('app.public.store.unexpected_error_occurred') + error);\n }\n };\n\n const selectedCategory = resources.filters.data.categories[0];\n const parent = resources.categories.data.find(c => c.id === selectedCategory?.parent_id);\n return (\n
\n
    \n
  • \n filterCategory(null)}>{t('app.public.store.products.all_products')}\n
  • \n {parent &&\n
  • \n filterCategory(parent)}>\n {parent.name}\n \n
  • \n }\n {selectedCategory &&\n
  • \n filterCategory(selectedCategory)}>\n {selectedCategory.name}\n \n
  • \n }\n
\n \n
\n \n
\n applyMachineFilters(resources.filters.data.machines.filter(machine => machine !== m))}\n onRemoveKeyword={() => applyKeywordFilter([])} />\n
\n
\n {products.map((product) => (\n \n ))}\n
\n {pageCount > 1 &&\n \n }\n
\n
\n );\n};\n\nconst StoreWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('store', react2angular(StoreWrapper, ['onError', 'onSuccess', 'currentUser', 'uiRouter']));\n\ninterface CategoryTree {\n parent: ProductCategory,\n children: ProductCategory[]\n}\n","import { IApplication } from '../../models/application';\nimport { Subscription } from '../../models/subscription';\nimport { FabModal } from '../base/fab-modal';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport * as React from 'react';\nimport SubscriptionAPI from '../../api/subscription';\nimport { useTranslation } from 'react-i18next';\nimport { HtmlTranslate } from '../base/html-translate';\n\ndeclare const Application: IApplication;\n\ninterface CancelSubscriptionModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n subscription: Subscription,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * Modam dialog shown to confirm the cancelation of the current running subscription of a customer\n */\nexport const CancelSubscriptionModal: React.FC = ({ isOpen, toggleModal, subscription, onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n\n /**\n * Callback triggered when the user has confirmed the cancelation of the subscription\n */\n const handleCancelConfirmed = () => {\n SubscriptionAPI.cancel(subscription.id).then(() => {\n toggleModal();\n onSuccess(t('app.admin.cancel_subscription_modal.subscription_canceled'));\n }).catch(onError);\n };\n\n return (\n \n \n \n );\n};\n\nconst CancelSubscriptionModalWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('cancelSubscriptionModal', react2angular(CancelSubscriptionModalWrapper, ['toggleModal', 'subscription', 'isOpen', 'onError', 'onSuccess']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { Subscription } from '../../models/subscription';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { useTranslation } from 'react-i18next';\nimport { FabAlert } from '../base/fab-alert';\nimport { FabInput } from '../base/fab-input';\nimport FormatLib from '../../lib/format';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport LocalPaymentAPI from '../../api/local-payment';\nimport { PaymentMethod } from '../../models/payment';\nimport { TDateISO } from '../../typings/date-iso';\n\ndeclare const Application: IApplication;\n\ninterface FreeExtendModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n subscription: Subscription,\n customerId: number,\n onSuccess: (message: string, newExpirationDate: Date) => void,\n onError: (message: string) => void,\n}\n\n/**\n * Modal dialog shown to extend the current subscription of a customer, for free\n */\nexport const FreeExtendModal: React.FC = ({ isOpen, toggleModal, subscription, customerId, onError, onSuccess }) => {\n // we do not render the modal if the subscription was not provided\n if (!subscription) return null;\n\n const { t } = useTranslation('admin');\n\n const [expirationDate, setExpirationDate] = useState(new Date(subscription.expired_at));\n const [freeDays, setFreeDays] = useState(0);\n\n // we update the number of free days when the new expiration date is updated\n useEffect(() => {\n if (!expirationDate || !subscription.expired_at) {\n setFreeDays(0);\n }\n // 86400000 = 1000 * 3600 * 24 = number of ms per day\n setFreeDays(Math.ceil((expirationDate.getTime() - new Date(subscription.expired_at).getTime()) / 86400000) || 0);\n }, [expirationDate]);\n\n /**\n * Return the formatted localized date for the given date\n */\n const formatDateTime = (date: TDateISO): string => {\n return t('app.admin.free_extend_modal.DATE_TIME', { DATE: FormatLib.date(date), TIME: FormatLib.time(date) });\n };\n\n /**\n * Return the given date formatted for the HTML input-date\n */\n const formatDefaultDate = (date: Date): string => {\n if (isNaN(date as unknown as number)) return null;\n\n return date.toISOString().substring(0, 10);\n };\n\n /**\n * Parse the given date and record it as the new expiration date of the subscription\n */\n const handleDateUpdate = (date: string): void => {\n setExpirationDate(new Date(Date.parse(date)));\n };\n\n /**\n * Callback triggered when the user validates the free extent of the subscription\n */\n const handleConfirmExtend = (): void => {\n LocalPaymentAPI.confirmPayment({\n customer_id: customerId,\n payment_method: PaymentMethod.Other,\n items: [\n {\n free_extension: {\n end_at: expirationDate\n }\n }\n ]\n }).then(() => {\n onSuccess(t('app.admin.free_extend_modal.extend_success'), expirationDate);\n toggleModal();\n }).catch(err => onError(err));\n };\n\n return (\n \n \n

{t('app.admin.free_extend_modal.offer_free_days_infos')}

\n

{t('app.admin.free_extend_modal.credits_will_remain_unchanged')}

\n
\n
\n \n \n \n \n \n \n \n
\n );\n};\n\nconst FreeExtendModalWrapper: React.FC = ({ toggleModal, subscription, customerId, isOpen, onSuccess, onError }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('freeExtendModal', react2angular(FreeExtendModalWrapper, ['toggleModal', 'subscription', 'customerId', 'isOpen', 'onError', 'onSuccess']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { Subscription } from '../../models/subscription';\nimport { FabModal, ModalSize } from '../base/fab-modal';\nimport { useTranslation } from 'react-i18next';\nimport { FabAlert } from '../base/fab-alert';\nimport { FabInput } from '../base/fab-input';\nimport FormatLib from '../../lib/format';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport { PaymentMethod, ShoppingCart } from '../../models/payment';\nimport moment from 'moment';\nimport { SelectSchedule } from '../payment-schedule/select-schedule';\nimport SubscriptionAPI from '../../api/subscription';\nimport PriceAPI from '../../api/price';\nimport { ComputePriceResult } from '../../models/price';\nimport { PaymentScheduleSummary } from '../payment-schedule/payment-schedule-summary';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport { LocalPaymentModal } from '../payment/local-payment/local-payment-modal';\nimport { User } from '../../models/user';\nimport { TDateISO } from '../../typings/date-iso';\n\ndeclare const Application: IApplication;\n\ninterface RenewModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n subscription?: Subscription,\n customer: User,\n operator: User,\n onSuccess: (message: string, newExpirationDate: Date) => void,\n onError: (message: string) => void,\n}\n\n/**\n * Modal dialog shown to renew the current subscription of a customer, for free\n */\nexport const RenewModal: React.FC = ({ isOpen, toggleModal, subscription, customer, operator, onError, onSuccess }) => {\n // we do not render the modal if the subscription was not provided\n if (!subscription) return null;\n\n const { t } = useTranslation('admin');\n\n const [expirationDate, setExpirationDate] = useState(new Date());\n const [localPaymentModal, setLocalPaymentModal] = useState(false);\n const [cart, setCart] = useState(null);\n const [price, setPrice] = useState(null);\n const [scheduleRequired, setScheduleRequired] = useState(false);\n\n // on init, we compute the new expiration date\n useEffect(() => {\n setExpirationDate(moment(subscription.expired_at)\n .add(subscription.plan.interval_count, subscription.plan.interval)\n .toDate());\n SubscriptionAPI.paymentsDetails(subscription.id)\n .then(res => setScheduleRequired(res.payment_schedule))\n .catch(err => onError(err));\n }, []);\n\n // when the payment schedule is toggled (requested/ignored), we update the cart accordingly\n useEffect(() => {\n setCart({\n customer_id: customer.id,\n items: [{\n subscription: {\n plan_id: subscription.plan.id,\n start_at: subscription.expired_at\n }\n }],\n payment_method: PaymentMethod.Other,\n payment_schedule: scheduleRequired\n });\n }, [scheduleRequired]);\n\n // when the cart is updated, re-compute the price and the payment schedule\n useEffect(() => {\n if (!cart) return;\n\n PriceAPI.compute(cart)\n .then(res => setPrice(res))\n .catch(err => onError(err));\n }, [cart]);\n\n /**\n * Return the formatted localized date for the given date\n */\n const formatDateTime = (date: Date|TDateISO): string => {\n return t('app.admin.renew_modal.DATE_TIME', { DATE: FormatLib.date(date), TIME: FormatLib.time(date) });\n };\n\n /**\n * Callback triggered when the payment of the subscription renewal was successful\n */\n const onPaymentSuccess = (): void => {\n onSuccess(t('app.admin.renew_modal.renew_success'), expirationDate);\n toggleModal();\n };\n\n /**\n * Open/closes the local payment modal\n */\n const toggleLocalPaymentModal = (): void => {\n setLocalPaymentModal(!localPaymentModal);\n };\n\n return (\n \n \n

{t('app.admin.renew_modal.renew_subscription_info')}

\n

{t('app.admin.renew_modal.credits_will_be_reset')}

\n
\n
\n
\n \n \n \n \n \n \n \n
\n {subscription.plan.monthly_payment && }\n {price?.schedule && }\n {price && !price?.schedule &&
\n

{t('app.admin.renew_modal.pay_in_one_go')}

\n {FormatLib.price(price.price)}\n
}\n
\n
\n \n
\n );\n};\n\nconst RenewModalWrapper: React.FC = ({ toggleModal, subscription, customer, operator, isOpen, onSuccess, onError }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('renewModal', react2angular(RenewModalWrapper, ['toggleModal', 'subscription', 'customer', 'operator', 'isOpen', 'onError', 'onSuccess']));\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport Select from 'react-select';\nimport { useTranslation } from 'react-i18next';\nimport { Subscription } from '../../models/subscription';\nimport { User } from '../../models/user';\nimport { PaymentMethod, ShoppingCart } from '../../models/payment';\nimport { FabModal } from '../base/fab-modal';\nimport SubscriptionAPI from '../../api/subscription';\nimport { Plan } from '../../models/plan';\nimport PlanAPI from '../../api/plan';\nimport { Loader } from '../base/loader';\nimport { react2angular } from 'react2angular';\nimport { IApplication } from '../../models/application';\nimport FormatLib from '../../lib/format';\nimport { SelectSchedule } from '../payment-schedule/select-schedule';\nimport { ComputePriceResult } from '../../models/price';\nimport { PaymentScheduleSummary } from '../payment-schedule/payment-schedule-summary';\nimport { PaymentSchedule } from '../../models/payment-schedule';\nimport PriceAPI from '../../api/price';\nimport { LocalPaymentModal } from '../payment/local-payment/local-payment-modal';\nimport { SelectOption } from '../../models/select';\n\ndeclare const Application: IApplication;\n\ninterface SubscribeModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n customer: User,\n operator: User,\n onSuccess: (message: string, subscription: Subscription) => void,\n onError: (message: string) => void,\n}\n\n/**\n * Modal dialog shown to create a subscription for the given customer\n */\nexport const SubscribeModal: React.FC = ({ isOpen, toggleModal, customer, operator, onError, onSuccess }) => {\n const { t } = useTranslation('admin');\n\n const [selectedPlan, setSelectedPlan] = useState(null);\n const [selectedSchedule, setSelectedSchedule] = useState(false);\n const [allPlans, setAllPlans] = useState>(null);\n const [price, setPrice] = useState(null);\n const [cart, setCart] = useState(null);\n const [localPaymentModal, setLocalPaymentModal] = useState(false);\n\n // fetch all plans from the API on component mount\n useEffect(() => {\n PlanAPI.index()\n .then(plans => setAllPlans(plans))\n .catch(error => onError(error));\n }, []);\n\n // when the plan is updated, update the default value for the payment schedule requirement\n useEffect(() => {\n if (!selectedPlan) return;\n\n setSelectedSchedule(selectedPlan.monthly_payment);\n }, [selectedPlan]);\n\n // when the plan or the requirement for a payment schedule are updated, update the cart accordingly\n useEffect(() => {\n if (!selectedPlan) return;\n\n setCart({\n customer_id: customer.id,\n items: [{\n subscription: {\n plan_id: selectedPlan.id\n }\n }],\n payment_method: PaymentMethod.Other,\n payment_schedule: selectedSchedule\n });\n }, [selectedSchedule, selectedPlan]);\n\n // when the cart is updated, update the price accordingly\n useEffect(() => {\n if (!cart) return;\n\n PriceAPI.compute(cart)\n .then(res => setPrice(res))\n .catch(err => onError(err));\n }, [cart]);\n\n /**\n * Callback triggered when the user selects a group in the dropdown list\n */\n const handlePlanSelect = (option: SelectOption): void => {\n const plan = allPlans.find(p => p.id === option.value);\n setSelectedPlan(plan);\n };\n\n /**\n * Callback triggered when the payment of the subscription was successful\n */\n const onPaymentSuccess = (res): void => {\n SubscriptionAPI.get(res.main_object.id).then(subscription => {\n onSuccess(t('app.admin.subscribe_modal.subscription_success'), subscription);\n toggleModal();\n }).catch(error => onError(error));\n };\n\n /**\n * Open/closes the local payment modal\n */\n const toggleLocalPaymentModal = (): void => {\n setLocalPaymentModal(!localPaymentModal);\n };\n\n /**\n * Convert all groups to the react-select format\n */\n const buildOptions = (): Array> => {\n if (!allPlans) return [];\n\n return allPlans.filter(p => !p.disabled && p.group_id === customer.group_id).map(p => {\n return { value: p.id, label: `${p.base_name} (${FormatLib.duration(p.interval, p.interval_count)})` };\n });\n };\n\n return (\n \n
\n \n \n \n
\n {errors.includes(documentType.id) && \n {t('app.logged.dashboard.supporting_documents_files.file_size_error', { SIZE: maxProofOfIdentityFileSizeMb })}\n }\n
\n );\n })}\n
\n {hasProofOfIdentityTypes() && (\n 0}>\n {t('app.logged.dashboard.supporting_documents_files.save')}\n \n )}\n \n );\n};\n\nconst SupportingDocumentsFilesWrapper: React.FC = ({ currentUser, onSuccess, onError }) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('supportingDocumentsFiles', react2angular(SupportingDocumentsFilesWrapper, ['currentUser', 'onSuccess', 'onError']));\n","import { BaseSyntheticEvent, useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { SupportingDocumentType } from '../../models/supporting-document-type';\n\ninterface SupportingDocumentsRefusalFormProps {\n proofOfIdentityTypes: Array,\n onChange: (field: string, value: string | Array) => void,\n}\n\n/**\n * Form to set the refuse the uploaded supporting documents\n */\nexport const SupportingDocumentsRefusalForm: React.FC = ({ proofOfIdentityTypes, onChange }) => {\n const { t } = useTranslation('admin');\n\n const [values, setValues] = useState>([]);\n const [message, setMessage] = useState('');\n\n /**\n * Callback triggered when the message has changed.\n */\n const handleMessageChange = (e: BaseSyntheticEvent): void => {\n const { value } = e.target;\n setMessage(value);\n onChange('message', value);\n };\n\n /**\n * Callback triggered when the document type checkbox is ticked or unticked.\n */\n const handleTypeSelectionChange = (value: number) => {\n return (event: BaseSyntheticEvent) => {\n let newValues: Array;\n if (event.target.checked) {\n newValues = values.concat(value);\n } else {\n newValues = values.filter(x => x !== value);\n }\n setValues(newValues);\n onChange('supporting_document_type_ids', newValues);\n };\n };\n\n /**\n * Verify if the provided type is currently ticked (i.e. about to be refused)\n */\n const isChecked = (typeId: number) => {\n return values.includes(typeId);\n };\n\n return (\n
\n
\n
\n {proofOfIdentityTypes.map(type =>
\n \n \n
)}\n
\n
\n \n \n
\n
\n
\n );\n};\n","import { useState } from 'react';\nimport * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { FabModal } from '../base/fab-modal';\nimport { SupportingDocumentType } from '../../models/supporting-document-type';\nimport { SupportingDocumentRefusal } from '../../models/supporting-document-refusal';\nimport { User } from '../../models/user';\nimport SupportingDocumentRefusalAPI from '../../api/supporting-document-refusal';\nimport { SupportingDocumentsRefusalForm } from './supporting-documents-refusal-form';\n\ninterface SupportingDocumentsRefusalModalProps {\n isOpen: boolean,\n toggleModal: () => void,\n onSuccess: (message: string) => void,\n onError: (message: string) => void,\n proofOfIdentityTypes: Array,\n operator: User,\n member: User\n}\n\n/**\n * Modal dialog to notify the member that his documents are refused\n */\nexport const SupportingDocumentsRefusalModal: React.FC = ({ isOpen, toggleModal, onSuccess, proofOfIdentityTypes, operator, member, onError }) => {\n const { t } = useTranslation('admin');\n\n const [data, setData] = useState({\n id: null,\n operator_id: operator.id,\n user_id: member.id,\n supporting_document_type_ids: [],\n message: ''\n });\n\n /**\n * Callback triggered when any field has changed in the child form\n */\n const handleRefusalChanged = (field: string, value: string | Array) => {\n setData({\n ...data,\n [field]: value\n });\n };\n\n /**\n * Save the refusal to the API and send a result message to the parent component\n */\n const handleSaveRefusal = async (): Promise => {\n try {\n await SupportingDocumentRefusalAPI.create(data);\n onSuccess(t('app.admin.supporting_documents_refusal_modal.refusal_successfully_sent'));\n } catch (e) {\n onError(t('app.admin.supporting_documents_refusal_modal.unable_to_send') + e);\n }\n };\n\n /**\n * Check if the refusal can be saved (i.e. is not empty)\n */\n const isPreventedSaveRefusal = (): boolean => {\n return !data.message || data.supporting_document_type_ids.length === 0;\n };\n\n return (\n \n \n \n );\n};\n","import * as React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport Select from 'react-select';\nimport { FabInput } from '../base/fab-input';\nimport { SupportingDocumentType } from '../../models/supporting-document-type';\nimport { Group } from '../../models/group';\nimport { SelectOption } from '../../models/select';\n\ninterface SupportingDocumentsTypeFormProps {\n groups: Array,\n supportingDocumentType?: SupportingDocumentType,\n onChange: (field: string, value: string | Array) => void,\n}\n\n/**\n * Form to set create/edit supporting documents type\n */\nexport const SupportingDocumentsTypeForm: React.FC = ({ groups, supportingDocumentType, onChange }) => {\n const { t } = useTranslation('admin');\n\n /**\n * Convert all groups to the react-select format\n */\n const buildOptions = (): Array> => {\n return groups.map(t => {\n return { value: t.id, label: t.name };\n });\n };\n\n /**\n * Return the group(s) associated with the current type, formatted to match the react-select format\n */\n const groupsValues = (): Array> => {\n const res = [];\n const groupIds = supportingDocumentType?.group_ids || [];\n if (groupIds.length > 0) {\n groups.forEach(t => {\n if (groupIds.indexOf(t.id) > -1) {\n res.push({ value: t.id, label: t.name });\n }\n });\n }\n return res;\n };\n\n /**\n * Callback triggered when the selection of group has changed.\n */\n const handleGroupsChange = (selectedOptions: Array>): void => {\n onChange('group_ids', selectedOptions.map(o => o.value));\n };\n\n /**\n * Callback triggered when the name has changed.\n */\n const handleNameChange = (value: string): void => {\n onChange('name', value);\n };\n\n return (\n
\n
\n {t('app.admin.settings.account.supporting_documents_type_form.type_form_info')}\n
\n
\n
\n )} />\n \n \n \n );\n};\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport AsyncSelect from 'react-select/async';\nimport { useTranslation } from 'react-i18next';\nimport MemberAPI from '../../api/member';\nimport { User } from '../../models/user';\nimport { SelectOption } from '../../models/select';\n\ninterface MemberSelectProps {\n defaultUser?: User,\n value?: User,\n onSelected?: (user: { id: number, name: string }) => void,\n noHeader?: boolean,\n hasError?: boolean\n}\n\n/**\n * This component allows privileged users (managers/admins) to select a user on whose behalf to act.\n */\nexport const MemberSelect: React.FC = ({ defaultUser, value, onSelected, noHeader, hasError }) => {\n const { t } = useTranslation('public');\n const [option, setOption] = useState>();\n\n useEffect(() => {\n if (defaultUser) {\n setOption({ value: defaultUser.id, label: defaultUser.name });\n }\n }, []);\n\n useEffect(() => {\n if (!defaultUser && option) {\n onSelected({ id: option.value, name: option.label });\n }\n if (!option && defaultUser) {\n setOption({ value: defaultUser.id, label: defaultUser.name });\n }\n }, [defaultUser]);\n\n useEffect(() => {\n if (value && value?.id !== option?.value) {\n setOption({ value: value.id, label: value.name });\n }\n if (!value) {\n setOption(null);\n }\n }, [value]);\n\n /**\n * search members by name\n */\n const loadMembers = async (inputValue: string): Promise>> => {\n if (!inputValue) {\n return [];\n }\n const data = await MemberAPI.search(inputValue);\n return data.map(u => {\n return { value: u.id, label: u.name };\n });\n };\n\n /**\n * callback for handle select changed\n */\n const onChange = (v: SelectOption) => {\n setOption(v);\n onSelected({ id: v.value, name: v.label });\n };\n\n return (\n
\n {!noHeader &&\n
\n

{t('app.public.member_select.select_a_member')}

\n
\n }\n \n
\n );\n};\n\nMemberSelect.defaultProps = {\n hasError: false\n};\n","import { UseFormRegister } from 'react-hook-form';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { useTranslation } from 'react-i18next';\nimport { FormInput } from '../form/form-input';\nimport { FormState } from 'react-hook-form/dist/types/form';\nimport { PasswordStrength } from './password-strength';\nimport * as React from 'react';\nimport { useState } from 'react';\nimport { Eye, EyeSlash } from 'phosphor-react';\n\ninterface PasswordInputProps {\n register: UseFormRegister,\n currentFormPassword: string,\n formState: FormState,\n}\n\n/**\n * Passwords inputs: new password and confirmation.\n */\nexport const PasswordInput = ({ register, currentFormPassword, formState }: PasswordInputProps) => {\n const { t } = useTranslation('shared');\n\n const [password, setPassword] = useState(null);\n const [inputType, setInputType] = useState<'password'|'text'>('password');\n\n /**\n * Callback triggered when the user types a password\n */\n const handlePasswordChange = (event: React.ChangeEvent) => {\n setPassword(event.target.value);\n };\n\n /**\n * Switch the password characters between hidden and displayed\n */\n const toggleShowPassword = () => {\n if (inputType === 'text') {\n setInputType('password');\n } else {\n setInputType('text');\n }\n };\n\n return (\n
\n : }\n addOnAction={toggleShowPassword}\n rules={{\n required: true,\n validate: (value: string) => {\n if (value.length < 12) {\n return t('app.shared.password_input.password_too_short') as string;\n }\n return true;\n }\n }}\n formState={formState}\n onChange={handlePasswordChange}\n label={t('app.shared.password_input.new_password')}\n tooltip={t('app.shared.password_input.help')}\n type={inputType} />\n \n {\n if (value !== currentFormPassword) {\n return t('app.shared.password_input.confirmation_mismatch') as string;\n }\n return true;\n }\n }}\n formState={formState}\n label={t('app.shared.password_input.confirm_password')}\n type=\"password\" />\n
\n );\n};\n","import * as React from 'react';\nimport { useEffect, useState } from 'react';\nimport { zxcvbn, zxcvbnOptions } from '@zxcvbn-ts/core';\nimport zxcvbnCommonPackage from '@zxcvbn-ts/language-common';\nimport { debounce as _debounce } from 'lodash';\nimport LocaliseLib from '../../lib/localise';\nimport type { ZxcvbnResult } from '@zxcvbn-ts/core/src/types';\nimport { useTranslation } from 'react-i18next';\n\ninterface PasswordStrengthProps {\n password?: string,\n}\n\nconst SPECIAL_CHARS = ['!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', ']', '^', '_', '{', '|', '}', '~', \"'\", '`', '\"'];\n\n/**\n * Shows a visual indicator of the password strength\n */\nexport const PasswordStrength: React.FC = ({ password }) => {\n const { t } = useTranslation('shared');\n\n const [strength, setStrength] = useState(null);\n const [hasRequirements, setHasRequirements] = useState(false);\n\n /*\n * zxcvbn library options\n * @see https://zxcvbn-ts.github.io/zxcvbn/guide/getting-started/\n */\n const options = {\n translations: null,\n graphs: zxcvbnCommonPackage.adjacencyGraphs,\n dictionary: LocaliseLib.zxcvbnDictionnaries()\n };\n zxcvbnOptions.setOptions(options);\n\n /**\n * Compute the strength of the given password and update the result in memory\n */\n const updateStrength = () => {\n if (typeof password === 'string') {\n if (checkRequirements()) {\n setHasRequirements(true);\n const result = zxcvbn(password);\n setStrength(result);\n } else {\n setHasRequirements(false);\n }\n }\n };\n\n /**\n * Check if the provided password meet the minimal requirements\n */\n const checkRequirements = (): boolean => {\n if (typeof password === 'string') {\n const chars = password.split('');\n return (chars.some(c => SPECIAL_CHARS.includes(c)) &&\n !!password.match(/[A-Z]/) &&\n !!password.match(/[a-z]/) &&\n !!password.match(/[0-9]/) &&\n password.length >= 12);\n }\n };\n\n useEffect(_debounce(updateStrength, 500), [password]);\n\n return (\n
\n {password && !hasRequirements && <>\n {t('app.shared.password_strength.not_in_requirements')}\n }\n {hasRequirements && strength && <>\n
\n {t(`app.shared.password_strength.${strength.score}`)}\n }\n
\n );\n};\n","import { useEffect, useState } from 'react';\nimport * as React from 'react';\nimport { react2angular } from 'react2angular';\nimport { useForm, useWatch, ValidateResult } from 'react-hook-form';\nimport { isNil as _isNil } from 'lodash';\nimport { User, UserFieldMapping, UserFieldsReservedForPrivileged } from '../../models/user';\nimport { IApplication } from '../../models/application';\nimport { Loader } from '../base/loader';\nimport { FormInput } from '../form/form-input';\nimport { useTranslation } from 'react-i18next';\nimport { GenderInput } from './gender-input';\nimport { ChangePassword } from './change-password';\nimport { PasswordInput } from './password-input';\nimport { FormSwitch } from '../form/form-switch';\nimport { FormRichText } from '../form/form-rich-text';\nimport MemberAPI from '../../api/member';\nimport { AvatarInput } from './avatar-input';\nimport { FabButton } from '../base/fab-button';\nimport { EditSocials } from '../socials/edit-socials';\nimport UserLib from '../../lib/user';\nimport AuthProviderAPI from '../../api/auth-provider';\nimport { FormSelect } from '../form/form-select';\nimport GroupAPI from '../../api/group';\nimport CustomAssetAPI from '../../api/custom-asset';\nimport { CustomAsset, CustomAssetName } from '../../models/custom-asset';\nimport { HtmlTranslate } from '../base/html-translate';\nimport TrainingAPI from '../../api/training';\nimport BrazillianAPI from '../../api/brazillian';\nimport TagAPI from '../../api/tag';\nimport { FormMultiSelect } from '../form/form-multi-select';\nimport ProfileCustomFieldAPI from '../../api/profile-custom-field';\nimport { ProfileCustomField } from '../../models/profile-custom-field';\nimport { SettingName } from '../../models/setting';\nimport SettingAPI from '../../api/setting';\nimport { SelectOption } from '../../models/select';\nimport ValidationLib from '../../lib/validation';\nimport Inputmask from 'inputmask';\n\ndeclare const Application: IApplication;\n\ninterface UserProfileFormProps {\n action: 'create' | 'update',\n size?: 'small' | 'large',\n user: User,\n operator: User,\n className?: string,\n onError: (message: string) => void,\n onSuccess: (user: User) => void,\n showGroupInput?: boolean,\n showTermsAndConditionsInput?: boolean,\n showTrainingsInput?: boolean,\n showTagsInput?: boolean,\n}\n\n/**\n * Form component to create or update a user\n */\nexport const UserProfileForm: React.FC = ({ action, size, user, operator, className, onError, onSuccess, showGroupInput, showTermsAndConditionsInput, showTrainingsInput, showTagsInput }) => {\n const { t } = useTranslation('shared');\n\n const { handleSubmit, register, control, formState, setValue, reset } = useForm({ defaultValues: { ...user } });\n const output = useWatch({ control });\n\n const [isOrganization, setIsOrganization] = useState(!_isNil(user.invoicing_profile_attributes.organization_attributes));\n const [isLocalDatabaseProvider, setIsLocalDatabaseProvider] = useState(false);\n const [groups, setGroups] = useState[]>([]);\n const [states, setStates] = useState[]>([]);\n const [cities, setCities] = useState[]>([]);\n const [originStateDisabled, setOriginStateDisabled] = useState(true);\n const [showResponsibleData, setShowResponsibleData] = useState(false);\n const [termsAndConditions, setTermsAndConditions] = useState(null);\n const [profileCustomFields, setProfileCustomFields] = useState([]);\n const [fieldsSettings, setFieldsSettings] = useState>(new Map());\n const [isSuccessfullySubmitted, setIsSuccessfullySubmitted] = React.useState(false);\n\n const ocupacionalStatus = [\n { value: '1', label: 'Empregado' },\n { value: '2', label: 'Desempregado' },\n { value: '3', label: 'Empregador' },\n { value: '4', label: 'Autônomo/Conta Própria' },\n { value: '5', label: 'Profissional Liberal' },\n { value: '6', label: '1º Emprego' },\n { value: '7', label: 'Aposentado' },\n { value: '8', label: 'Microempreendedor Individual - MEI' },\n { value: '9', label: 'Aprendiz com contrato' }\n ];\n\n const educationalLevels = [\n { value: '1', label: 'Analfabeto' },\n { value: '2', label: 'Até o 5º ano incompleto do ensino fundamental' },\n { value: '3', label: '5º ano completo do ensino fundamental' },\n { value: '4', label: 'Do 6º ao 9º ano do ensino fundamental' },\n { value: '5', label: 'Ensino fundamental completo' },\n { value: '6', label: 'Ensino médio incompleto' },\n { value: '7', label: 'Ensino médio completo' },\n { value: '8', label: 'Educação superior incompleto' },\n { value: '9', label: 'Educação superior completo' },\n { value: 'A', label: 'Pós Grad. incompleto' },\n { value: 'B', label: 'Pós Grad. completo' },\n { value: 'C', label: 'Mestrado incompleto' },\n { value: 'D', label: 'Mestrado completo' },\n { value: 'E', label: 'Doutorado incompleto' },\n { value: 'F', label: 'Doutorado completo' },\n { value: 'G', label: 'Pós Dout. incompleto' },\n { value: 'H', label: 'Pós Dout. completo' }\n ];\n\n useEffect(() => {\n AuthProviderAPI.active().then(data => {\n setIsLocalDatabaseProvider(data.providable_type === 'DatabaseProvider');\n }).catch(error => onError(error));\n if (showGroupInput) {\n GroupAPI.index({ disabled: false }).then(data => {\n setGroups(buildOptions(data));\n }).catch(error => onError(error));\n }\n if (showTermsAndConditionsInput) {\n CustomAssetAPI.get(CustomAssetName.CguFile).then(cgu => {\n if (cgu?.custom_asset_file_attributes) setTermsAndConditions(cgu);\n }).catch(error => onError(error));\n }\n ProfileCustomFieldAPI.index({ actived: true }).then(data => {\n setProfileCustomFields(data);\n const userProfileCustomFields = data.map(f => {\n const upcf = user?.invoicing_profile_attributes?.user_profile_custom_fields_attributes?.find(uf => uf.profile_custom_field_id === f.id);\n return upcf || {\n value: '',\n invoicing_profile_id: user.invoicing_profile_attributes.id,\n profile_custom_field_id: f.id\n };\n });\n setValue('invoicing_profile_attributes.user_profile_custom_fields_attributes', userProfileCustomFields);\n }).catch(error => onError(error));\n BrazillianAPI.states().then(data => {\n const items = data.map(t => {\n return { value: t.sigla, label: t.nome };\n });\n setStates(items);\n }).catch(error => onError(error));\n SettingAPI.query(['phone_required', 'address_required', 'external_id'])\n .then(settings => setFieldsSettings(settings))\n .catch(error => onError(error));\n\n checkIsUnder18(user.statistic_profile_attributes.birthday);\n if (user.profile_attributes.origin_city) {\n loadCities(user.profile_attributes.origin_state);\n }\n Inputmask({ mask: '999.999.999-99', clearMaskOnLostFocus: true }).mask('[name=\"profile_attributes.cpf\"]');\n Inputmask({ mask: '999.999.999-99', clearMaskOnLostFocus: true }).mask('[name=\"profile_attributes.financial_responsible_cpf\"]');\n Inputmask({ mask: '99999-999', clearMaskOnLostFocus: true }).mask('[name=\"profile_attributes.zipcode\"]');\n }, []);\n\n /**\n * Check if is under 18 to show a responsible data\n */\n const checkIsUnder18 = (date: Date | string) => {\n setShowResponsibleData(isUnder18(date));\n };\n\n /**\n * Load cities on change state\n */\n const loadCities = (uf: string) => {\n setOriginStateDisabled(true);\n BrazillianAPI.cities(uf).then(data => {\n const items = data.map(t => {\n return { value: t.nome, label: t.nome };\n });\n setCities(items);\n setOriginStateDisabled(false);\n }).catch(error => onError(error));\n };\n\n /**\n * Calculate if birth date is under 18\n */\n const isUnder18 = (dateString: Date | string) => {\n const currentDate = new Date();\n const birthDate = new Date(dateString);\n const ageDifference = currentDate.getFullYear() - birthDate.getFullYear();\n if (ageDifference < 18) {\n return true;\n }\n if (\n ageDifference === 18 &&\n (birthDate.getMonth() > currentDate.getMonth() ||\n (birthDate.getMonth() === currentDate.getMonth() &&\n birthDate.getDate() > currentDate.getDate()))\n ) {\n return true;\n }\n return false;\n };\n\n /**\n * Load CEP data on change Zipcode\n */\n const loadZipCode = (event: React.ChangeEvent) => {\n const zipcode = event.target.value.replace(/\\D/g, '');\n if (zipcode.length !== 8) return;\n BrazillianAPI.zipcode(zipcode).then(data => {\n setValue('profile_attributes.street', data.logradouro, { shouldDirty: true });\n setValue('profile_attributes.neighborhood', data.bairro, { shouldDirty: true });\n setValue('profile_attributes.city', data.localidade, { shouldDirty: true });\n setValue('profile_attributes.state', data.uf, { shouldDirty: true });\n }).catch(error => onError(error));\n };\n\n /**\n * Convert the provided array of items to the react-select format\n */\n const buildOptions = (items: Array<{ id?: number, name: string }>): Array> => {\n return items.map(t => {\n return { value: t.id, label: t.name };\n });\n };\n\n /**\n * Asynchronously load the full list of enabled trainings to display in the drop-down select field\n */\n const loadTrainings = (inputValue: string, callback: (options: Array>) => void): void => {\n TrainingAPI.index({ disabled: false }).then(data => {\n callback(buildOptions(data));\n }).catch(error => onError(error));\n };\n\n /**\n * Asynchronously load the full list of tags to display in the drop-down select field\n */\n const loadTags = (inputValue: string, callback: (options: Array>) => void): void => {\n TagAPI.index().then(data => {\n callback(buildOptions(data));\n }).catch(error => onError(error));\n };\n\n /**\n * Callback triggered when the form is submitted: process with the user creation or update.\n */\n const onSubmit = (event: React.FormEvent) => {\n if (showTermsAndConditionsInput) {\n // When the form is submitted, we consider that the user should have accepted the terms and conditions,\n // so we mark the field as dirty, even if he doesn't touch it. Like that, the error message is displayed.\n setValue('cgu', !!output.cgu, { shouldDirty: true, shouldTouch: true });\n }\n\n return handleSubmit((data: User) => {\n MemberAPI[action](data)\n .then(res => {\n reset(res);\n onSuccess(res);\n setIsSuccessfullySubmitted(true);\n })\n .catch((error) => { onError(error); });\n })(event);\n };\n\n /**\n * Check if the given field path should be disabled\n */\n const isDisabled = function (id: string) {\n // some fields may be reserved in edition for priviledged users\n if (UserFieldsReservedForPrivileged.includes(id) && !(new UserLib(operator).isPrivileged(user))) {\n return true;\n }\n // if the current provider is the local database, then all fields are enabled\n if (isLocalDatabaseProvider) {\n return false;\n }\n\n // if the current provider is not the local database, then fields are disabled based on their mapping status.\n return user.mapped_from_sso?.includes(UserFieldMapping[id]);\n };\n\n /**\n * Check if the user has accepted the terms and conditions\n */\n const checkAcceptTerms = function (value: boolean): ValidateResult {\n return value === true || (t('app.shared.user_profile_form.must_accept_terms') as string);\n };\n\n const userNetworks = new UserLib(user).getUserSocialNetworks();\n\n return (\n \n
\n \n
\n
\n
\n

{t('app.shared.user_profile_form.personal_data')}

\n
\n \n \n
\n
\n \n \n
\n
\n checkIsUnder18(event.target.value)}\n formState={formState}\n type=\"date\"\n nullable />\n \n \n
\n
\n \n \n
\n
\n \n \n \n
\n
\n \n
\n {showResponsibleData &&
\n \n \n
}\n
\n \n \n
\n
\n \n \n \n
\n
\n \n \n \n \n
\n
\n \n
\n
\n
\n

{t('app.shared.user_profile_form.account_data')}

\n \n {fieldsSettings.get('external_id') === 'true' && }\n \n {isLocalDatabaseProvider &&
\n { action === 'update' && }\n {action === 'create' && }\n
}\n
\n
\n

{t('app.shared.user_profile_form.organization_data')}

\n \n {isOrganization &&
\n \n \n \n \n {profileCustomFields.map((f, i) => {\n return ();\n })}\n
}\n
\n
\n

{t('app.shared.user_profile_form.profile_data')}

\n
\n \n \n
\n
\n \n \n
\n
\n
\n

{t('app.shared.user_profile_form.account_networks')}

\n \n
\n
\n

{t('app.shared.user_profile_form.preferences_data')}

\n \n \n
\n {showGroupInput &&
\n \n
}\n {showTrainingsInput &&
\n \n
}\n {showTagsInput &&
\n \n
}\n {new UserLib(operator).isPrivileged(user) &&
\n \n
}\n {showTermsAndConditionsInput && termsAndConditions &&
\n }\n />\n
}\n
\n {t('app.shared.user_profile_form.save')}\n
\n
\n \n );\n};\n\nUserProfileForm.defaultProps = {\n size: 'large',\n showGroupInput: false,\n showTrainingsInput: false,\n showTermsAndConditionsInput: false,\n showTagsInput: false\n};\n\nconst UserProfileFormWrapper: React.FC = (props) => {\n return (\n \n \n \n );\n};\n\nApplication.Components.component('userProfileForm', react2angular(UserProfileFormWrapper, ['action', 'size', 'user', 'operator', 'className', 'onError', 'onSuccess', 'showGroupInput', 'showTermsAndConditionsInput', 'showTagsInput', 'showTrainingsInput']));\n","import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport Switch from 'react-switch';\nimport _ from 'lodash';\nimport { useTranslation } from 'react-i18next';\nimport { User } from '../../models/user';\nimport { IApplication } from '../../models/application';\nimport { react2angular } from 'react2angular';\nimport MemberAPI from '../../api/member';\nimport { TDateISO } from '../../typings/date-iso';\n\ndeclare const Application: IApplication;\n\ninterface UserValidationProps {\n member: User\n onSuccess: (user: User, message: string) => void,\n onError: (message: string) => void,\n}\n\n/**\n * This component allows to configure boolean value for a setting.\n */\nexport const UserValidation: React.FC = ({ member, onSuccess, onError }) => {\n const { t } = useTranslation('admin');\n\n const [value, setValue] = useState(!!(member?.validated_at));\n\n useEffect(() => {\n setValue(!!(member?.validated_at));\n }, [member]);\n\n /**\n * Callback triggered when the 'switch' is changed.\n */\n const handleChanged = (_value: boolean) => {\n setValue(_value);\n const _member = _.clone(member);\n if (_value) {\n _member.validated_at = new Date().toISOString() as TDateISO;\n } else {\n _member.validated_at = null;\n }\n MemberAPI.validate(_member)\n .then((user: User) => {\n onSuccess(user, t(`app.admin.user_validation.${_value ? 'validate' : 'invalidate'}_member_success`));\n }).catch(err => {\n setValue(!_value);\n onError(t(`app.admin.user_validation.${_value ? 'validate' : 'invalidate'}_member_error`) + err);\n });\n };\n\n return (\n
\n \n \n
\n );\n};\n\nApplication.Components.component('userValidation', react2angular(UserValidation, ['member', 'onSuccess', 'onError']));\n","'use strict';\n\nApplication.Controllers.controller('AboutController', ['$scope', 'Setting', 'CustomAsset', function ($scope, Setting, CustomAsset) {\n /* PUBLIC SCOPE */\n\n Setting.get({ name: 'about_title' }, data => { $scope.aboutTitle = data.setting; });\n\n Setting.get({ name: 'about_body' }, data => { $scope.aboutBody = data.setting; });\n\n Setting.get({ name: 'about_contacts' }, data => { $scope.aboutContacts = data.setting; });\n\n Setting.get({ name: 'privacy_body' }, data => { $scope.privacyPolicy = data.setting; });\n\n // retrieve the CGU\n CustomAsset.get({ name: 'cgu-file' }, cgu => { $scope.cgu = cgu.custom_asset; });\n\n // retrieve the CGV\n CustomAsset.get({ name: 'cgv-file' }, cgv => { $scope.cgv = cgv.custom_asset; });\n}\n]);\n","/**\n * Controller used in abuses management page\n */\nApplication.Controllers.controller('AbusesController', ['$scope', '$state', 'Abuse', 'abusesPromise', 'dialogs', 'growl', '_t',\n function ($scope, $state, Abuse, abusesPromise, dialogs, growl, _t) {\n /* PUBLIC SCOPE */\n\n // List of all reported abuses\n $scope.abuses = [];\n\n /**\n * Callback handling a click on the ✓ button: confirm before delete\n */\n $scope.confirmProcess = function (abuseId) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.manage_abuses.confirmation_required'),\n msg: _t('app.admin.manage_abuses.report_will_be_destroyed')\n };\n }\n }\n },\n function () { // cancel confirmed\n Abuse.remove({ id: abuseId }, function () { // successfully canceled\n growl.success(_t('app.admin.manage_abuses.report_removed'));\n Abuse.query({}, function (abuses) {\n $scope.abuses = abuses.abuses.filter(a => a.signaled_type === 'Project');\n });\n }\n , function () { // error while canceling\n growl.error(_t('app.admin.manage_abuses.failed_to_remove'));\n });\n }\n );\n };\n\n /* PRIVATE SCOPE */\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // we display only abuses related to projects\n $scope.abuses = abusesPromise.abuses.filter(a => a.signaled_type === 'Project');\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n camelcase,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/* COMMON CODE */\n\n// list of supported authentication methods\nconst METHODS = {\n DatabaseProvider: 'local_database',\n OAuth2Provider: 'o_auth2',\n OpenIdConnectProvider: 'openid_connect'\n};\n\n/**\n * Iterate through the provided array and return the index of the requested element\n * @param elements {Array<{id:*}>}\n * @param id {*} id of the element to retrieve in the list\n * @returns {number} index of the requested element, in the provided array\n */\nconst findIdxById = function (elements, id) {\n return (elements.map(function (elem) { return elem.id; })).indexOf(id);\n};\n\n/**\n * Page listing all authentication providers\n */\nApplication.Controllers.controller('AuthentificationController', ['$scope', '$state', '$rootScope', 'dialogs', 'growl', 'authProvidersPromise', 'AuthProvider', '_t',\n function ($scope, $state, $rootScope, dialogs, growl, authProvidersPromise, AuthProvider, _t) {\n /* PUBLIC SCOPE */\n\n // full list of authentication providers\n $scope.providers = authProvidersPromise;\n\n /**\n * Translate the classname into an explicit textual message\n * @param type {string} Ruby polymorphic model classname\n * @returns {string}\n */\n $scope.getType = function (type) {\n const text = METHODS[type];\n if (typeof text !== 'undefined') {\n return _t(`app.admin.members.authentication_form.${text}`);\n } else {\n return _t('app.admin.members.authentication_form.unknown') + type;\n }\n };\n\n /**\n * Translate the status string into an explicit textual message\n * @param status {string} active | pending | previous\n * @returns {string}\n */\n $scope.getState = function (status) {\n switch (status) {\n case 'active': return _t('app.admin.members.authentication_form.active');\n case 'pending': return _t('app.admin.members.authentication_form.pending');\n case 'previous': return _t('app.admin.members.authentication_form.previous_provider');\n default: return _t('app.admin.members.authentication_form.unknown') + status;\n }\n };\n\n /**\n * Ask for confirmation then delete the specified provider\n * @param providers {Array} full list of authentication providers\n * @param provider {Object} provider to delete\n */\n $scope.destroyProvider = function (providers, provider) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.members.authentication_form.confirmation_required'),\n msg: _t('app.admin.members.authentication_form.do_you_really_want_to_delete_the_TYPE_authentication_provider_NAME', { TYPE: $scope.getType(provider.providable_type), NAME: provider.name })\n };\n }\n }\n },\n function () {\n // the admin has confirmed, delete\n AuthProvider.delete(\n { id: provider.id },\n function () {\n providers.splice(findIdxById(providers, provider.id), 1);\n growl.success(_t('app.admin.members.authentication_form.authentication_provider_successfully_deleted'));\n },\n function () { growl.error(_t('app.admin.members.authentication_form.an_error_occurred_unable_to_delete_the_specified_provider')); }\n );\n }\n );\n };\n }\n\n]);\n\n/**\n * Page to add a new authentication provider\n */\nApplication.Controllers.controller('NewAuthenticationController', ['$scope', '$state', 'growl',\n function ($scope, $state, growl) {\n /**\n * Shows a success message forwarded from a child react component\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n $scope.cancel();\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n $scope.cancel = function () { $state.go('app.admin.members'); };\n }\n]);\n\n/**\n * Page to edit an already added authentication provider\n */\nApplication.Controllers.controller('EditAuthenticationController', ['$scope', '$state', 'growl', 'providerPromise',\n function ($scope, $state, growl, providerPromise) {\n // parameters of the currently edited authentication provider\n $scope.provider = cleanProvider(providerPromise);\n\n /**\n * Shows a success message forwarded from a child react component\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n $scope.cancel = function () { $state.go('app.admin.members'); };\n\n // prepare the provider for the react-hook-form\n function cleanProvider (provider) {\n delete provider.$promise;\n delete provider.$resolved;\n return provider;\n }\n }\n]);\n","/* eslint-disable\n camelcase,\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in the calendar management page\n */\n\nApplication.Controllers.controller('AdminCalendarController', ['$scope', '$state', '$uibModal', 'moment', 'AuthService', 'Availability', 'SlotsReservation', 'Setting', 'Export', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Member', 'uiTourService', 'trainingsPromise', 'spacesPromise', 'machineCategoriesPromise', '$aside',\n function ($scope, $state, $uibModal, moment, AuthService, Availability, SlotsReservation, Setting, Export, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, plansPromise, groupsPromise, settingsPromise, _t, uiCalendarConfig, CalendarConfig, Member, uiTourService, trainingsPromise, spacesPromise, machineCategoriesPromise, $aside) {\n /* PRIVATE STATIC CONSTANTS */\n machinesPromise.forEach(m => m.checked = true);\n trainingsPromise.forEach(t => t.checked = true);\n spacesPromise.forEach(s => s.checked = true);\n\n // check all formation/machine is select in filter\n const isSelectAll = (type, scope) => scope[type].length === scope[type].filter(t => t.checked).length;\n\n // The calendar is divided in slots of 30 minutes\n const BASE_SLOT = '00:30:00';\n\n // The bookings can be positioned every half hours\n const BOOKING_SNAP = '00:30:00';\n\n // We do not allow the creation of slots that are not a multiple of 60 minutes\n const SLOT_MULTIPLE = parseInt(settingsPromise.slot_duration, 10);\n\n /* PUBLIC SCOPE */\n\n // List of trainings\n $scope.trainings = trainingsPromise.filter(t => !t.disabled);\n\n // list of the FabLab machines\n $scope.machines = machinesPromise.filter(m => !m.disabled && m.reservable);\n\n // List of machine categories\n $scope.machineCategories = machineCategoriesPromise;\n\n // List of machines group by category\n $scope.machinesGroupByCategory = [];\n\n // List of spaces\n $scope.spaces = spacesPromise.filter(t => !t.disabled);\n\n // currently selected availability\n $scope.availability = null;\n\n // corresponding fullCalendar item in the DOM\n $scope.availabilityDom = null;\n\n // Should we show the scheduled events in the calendar?\n $scope.eventsInCalendar = (settingsPromise.events_in_calendar === 'true');\n\n // fullCalendar (v2) configuration\n $scope.calendarConfig = CalendarConfig({\n slotDuration: BASE_SLOT,\n snapDuration: BOOKING_SNAP,\n selectable: true,\n selectHelper: true,\n minTime: moment.duration(moment(bookingWindowStart.setting.value).format('HH:mm:ss')),\n maxTime: moment.duration(moment(bookingWindowEnd.setting.value).format('HH:mm:ss')),\n select (start, end, jsEvent, view) {\n return calendarSelectCb(start, end, jsEvent, view);\n },\n eventClick (event, jsEvent, view) {\n return calendarEventClickCb(event, jsEvent, view);\n },\n eventRender (event, element, view) {\n return eventRenderCb(event, element, view);\n },\n viewRender (view, element) {\n return viewRenderCb(view, element);\n },\n loading (isLoading, view) {\n return loadingCb(isLoading, view);\n }\n });\n\n /**\n * Open a confirmation modal to cancel the booking of a user for the currently selected event.\n * @param slot_reservation {Object} reserved slot, as returned by /api/availabilities/:id/reservations\n */\n $scope.cancelBooking = function (slot_reservation) {\n // open a confirmation dialog\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.calendar.confirmation_required'),\n msg: _t('app.admin.calendar.do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION'\n , { GENDER: getGender($scope.currentUser), USER: slot_reservation.user.name, DATE: moment(slot_reservation.start_at).format('L'), TIME: moment(slot_reservation.start_at).format('LT'), RESERVATION: slot_reservation.reservable.name })\n };\n }\n }\n },\n function () {\n // the admin has confirmed, cancel the reservation\n SlotsReservation.cancel(\n { id: slot_reservation.id },\n function (data, status) { // success\n // update the canceled_at attribute\n for (const resa of Array.from($scope.reservations)) {\n if (resa.id === data.id) {\n resa.canceled_at = data.canceled_at;\n break;\n }\n }\n // notify the admin\n return growl.success(_t('app.admin.calendar.reservation_was_successfully_cancelled'));\n },\n function (data, status) { // failed\n growl.error(_t('app.admin.calendar.reservation_cancellation_failed'));\n }\n );\n }\n );\n };\n\n /**\n * Open a confirmation modal to remove a machine for the currently selected availability,\n * except if it is the last machine of the reservation.\n * @param machine {Object} must contain the machine ID and name\n */\n $scope.removeMachine = function (machine) {\n if ($scope.availability.machine_ids.length === 1) {\n return growl.error(_t('app.admin.calendar.unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather'));\n } else {\n // open a confirmation dialog\n return dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.calendar.confirmation_required'),\n msg: _t('app.admin.calendar.do_you_really_want_to_remove_MACHINE_from_this_slot', { GENDER: getGender($scope.currentUser), MACHINE: machine.name }) + ' ' +\n _t('app.admin.calendar.this_will_prevent_any_new_reservation_on_this_slot_but_wont_cancel_those_existing') + '
' +\n _t('app.admin.calendar.beware_this_cannot_be_reverted') + ''\n };\n }\n }\n }\n , function () {\n // the admin has confirmed, remove the machine\n const machines = $scope.availability.machine_ids;\n for (let m_id = 0; m_id < machines.length; m_id++) {\n const key = machines[m_id];\n if (m_id === machine.id) {\n machines.splice(key, 1);\n }\n }\n\n return Availability.update({ id: $scope.availability.id }, { availability: { machines_attributes: [{ id: machine.id, _destroy: true }] } }\n , function (data, status) { // success\n // update the machine_ids attribute\n $scope.availability.machine_ids = data.machine_ids;\n $scope.availability.title = data.title;\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n // notify the admin\n return growl.success(_t('app.admin.calendar.the_machine_was_successfully_removed_from_the_slot'));\n }\n , function (data, status) { // failed\n growl.error(_t('app.admin.calendar.deletion_failed'));\n }\n );\n });\n }\n };\n\n /**\n * Open a confirmation modal to remove a plan for the currently selected availability,\n * @param plan {Object} must contain the machine ID and name\n */\n $scope.removePlan = function (plan) {\n // open a confirmation dialog\n return dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.calendar.confirmation_required'),\n msg: _t('app.admin.calendar.do_you_really_want_to_remove_PLAN_from_this_slot', { GENDER: getGender($scope.currentUser), PLAN: plan.name })\n };\n }\n }\n },\n function () {\n // the admin has confirmed, remove the plan\n _.drop($scope.availability.plan_ids, plan.id);\n\n Availability.update({ id: $scope.availability.id }, { availability: { plans_attributes: [{ id: plan.id, _destroy: true }] } }\n , function (data, status) { // success\n // update the plan_ids attribute\n $scope.availability.plan_ids = data.plan_ids;\n $scope.availability.plans = availabilityPlans();\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n // notify the admin\n return growl.success(_t('app.admin.calendar.the_plan_was_successfully_removed_from_the_slot'));\n }\n , function (data, status) { // failed\n growl.error(_t('app.admin.calendar.deletion_failed'));\n }\n );\n });\n };\n\n /**\n * Callback to alert the admin that the export request was acknowledged and is\n * processing right now.\n */\n $scope.alertExport = function (type) {\n Export.status({ category: 'availabilities', type }).then(function (res) {\n if (!res.data.exists) {\n return growl.success(_t('app.admin.calendar.export_is_running_you_ll_be_notified_when_its_ready'));\n }\n });\n };\n\n /**\n * Mark the selected slot as unavailable for new reservations or allow reservations again on it\n */\n $scope.toggleLockReservations = function () {\n // first, define a shortcut to the lock property\n const locked = $scope.availability.lock;\n // then check if we'll allow reservations locking\n let prevent = !locked; // if currently locked, allow unlock anyway\n if (!locked) {\n prevent = false;\n angular.forEach($scope.reservations, function (r) {\n if (r.canceled_at === null) {\n return prevent = true;\n }\n }); // if currently unlocked and has any non-cancelled reservation, disallow locking\n }\n if (!prevent) {\n // open a confirmation dialog\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.calendar.confirmation_required'),\n msg: locked ? _t('app.admin.calendar.do_you_really_want_to_allow_reservations') : _t('app.admin.calendar.do_you_really_want_to_block_this_slot')\n };\n }\n }\n },\n function () {\n // the admin has confirmed, lock/unlock the slot\n Availability.lock(\n { id: $scope.availability.id },\n { lock: !locked },\n function (data) { // success\n $scope.availability = data;\n growl.success(locked ? _t('app.admin.calendar.unlocking_success') : _t('app.admin.calendar.locking_success'));\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n },\n function (error) { // failed\n growl.error(locked ? _t('app.admin.calendar.unlocking_failed') : _t('app.admin.calendar.locking_failed'));\n console.error(error);\n }\n );\n }\n );\n } else {\n return growl.error(_t('app.admin.calendar.unlockable_because_reservations'));\n }\n };\n\n /**\n * Confirm and destroy the slot in $scope.availability\n */\n $scope.removeSlot = function () {\n // open a confirmation dialog\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/admin/calendar/deleteRecurrent.html',\n size: 'md',\n controller: 'DeleteRecurrentAvailabilityController',\n resolve: {\n availabilityPromise: ['Availability', function (Availability) { return Availability.get({ id: $scope.availability.id }).$promise; }]\n }\n });\n // once the dialog was closed, do things depending on the result\n modalInstance.result.then(function (res) {\n if (res.status === 'success') {\n $scope.availability = null;\n }\n for (const availability of res.availabilities) {\n uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents', availability);\n }\n });\n };\n\n /**\n * Setup the feature-tour for the admin/calendar page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupCalendarTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('calendar');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.calendar.welcome.title'),\n content: _t('app.admin.tour.calendar.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.admin-calendar .fc-view-container',\n stepId: 'agenda',\n order: 1,\n title: _t('app.admin.tour.calendar.agenda.title'),\n content: _t('app.admin.tour.calendar.agenda.content'),\n placement: 'right',\n popupClass: 'width-350'\n });\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: '.admin-calendar .export-xls-button',\n stepId: 'export',\n order: 2,\n title: _t('app.admin.tour.calendar.export.title'),\n content: _t('app.admin.tour.calendar.export.content'),\n placement: 'left'\n });\n }\n uitour.createStep({\n selector: '.heading .import-ics-button',\n stepId: 'import',\n order: 3,\n title: _t('app.admin.tour.calendar.import.title'),\n content: _t('app.admin.tour.calendar.import.content'),\n placement: 'left'\n });\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 4,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('calendar') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'calendar' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('calendar') < 0) {\n uitour.start();\n }\n };\n\n // filter availabilities if have change\n $scope.filterAvailabilities = function (filter, scope) {\n if (!scope) { scope = $scope; }\n scope.filter = ($scope.filter = {\n trainings: isSelectAll('trainings', scope),\n machines: isSelectAll('machines', scope),\n spaces: isSelectAll('spaces', scope),\n evt: filter.evt,\n dispo: filter.dispo,\n reserved: filter.reserved\n });\n scope.machinesGroupByCategory.forEach(c => c.checked = _.every(c.machines, 'checked'));\n // remove all\n $scope.eventSources.splice(0, $scope.eventSources.length);\n // recreate source for trainings/machines/events with new filters\n $scope.eventSources.push({\n url: availabilitySourceUrl(),\n textColor: 'black'\n });\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n };\n\n // a variable for formation/machine/event/dispo checkbox is or not checked\n $scope.filter = {\n trainings: isSelectAll('trainings', $scope),\n machines: isSelectAll('machines', $scope),\n spaces: isSelectAll('spaces', $scope),\n evt: true,\n dispo: true,\n reserved: false\n };\n\n // toggle to select all formation/machine\n $scope.toggleFilter = function (type, filter, machineCategoryId) {\n if (type === 'machineCategory') {\n const category = _.find($scope.machinesGroupByCategory, (c) => (c.id).toString() === machineCategoryId);\n if (category) {\n category.machines.forEach(m => m.checked = category.checked);\n }\n filter.machines = isSelectAll('machines', $scope);\n } else {\n $scope[type].forEach(t => t.checked = filter[type]);\n if (type === 'machines') {\n $scope.machinesGroupByCategory.forEach(t => t.checked = filter[type]);\n }\n }\n $scope.filterAvailabilities(filter, $scope);\n };\n\n $scope.openFilterAside = () =>\n $aside.open({\n templateUrl: '/calendar/filterAside.html',\n placement: 'right',\n size: 'md',\n backdrop: false,\n resolve: {\n trainings () {\n return $scope.trainings;\n },\n machines () {\n return $scope.machines;\n },\n machinesGroupByCategory () {\n return $scope.machinesGroupByCategory;\n },\n spaces () {\n return $scope.spaces;\n },\n filter () {\n return $scope.filter;\n },\n toggleFilter () {\n return $scope.toggleFilter;\n },\n filterAvailabilities () {\n return $scope.filterAvailabilities;\n }\n },\n controller: ['$scope', '$uibModalInstance', 'trainings', 'machines', 'machinesGroupByCategory', 'spaces', 'filter', 'toggleFilter', 'filterAvailabilities', 'AuthService', function ($scope, $uibModalInstance, trainings, machines, machinesGroupByCategory, spaces, filter, toggleFilter, filterAvailabilities, AuthService) {\n $scope.trainings = trainings;\n $scope.machines = machines;\n $scope.machinesGroupByCategory = machinesGroupByCategory;\n $scope.hasMachineCategory = _.some(machines, 'machine_category_id');\n $scope.spaces = spaces;\n $scope.filter = filter;\n $scope.accordion = {\n trainings: false,\n machines: false,\n spaces: false\n };\n $scope.machinesGroupByCategory.forEach(c => $scope.accordion[c.name] = false);\n\n $scope.toggleAccordion = (type) => $scope.accordion[type] = !$scope.accordion[type];\n\n $scope.toggleFilter = (type, filter, machineCategoryId) => toggleFilter(type, filter, machineCategoryId);\n\n $scope.filterAvailabilities = filter => filterAvailabilities(filter, $scope);\n\n $scope.isAuthorized = AuthService.isAuthorized;\n\n return $scope.close = function (e) {\n $uibModalInstance.dismiss();\n return e.stopPropagation();\n };\n }]\n });\n\n /* PRIVATE SCOPE */\n const getFilter = function () {\n const t = $scope.trainings.filter(t => t.checked).map(t => t.id);\n const m = $scope.machines.filter(m => m.checked).map(m => m.id);\n const s = $scope.spaces.filter(s => s.checked).map(s => s.id);\n return { t, m, s, evt: $scope.filter.evt, dispo: $scope.filter.dispo, reserved: $scope.filter.reserved };\n };\n\n const availabilitySourceUrl = () => `/api/availabilities?${$.param(getFilter())}`;\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // bind the availabilities slots with full-Calendar events\n $scope.eventSources = [{\n url: availabilitySourceUrl(),\n textColor: 'black'\n }];\n // group machines by category\n _.forIn(_.groupBy($scope.machines, 'machine_category_id'), (ms, categoryId) => {\n const category = _.find($scope.machineCategories, (c) => (c.id).toString() === categoryId);\n $scope.machinesGroupByCategory.push({\n id: categoryId,\n name: category ? category.name : _t('app.shared.machine.machine_uncategorized'),\n checked: true,\n machine_ids: category ? category.machine_ids : [],\n machines: ms\n });\n });\n };\n\n /**\n * Return an enumerable meaninful string for the gender of the provider user\n * @param user {Object} Database user record\n * @return {string} 'male' or 'female'\n */\n const getGender = function (user) {\n if (user.statistic_profile_attributes) {\n if (user.statistic_profile_attributes.gender === 'true') { return 'male'; } else { return 'female'; }\n } else { return 'other'; }\n };\n\n /**\n * Return a list of plans classified by group\n *\n * @returns {array}\n */\n const availabilityPlans = function () {\n const plansClassifiedByGroup = [];\n const _plans = _.filter(plansPromise, function (p) { return _.includes($scope.availability.plan_ids, p.id); });\n for (const group of Array.from(groupsPromise)) {\n const groupObj = { id: group.id, name: group.name, plans: [] };\n for (const plan of Array.from(_plans)) {\n if (plan.group_id === group.id) { groupObj.plans.push(plan); }\n }\n if (groupObj.plans.length > 0) {\n plansClassifiedByGroup.push(groupObj);\n }\n }\n return plansClassifiedByGroup;\n };\n\n // Triggered when the admin drag on the agenda to create a new reservable slot.\n // @see http://fullcalendar.io/docs/selection/select_callback/\n //\n const calendarSelectCb = function (start, end, jsEvent, view) {\n start = moment.tz(start.toISOString(), Fablab.timezone);\n end = moment.tz(end.toISOString(), Fablab.timezone);\n if (view.name === 'month') {\n end = end.subtract(1, 'day').startOf('day');\n }\n\n // check if slot is not in the past\n const today = new Date();\n if (Math.trunc((start.valueOf() - today) / (60 * 1000)) < 0) {\n return dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.calendar.event_in_the_past'),\n msg: _t('app.admin.calendar.confirm_create_event_in_the_past')\n };\n }\n }\n },\n function () { // confirmed\n startAvailabilityCreation(start, end);\n }, function () { // canceled\n uiCalendarConfig.calendars.calendar.fullCalendar('unselect');\n });\n }\n\n startAvailabilityCreation(start, end);\n };\n\n /**\n * Start the process to create a new availability between the given start and end datetimes\n */\n const startAvailabilityCreation = function (start, end) {\n // check that the selected slot is an multiple of SLOT_MULTIPLE (ie. not decimal)\n const slots = Math.trunc((end.valueOf() - start.valueOf()) / (60 * 1000)) / SLOT_MULTIPLE;\n if (!Number.isInteger(slots)) {\n // otherwise, round it to upper decimal\n const upper = (Math.ceil(slots) || 1) * SLOT_MULTIPLE;\n end = moment(start).add(upper, 'minutes');\n }\n\n // then we open a modal window to let the admin specify the slot type\n const modalInstance = $uibModal.open({\n templateUrl: '/admin/calendar/eventModal.html',\n controller: 'CreateEventModalController',\n backdrop: 'static',\n keyboard: false,\n resolve: {\n start () { return start; },\n end () { return end; },\n slots () { return Math.ceil(slots); },\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }],\n spacesPromise: ['Space', function (Space) { return Space.query().$promise; }],\n tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }],\n plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n slotDurationPromise: ['Setting', function (Setting) { return Setting.get({ name: 'slot_duration' }).$promise; }]\n }\n });\n // when the modal is closed, we send the slot to the server for saving\n modalInstance.result.then(\n function (availability) {\n uiCalendarConfig.calendars.calendar.fullCalendar(\n 'renderEvent',\n {\n id: availability.id,\n title: availability.title,\n start: availability.start_at,\n end: availability.end_at,\n textColor: 'black',\n backgroundColor: availability.backgroundColor,\n borderColor: availability.borderColor,\n tag_ids: availability.tag_ids,\n tags: availability.tags,\n machine_ids: availability.machine_ids,\n plan_ids: availability.plan_ids,\n slot_duration: availability.slot_duration\n },\n true\n );\n },\n function () { uiCalendarConfig.calendars.calendar.fullCalendar('unselect'); }\n );\n\n return uiCalendarConfig.calendars.calendar.fullCalendar('unselect');\n };\n\n /**\n * Triggered when the admin clicks on a availability slot in the agenda.\n * @see http://fullcalendar.io/docs/mouse/eventClick/\n */\n const calendarEventClickCb = function (event, jsEvent, view) {\n $scope.availability = event;\n $scope.availability.plans = availabilityPlans();\n\n // mark the side panel as available to be opened\n $('label.calendar-admin-info').removeClass('is-empty');\n\n if ($scope.availabilityDom) {\n $scope.availabilityDom.classList.remove('fc-selected');\n }\n $scope.availabilityDom = jsEvent.target.closest('.fc-event');\n $scope.availabilityDom.classList.add('fc-selected');\n\n // if the user has clicked on the delete event button, delete the event\n if ($(jsEvent.target).hasClass('remove-event')) {\n return $scope.removeSlot();\n // if the user has only clicked on the event, display its reservations\n } else {\n return Availability.reservations({ id: event.id }, function (reservations) { $scope.reservations = reservations; });\n }\n };\n\n /**\n * Triggered when fullCalendar tries to graphicaly render an event block.\n * Append the event tag into the block, just after the event title.\n * @see http://fullcalendar.io/docs/event_rendering/eventRender/\n */\n const eventRenderCb = function (event, element) {\n if (event.available_type !== 'event') {\n element.find('.fc-content').prepend('');\n }\n if (event.tags && event.tags.length > 0) {\n let html = '';\n for (const tag of Array.from(event.tags)) {\n html += `${tag.name} `;\n }\n element.find('.fc-title').append(`
${html}`);\n }\n };\n\n /**\n * Triggered when resource fetching starts/stops.\n * @see https://fullcalendar.io/docs/resource_data/loading/\n */\n const loadingCb = function (isLoading, view) {\n if (isLoading && uiCalendarConfig.calendars.calendar) {\n // we remove existing events when fetching starts to prevent duplicates\n uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');\n }\n };\n\n /**\n * Triggered when the view is changed\n * @see https://fullcalendar.io/docs/v3/viewRender#v2\n */\n const viewRenderCb = function (view, element) {\n // we unselect the current event to keep consistency\n $scope.availability = null;\n $scope.availabilityDom = null;\n\n // mark the side panel as available to hide because no event is selected anymore\n $('label.calendar-admin-info').addClass('is-empty');\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n\n]);\n\n/**\n * Controller used in the slot creation modal window\n */\nApplication.Controllers.controller('CreateEventModalController', ['$scope', '$uibModalInstance', '$sce', 'moment', 'start', 'end', 'slots', 'machinesPromise', 'Availability', 'trainingsPromise', 'spacesPromise', 'tagsPromise', 'plansPromise', 'groupsPromise', 'slotDurationPromise', 'growl', '_t',\n function ($scope, $uibModalInstance, $sce, moment, start, end, slots, machinesPromise, Availability, trainingsPromise, spacesPromise, tagsPromise, plansPromise, groupsPromise, slotDurationPromise, growl, _t) {\n // $uibModal parameter\n $scope.start = start;\n\n // $uibModal parameter\n $scope.end = end;\n\n // machines list\n $scope.machines = machinesPromise.filter(function (m) { return !m.disabled && m.reservable; });\n\n // trainings list\n $scope.trainings = trainingsPromise.filter(function (t) { return !t.disabled; });\n\n // spaces list\n $scope.spaces = spacesPromise.filter(function (s) { return !s.disabled; });\n\n // all tags list\n $scope.tags = tagsPromise;\n\n $scope.isOnlySubscriptions = false;\n $scope.selectedPlans = [];\n $scope.selectedPlansBinding = {};\n // list of plans, classified by group\n $scope.plansClassifiedByGroup = [];\n\n // machines associated with the created slot\n $scope.selectedMachines = [];\n $scope.selectedMachinesBinding = {};\n\n // training associated with the created slot\n $scope.selectedTraining = null;\n\n // space associated with the created slot\n $scope.selectedSpace = null;\n\n // UI step\n $scope.step = 1;\n\n // the user is not able to edit the ending time of the availability, unless he set the type to 'training'\n $scope.endDateReadOnly = true;\n\n // timepickers configuration\n $scope.timepickers = {\n start: {\n hstep: 1,\n mstep: 5\n },\n end: {\n hstep: 1,\n mstep: 5\n }\n };\n\n // slot details\n $scope.availability = {\n start_at: start,\n end_at: end,\n available_type: $scope.$root.modules.machines ? 'machines' : undefined, // default to machines if enabled\n tag_ids: [],\n is_recurrent: false,\n period: 'week',\n nb_periods: 1,\n end_date: undefined, // recurrence end\n slot_duration: parseInt(slotDurationPromise.setting.value, 10)\n };\n\n // recurrent slots\n $scope.occurrences = [];\n\n // localized name(s) of the reservable item(s)\n $scope.reservableName = '';\n\n // localized name(s) of the selected tag(s)\n $scope.tagsName = '';\n\n // localized name(s) of the selected plan(s)\n $scope.plansName = '';\n\n // number of slots for this availability\n $scope.slots_nb = slots;\n\n /**\n * Adds or removes the provided machine from the current slot\n * @param machine {Object}\n */\n $scope.toggleSelection = function (machine) {\n const index = $scope.selectedMachines.indexOf(machine);\n if (index > -1) {\n return $scope.selectedMachines.splice(index, 1);\n } else {\n return $scope.selectedMachines.push(machine);\n }\n };\n\n /**\n * Select/unselect all the machines\n */\n $scope.toggleAll = function () {\n const count = $scope.selectedMachines.length;\n $scope.selectedMachines = [];\n $scope.selectedMachinesBinding = {};\n if (count === 0) {\n $scope.machines.forEach(function (machine) {\n $scope.selectedMachines.push(machine);\n $scope.selectedMachinesBinding[machine.id] = true;\n });\n }\n };\n\n /**\n * Adds or removes the provided plan from the current slot\n * @param plan {Object}\n */\n $scope.toggleSelectPlan = function (plan) {\n const index = $scope.selectedPlans.indexOf(plan);\n if (index > -1) {\n return $scope.selectedPlans.splice(index, 1);\n } else {\n return $scope.selectedPlans.push(plan);\n }\n };\n\n /**\n * Select/unselect all the plans\n */\n $scope.toggleAllPlans = function () {\n const count = $scope.selectedPlans.length;\n $scope.selectedPlans = [];\n $scope.selectedPlansBinding = {};\n if (count === 0) {\n plansPromise.filter(p => !p.disabled).forEach(function (plan) {\n $scope.selectedPlans.push(plan);\n $scope.selectedPlansBinding[plan.id] = true;\n });\n }\n };\n\n /**\n * Callback for the modal window validation: save the slot and closes the modal\n */\n $scope.ok = function () {\n if ($scope.availability.available_type === 'machines') {\n if ($scope.selectedMachines.length > 0) {\n $scope.availability.machine_ids = $scope.selectedMachines.map(function (m) { return m.id; });\n } else {\n growl.error(_t('app.admin.calendar.you_should_select_at_least_a_machine'));\n return;\n }\n } else if ($scope.availability.available_type === 'training') {\n $scope.availability.training_ids = [$scope.selectedTraining.id];\n } else if ($scope.availability.available_type === 'space') {\n $scope.availability.space_ids = [$scope.selectedSpace.id];\n }\n if ($scope.availability.is_recurrent) {\n $scope.availability.occurrences = $scope.occurrences;\n }\n if ($scope.isOnlySubscriptions && $scope.selectedPlans.length > 0) {\n $scope.availability.plan_ids = $scope.selectedPlans.map(function (p) { return p.id; });\n }\n return Availability.save(\n { availability: $scope.availability },\n function (availability) { $uibModalInstance.close(availability); }\n );\n };\n\n /**\n * Move the modal UI to the next step\n */\n $scope.next = function () {\n if ($scope.step === 1) { return validateType(); }\n if ($scope.step === 2) { return validateSelection(); }\n if ($scope.step === 3) { return validateTimes(); }\n if ($scope.step === 5) { return validateRecurrence(); }\n return $scope.step++;\n };\n\n /**\n * Move the modal UI to the next step\n */\n $scope.previous = function () { return $scope.step--; };\n\n /**\n * Callback to cancel the slot creation\n */\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n\n /**\n * For training/space availabilities, set the maximum number of people allowed registering on this slot.\n * Also, set the default slot duration\n */\n $scope.setNbTotalPlaces = function () {\n if ($scope.availability.available_type === 'training') {\n $scope.availability.nb_total_places = $scope.selectedTraining.nb_total_places;\n } else if ($scope.availability.available_type === 'space') {\n $scope.availability.nb_total_places = $scope.selectedSpace.default_places;\n }\n };\n\n /*\n * Test if the current availability type is divided in slots\n */\n $scope.isTypeDivided = function () {\n return isTypeDivided($scope.availability.available_type);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if ($scope.trainings.length > 0) {\n $scope.selectedTraining = $scope.trainings[0];\n }\n if ($scope.spaces.length > 0) {\n $scope.selectedSpace = $scope.spaces[0];\n }\n\n // when disable is only subscriptions option, reset all selected plans\n $scope.$watch('isOnlySubscriptions', function (value) {\n if (!value) {\n $scope.selectedPlans = [];\n $scope.selectedPlansBinding = {};\n }\n });\n\n // group plans by Group\n for (const group of groupsPromise.filter(g => !g.disabled)) {\n const groupObj = { id: group.id, name: group.name, plans: [] };\n for (const plan of plansPromise.filter(g => !g.disabled)) {\n if (plan.group_id === group.id) { groupObj.plans.push(plan); }\n }\n if (groupObj.plans.length > 0) {\n $scope.plansClassifiedByGroup.push(groupObj);\n }\n }\n\n // When the slot duration changes, we increment the availability to match the value\n $scope.$watch('availability.slot_duration', function (newValue, oldValue, scope) {\n if (newValue === undefined) return;\n\n const startSlot = moment($scope.start);\n startSlot.add(newValue * $scope.slots_nb, 'minutes');\n $scope.end = startSlot.toDate();\n });\n\n // When the number of slot changes, we increment the availability to match the value\n $scope.$watch('slots_nb', function (newValue, oldValue, scope) {\n const startSlot = moment($scope.start);\n startSlot.add($scope.availability.slot_duration * newValue, 'minutes');\n $scope.end = startSlot.toDate();\n });\n\n // When we configure a machine/space availability, do not let the user change the end time, as the total\n // time must be dividable by $scope.availability.slot_duration minutes (base slot duration). For training availabilities, the user\n // can configure any duration as it does not matters.\n $scope.$watch('availability.available_type', function (newValue, oldValue, scope) {\n if (isTypeDivided(newValue)) {\n $scope.endDateReadOnly = true;\n const slotDuration = $scope.availability.slot_duration || parseInt(slotDurationPromise.setting.value, 10);\n const slotsCurrentRange = Math.trunc(($scope.end.valueOf() - $scope.start.valueOf()) / (60 * 1000)) / slotDuration;\n if (!Number.isInteger(slotsCurrentRange)) {\n // otherwise, round it to upper decimal\n const upperSlots = Math.ceil(slotsCurrentRange);\n const upper = upperSlots * $scope.availability.slot_duration;\n $scope.end = moment($scope.start).add(upper, 'minutes').toDate();\n $scope.slots_nb = upperSlots;\n } else {\n $scope.slots_nb = slotsCurrentRange;\n }\n $scope.availability.end_at = $scope.end;\n } else {\n $scope.endDateReadOnly = false;\n }\n });\n\n // When the start date is changed, if we are configuring a machine/space availability,\n // maintain the relative length of the slot (ie. change the end time accordingly)\n $scope.$watch('start', function (newValue, oldValue, scope) {\n // adjust the end time\n const endSlot = moment($scope.end);\n endSlot.add(moment(newValue).diff(oldValue), 'milliseconds');\n $scope.end = endSlot.toDate();\n\n // update availability object\n $scope.availability.start_at = $scope.start;\n });\n\n // Maintain consistency between the end time and the date object in the availability object\n $scope.$watch('end', function (newValue, oldValue, scope) {\n if (newValue.valueOf() !== oldValue.valueOf()) {\n // we prevent the admin from setting the end of the availability before its beginning\n if (moment($scope.start).add($scope.availability.slot_duration, 'minutes').isAfter(newValue)) {\n $scope.end = oldValue;\n }\n // update availability object\n $scope.availability.end_at = $scope.end;\n }\n });\n };\n\n /*\n * Test if the provided availability type is divided in slots\n */\n const isTypeDivided = function (type) {\n return ((type === 'machines') || (type === 'space'));\n };\n\n /**\n * Validates that a machine or more was/were selected before continuing to step 3 (adjust time + tags)\n */\n const validateSelection = function () {\n if ($scope.availability.available_type === 'machines') {\n if ($scope.selectedMachines.length === 0) {\n return growl.error(_t('app.admin.calendar.you_should_select_at_least_a_machine'));\n }\n }\n $scope.step++;\n };\n\n /**\n * Validates that the slots/availability date and times are correct\n */\n const validateTimes = function () {\n if (moment($scope.end).isSameOrBefore($scope.start)) {\n return growl.error(_t('app.admin.calendar.inconsistent_times'));\n }\n if ($scope.isTypeDivided()) {\n if (!$scope.slots_nb) {\n return growl.error(_t('app.admin.calendar.min_one_slot'));\n }\n if (!$scope.availability.slot_duration) {\n return growl.error(_t('app.admin.calendar.min_slot_duration'));\n }\n }\n $scope.step++;\n };\n\n /**\n * Validates that the recurrence parameters were correctly set before continuing to step 5 (summary)\n */\n const validateRecurrence = function () {\n if ($scope.availability.is_recurrent) {\n if (!$scope.availability.period) {\n return growl.error(_t('app.admin.calendar.select_period'));\n }\n if (!$scope.availability.nb_periods || $scope.availability.nb_periods < 1) {\n return growl.error(_t('app.admin.calendar.select_nb_period'));\n }\n if (!$scope.availability.end_date) {\n return growl.error(_t('app.admin.calendar.select_end_date'));\n }\n }\n // settings are ok\n computeOccurrences();\n computeNames();\n $scope.step++;\n };\n\n /**\n * Initialize some settings, depending on the availability type, before continuing to step 2 (select a machine/training/space)\n */\n const validateType = function () {\n if ($scope.availability.available_type === null || $scope.availability.available_type === undefined) {\n return growl.error(_t('app.admin.calendar.select_type'));\n }\n $scope.setNbTotalPlaces();\n if ($scope.availability.available_type === 'training') {\n $scope.availability.slot_duration = undefined;\n } else {\n $scope.availability.slot_duration = parseInt(slotDurationPromise.setting.value, 10);\n }\n $scope.step++;\n };\n\n /**\n * Compute the various occurrences of the availability, according to the recurrence settings\n */\n const computeOccurrences = function () {\n $scope.occurrences = [];\n\n if ($scope.availability.is_recurrent) {\n const date = moment($scope.availability.start_at);\n const diff = moment($scope.availability.end_at).diff($scope.availability.start_at);\n const end = moment($scope.availability.end_date).endOf('day');\n while (date.isBefore(end)) {\n const occur_end = moment(date).add(diff, 'ms');\n $scope.occurrences.push({\n start_at: date.toDate(),\n end_at: occur_end.toDate()\n });\n date.add($scope.availability.nb_periods, $scope.availability.period);\n }\n } else {\n $scope.occurrences.push({\n start_at: $scope.availability.start_at,\n end_at: $scope.availability.end_at\n });\n }\n };\n\n const computeNames = function () {\n $scope.reservableName = '';\n switch ($scope.availability.available_type) {\n case 'machines':\n $scope.reservableName = localizedList($scope.selectedMachines);\n break;\n case 'training':\n $scope.reservableName = `${$scope.selectedTraining.name}`;\n break;\n case 'space':\n $scope.reservableName = `${$scope.selectedSpace.name}`;\n break;\n default:\n $scope.reservableName = `${_t('app.admin.calendar.none')}`;\n }\n const tags = $scope.tags.filter(function (t) {\n return $scope.availability.tag_ids.indexOf(t.id) > -1;\n });\n $scope.tagsName = localizedList(tags);\n if ($scope.isOnlySubscriptions && $scope.selectedPlans.length > 0) {\n $scope.plansName = localizedList($scope.selectedPlans, 'base_name');\n }\n };\n\n const localizedList = function (items, attr = 'name') {\n if (items.length === 0) return `${_t('app.admin.calendar.none')}`;\n\n const names = items.map(function (i) { return $sce.trustAsHtml(`${i[attr]}`); });\n if (items.length > 1) return names.slice(0, -1).join(', ') + ` ${_t('app.admin.calendar.and')} ` + names[names.length - 1];\n\n return names[0];\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the slot deletion modal window\n */\nApplication.Controllers.controller('DeleteRecurrentAvailabilityController', ['$scope', '$uibModalInstance', 'Availability', 'availabilityPromise', 'growl', '_t',\n function ($scope, $uibModalInstance, Availability, availabilityPromise, growl, _t) {\n // is the current slot (to be deleted) recurrent?\n $scope.isRecurrent = availabilityPromise.is_recurrent;\n\n // with recurrent slots: how many slots should we delete?\n $scope.deleteMode = 'single';\n\n /**\n * Confirmation callback\n */\n $scope.ok = function () {\n const { id, start_at, end_at } = availabilityPromise;\n // the admin has confirmed, delete the slot\n Availability.delete(\n { id, mode: $scope.deleteMode },\n function (res) {\n // delete success\n if (res.deleted > 1) {\n growl.success(_t(\n 'app.admin.calendar.slots_deleted',\n { START: moment(start_at).format('LL LT'), COUNT: res.deleted - 1 }\n ));\n } else {\n growl.success(_t(\n 'app.admin.calendar.slot_successfully_deleted',\n { START: moment(start_at).format('LL LT'), END: moment(end_at).format('LT') }\n ));\n }\n $uibModalInstance.close({\n status: 'success',\n availabilities: res.details.map(function (d) { return d.availability.id; })\n });\n },\n function (res) {\n // not everything was deleted\n const { data } = res;\n if (data.total > 1) {\n growl.warning(_t(\n 'app.admin.calendar.slots_not_deleted',\n { TOTAL: data.total, COUNT: data.total - data.deleted }\n ));\n } else {\n growl.error(_t(\n 'app.admin.calendar.unable_to_delete_the_slot',\n { START: moment(start_at).format('LL LT'), END: moment(end_at).format('LT') }\n ));\n }\n $uibModalInstance.close({\n status: 'failed',\n availabilities: data.details.filter(function (d) { return d.status; }).map(function (d) { return d.availability.id; })\n });\n });\n };\n\n /**\n * Cancellation callback\n */\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }\n]);\n\n/**\n * Controller used in the iCalendar (ICS) imports management page\n */\n\nApplication.Controllers.controller('AdminICalendarController', ['$scope', 'iCalendars', 'ICalendar', 'dialogs', 'growl', '_t',\n function ($scope, iCalendars, ICalendar, dialogs, growl, _t) {\n // list of ICS sources\n $scope.calendars = iCalendars;\n\n // configuration of a new ICS source\n $scope.newCalendar = {\n color: undefined,\n text_color: undefined,\n url: undefined,\n name: undefined,\n text_hidden: false\n };\n\n /**\n * Save the new iCalendar in database\n */\n $scope.save = function () {\n ICalendar.save({}, { i_calendar: $scope.newCalendar }, function (data) {\n // success\n $scope.calendars.push(data);\n $scope.newCalendar.url = undefined;\n $scope.newCalendar.name = undefined;\n $scope.newCalendar.color = null;\n $scope.newCalendar.text_color = null;\n $scope.newCalendar.text_hidden = false;\n }, function (error) {\n // failed\n growl.error(_t('app.admin.icalendar.create_error'));\n console.error(error);\n });\n };\n\n /**\n * Return a CSS-like style of the given calendar configuration\n * @param calendar\n */\n $scope.calendarStyle = function (calendar) {\n return {\n 'border-color': calendar.color,\n color: calendar.text_color,\n width: calendar.text_hidden ? '50px' : 'auto',\n height: calendar.text_hidden ? '21px' : 'auto'\n };\n };\n\n /**\n * Delete the given calendar from the database\n * @param calendar\n */\n $scope.delete = function (calendar) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.icalendar.confirmation_required'),\n msg: _t('app.admin.icalendar.confirm_delete_import')\n };\n }\n }\n },\n function () {\n ICalendar.delete(\n { id: calendar.id },\n function () {\n // success\n const idx = $scope.calendars.indexOf(calendar);\n $scope.calendars.splice(idx, 1);\n growl.info(_t('app.admin.icalendar.delete_success'));\n }, function (error) {\n // failed\n growl.error(_t('app.admin.icalendar.delete_failed'));\n console.error(error);\n }\n );\n }\n );\n };\n\n /**\n * Asynchronously re-fetches the events from the given calendar\n * @param calendar\n */\n $scope.sync = function (calendar) {\n ICalendar.sync(\n { id: calendar.id },\n function () {\n // success\n growl.info(_t('app.admin.icalendar.refresh'));\n }, function (error) {\n // failed\n growl.error(_t('app.admin.icalendar.sync_failed'));\n console.error(error);\n }\n );\n };\n }\n]);\n","/* COMMON CODE */\n\n// The validity per user defines how many time a user may ba able to use the same coupon\n// Here are the various options for this parameter\nconst VALIDITIES = ['once', 'forever'];\n\n/**\n * Controller used in the coupon creation page\n */\nApplication.Controllers.controller('NewCouponController', ['$scope', '$state', 'Coupon', 'growl', '_t',\n function ($scope, $state, Coupon, growl, _t) {\n // Values for the coupon currently created\n $scope.coupon = {\n active: true,\n type: 'percent_off'\n };\n\n // Options for the validity per user\n $scope.validities = VALIDITIES;\n\n // Default parameters for AngularUI-Bootstrap datepicker (used for coupon validity limit selection)\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: moment().toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Return a localized human-readable name for the provided validity\n */\n $scope.validityName = function (validity) {\n return _t(`app.shared.coupon.${validity}`);\n };\n\n /**\n * Shows/hides the validity limit datepicker\n * @param $event {Object} jQuery event object\n */\n $scope.toggleDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n $scope.datePicker.opened = !$scope.datePicker.opened;\n };\n\n /**\n * Callback to save the new coupon in $scope.coupon and redirect the user to the listing page\n */\n $scope.saveCoupon = () =>\n Coupon.save({ coupon: $scope.coupon }, coupon => $state.go('app.admin.pricing')\n , function (err) {\n growl.error(_t('app.admin.coupons_new.unable_to_create_the_coupon_check_code_already_used'));\n console.error(err);\n });\n }\n]);\n\n/**\n * Controller used in the coupon edition page\n */\nApplication.Controllers.controller('EditCouponController', ['$scope', '$state', 'Coupon', 'couponPromise', '_t', 'growl',\n function ($scope, $state, Coupon, couponPromise, _t, growl) {\n /* PUBLIC SCOPE */\n\n // Used in the form to freeze unmodifiable fields\n $scope.mode = 'EDIT';\n\n // Coupon to edit\n $scope.coupon = couponPromise;\n\n // Options for the validity per user\n $scope.validities = VALIDITIES;\n\n // Mapping for validation errors\n $scope.errors = {};\n\n // Default parameters for AngularUI-Bootstrap datepicker (used for coupon validity limit selection)\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: moment().toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Return a localized human-readable name for the provided validity\n */\n $scope.validityName = function (validity) {\n return _t(`app.shared.coupon.${validity}`);\n };\n\n /**\n * Shows/hides the validity limit datepicker\n * @param $event {Object} jQuery event object\n */\n $scope.toggleDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n $scope.datePicker.opened = !$scope.datePicker.opened;\n };\n\n /**\n * Callback to save the coupon's changes to the API\n */\n $scope.updateCoupon = function () {\n $scope.errors = {};\n Coupon.update({ id: $scope.coupon.id }, { coupon: $scope.coupon }, coupon => $state.go('app.admin.pricing')\n , function (err) {\n growl.error(_t('app.admin.coupons_edit.unable_to_update_the_coupon_an_error_occurred'));\n $scope.errors = err.data;\n });\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // parse the date if any\n if (couponPromise.valid_until) {\n $scope.coupon.valid_until = moment(couponPromise.valid_until).toDate();\n }\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n camelcase,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/* COMMON CODE */\n\n/**\n * Provides a set of common properties and methods to the $scope parameter. They are used\n * in the various events' admin controllers.\n *\n * Provides :\n * - $scope.datePicker = {}\n * - $scope.event_themes = []\n * - $scope.submited(content)\n * - $scope.cancel()\n * - $scope.addFile()\n * - $scope.deleteFile(file)\n * - $scope.fileinputClass(v)\n * - $scope.toggleStartDatePicker($event)\n * - $scope.toggleEndDatePicker($event)\n * - $scope.toggleRecurrenceEnd(e)\n * - $scope.addPrice()\n * - $scope.removePrice(price, $event)\n * - $scope.handleEventChange(?)\n *\n * Requires :\n * - $scope.event.event_files_attributes = []\n * - $scope.event.\n * - $state (Ui-Router) [ 'app.public.events_list' ]\n */\nclass EventsController {\n constructor ($scope, $state) {\n /**\n * Changes the user's view to the events list page\n */\n $scope.cancel = function () { $state.go('app.public.events_list'); };\n }\n}\n\n/**\n * Controller used in the events listing page (admin view)\n */\nApplication.Controllers.controller('AdminEventsController', ['$scope', '$state', 'dialogs', '$uibModal', 'growl', 'AuthService', 'Event', 'Category', 'EventTheme', 'AgeRange', 'PriceCategory', 'eventsPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t', 'Member', 'uiTourService', 'settingsPromise', '$uiRouter',\n function ($scope, $state, dialogs, $uibModal, growl, AuthService, Event, Category, EventTheme, AgeRange, PriceCategory, eventsPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t, Member, uiTourService, settingsPromise, $uiRouter) {\n /* PUBLIC SCOPE */\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n // the following item is used by the UnsavedFormAlert component to detect a page change\n $scope.uiRouter = $uiRouter;\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n growl.error(message);\n };\n\n // By default, the pagination mode is activated to limit the page size\n $scope.paginateActive = true;\n\n // The events displayed on the page\n $scope.events = eventsPromise;\n\n // Current virtual page\n $scope.page = 1;\n\n // Temporary datastore for creating new elements\n $scope.inserted = {\n category: null,\n theme: null,\n age_range: null\n };\n\n // List of categories for the events\n $scope.categories = categoriesPromise;\n\n // List of events themes\n $scope.themes = themesPromise;\n\n // List of age ranges\n $scope.ageRanges = ageRangesPromise;\n\n // List of price categories for the events\n $scope.priceCategories = priceCategoriesPromise;\n\n // Default: we display all events (no restriction)\n $scope.eventsScope =\n { selected: '' };\n\n // default tab: events list\n $scope.tabs = { active: 1 };\n\n /**\n * Adds a bucket of events to the bottom of the page, grouped by month\n */\n $scope.loadMoreEvents = function () {\n $scope.page += 1;\n return Event.query({ page: $scope.page, scope: $scope.eventsScope.selected }, function (data) {\n $scope.events = $scope.events.concat(data);\n return paginationCheck(data, $scope.events);\n });\n };\n\n /**\n * Saves a new element / Update an existing one to the server (form validation callback)\n * @param model {string} model name\n * @param data {Object} element name\n * @param [id] {number} element id, in case of update\n */\n $scope.saveElement = function (model, data, id) {\n if (id != null) {\n return getModel(model)[0].update({ id }, data);\n } else {\n return getModel(model)[0].save(data, function (resp) { getModel(model)[1][getModel(model)[1].length - 1].id = resp.id; });\n }\n };\n\n /**\n * Deletes the element at the specified index\n * @param model {string} model name\n * @param index {number} element index in the $scope[model] array\n */\n $scope.removeElement = function (model, index) {\n if ((model === 'category') && (getModel(model)[1].length === 1)) {\n growl.error(_t('app.admin.events.at_least_one_category_is_required') + ' ' + _t('app.admin.events.unable_to_delete_the_last_one'));\n return false;\n }\n if (getModel(model)[1][index].related_to > 0) {\n growl.error(_t('app.admin.events.unable_to_delete_ELEMENT_already_in_use_NUMBER_times', { ELEMENT: model, NUMBER: getModel(model)[1][index].related_to }));\n return false;\n }\n return dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.events.confirmation_required'),\n msg: _t('app.admin.events.do_you_really_want_to_delete_this_ELEMENT', { ELEMENT: model })\n };\n }\n }\n }\n , function () { // delete confirmed\n getModel(model)[0].delete(getModel(model)[1][index], null, function () { getModel(model)[1].splice(index, 1); }\n , function () { growl.error(_t('app.admin.events.unable_to_delete_an_error_occured')); });\n });\n };\n\n /**\n * Creates a new empty entry in the $scope[model] array\n * @param model {string} model name\n */\n $scope.addElement = function (model) {\n $scope.inserted[model] = {\n name: '',\n related_to: 0\n };\n return getModel(model)[1].push($scope.inserted[model]);\n };\n\n /**\n * Removes the newly inserted but not saved element / Cancel the current element modification\n * @param model {string} model name\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} element index in the $scope[model] array\n */\n $scope.cancelElement = function (model, rowform, index) {\n if (getModel(model)[1][index].id != null) {\n return rowform.$cancel();\n } else {\n return getModel(model)[1].splice(index, 1);\n }\n };\n\n /**\n * Open a modal dialog allowing the definition of a new price category.\n * Save it once filled and handle the result.\n */\n $scope.newPriceCategory = function () {\n $uibModal.open({\n templateUrl: '/admin/events/price_form.html',\n size: 'md',\n resolve: {\n category () { return {}; }\n },\n controller: 'PriceCategoryController'\n }).result.finally(null).then(function (p_cat) {\n // save the price category to the API\n PriceCategory.save(p_cat, function (cat) {\n $scope.priceCategories.push(cat);\n return growl.success(_t('app.admin.events.price_category_successfully_created'));\n }\n , function (err) {\n growl.error(_t('app.admin.events.unable_to_add_the_price_category_check_name_already_used'));\n return console.error(err);\n });\n });\n };\n /**\n * Update the given price category with the new properties\n * to specify in a modal dialog\n * @param index {number} index of the caterory in the $scope.priceCategories array\n * @param id {number} price category ID, must match the ID of the category at the index specified above\n */\n $scope.editPriceCategory = function (id, index) {\n if ($scope.priceCategories[index].id !== id) {\n return growl.error(_t('app.admin.events.unexpected_error_occurred_please_refresh'));\n } else {\n return $uibModal.open({\n templateUrl: '/admin/events/price_form.html',\n size: 'md',\n resolve: {\n category () { return $scope.priceCategories[index]; }\n },\n controller: 'PriceCategoryController'\n }).result.finally(null).then(function (p_cat) {\n // update the price category to the API\n PriceCategory.update({ id }, { price_category: p_cat }, function (cat) {\n $scope.priceCategories[index] = cat;\n return growl.success(_t('app.admin.events.price_category_successfully_updated'));\n }\n , function (err) {\n growl.error(_t('app.admin.events.unable_to_update_the_price_category'));\n return console.error(err);\n });\n });\n }\n };\n\n /**\n * Delete the given price category from the API\n * @param index {number} index of the caterory in the $scope.priceCategories array\n * @param id {number} price category ID, must match the ID of the category at the index specified above\n */\n $scope.removePriceCategory = function (id, index) {\n if ($scope.priceCategories[index].id !== id) {\n return growl.error(_t('app.admin.events.unexpected_error_occurred_please_refresh'));\n } else if ($scope.priceCategories[index].events > 0) {\n return growl.error(_t('app.admin.events.unable_to_delete_this_price_category_because_it_is_already_used'));\n } else {\n return dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.events.confirmation_required'),\n msg: _t('app.admin.events.do_you_really_want_to_delete_this_price_category')\n };\n }\n }\n },\n function () { // delete confirmed\n PriceCategory.remove(\n { id },\n function () { // successfully deleted\n growl.success(_t('app.admin.events.price_category_successfully_deleted'));\n $scope.priceCategories.splice(index, 1);\n },\n function () { growl.error(_t('app.admin.events.price_category_deletion_failed')); }\n );\n }\n );\n }\n };\n\n /**\n * Triggered when the admin changes the events filter (all, passed, future).\n * We request the first page of corresponding events to the API\n */\n $scope.changeScope = function () {\n Event.query({ page: 1, scope: $scope.eventsScope.selected }, function (data) {\n $scope.events = data;\n return paginationCheck(data, $scope.events);\n });\n return $scope.page = 1;\n };\n\n /**\n * Setup the feature-tour for the admin/events page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupEventsTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('events');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.events.welcome.title'),\n content: _t('app.admin.tour.events.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.events-management .events-list',\n stepId: 'list',\n order: 1,\n title: _t('app.admin.tour.events.list.title'),\n content: _t('app.admin.tour.events.list.content'),\n placement: 'top'\n });\n uitour.createStep({\n selector: '.events-management .events-list-filter',\n stepId: 'filter',\n order: 2,\n title: _t('app.admin.tour.events.filter.title'),\n content: _t('app.admin.tour.events.filter.content'),\n placement: 'bottom'\n });\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: '.events-management .events-categories',\n stepId: 'categories',\n order: 3,\n title: _t('app.admin.tour.events.categories.title'),\n content: _t('app.admin.tour.events.categories.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.events-management .events-themes',\n stepId: 'themes',\n order: 4,\n title: _t('app.admin.tour.events.themes.title'),\n content: _t('app.admin.tour.events.themes.content'),\n placement: 'top'\n });\n uitour.createStep({\n selector: '.events-management .events-age-ranges',\n stepId: 'ages',\n order: 5,\n title: _t('app.admin.tour.events.ages.title'),\n content: _t('app.admin.tour.events.ages.content'),\n placement: 'top'\n });\n uitour.createStep({\n selector: '.events-management .prices-tab',\n stepId: 'prices',\n order: 6,\n title: _t('app.admin.tour.events.prices.title'),\n content: _t('app.admin.tour.events.prices.content'),\n placement: 'bottom'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 7,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on step change, change the active tab if needed\n uitour.on('stepChanged', function (nextStep) {\n if (nextStep.stepId === 'list' || nextStep.stepId === 'filter') { $scope.tabs.active = 0; }\n if (nextStep.stepId === 'categories' || nextStep.stepId === 'ages') { $scope.tabs.active = 1; }\n if (nextStep.stepId === 'prices') { $scope.tabs.active = 2; }\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('events') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'events' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('events') < 0) {\n uitour.start();\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n paginationCheck(eventsPromise, $scope.events);\n };\n\n /**\n * Check if all events are already displayed OR if the button 'load more events'\n * is required\n * @param lastEvents {Array} last events loaded onto the diplay (ie. last \"page\")\n * @param events {Array} full list of events displayed on the page (not only the last retrieved)\n */\n const paginationCheck = function (lastEvents, events) {\n if (lastEvents.length > 0) {\n if (events.length >= lastEvents[0].nb_total_events) {\n return $scope.paginateActive = false;\n } else {\n return $scope.paginateActive = true;\n }\n } else {\n return $scope.paginateActive = false;\n }\n };\n\n /**\n * Return the model and the datastore matching the given name\n * @param name {string} 'category', 'theme' or 'age_range'\n * @return {[Object, Array]} model and datastore\n */\n const getModel = function (name) {\n switch (name) {\n case 'category': return [Category, $scope.categories];\n case 'theme': return [EventTheme, $scope.themes];\n case 'age_range': return [AgeRange, $scope.ageRanges];\n default: return [null, []];\n }\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n\n/**\n * Controller used in the reservations listing page for a specific event\n */\nApplication.Controllers.controller('ShowEventReservationsController', ['$scope', 'eventPromise', 'reservationsPromise', function ($scope, eventPromise, reservationsPromise) {\n // retrieve the event from the ID provided in the current URL\n $scope.event = eventPromise;\n\n // list of reservations for the current event\n $scope.reservations = reservationsPromise;\n\n /**\n * Test if the provided reservation has been cancelled\n * @param reservation {Reservation}\n * @returns {boolean}\n */\n $scope.isCancelled = function (reservation) {\n return !!(reservation.slots_reservations_attributes[0].canceled_at);\n };\n}]);\n\n/**\n * Controller used in the event creation page\n */\nApplication.Controllers.controller('NewEventController', ['$scope', '$state', 'CSRF', 'growl',\n function ($scope, $state, CSRF, growl) {\n CSRF.setMetaTags();\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n // Using the EventsController\n return new EventsController($scope, $state);\n }\n]);\n\n/**\n * Controller used in the events edition page\n */\nApplication.Controllers.controller('EditEventController', ['$scope', '$state', 'CSRF', 'eventPromise', 'growl',\n function ($scope, $state, CSRF, eventPromise, growl) {\n /* PUBLIC SCOPE */\n\n // Retrieve the event details, in case of error the user is redirected to the events listing\n $scope.event = cleanEvent(eventPromise);\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n // Using the EventsController\n return new EventsController($scope, $state);\n };\n\n // prepare the event for the react-hook-form\n function cleanEvent (event) {\n delete event.$promise;\n delete event.$resolved;\n return event;\n }\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the event edit-mode modal window\n */\nApplication.Controllers.controller('EditRecurrentEventController', ['$scope', '$uibModalInstance', 'editMode', 'growl', 'initialDates', 'currentEvent', '_t',\n function ($scope, $uibModalInstance, editMode, growl, initialDates, currentEvent, _t) {\n // with recurrent slots: how many slots should we update?\n $scope.editMode = editMode;\n\n /**\n * Confirmation callback\n */\n $scope.ok = function () {\n $uibModalInstance.close({\n editMode: $scope.editMode\n });\n };\n\n /**\n * Test if any of the dates of the event has changed\n */\n $scope.hasDateChanged = function () {\n return (!moment(initialDates.start).isSame(currentEvent.start_date, 'day') || !moment(initialDates.end).isSame(currentEvent.end_date, 'day'));\n };\n\n /**\n * Cancellation callback\n */\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }\n]);\n","/* eslint-disable\n camelcase,\n no-return-assign,\n no-undef,\n no-unreachable,\n no-unused-vars,\n n/no-callback-literal,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS205: Consider reworking code to avoid use of IIFEs\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Controllers.controller('GraphsController', ['$scope', '$state', '$rootScope', '$transitions', 'es', 'Statistics', '_t',\n function ($scope, $state, $rootScope, $transitions, es, Statistics, _t) {\n /* PRIVATE STATIC CONSTANTS */\n\n // height of the HTML/SVG charts elements in pixels\n const CHART_HEIGHT = 500;\n\n // Label of the charts' horizontal axes\n const X_AXIS_LABEL = _t('app.admin.stats_graphs.date');\n\n // Label of the charts' vertical axes\n const Y_AXIS_LABEL = _t('app.admin.stats_graphs.number');\n\n // Colors for the line charts. Each new line uses the next color in this array\n const CHART_COLORS = ['#b35a94', '#1c5794', '#00b49e', '#6fac48', '#ebcf4a', '#fd7e33', '#ca3436', '#a26e3a'];\n\n /* PUBLIC SCOPE */\n\n // ui-view transitions optimization: if true, the charts will never be refreshed\n $scope.preventRefresh = false;\n\n // statistics structure in elasticSearch\n $scope.statistics = [];\n\n // statistics data recovered from elasticSearch\n $scope.data = null;\n\n // default interval: one day\n $scope.display =\n { interval: 'week' };\n\n // active tab will be set here\n $scope.selectedIndex = null;\n\n // ui-bootstrap active tab index\n $scope.selectedTab = 0;\n\n // for palmares graphs, filters values are stored here\n $scope.ranking = {\n sortCriterion: 'ca',\n groupCriterion: 'subType'\n };\n\n // default: we do not open the datepicker menu\n $scope.datePicker =\n { show: false };\n\n // datePicker parameters for interval beginning\n $scope.datePickerStart = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: null,\n maxDate: moment().subtract(1, 'day').toDate(),\n selected: moment().utc().subtract(1, 'months').subtract(1, 'day').startOf('day').toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n // datePicker parameters for interval ending\n $scope.datePickerEnd = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: null,\n maxDate: moment().subtract(1, 'day').toDate(),\n selected: moment().subtract(1, 'day').endOf('day').toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Callback to open the datepicker (interval start)\n * @param {Object} jQuery event object\n */\n $scope.toggleStartDatePicker = $event => toggleDatePicker($event, $scope.datePickerStart);\n\n /**\n * Callback to open the datepicker (interval end)\n * @param {Object} jQuery event object\n */\n $scope.toggleEndDatePicker = $event => toggleDatePicker($event, $scope.datePickerEnd);\n\n /**\n * Callback called when the active tab is changed.\n * Recover the current tab and store its value in $scope.selectedIndex\n * @param tab {Object} elasticsearch statistic structure\n * @param index {number} index of the tab in the $scope.statistics array\n */\n $scope.setActiveTab = function (tab, index) {\n $scope.selectedIndex = tab;\n $scope.selectedTab = index;\n $scope.ranking.groupCriterion = 'subType';\n if (tab.ca) {\n $scope.ranking.sortCriterion = 'ca';\n } else {\n $scope.ranking.sortCriterion = tab.types[0].key;\n }\n return refreshChart();\n };\n\n /**\n * Returns true if the provided tab must be hidden due to some global or local configuration\n * @param tab {Object} elasticsearch statistic structure (from statistic_indices table)\n */\n $scope.hiddenTab = function (tab) {\n if (tab.graph) {\n return !((tab.es_type_key === 'subscription' && !$rootScope.modules.plans) ||\n (tab.es_type_key === 'training' && !$rootScope.modules.trainings) ||\n (tab.es_type_key === 'machine' && !$rootScope.modules.machines));\n }\n return false;\n };\n\n /**\n * Callback to close the date-picking popup and refresh the results\n */\n $scope.validateDateChange = function () {\n $scope.datePicker.show = false;\n return refreshChart();\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n Statistics.query(function (stats) {\n $scope.statistics = stats;\n // watch the interval changes to refresh the graph\n $scope.$watch(scope => scope.display.interval\n , (newValue, oldValue) => refreshChart());\n $scope.$watch(scope => scope.ranking.sortCriterion\n , (newValue, oldValue) => refreshChart());\n $scope.$watch(scope => scope.ranking.groupCriterion\n , (newValue, oldValue) => refreshChart());\n return refreshChart();\n\n // set the default tab to \"machines\" if \"subscriptions\" are disabled\n if (!$rootScope.modules.plans) {\n const idx = $scope.statistics.findIndex(s => s.es_type_key === 'machine');\n $scope.setActiveTab($scope.statistics[idx], idx);\n } else {\n const idx = $scope.statistics.findIndex(s => s.es_type_key === 'subscription');\n $scope.setActiveTab($scope.statistics[idx], idx);\n }\n });\n\n // workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected\n // which will cause every tabs to reload, one by one, when the view is closed\n $transitions.onStart({ to: 'app.admin.stats_graphs' }, function (trans) {\n if (Object.keys(trans.from().params).length === 0) {\n return $scope.preventRefresh = true;\n }\n });\n };\n\n /**\n * Generic function to toggle a bootstrap datePicker\n * @param $event {Object} jQuery event object\n * @param datePicker {Object} settings object of the concerned datepicker. Must have an 'opened' property\n */\n const toggleDatePicker = function ($event, datePicker) {\n $event.preventDefault();\n $event.stopPropagation();\n return datePicker.opened = !datePicker.opened;\n };\n\n /**\n * Query elasticSearch according to the current parameters and update the chart\n */\n const refreshChart = function () {\n if ($scope.selectedIndex && !$scope.preventRefresh) {\n return query($scope.selectedIndex, function (aggregations, error) {\n if (error) {\n return console.error(error);\n } else {\n if ($scope.selectedIndex.graph.chart_type !== 'discreteBarChart') {\n $scope.data = formatAggregations(aggregations);\n return angular.forEach($scope.data, (datum, key) => updateChart($scope.selectedIndex.graph.chart_type, datum, key));\n } else {\n $scope.data = formatRankingAggregations(aggregations, $scope.selectedIndex.graph.limit, $scope.ranking.groupCriterion);\n return updateChart($scope.selectedIndex.graph.chart_type, $scope.data.ranking, $scope.selectedIndex.es_type_key);\n }\n }\n });\n }\n };\n\n /**\n * Callback used in NVD3 to print timestamps as literal dates on the X axis\n */\n const xAxisTickFormatFunction = function (d, x, y) {\n /* WARNING !! These tests (typeof/instanceof) may become broken on nvd3 update */\n if ($scope.display.interval === 'day') {\n if ((typeof d === 'number') || d instanceof Date) {\n return d3.time.format(Fablab.d3DateFormat)(moment(d).toDate());\n } else { // typeof d == 'string'\n return d;\n }\n } else if ($scope.display.interval === 'week') {\n if ((typeof x === 'number') || d instanceof Date) {\n return d3.time.format(_t('app.admin.stats_graphs.week_short') + ' %U')(moment(d).toDate());\n } else if (typeof d === 'number') {\n return _t('app.admin.stats_graphs.week_of_START_to_END', { START: moment(d).format('L'), END: moment(d).add(6, 'days').format('L') });\n } else { // typeof d == 'string'\n return d;\n }\n } else if ($scope.display.interval === 'month') {\n if (typeof d === 'number') {\n const label = moment(d).format('MMMM YYYY');\n return label.substr(0, 1).toUpperCase() + label.substr(1).toLowerCase();\n } else { // typeof d == 'string'\n return d;\n }\n }\n };\n\n /**\n * Format aggregations as retuned by elasticSearch to an understandable format for NVD3\n * @param aggs {Object} as returned by elasticsearch\n */\n const formatAggregations = function (aggs) {\n const format = {};\n\n angular.forEach(aggs, function (type, type_key) { // go through aggs[$TYPE] where $TYPE = month|year|hour|booking|...\n format[type_key] = [];\n if (type.subgroups) {\n return angular.forEach(type.subgroups.buckets, subgroup => // go through aggs.$TYPE.subgroups.buckets where each bucket represent a $SUBTYPE\n angular.forEach($scope.selectedIndex.types, function (cur_type) { // in the mean time, go through the types of the current index (active tab) ...\n if (cur_type.key === type_key) { // ... looking for the type matching $TYPE\n return (() => {\n const result = [];\n for (let it_st = 0, end = cur_type.subtypes.length - 1; it_st <= end; it_st++) { // when we've found it, iterate over its subtypes ...\n const cur_subtype = cur_type.subtypes[it_st];\n if (subgroup.key === cur_subtype.key) { // ... which match $SUBTYPE\n // then we construct NVD3 dataSource according to these information\n const dataSource = {\n values: [],\n key: cur_subtype.label,\n total: 0,\n color: CHART_COLORS[it_st],\n area: true\n };\n // finally, we iterate over 'intervals' buckets witch contains\n // per date aggregations for our current dataSource\n angular.forEach(subgroup.intervals.buckets, function (interval) {\n dataSource.values.push({\n x: interval.key,\n y: interval.total.value\n });\n return dataSource.total += parseInt(interval.total.value);\n });\n dataSource.key += ` (${dataSource.total})`;\n result.push(format[type_key].push(dataSource));\n } else {\n result.push(undefined);\n }\n }\n return result;\n })();\n }\n })\n );\n }\n });\n return format;\n };\n\n /**\n * Format aggregations for ranking charts to an understandable format for NVD3\n * @param aggs {Object} as returned by elasticsearch\n * @param limit {number} limit the number of stats in the bar chart\n * @param typeKey {String} field name witch results are grouped by\n */\n const formatRankingAggregations = function (aggs, limit, typeKey) {\n const format =\n { ranking: [] };\n\n let it = 0;\n while (it < aggs.subgroups.buckets.length) {\n const bucket = aggs.subgroups.buckets[it];\n const dataSource = {\n values: [],\n key: getRankingLabel(bucket.key, typeKey),\n color: CHART_COLORS[it],\n area: true\n };\n dataSource.values.push({\n x: getRankingLabel(bucket.key, typeKey),\n y: bucket.total.value\n });\n format.ranking.push(dataSource);\n it++;\n }\n const getY = object => object.values[0].y;\n format.ranking = stableSort(format.ranking, 'DESC', getY).slice(0, limit);\n for (let i = 0, end = format.ranking.length; i <= end; i++) {\n if (typeof format.ranking[i] === 'undefined') { format.ranking.splice(i, 1); }\n }\n return format;\n };\n\n /**\n * For BarCharts, return the label for a given bar\n * @param key {string} raw value of the label\n * @param typeKey {string} name of the field the results are grouped by\n */\n const getRankingLabel = function (key, typeKey) {\n if ($scope.selectedIndex) {\n if (typeKey === 'subType') {\n for (const type of Array.from($scope.selectedIndex.types)) {\n for (const subtype of Array.from(type.subtypes)) {\n if (subtype.key === key) {\n return subtype.label;\n }\n }\n }\n } else {\n for (const field of Array.from($scope.selectedIndex.additional_fields)) {\n if (field.key === typeKey) {\n switch (field.data_type) {\n case 'date': return moment(key).format('LL'); break;\n case 'list': return key.name; break;\n default: return key;\n }\n }\n }\n }\n }\n };\n\n /**\n * Prepare the elasticSearch query for the stats matching the current controller's parameters\n * @param index {{id:{number}, es_type_key:{string}, label:{string}, table:{boolean}, additional_fields:{Array},\n * types:{Array}, graph:{Object}}} elasticSearch type in stats index to query\n * @param callback {function} function be to run after results were retrieved,\n * it will receive two parameters : results {Array}, error {String} (if any)\n */\n const query = function (index, callback) {\n // invalid callback handeling\n if (typeof (callback) !== 'function') {\n console.error('[graphsController::query] Error: invalid callback provided');\n return;\n }\n if (!index) {\n callback([], '[graphsController::query] Error: invalid index provided');\n return;\n }\n\n if (index.graph.chart_type !== 'discreteBarChart') {\n // list statistics types\n const stat_types = [];\n for (const t of Array.from(index.types)) {\n if (t.graph) {\n stat_types.push(t.key);\n }\n }\n\n // exception handeling\n if (stat_types.length === 0) {\n callback([], 'Error: Unable to retrieve any graphical statistic types in the provided index');\n }\n\n let type_it = 0;\n const results = {};\n let error = '';\n const recursiveCb = function () {\n if (type_it < stat_types.length) {\n return queryElasticStats(index.es_type_key, stat_types[type_it], function (prevResults, prevError) {\n if (prevError) {\n console.error(`[graphsController::query] ${prevError}`);\n error += `\\n${prevError}`;\n }\n results[stat_types[type_it]] = prevResults;\n type_it++;\n return recursiveCb();\n });\n } else {\n return callback(results);\n }\n };\n return recursiveCb();\n } else { // palmares (ranking)\n return queryElasticRanking(index.es_type_key, $scope.ranking.groupCriterion, $scope.ranking.sortCriterion, function (results, error) {\n if (error) {\n return callback([], error);\n } else {\n return callback(results);\n }\n });\n }\n };\n\n /**\n * Run the elasticSearch query to retreive the /stats/type aggregations\n * @param esType {String} elasticSearch document type (subscription|machine|training|...)\n * @param statType {String} statistics type (year|month|hour|booking|...)\n * @param callback {function} function be to run after results were retrieved,\n * it will receive two parameters : results {Array}, error {String} (if any)\n */\n const queryElasticStats = function (esType, statType, callback) {\n // handle invalid callback\n if (typeof (callback) !== 'function') {\n console.error('[graphsController::queryElasticStats] Error: invalid callback provided');\n return;\n }\n if (!esType || !statType) {\n callback([], '[graphsController::queryElasticStats] Error: invalid parameters provided');\n }\n\n // run query\n return es.search({\n index: 'stats',\n type: esType,\n searchType: 'query_then_fetch',\n size: 0,\n 'stat-type': statType,\n 'custom-query': '',\n 'start-date': moment($scope.datePickerStart.selected).format(),\n 'end-date': moment($scope.datePickerEnd.selected).format(),\n body: buildElasticAggregationsQuery(statType, $scope.display.interval, moment($scope.datePickerStart.selected), moment($scope.datePickerEnd.selected))\n }\n , function (error, response) {\n if (error) {\n return callback([], `Error: something unexpected occurred during elasticSearch query: ${error}`);\n } else {\n return callback(response.aggregations);\n }\n });\n };\n\n /**\n * For ranking displays, run the elasticSearch query to retreive the /stats/type aggregations\n * @param esType {string} elasticSearch document type (subscription|machine|training|...)\n * @param groupKey {string} statistics subtype or custom field\n * @param sortKey {string} statistics type or 'ca'\n * @param callback {function} function be to run after results were retrieved,\n * it will receive two parameters : results {Array}, error {String} (if any)\n */\n const queryElasticRanking = function (esType, groupKey, sortKey, callback) {\n // handle invalid callback\n if (typeof (callback) !== 'function') {\n return console.error('[graphsController::queryElasticRanking] Error: invalid callback provided');\n }\n if (!esType || !groupKey || !sortKey) {\n return callback([], '[graphsController::queryElasticRanking] Error: invalid parameters provided');\n }\n\n // run query\n return es.search({\n index: 'stats',\n type: esType,\n searchType: 'query_then_fetch',\n size: 0,\n body: buildElasticAggregationsRankingQuery(groupKey, sortKey, moment($scope.datePickerStart.selected), moment($scope.datePickerEnd.selected))\n }\n , function (error, response) {\n if (error) {\n return callback([], `Error: something unexpected occurred during elasticSearch query: ${error}`);\n } else {\n return callback(response.aggregations);\n }\n });\n };\n\n /**\n * Parse a final elastic results bucket and return a D3 compatible object\n * @param bucket {{key_as_string:{String}, key:{Number}, doc_count:{Number}, total:{{value:{Number}}}}} interval bucket\n */\n const parseElasticBucket = bucket => [bucket.key, bucket.total.value];\n\n /**\n * Build an object representing the content of the REST-JSON query to elasticSearch, based on the parameters\n * currently defined for data aggegations.\n * @param type {String} statistics type (visit|rdv|rating|ca|plan|account|search|...)\n * @param interval {String} statistics interval (year|quarter|month|week|day|hour|minute|second)\n * @param intervalBegin {moment} statitics interval beginning (moment.js type)\n * @param intervalEnd {moment} statitics interval ending (moment.js type)\n */\n const buildElasticAggregationsQuery = function (type, interval, intervalBegin, intervalEnd) {\n const q = {\n query: {\n bool: {\n must: [\n {\n match: { type }\n },\n {\n range: {\n date: {\n gte: intervalBegin.format(),\n lte: intervalEnd.format()\n }\n }\n }\n ]\n }\n },\n aggregations: {\n subgroups: {\n terms: {\n field: 'subType'\n }, // TODO allow aggregate by custom field\n aggregations: {\n intervals: {\n date_histogram: {\n field: 'date',\n interval,\n min_doc_count: 0,\n extended_bounds: {\n min: intervalBegin.valueOf(),\n max: intervalEnd.valueOf()\n }\n },\n aggregations: {\n total: {\n sum: {\n field: 'stat'\n }\n }\n }\n }\n }\n }\n }\n };\n\n // scale weeks on sunday as nvd3 supports only these weeks\n if (interval === 'week') {\n q.aggregations.subgroups.aggregations.intervals.date_histogram.offset = '-1d';\n // scale days to UTC time\n } else if (interval === 'day') {\n const offset = moment().utcOffset();\n q.aggregations.subgroups.aggregations.intervals.date_histogram.offset = (-offset) + 'm';\n }\n return q;\n };\n\n /**\n * Build an object representing the content of the REST-JSON query to elasticSearch, based on the parameters\n * currently defined for data aggegations.\n * @param groupKey {String} statistics subtype or custom field\n * @param sortKey {String} statistics type or 'ca'\n * @param intervalBegin {moment} statitics interval beginning (moment.js type)\n * @param intervalEnd {moment} statitics interval ending (moment.js type)\n */\n const buildElasticAggregationsRankingQuery = function (groupKey, sortKey, intervalBegin, intervalEnd) {\n const q = {\n query: {\n bool: {\n must: [\n {\n range: {\n date: {\n gte: intervalBegin.format(),\n lte: intervalEnd.format()\n }\n }\n },\n {\n term: {\n type: 'booking'\n }\n }\n ]\n }\n },\n aggregations: {\n subgroups: {\n terms: {\n field: groupKey,\n size: 10,\n order: {\n total: 'desc'\n }\n },\n aggregations: {\n top_events: {\n top_hits: {\n size: 1,\n sort: [\n { ca: 'desc' }\n ]\n }\n },\n total: {\n sum: {\n field: 'stat'\n }\n }\n }\n }\n }\n };\n\n // results must be sorted and limited later by angular\n if (sortKey !== 'ca') {\n angular.forEach(q.query.bool.must, function (must) {\n if (must.term) {\n return must.term.type = sortKey;\n }\n });\n } else {\n q.aggregations.subgroups.aggregations.total.sum.field = sortKey;\n }\n\n return q;\n };\n\n /**\n * Redraw the NDV3 chart using the provided data\n * @param chart_type {String} stackedAreaChart|discreteBarChart|lineChart\n * @param data {Array} array of NVD3 dataSources\n * @param type {String} which chart to update (statistic type key)\n */\n const updateChart = function (chart_type, data, type) {\n const id = `#chart-${type} svg`;\n\n // clean old charts\n d3.selectAll(id + ' > *').remove();\n\n return nv.addGraph(function () {\n // no data or many dates, display line charts\n let chart;\n if ((data.length === 0) || ((data[0].values.length > 1) && (chart_type !== 'discreteBarChart'))) {\n if (chart_type === 'stackedAreaChart') {\n chart = nv.models.stackedAreaChart().useInteractiveGuideline(true);\n } else {\n chart = nv.models.lineChart().useInteractiveGuideline(true);\n }\n\n if (data.length > 0) {\n if ($scope.display.interval === 'day') {\n setTimeScale(chart.xAxis, chart.xScale, [d3.time.day, data[0].values.length]);\n } else if ($scope.display.interval === 'week') {\n setTimeScale(chart.xAxis, chart.xScale, [d3.time.week, data[0].values.length]);\n } else if ($scope.display.interval === 'month') {\n setTimeScale(chart.xAxis, chart.xScale, [d3.time.month, data[0].values.length]);\n }\n }\n\n chart.xAxis.tickFormat(xAxisTickFormatFunction);\n chart.yAxis.tickFormat(d3.format('d'));\n\n chart.xAxis.axisLabel(X_AXIS_LABEL);\n chart.yAxis.axisLabel(Y_AXIS_LABEL);\n\n // only one date, display histograms\n } else {\n chart = nv.models.discreteBarChart();\n chart.tooltip.enabled(false);\n chart.showValues(true);\n chart.x(d => d.label);\n chart.y(d => d.value);\n data = prepareDataForBarChart(data, type);\n }\n\n // common for each charts\n chart.margin({ left: 100, right: 100 });\n chart.noData(_t('app.admin.stats_graphs.no_data_for_this_period'));\n chart.height(CHART_HEIGHT);\n\n // add new chart to the page\n d3.select(id).datum(data).transition().duration(350).call(chart);\n\n // resize the graph when the page is resized\n nv.utils.windowResize(chart.update);\n // return the chart\n return chart;\n });\n };\n\n /**\n * Given an NVD3 line chart axis, scale it to display ordinated dates, according to the given arguments\n */\n const setTimeScale = function (nvd3Axis, nvd3Scale, argsArray) {\n const scale = d3.time.scale();\n\n nvd3Axis.scale(scale);\n nvd3Scale(scale);\n\n if (!argsArray && !argsArray.length) {\n const oldTicks = nvd3Axis.axis.ticks;\n return nvd3Axis.axis.ticks = () => oldTicks.apply(nvd3Axis.axis, argsArray);\n }\n };\n\n /**\n * Translate line chart data in dates row to bar chart data, one bar per type.\n */\n const prepareDataForBarChart = function (data, type) {\n const newData = [{\n key: type,\n values: []\n }\n ];\n for (const info of Array.from(data)) {\n if (info) {\n newData[0].values.push({\n label: info.key,\n value: info.values[0].y,\n color: info.color\n });\n }\n }\n\n return newData;\n };\n\n /**\n * Sort the provided array, in the specified order, on the value returned by the callback.\n * This is a stable-sorting algorithm implementation, ie. two call with the same array will return the same results\n * orders, especially with equal values.\n * @param array {Array} the array to sort\n * @param order {string} 'ASC' or 'DESC'\n * @param getValue {function} the callback which will return the value on which the sort will occurs\n * @returns {Array}\n */\n const stableSort = function (array, order, getValue) {\n // prepare sorting\n const keys_order = [];\n const result = [];\n for (let i = 0, end = array.length; i <= end; i++) {\n keys_order[array[i]] = i;\n result.push(array[i]);\n }\n\n // callback for javascript native Array.sort()\n const sort_fc = function (a, b) {\n const val_a = getValue(a);\n const val_b = getValue(b);\n if (val_a === val_b) {\n return keys_order[a] - keys_order[b];\n }\n if (val_a < val_b) {\n if (order === 'ASC') {\n return -1;\n } else { return 1; }\n } else {\n if (order === 'ASC') {\n return 1;\n } else { return -1; }\n }\n };\n\n // finish the sort\n result.sort(sort_fc);\n return result;\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Controllers.controller('GroupsController', ['$scope', 'groupsPromise', 'Group', 'growl', '_t', function ($scope, groupsPromise, Group, growl, _t) {\n // List of users groups\n $scope.groups = groupsPromise;\n\n // Default: we show only enabled groups\n $scope.groupFiltering = 'enabled';\n\n // Available options for filtering groups by status\n $scope.filterDisabled = [\n 'enabled',\n 'disabled',\n 'all'\n ];\n\n /**\n * Removes the newly inserted but not saved group / Cancel the current group modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} group index in the $scope.groups array\n */\n $scope.cancelGroup = function (rowform, index) {\n if ($scope.groups[index].id != null) {\n return rowform.$cancel();\n } else {\n return $scope.groups.splice(index, 1);\n }\n };\n\n /**\n * Creates a new empty entry in the $scope.groups array\n */\n $scope.addGroup = function () {\n $scope.inserted =\n { name: '' };\n return $scope.groups.push($scope.inserted);\n };\n\n /**\n * Saves a new group / Update an existing group to the server (form validation callback)\n * @param data {Object} group name\n * @param [id] {number} group id, in case of update\n */\n $scope.saveGroup = function (data, id) {\n if (id != null) {\n return Group.update({ id }, { group: data }, response => growl.success(_t('app.admin.members.group_form.changes_successfully_saved'))\n , () => growl.error(_t('app.admin.members.group_form.an_error_occurred_while_saving_changes')));\n } else {\n return Group.save({ group: data }, function (resp) {\n growl.success(_t('app.admin.members.group_form.new_group_successfully_saved'));\n return $scope.groups[$scope.groups.length - 1].id = resp.id;\n }\n , function () {\n growl.error(_t('app.admin.members.group_form.an_error_occurred_when_saving_the_new_group'));\n return $scope.groups.splice($scope.groups.length - 1, 1);\n });\n }\n };\n\n /**\n * Deletes the group at the specified index\n * @param groupId {number} group id to delete\n */\n $scope.removeGroup = (groupId) => {\n Group.delete({ id: groupId }, function (resp) {\n growl.success(_t('app.admin.members.group_form.group_successfully_deleted'));\n const index = $scope.groups.findIndex(e => e.id === groupId);\n $scope.groups.splice(index, 1);\n }\n , () => growl.error(_t('app.admin.members.group_form.unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it')));\n };\n\n /**\n * Enable/disable the group at the specified index\n * @param groupId {number} id of the group to enable/disable\n */\n return $scope.toggleDisableGroup = function (groupId) {\n const index = $scope.groups.findIndex(e => e.id === groupId);\n const group = $scope.groups[index];\n if (!group.disabled && (group.users > 0)) {\n return growl.error(_t('app.admin.members.group_form.unable_to_disable_group_with_users', { USERS: group.users }));\n } else {\n return Group.update({ id: group.id }, { group: { disabled: !group.disabled } }, function (response) {\n $scope.groups[index] = response;\n return growl.success(_t('app.admin.members.group_form.group_successfully_enabled_disabled', { STATUS: response.disabled }));\n }\n , () => growl.error(_t('app.admin.members.group_form.unable_to_enable_disable_group', { STATUS: !group.disabled })));\n }\n };\n}\n\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-undef,\n no-useless-escape,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in the admin invoices listing page\n */\nApplication.Controllers.controller('InvoicesController', ['$scope', '$state', 'Invoice', 'AccountingPeriod', 'AuthService', 'invoices', 'closedPeriods', '$uibModal', 'growl', '$filter', 'Setting', 'settings', 'stripeSecretKey', '_t', 'Member', 'uiTourService', 'Payment', 'onlinePaymentStatus', '$uiRouter',\n function ($scope, $state, Invoice, AccountingPeriod, AuthService, invoices, closedPeriods, $uibModal, growl, $filter, Setting, settings, stripeSecretKey, _t, Member, uiTourService, Payment, onlinePaymentStatus, $uiRouter) {\n /* PRIVATE STATIC CONSTANTS */\n\n // number of invoices loaded each time we click on 'load more...'\n const INVOICES_PER_PAGE = 20;\n\n // fake stripe secret key\n const STRIPE_SK_HIDDEN = 'sk_test_hidden-hidden-hidden-hid';\n\n /* PUBLIC SCOPE */\n\n // default active tab\n $scope.tabs = {\n active: settings.invoicing_module === 'true' ? 0 : 1\n };\n\n // List of all invoices\n $scope.invoices = invoices;\n\n // Invoices filters\n $scope.searchInvoice = {\n date: null,\n name: '',\n reference: ''\n };\n\n // currently displayed page of invoices (search results)\n $scope.page = 1;\n\n // true when all invoices are loaded\n $scope.noMoreResults = false;\n\n // Default invoices ordering/sorting\n $scope.orderInvoice = '-date';\n\n $scope.isOpenVatModal = false;\n\n // Invoices parameters\n $scope.invoice = {\n logo: null,\n reference: {\n model: '',\n help: null,\n templateUrl: '/admin/invoices/settings/editReference.html'\n },\n code: {\n model: '',\n active: true,\n templateUrl: '/admin/invoices/settings/editCode.html'\n },\n number: {\n model: '',\n help: null,\n templateUrl: '/admin/invoices/settings/editNumber.html'\n },\n VAT: {\n rate: 19.6,\n name: 'VAT',\n rateMachine: '',\n active: false\n },\n text: {\n content: ''\n },\n legals: {\n content: ''\n }\n };\n\n // all settings\n $scope.allSettings = settings;\n\n // is the stripe private set?\n $scope.stripeSecretKey = (stripeSecretKey.isPresent ? STRIPE_SK_HIDDEN : '');\n\n // has any online payment been already made?\n $scope.onlinePaymentStatus = onlinePaymentStatus.status;\n\n // Placeholding date for the invoice creation\n $scope.today = moment();\n\n // Placeholding date for the reservation begin\n $scope.inOneWeek = moment().add(1, 'week').startOf('hour');\n\n // Placeholding date for the reservation end\n $scope.inOneWeekAndOneHour = moment().add(1, 'week').add(1, 'hour').startOf('hour');\n\n // Is shown the modal dialog to select a payment gateway\n $scope.openSelectGatewayModal = false;\n\n // the following item is used by the UnsavedFormAlert component to detect a page change\n $scope.uiRouter = $uiRouter;\n\n /**\n * This callback triggers the opening/closing of the VAT configuration modal\n */\n $scope.toggleVatModal = function () {\n setTimeout(() => {\n $scope.isOpenVatModal = !$scope.isOpenVatModal;\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered when the VAT settings were successfully updated\n */\n $scope.onVATSuccess = (message) => {\n $scope.onSuccess(message);\n Setting.query({ names: \"['invoice_VAT-name', 'invoice_VAT-rate']\" }, (vatSettings) => {\n $scope.invoice.VAT.rate = vatSettings['invoice_VAT-rate'];\n $scope.invoice.VAT.name = vatSettings['invoice_VAT-name'];\n }, $scope.onError);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /**\n * Return the VAT rate applicable to the machine reservations\n * @return {number}\n */\n $scope.getMachineExampleRate = function () {\n return $scope.invoice.VAT.rateMachine || $scope.invoice.VAT.rate;\n };\n\n /**\n * Change the invoices ordering criterion to the one provided\n * @param orderBy {string} ordering criterion\n */\n $scope.setOrderInvoice = function (orderBy) {\n if ($scope.orderInvoice === orderBy) {\n $scope.orderInvoice = `-${orderBy}`;\n } else {\n $scope.orderInvoice = orderBy;\n }\n\n resetSearchInvoice();\n return invoiceSearch();\n };\n\n /**\n * Open a modal window asking the admin the details to refund the user about the provided invoice\n * @param invoice {Object} invoice inherited from angular's $resource\n */\n $scope.generateAvoirForInvoice = function (invoice) {\n // open modal\n const modalInstance = $uibModal.open({\n templateUrl: '/admin/invoices/avoirModal.html',\n controller: 'AvoirModalController',\n resolve: {\n invoice () { return invoice; },\n closedPeriods () { return AccountingPeriod.query().$promise; },\n lastClosingEnd () { return AccountingPeriod.lastClosingEnd().$promise; }\n }\n });\n\n // once done, update the invoice model and inform the admin\n return modalInstance.result.then(function (res) {\n $scope.invoices.unshift(res.avoir);\n return Invoice.get({ id: invoice.id }, function (data) {\n invoice.has_avoir = data.has_avoir;\n return growl.success(_t('app.admin.invoices.refund_invoice_successfully_created'));\n });\n });\n };\n\n /**\n * Generate an invoice reference sample from the parametrized model\n * @returns {string} invoice reference sample\n */\n $scope.mkReference = function () {\n let sample = $scope.invoice.reference.model;\n if (sample) {\n // invoice number per day (dd..dd)\n sample = sample.replace(/d+(?![^\\[]*])/g, function (match, offset, string) { return padWithZeros(2, match.length); });\n // invoice number per month (mm..mm)\n sample = sample.replace(/m+(?![^\\[]*])/g, function (match, offset, string) { return padWithZeros(12, match.length); });\n // invoice number per year (yy..yy)\n sample = sample.replace(/y+(?![^\\[]*])/g, function (match, offset, string) { return padWithZeros(8, match.length); });\n // date information\n sample = sample.replace(/[YMD]+(?![^\\[]*])/g, function (match, offset, string) { return $scope.today.format(match); });\n // information about online selling (X[text])\n sample = sample.replace(/X\\[([^\\]]+)\\]/g, function (match, p1, offset, string) { return p1; });\n // information about wallet (W[text]) - does not apply here\n sample = sample.replace(/W\\[([^\\]]+)\\]/g, '');\n // information about refunds (R[text]) - does not apply here\n sample = sample.replace(/R\\[([^\\]]+)\\]/g, '');\n // information about payment schedules (S[text]) -does not apply here\n sample = sample.replace(/S\\[([^\\]]+)\\]/g, '');\n }\n return sample;\n };\n\n /**\n * Generate an order number sample from the parametrized model\n * @returns {string} invoice reference sample\n */\n $scope.mkNumber = function () {\n let sample = $scope.invoice.number.model;\n if (sample) {\n // global order number (nn..nn)\n sample = sample.replace(/n+(?![^\\[]*])/g, function (match, offset, string) { return padWithZeros(327, match.length); });\n // order number per year (yy..yy)\n sample = sample.replace(/y+(?![^\\[]*])/g, function (match, offset, string) { return padWithZeros(8, match.length); });\n // order number per month (mm..mm)\n sample = sample.replace(/m+(?![^\\[]*])/g, function (match, offset, string) { return padWithZeros(12, match.length); });\n // order number per day (dd..dd)\n sample = sample.replace(/d+(?![^\\[]*])/g, function (match, offset, string) { return padWithZeros(2, match.length); });\n // date information\n sample = sample.replace(/[YMD]+(?![^\\[]*])/g, function (match, offset, string) { return $scope.today.format(match); });\n }\n return sample;\n };\n\n /**\n * Open a modal dialog allowing the user to edit the invoice reference generation template\n */\n $scope.openEditReference = function () {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: $scope.invoice.reference.templateUrl,\n size: 'lg',\n resolve: {\n model () {\n return $scope.invoice.reference.model;\n }\n },\n controller: ['$scope', '$uibModalInstance', 'model', function ($scope, $uibModalInstance, model) {\n $scope.model = model;\n $scope.ok = function () { $uibModalInstance.close($scope.model); };\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }]\n });\n\n modalInstance.result.then(function (model) {\n Setting.update({ name: 'invoice_reference' }, { value: model }, function (data) {\n $scope.invoice.reference.model = model;\n growl.success(_t('app.admin.invoices.invoice_reference_successfully_saved'));\n }\n , function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_invoice_reference'));\n console.error(error);\n });\n });\n };\n\n /**\n * Open a modal dialog allowing the user to edit the invoice code\n */\n $scope.openEditCode = function () {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: $scope.invoice.code.templateUrl,\n size: 'lg',\n resolve: {\n model () {\n return $scope.invoice.code.model;\n },\n active () {\n return $scope.invoice.code.active;\n }\n },\n controller: ['$scope', '$uibModalInstance', 'model', 'active', function ($scope, $uibModalInstance, model, active) {\n $scope.codeModel = model;\n $scope.isSelected = active;\n\n $scope.ok = function () { $uibModalInstance.close({ model: $scope.codeModel, active: $scope.isSelected }); };\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }]\n });\n\n return modalInstance.result.then(function (result) {\n Setting.update({ name: 'invoice_code-value' }, { value: result.model }, function (data) {\n $scope.invoice.code.model = result.model;\n if (result.active) {\n return growl.success(_t('app.admin.invoices.invoicing_code_succesfully_saved'));\n }\n }\n , function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_invoicing_code'));\n console.error(error);\n });\n\n return Setting.update({ name: 'invoice_code-active' }, { value: result.active ? 'true' : 'false' }, function (data) {\n $scope.invoice.code.active = result.active;\n if (result.active) {\n return growl.success(_t('app.admin.invoices.code_successfully_activated'));\n } else {\n return growl.success(_t('app.admin.invoices.code_successfully_disabled'));\n }\n }\n , function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.invoices.an_error_occurred_while_activating_the_invoicing_code'));\n console.error(error);\n });\n });\n };\n\n /**\n * Open a modal dialog allowing the user to edit the invoice number\n */\n $scope.openEditInvoiceNb = function () {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: $scope.invoice.number.templateUrl,\n size: 'lg',\n resolve: {\n model () {\n return $scope.invoice.number.model;\n }\n },\n controller: ['$scope', '$uibModalInstance', 'model', function ($scope, $uibModalInstance, model) {\n $scope.model = model;\n $scope.ok = function () { $uibModalInstance.close($scope.model); };\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }]\n });\n\n return modalInstance.result.then(function (model) {\n Setting.update({ name: 'invoice_order-nb' }, { value: model }, function (data) {\n $scope.invoice.number.model = model;\n return growl.success(_t('app.admin.invoices.order_number_successfully_saved'));\n }\n , function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_order_number'));\n console.error(error);\n });\n });\n };\n\n /**\n * Open a modal dialog allowing the user to edit the VAT parameters for the invoices\n * The VAT can be disabled and its rate can be configured\n */\n $scope.openEditVAT = function () {\n $scope.toggleVatModal();\n };\n\n /**\n * Callback to save the value of the text zone when editing is done\n */\n $scope.textEditEnd = function (event) {\n const parsed = parseHtml($scope.invoice.text.content);\n return Setting.update({ name: 'invoice_text' }, { value: parsed }, function (data) {\n $scope.invoice.text.content = parsed;\n return growl.success(_t('app.admin.invoices.text_successfully_saved'));\n }\n , function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_text'));\n console.error(error);\n });\n };\n\n /**\n * Callback to save the value of the legal information zone when editing is done\n */\n $scope.legalsEditEnd = function (event) {\n const parsed = parseHtml($scope.invoice.legals.content);\n return Setting.update({ name: 'invoice_legals' }, { value: parsed }, function (data) {\n $scope.invoice.legals.content = parsed;\n return growl.success(_t('app.admin.invoices.address_and_legal_information_successfully_saved'));\n }\n , function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_address_and_the_legal_information'));\n console.error(error);\n });\n };\n\n /**\n * Callback when any of the filters changes.\n * Full reload the results list\n */\n $scope.handleFilterChange = function () {\n if (searchTimeout) clearTimeout(searchTimeout);\n searchTimeout = setTimeout(function () {\n resetSearchInvoice();\n invoiceSearch();\n }, 300);\n };\n\n /**\n * Callback for the 'load more' button.\n * Will load the next results of the current search, if any\n */\n $scope.showNextInvoices = function () {\n $scope.page += 1;\n invoiceSearch(true);\n };\n\n /**\n * Open a modal allowing the user to close an accounting period and to\n * view all periods already closed.\n */\n $scope.closeAnAccountingPeriod = function () {\n // open modal\n $uibModal.open({\n templateUrl: '/admin/invoices/closePeriodModal.html',\n controller: 'ClosePeriodModalController',\n backdrop: 'static',\n keyboard: false,\n size: 'lg',\n resolve: {\n periods () { return AccountingPeriod.query().$promise; },\n lastClosingEnd () { return AccountingPeriod.lastClosingEnd().$promise; }\n }\n });\n };\n\n $scope.toggleExportModal = function () {\n $uibModal.open({\n templateUrl: '/admin/invoices/accountingExportModal.html',\n controller: 'AccountingExportModalController',\n size: 'xl'\n });\n };\n\n /**\n * Test if the given date is within a closed accounting period\n * @param date {Date} date to test\n * @returns {boolean} true if closed, false otherwise\n */\n $scope.isDateClosed = function (date) {\n for (const period of closedPeriods) {\n if (moment(date).isBetween(moment.utc(period.start_at).startOf('day'), moment.utc(period.end_at).endOf('day'), null, '[]')) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Return the name of the operator that creates the invoice\n */\n $scope.operatorName = function (invoice) {\n if (!invoice.operator) return '';\n\n return `${invoice.operator.first_name} ${invoice.operator.last_name}`;\n };\n\n /**\n * Open a modal dialog which ask the user to select the payment gateway to use\n * @param onlinePaymentModule {{name: String, value: String}} setting that defines the next status of the online payment module\n */\n $scope.selectPaymentGateway = function (onlinePaymentModule) {\n // if the online payment is about to be disabled, accept the change without any further question\n if (onlinePaymentModule.value === false) return true;\n\n // otherwise, open a modal to ask for the selection of a payment gateway\n setTimeout(() => {\n $scope.openSelectGatewayModal = true;\n $scope.$apply();\n }, 50);\n return new Promise(function (resolve, reject) {\n gatewayHandlers.resolve = resolve;\n gatewayHandlers.reject = reject;\n }).catch(() => { /* WORKAROUND: it seems we can't catch the rejection from the boolean-setting directive */ });\n };\n\n /**\n * This will open/close the gateway selection modal\n */\n $scope.toggleSelectGatewayModal = function () {\n setTimeout(() => {\n $scope.openSelectGatewayModal = !$scope.openSelectGatewayModal;\n $scope.$apply();\n if (!$scope.openSelectGatewayModal && gatewayHandlers.reject) {\n gatewayHandlers.reject();\n resetPromiseHandlers();\n }\n }, 50);\n };\n\n /**\n * Callback triggered after the gateway was successfully configured in the dedicated modal\n */\n $scope.onGatewayModalSuccess = function (updatedSettings) {\n if (gatewayHandlers.resolve) {\n gatewayHandlers.resolve(true);\n resetPromiseHandlers();\n }\n\n $scope.toggleSelectGatewayModal();\n $scope.allSettings.payment_gateway = updatedSettings.get('payment_gateway').value;\n if ($scope.allSettings.payment_gateway === 'stripe') {\n $scope.allSettings.stripe_public_key = updatedSettings.get('stripe_public_key').value;\n Setting.isPresent({ name: 'stripe_secret_key' }, function (res) {\n $scope.stripeSecretKey = (res.isPresent ? STRIPE_SK_HIDDEN : '');\n });\n Payment.onlinePaymentStatus(function (res) {\n const value = res.status.toString();\n $scope.onlinePaymentStatus = value;\n $scope.allSettings.online_payment_module = value;\n });\n }\n };\n\n /**\n * Callback triggered after the gateway failed to be configured\n */\n $scope.onGatewayModalError = function (message) {\n growl.error(_t('app.admin.invoices.payment.gateway_configuration_error') + message);\n };\n\n /**\n * Callback triggered when the PayZen currency was successfully updated\n */\n $scope.alertPayZenCurrencyUpdated = function (currency) {\n growl.success(_t('app.admin.invoices.payment.payzen_settings.currency_updated', { CURRENCY: currency }));\n };\n\n /**\n * Setup the feature-tour for the admin/invoices page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupInvoicesTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('invoices');\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.invoices.welcome.title'),\n content: _t('app.admin.tour.invoices.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n } else {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome_manager',\n order: 0,\n title: _t('app.admin.tour.invoices.welcome_manager.title'),\n content: _t('app.admin.tour.invoices.welcome_manager.content'),\n placement: 'bottom',\n orphan: true\n });\n }\n if (settings.invoicing_module === 'true' && $scope.invoices.length > 0) {\n uitour.createStep({\n selector: '.invoices-management .invoices-list',\n stepId: 'list',\n order: 1,\n title: _t('app.admin.tour.invoices.list.title'),\n content: _t('app.admin.tour.invoices.list.content'),\n placement: 'top'\n });\n uitour.createStep({\n selector: '.invoices-management .invoices-list .chained-indicator',\n stepId: 'chained',\n order: 2,\n title: _t('app.admin.tour.invoices.chained.title'),\n content: _t('app.admin.tour.invoices.chained.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.invoices-management .invoices-list .download-button',\n stepId: 'download',\n order: 3,\n title: _t('app.admin.tour.invoices.download.title'),\n content: _t('app.admin.tour.invoices.download.content'),\n placement: 'left'\n });\n uitour.createStep({\n selector: '.invoices-management .invoices-list .refund-button',\n stepId: 'refund',\n order: 4,\n title: _t('app.admin.tour.invoices.refund.title'),\n content: _t('app.admin.tour.invoices.refund.content'),\n placement: 'left'\n });\n }\n if (settings.invoicing_module === 'true') {\n uitour.createStep({\n selector: '.invoices-management .payment-schedules-list',\n stepId: 'payment-schedules',\n order: 5,\n title: _t('app.admin.tour.invoices.payment-schedules.title'),\n content: _t('app.admin.tour.invoices.payment-schedules.content'),\n placement: 'bottom'\n });\n }\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: '.invoices-management .invoices-settings',\n stepId: 'settings',\n order: 6,\n title: _t('app.admin.tour.invoices.settings.title'),\n content: _t('app.admin.tour.invoices.settings.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.invoices-management .accounting-codes-tab',\n stepId: 'codes',\n order: 7,\n title: _t('app.admin.tour.invoices.codes.title'),\n content: _t('app.admin.tour.invoices.codes.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.heading .export-accounting-button',\n stepId: 'export',\n order: 8,\n title: _t('app.admin.tour.invoices.export.title'),\n content: _t('app.admin.tour.invoices.export.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.invoices-management .payment-settings',\n stepId: 'payment',\n order: 9,\n title: _t('app.admin.tour.invoices.payment.title'),\n content: _t('app.admin.tour.invoices.payment.content'),\n placement: 'bottom',\n popupClass: 'shift-left-50'\n });\n uitour.createStep({\n selector: '.heading .close-accounting-periods-button',\n stepId: 'periods',\n order: 10,\n title: _t('app.admin.tour.invoices.periods.title'),\n content: _t('app.admin.tour.invoices.periods.content'),\n placement: 'bottom',\n popupClass: 'shift-left-50'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 11,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on step change, change the active tab if needed\n uitour.on('stepChanged', function (nextStep) {\n if (nextStep.stepId === 'list' || nextStep.stepId === 'refund') {\n $scope.tabs.active = 0;\n }\n if (nextStep.stepId === 'settings') {\n $scope.tabs.active = 1;\n }\n if (nextStep.stepId === 'codes' || nextStep.stepId === 'export') {\n $scope.tabs.active = 2;\n }\n if (nextStep.stepId === 'payment') {\n $scope.tabs.active = 3;\n }\n if (nextStep.stepId === 'payment-schedules') {\n $scope.tabs.active = 4;\n }\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('invoices') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'invoices' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settings.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('invoices') < 0) {\n uitour.start();\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if (!invoices[0] || (invoices[0].maxInvoices <= $scope.invoices.length)) {\n $scope.noMoreResults = true;\n }\n\n // retrieve settings from the DB through the API\n $scope.invoice.legals.content = settings.invoice_legals;\n $scope.invoice.text.content = settings.invoice_text;\n $scope.invoice.VAT.rate = parseFloat(settings['invoice_VAT-rate']);\n $scope.invoice.VAT.active = (settings['invoice_VAT-active'] === 'true');\n $scope.invoice.VAT.name = settings['invoice_VAT-name'];\n $scope.invoice.VAT.rateMachine = settings['invoice_VAT-rate_Machine'] ? parseFloat(settings['invoice_VAT-rate_Machine']) : '';\n $scope.invoice.number.model = settings['invoice_order-nb'];\n $scope.invoice.code.model = settings['invoice_code-value'];\n $scope.invoice.code.active = (settings['invoice_code-active'] === 'true');\n $scope.invoice.reference.model = settings.invoice_reference;\n $scope.invoice.logo = {\n filetype: 'image/png',\n filename: 'logo.png',\n base64: settings.invoice_logo\n };\n\n // Watch the logo, when a change occurs, save it\n $scope.$watch('invoice.logo', function () {\n if ($scope.invoice.logo && $scope.invoice.logo.filesize) {\n return Setting.update(\n { name: 'invoice_logo' },\n { value: $scope.invoice.logo.base64 },\n function (data) { growl.success(_t('app.admin.invoices.logo_successfully_saved')); },\n function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.invoices.an_error_occurred_while_saving_the_logo'));\n console.error(error);\n }\n );\n }\n });\n\n // Clean before the controller is destroyed\n $scope.$on('$destroy', function () {\n if (gatewayHandlers.reject) {\n gatewayHandlers.reject();\n resetPromiseHandlers();\n }\n });\n };\n\n /**\n * Will temporize the search query to prevent overloading the API\n */\n let searchTimeout = null;\n\n /**\n * We must delay the save of the 'payment gateway' parameter, until the gateway is configured.\n * To do so, we use a promise, with the resolve/reject callback stored here\n * @see https://stackoverflow.com/q/26150232\n */\n const gatewayHandlers = {\n resolve: null,\n reject: null\n };\n\n /**\n * Output the given integer with leading zeros. If the given value is longer than the given\n * length, it will be truncated.\n * @param value {number} the integer to pad\n * @param length {number} the length of the resulting string.\n */\n const padWithZeros = function (value, length) { return (1e15 + value + '').slice(-length); };\n\n /**\n * Reset the promise handlers (reject/resolve) to their initial value.\n * This will prevent an already resolved promise to be triggered again.\n */\n const resetPromiseHandlers = function () {\n gatewayHandlers.resolve = null;\n gatewayHandlers.reject = null;\n };\n\n /**\n * Remove every unsupported html tag from the given html text (like

, , ...).\n * The supported tags are , , and
.\n * @param html {string} single line html text\n * @return {string} multi line simplified html text\n */\n const parseHtml = function (html) {\n return html.replace(/<\\/?(\\w+)((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)\\/?>/g, function (match, p1, offset, string) {\n if (['b', 'u', 'i', 'br'].includes(p1)) {\n return match;\n } else {\n return '';\n }\n });\n };\n\n /**\n * Reinitialize the context of invoices' search to display new results set\n */\n const resetSearchInvoice = function () {\n $scope.page = 1;\n return $scope.noMoreResults = false;\n };\n\n /**\n * Run a search query with the current parameters set concerning invoices, then affect or concat the results\n * to $scope.invoices\n * @param [concat] {boolean} if true, the result will be append to $scope.invoices instead of being affected\n */\n const invoiceSearch = function (concat) {\n Invoice.list({\n query: {\n number: $scope.searchInvoice.reference,\n customer: $scope.searchInvoice.name,\n date: $scope.searchInvoice.date,\n order_by: $scope.orderInvoice,\n page: $scope.page,\n size: INVOICES_PER_PAGE\n }\n }, function (invoices) {\n if (concat) {\n $scope.invoices = $scope.invoices.concat(invoices);\n } else {\n $scope.invoices = invoices;\n }\n\n if (!invoices[0] || (invoices[0].maxInvoices <= $scope.invoices.length)) {\n return $scope.noMoreResults = true;\n }\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the invoice refunding modal window\n */\nApplication.Controllers.controller('AvoirModalController', ['$scope', '$uibModalInstance', 'invoice', 'closedPeriods', 'lastClosingEnd', 'Invoice', 'growl', '_t',\n function ($scope, $uibModalInstance, invoice, closedPeriods, lastClosingEnd, Invoice, growl, _t) {\n /* PUBLIC SCOPE */\n\n // invoice linked to the current refund\n $scope.invoice = invoice;\n\n // Associative array containing invoice_item ids associated with boolean values\n $scope.partial = {};\n\n // Default refund parameters\n $scope.avoir = {\n invoice_id: invoice.id,\n subscription_to_expire: false,\n invoice_items_ids: []\n };\n\n // End date of last closed accounting period or date of first invoice\n $scope.lastClosingEnd = moment.utc(lastClosingEnd.last_end_date).toDate();\n\n // Possible refunding methods\n $scope.avoirModes = [\n { name: _t('app.admin.invoices.none'), value: 'none' },\n { name: _t('app.admin.invoices.by_cash'), value: 'cash' },\n { name: _t('app.admin.invoices.by_cheque'), value: 'cheque' },\n { name: _t('app.admin.invoices.by_transfer'), value: 'transfer' }\n ];\n\n if (Fablab.walletModule) {\n $scope.avoirModes.push({ name: _t('app.admin.invoices.by_wallet'), value: 'wallet' });\n }\n\n // If a subscription was took with the current invoice, should it be canceled or not\n $scope.subscriptionExpireOptions = {};\n $scope.subscriptionExpireOptions[_t('app.shared.buttons.yes')] = true;\n $scope.subscriptionExpireOptions[_t('app.shared.buttons.no')] = false;\n\n // AngularUI-Bootstrap datepicker parameters to define when to refund\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Callback to open the datepicker\n */\n $scope.openDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n $scope.datePicker.opened = true;\n };\n\n /**\n * Validate the refunding and generate a refund invoice\n */\n $scope.ok = function () {\n // check that at least 1 element of the invoice is refunded\n $scope.avoir.invoice_items_ids = [];\n for (const itemId in $scope.partial) {\n if (Object.prototype.hasOwnProperty.call($scope.partial, itemId)) {\n const refundItem = $scope.partial[itemId];\n if (refundItem) {\n $scope.avoir.invoice_items_ids.push(parseInt(itemId));\n }\n }\n }\n\n if ($scope.avoir.invoice_items_ids.length === 0) {\n return growl.error(_t('app.admin.invoices.you_must_select_at_least_one_element_to_create_a_refund'));\n } else {\n return Invoice.save(\n { avoir: $scope.avoir },\n function (avoir) { // success\n $uibModalInstance.close({ avoir, invoice: $scope.invoice });\n },\n function () { // failed\n growl.error(_t('app.admin.invoices.unable_to_create_the_refund'));\n }\n );\n }\n };\n\n /**\n * Cancel the refund, dismiss the modal window\n */\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n\n /**\n * Test if the given date is within a closed accounting period\n * @param date {Date} date to test\n * @returns {boolean} true if closed, false otherwise\n */\n $scope.isDateClosed = function (date) {\n for (const period of closedPeriods) {\n if (moment(date).isBetween(moment.utc(period.start_at).startOf('day'), moment.utc(period.end_at).endOf('day'), null, '[]')) {\n return true;\n }\n }\n return false;\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // if the invoice was paid with stripe, allow refunding through stripe\n Invoice.get({ id: invoice.id }, function (data) {\n $scope.invoice = data;\n // default : all elements of the invoice are refund\n return Array.from(data.items).map(function (item) {\n return ($scope.partial[item.id] = (typeof item.avoir_item_id !== 'number'));\n });\n });\n\n if (invoice.online_payment) {\n return $scope.avoirModes.push({ name: _t('app.admin.invoices.online_payment'), value: 'card' });\n }\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the modal window allowing an admin to close an accounting period\n */\nApplication.Controllers.controller('ClosePeriodModalController', ['$scope', '$uibModalInstance', '$window', '$sce', 'Invoice', 'AccountingPeriod', 'periods', 'lastClosingEnd', 'dialogs', 'growl', '_t',\n function ($scope, $uibModalInstance, $window, $sce, Invoice, AccountingPeriod, periods, lastClosingEnd, dialogs, growl, _t) {\n const YESTERDAY = moment.utc({ h: 0, m: 0, s: 0, ms: 0 }).subtract(1, 'day').toDate();\n const LAST_CLOSING = moment.utc(lastClosingEnd.last_end_date).toDate();\n const MAX_END = moment.utc(lastClosingEnd.last_end_date).add(1, 'year').subtract(1, 'day').toDate();\n\n /* PUBLIC SCOPE */\n\n // date pickers values are bound to these variables\n $scope.period = {\n start_at: LAST_CLOSING,\n end_at: moment(YESTERDAY).isBefore(MAX_END) ? YESTERDAY : MAX_END\n };\n\n // any form errors will come here\n $scope.errors = {};\n\n // will match any error about invoices\n $scope.invoiceErrorRE = /^invoice_(.+)$/;\n\n // existing closed periods, provided by the API\n $scope.accountingPeriods = periods;\n\n // closing a period may take a long time so we need to prevent the user from double-clicking the close button while processing\n $scope.pendingCreation = false;\n\n // AngularUI-Bootstrap datepickers parameters to define the period to close\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n // default: datePicker are not shown\n startOpened: false,\n endOpened: false,\n minDate: LAST_CLOSING,\n maxDate: moment(YESTERDAY).isBefore(MAX_END) ? YESTERDAY : MAX_END,\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Callback to open the datepicker\n */\n $scope.toggleDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n $scope.datePicker.endOpened = !$scope.datePicker.endOpened;\n };\n\n /**\n * Validate the close period creation\n */\n $scope.ok = function () {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.invoices.confirmation_required'),\n msg: $sce.trustAsHtml(\n _t(\n 'app.admin.invoices.confirm_close_START_END',\n { START: moment.utc($scope.period.start_at).format('LL'), END: moment.utc($scope.period.end_at).format('LL') }\n ) +\n '

' +\n _t('app.admin.invoices.period_must_match_fiscal_year') +\n '

' +\n _t('app.admin.invoices.this_may_take_a_while')\n )\n };\n }\n }\n },\n function () { // creation confirmed\n $scope.pendingCreation = true;\n AccountingPeriod.save(\n {\n accounting_period: {\n start_at: moment.utc($scope.period.start_at).toDate(),\n end_at: moment.utc($scope.period.end_at).endOf('day').toDate()\n }\n },\n function (resp) {\n $scope.pendingCreation = false;\n growl.success(_t(\n 'app.admin.invoices.period_START_END_closed_success',\n { START: moment.utc(resp.start_at).format('LL'), END: moment.utc(resp.end_at).format('LL') }\n ));\n $uibModalInstance.close(resp);\n },\n function (error) {\n $scope.pendingCreation = false;\n growl.error(_t('app.admin.invoices.failed_to_close_period'));\n $scope.errors = error.data;\n }\n );\n }\n );\n };\n\n /**\n * Just dismiss the modal window\n */\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n\n /**\n * Trigger the API call to download the JSON archive of the closed accounting period\n */\n $scope.downloadArchive = function (period) {\n $window.location.href = `/api/accounting_periods/${period.id}/archive`;\n };\n }\n]);\n\nApplication.Controllers.controller('AccountingExportModalController', ['$scope', '$uibModalInstance', 'Invoice', 'Export', 'CSRF', 'growl', '_t',\n function ($scope, $uibModalInstance, Invoice, Export, CSRF, growl, _t) {\n // Retrieve Anti-CSRF tokens from cookies\n CSRF.setMetaTags();\n\n const SETTINGS = {\n acd: {\n format: 'csv',\n encoding: 'ISO-8859-1',\n separator: ';',\n dateFormat: '%d/%m/%Y',\n labelMaxLength: 50,\n decimalSeparator: ',',\n exportInvoicesAtZero: false,\n columns: ['journal_code', 'date', 'account_code', 'account_label', 'piece', 'line_label', 'debit_origin', 'credit_origin', 'debit_euro', 'credit_euro', 'lettering']\n },\n vat: {\n format: 'csv',\n encoding: 'UTF-8',\n separator: ';',\n dateFormat: '%Y-%m-%d',\n labelMaxLength: 'N/A',\n decimalSeparator: '.',\n exportInvoicesAtZero: false,\n columns: ['start_date', 'end_date', 'vat_rate', 'amount']\n }\n };\n\n /* PUBLIC SCOPE */\n\n // API URL where the form will be posted\n $scope.actionUrl = '/api/accounting/export';\n\n // Form action on the above URL\n $scope.method = 'post';\n\n // Anti-CSRF token to inject into the download form\n $scope.csrfToken = angular.element('meta[name=\"csrf-token\"]')[0].content;\n\n // API request body to generate the export\n $scope.query = null;\n\n // binding to radio button \"export to\"\n $scope.exportTarget = {\n type: null,\n software: null,\n startDate: null,\n endDate: null,\n settings: null\n };\n\n // AngularUI-Bootstrap datepicker parameters to define export dates range\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: { // default: datePickers are not shown\n start: false,\n end: false\n },\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n // Date of the first invoice\n $scope.firstInvoice = null;\n\n /**\n * Validate the export\n */\n $scope.ok = function () {\n const statusQry = mkQuery();\n $scope.query = statusQry;\n\n Export.status(statusQry).then(function (res) {\n if (!res.data.exists) {\n growl.success(_t('app.admin.invoices.export_is_running'));\n }\n $uibModalInstance.close(res);\n });\n };\n\n /**\n * Callback to open/close one of the datepickers\n * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-\n * @param picker {string} start | end\n */\n $scope.toggleDatePicker = function (event, picker) {\n event.preventDefault();\n $scope.datePicker.opened[picker] = !$scope.datePicker.opened[picker];\n };\n\n /**\n * Will fill the export settings, according to the selected software\n * @param software {String} must be one of SETTINGS.*\n */\n $scope.fillSettings = function (software) {\n $scope.exportTarget.settings = SETTINGS[software];\n };\n\n /**\n * Just dismiss the modal window\n */\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // Get info about the very first invoice on the system\n Invoice.first(function (data) {\n $scope.firstInvoice = data.date;\n $scope.exportTarget.startDate = data.date;\n $scope.exportTarget.endDate = moment().toISOString();\n });\n };\n\n /**\n * Prepare the query for the export API\n * @returns {{extension: *, query: *, category: string, type: *, key: *}}\n */\n const mkQuery = function () {\n return {\n category: 'accounting',\n type: $scope.exportTarget.software,\n extension: $scope.exportTarget.settings.format,\n key: $scope.exportTarget.settings.separator,\n query: JSON.stringify({\n columns: $scope.exportTarget.settings.columns,\n encoding: $scope.exportTarget.settings.encoding,\n date_format: $scope.exportTarget.settings.dateFormat,\n start_date: moment.utc($scope.exportTarget.startDate).startOf('day').toISOString(),\n end_date: moment.utc($scope.exportTarget.endDate).endOf('day').toISOString(),\n label_max_length: $scope.exportTarget.settings.labelMaxLength,\n decimal_separator: $scope.exportTarget.settings.decimalSeparator,\n export_invoices_at_zero: $scope.exportTarget.settings.exportInvoicesAtZero\n })\n };\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n'use strict';\n\nApplication.Controllers.controller('AdminMachinesController', ['$scope', 'CSRF', 'growl', '$state', '_t', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', 'machinesPromise', 'helpers', '$uiRouter',\n function ($scope, CSRF, growl, $state, _t, AuthService, settingsPromise, Member, uiTourService, machinesPromise, helpers, $uiRouter) {\n /* PUBLIC SCOPE */\n\n // the following item is used by the UnsavedFormAlert component to detect a page change\n $scope.uiRouter = $uiRouter;\n\n // default tab: machines list\n $scope.tabs = { active: 0 };\n\n // the application global settings\n $scope.settings = settingsPromise;\n\n /**\n * Redirect the user to the machine details page\n */\n $scope.showMachine = function (machine) { $state.go('app.public.machines_show', { id: machine.slug }); };\n\n /**\n * Shows an error message forwarded from a child component\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Shows a success message forwarded from a child react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Open the modal dialog to log the user and resolves the returned promise when the logging process\n * was successfully completed.\n */\n $scope.onLoginRequest = function (e) {\n return new Promise((resolve, _reject) => {\n $scope.login(e, resolve);\n });\n };\n\n /**\n * Redirect the user to the training reservation page\n */\n $scope.onEnrollRequest = function (trainingId) {\n $state.go('app.logged.trainings_reserve', { id: trainingId });\n };\n\n /**\n * Callback to book a reservation for the current machine\n */\n $scope.reserveMachine = function (machine) {\n $state.go('app.logged.machines_reserve', { id: machine.slug });\n };\n\n $scope.canProposePacks = function () {\n return AuthService.isAuthorized(['admin', 'manager']) || !helpers.isUserValidationRequired($scope.settings, 'pack') || (helpers.isUserValidationRequired($scope.settings, 'pack') && helpers.isUserValidated($scope.currentUser));\n };\n\n /**\n * Setup the feature-tour for the machines page. (admins only)\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupMachinesTour = function () {\n // setup the tour for admins only\n if (AuthService.isAuthorized(['admin', 'manager'])) {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('machines');\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.public.tour.machines.welcome.title'),\n content: _t('app.public.tour.machines.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n if (machinesPromise.length > 0) {\n uitour.createStep({\n selector: '.machines-list .show-button',\n stepId: 'view',\n order: 1,\n title: _t('app.public.tour.machines.view.title'),\n content: _t('app.public.tour.machines.view.content'),\n placement: 'top'\n });\n }\n } else {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome_manager',\n order: 0,\n title: _t('app.public.tour.machines.welcome_manager.title'),\n content: _t('app.public.tour.machines.welcome_manager.content'),\n placement: 'bottom',\n orphan: true\n });\n }\n if (machinesPromise.length > 0) {\n uitour.createStep({\n selector: '.machines-list .reserve-button',\n stepId: 'reserve',\n order: 2,\n title: _t('app.public.tour.machines.reserve.title'),\n content: _t('app.public.tour.machines.reserve.content'),\n placement: 'top'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 3,\n title: _t('app.public.tour.conclusion.title'),\n content: _t('app.public.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('machines') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'machines' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('machines') < 0) {\n uitour.start();\n }\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-self-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/* COMMON CODE */\n\n/**\n * Provides a set of common properties and methods to the $scope parameter. They are used\n * in the various members' admin controllers.\n *\n * Provides :\n * - $scope.groups = [{Group}]\n * - $scope.trainings = [{Training}]\n * - $scope.plans = []\n * - $scope.datePicker = {}\n * - $scope.submited(content)\n * - $scope.cancel()\n * - $scope.fileinputClass(v)\n * - $scope.openDatePicker($event)\n * - $scope.openSubscriptionDatePicker($event)\n *\n * Requires :\n * - $state (Ui-Router) [ 'app.admin.members' ]\n */\nclass MembersController {\n constructor ($scope, $state, Group, Training) {\n // Retrieve the profiles groups (e.g. students ...)\n Group.query(function (groups) { $scope.groups = groups.filter(function (g) { return !g.disabled; }); });\n\n // Retrieve the list of available trainings\n Training.query().$promise.then(function (data) {\n $scope.trainings = data.map(function (d) {\n return ({\n id: d.id,\n name: d.name,\n disabled: d.disabled\n });\n });\n });\n\n // Default parameters for AngularUI-Bootstrap datepicker\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n subscription_date_opened: false,\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Shows the birthday datepicker\n * @param $event {Object} jQuery event object\n */\n $scope.openDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n return $scope.datePicker.opened = true;\n };\n\n /**\n * Shows the end of subscription datepicker\n * @param $event {Object} jQuery event object\n */\n $scope.openSubscriptionDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n return $scope.datePicker.subscription_date_opened = true;\n };\n\n /**\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when an upload is done: any raised error will be stacked in the\n * $scope.alerts array. If everything goes fine, the user is redirected to the members listing page.\n * @param content {Object} JSON - The result of the upload\n */\n $scope.submited = function (content) {\n if ((content.id == null)) {\n $scope.alerts = [];\n return angular.forEach(content, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n } else {\n return $state.go('app.admin.members');\n }\n };\n\n /**\n * Changes the admin's view to the members list page\n */\n $scope.cancel = function () { $state.go('app.admin.members'); };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder, or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n }\n}\n\n/**\n * Controller used in the members/groups management page\n */\nApplication.Controllers.controller('AdminMembersController', ['$scope', '$sce', '$uibModal', 'membersPromise', 'adminsPromise', 'partnersPromise', 'managersPromise', 'growl', 'Admin', 'AuthService', 'dialogs', '_t', 'Member', 'Export', 'User', 'uiTourService', 'settingsPromise', '$location',\n function ($scope, $sce, $uibModal, membersPromise, adminsPromise, partnersPromise, managersPromise, growl, Admin, AuthService, dialogs, _t, Member, Export, User, uiTourService, settingsPromise, $location) {\n /* PRIVATE STATIC CONSTANTS */\n\n // number of users loaded each time we click on 'load more...'\n const USERS_PER_PAGE = 20;\n\n /* PUBLIC SCOPE */\n\n // members list\n $scope.members = membersPromise;\n\n $scope.member = {\n // Members plain-text filtering. Default: not filtered\n searchText: '',\n // Members ordering/sorting. Default: not sorted\n order: 'id',\n // the currently displayed page of members\n page: 1,\n // true when all members where loaded\n noMore: false,\n // default filter for members\n memberFilter: 'all',\n // options for members filtering\n memberFilters: [\n 'all',\n 'not_confirmed',\n 'inactive_for_3_years'\n ]\n };\n\n // admins list\n $scope.admins = adminsPromise.admins.filter(function (m) { return m.id !== Fablab.adminSysId; });\n\n // is user validation required\n $scope.enableUserValidationRequired = (settingsPromise.user_validation_required === 'true');\n\n // should we display the username in the list?\n $scope.displayUsername = (settingsPromise.show_username_in_admin_list === 'true');\n\n // Admins ordering/sorting. Default: not sorted\n $scope.orderAdmin = null;\n\n // partners list\n $scope.partners = partnersPromise;\n\n // Partners ordering/sorting. Default: not sorted\n $scope.orderPartner = null;\n\n // managers list\n $scope.managers = managersPromise;\n\n // Managers ordering/sorting. Default: not sorted\n $scope.orderManager = null;\n\n // default tab: members list\n const defaultActiveTab = $location.search().tabs ? parseInt($location.search().tabs, 10) : 0;\n $scope.tabs = { active: defaultActiveTab, sub: 0 };\n\n /**\n * Change the members ordering criterion to the one provided\n * @param orderBy {string} ordering criterion\n */\n $scope.setOrderMember = function (orderBy) {\n if ($scope.member.order === orderBy) {\n $scope.member.order = `-${orderBy}`;\n } else {\n $scope.member.order = orderBy;\n }\n\n resetSearchMember();\n return memberSearch();\n };\n\n /**\n * Change the admins ordering criterion to the one provided\n * @param orderAdmin {string} ordering criterion\n */\n $scope.setOrderAdmin = function (orderAdmin) {\n if ($scope.orderAdmin === orderAdmin) {\n return $scope.orderAdmin = `-${orderAdmin}`;\n } else {\n return $scope.orderAdmin = orderAdmin;\n }\n };\n\n /**\n * Change the partners ordering criterion to the one provided\n * @param orderPartner {string} ordering criterion\n */\n $scope.setOrderPartner = function (orderPartner) {\n if ($scope.orderPartner === orderPartner) {\n return $scope.orderPartner = `-${orderPartner}`;\n } else {\n return $scope.orderPartner = orderPartner;\n }\n };\n\n /**\n * Change the managers ordering criterion to the one provided\n * @param orderManager {string} ordering criterion\n */\n $scope.setOrderManager = function (orderManager) {\n if ($scope.orderManager === orderManager) {\n return $scope.orderManager = `-${orderManager}`;\n } else {\n return $scope.orderManager = orderManager;\n }\n };\n\n /**\n * Open a modal dialog allowing the admin to create a new partner user\n */\n $scope.openPartnerNewModal = function () {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/shared/_partner_new_modal.html',\n size: 'lg',\n controller: ['$scope', '$uibModalInstance', 'User', function ($scope, $uibModalInstance, User) {\n $scope.partner = {};\n\n $scope.ok = function () {\n User.save(\n {},\n { user: $scope.partner },\n function (user) {\n $scope.partner.id = user.id;\n $scope.partner.name = `${user.first_name} ${user.last_name}`;\n $uibModalInstance.close($scope.partner);\n },\n function (error) {\n growl.error(_t('app.admin.plans.new.unable_to_save_this_user_check_that_there_isnt_an_already_a_user_with_the_same_name'));\n console.error(error);\n }\n );\n };\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }]\n });\n // once the form was validated successfully ...\n return modalInstance.result.then(function (partner) {\n $scope.partners.push(partner);\n });\n };\n\n /**\n * Ask for confirmation then delete the specified user\n * @param memberId {number} identifier of the user to delete\n */\n $scope.deleteMember = function (memberId) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.members.confirmation_required'),\n msg: $sce.trustAsHtml(_t('app.admin.members.confirm_delete_member') + '

' + _t('app.admin.members.this_may_take_a_while_please_wait'))\n };\n }\n }\n },\n function () { // cancel confirmed\n Member.delete(\n { id: memberId },\n function () {\n $scope.members.splice(findItemIdxById($scope.members, memberId), 1);\n return growl.success(_t('app.admin.members.member_successfully_deleted'));\n },\n function (error) {\n growl.error(_t('app.admin.members.unable_to_delete_the_member'));\n console.error(error);\n }\n );\n }\n );\n };\n\n /**\n * Ask for confirmation then delete the specified administrator\n * @param admins {Array} full list of administrators\n * @param admin {Object} administrator to delete\n */\n $scope.destroyAdmin = function (admins, admin) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.members.confirmation_required'),\n msg: $sce.trustAsHtml(_t('app.admin.members.do_you_really_want_to_delete_this_administrator_this_cannot_be_undone') + '

' + _t('app.admin.members.this_may_take_a_while_please_wait'))\n };\n }\n }\n },\n function () { // cancel confirmed\n Admin.delete(\n { id: admin.id },\n function () {\n admins.splice(findItemIdxById(admins, admin.id), 1);\n return growl.success(_t('app.admin.members.administrator_successfully_deleted'));\n },\n function (error) {\n growl.error(_t('app.admin.members.unable_to_delete_the_administrator'));\n console.error(error);\n }\n );\n }\n );\n };\n\n /**\n * Ask for confirmation then delete the specified partner\n * @param partners {Array} full list of partners\n * @param partner {Object} partner to delete\n */\n $scope.destroyPartner = function (partners, partner) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.members.confirmation_required'),\n msg: $sce.trustAsHtml(_t('app.admin.members.delete_this_partner') + '

' + _t('app.admin.members.this_may_take_a_while_please_wait'))\n };\n }\n }\n },\n function () { // cancel confirmed\n User.delete(\n { id: partner.id },\n function () {\n partners.splice(findItemIdxById(partners, partner.id), 1);\n return growl.success(_t('app.admin.members.partner_successfully_deleted'));\n },\n function (error) {\n growl.error(_t('app.admin.members.unable_to_delete_the_partner'));\n console.error(error);\n }\n );\n }\n );\n };\n\n /**\n * Ask for confirmation then delete the specified manager\n * @param managers {Array} full list of managers\n * @param manager {Object} manager to delete\n */\n $scope.destroyManager = function (managers, manager) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.members.confirmation_required'),\n msg: $sce.trustAsHtml(_t('app.admin.members.delete_this_manager') + '

' + _t('app.admin.members.this_may_take_a_while_please_wait'))\n };\n }\n }\n },\n function () { // cancel confirmed\n User.delete(\n { id: manager.id },\n function () {\n managers.splice(findItemIdxById(managers, manager.id), 1);\n return growl.success(_t('app.admin.members.manager_successfully_deleted'));\n },\n function (error) {\n growl.error(_t('app.admin.members.unable_to_delete_the_manager'));\n console.error(error);\n }\n );\n }\n );\n };\n\n /**\n * Callback for the 'load more' button.\n * Will load the next results of the current search, if any\n */\n $scope.showNextMembers = function () {\n $scope.member.page += 1;\n return memberSearch(true);\n };\n\n /**\n * Callback when the search field content changes: reload the search results\n */\n $scope.updateTextSearch = function () {\n if (searchTimeout) clearTimeout(searchTimeout);\n searchTimeout = setTimeout(function () {\n resetSearchMember();\n memberSearch();\n }, 300);\n };\n\n /**\n * Callback when the member filter changes: reload the search results\n */\n $scope.updateMemberFilter = function () {\n resetSearchMember();\n memberSearch();\n };\n\n /**\n * Callback to alert the admin that the export request was acknowledged and is\n * processing right now.\n */\n $scope.alertExport = function (type) {\n Export.status({ category: 'users', type }).then(function (res) {\n if (!res.data.exists) {\n return growl.success(_t('app.admin.members.export_is_running_you_ll_be_notified_when_its_ready'));\n }\n });\n };\n\n /**\n * Set up the feature-tour for the admin/members page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupMembersTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('members');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.members.welcome.title'),\n content: _t('app.admin.tour.members.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.members-management .members-list',\n stepId: 'list',\n order: 1,\n title: _t('app.admin.tour.members.list.title'),\n content: _t('app.admin.tour.members.list.content'),\n placement: 'top'\n });\n uitour.createStep({\n selector: '.members-management .search-members',\n stepId: 'search',\n order: 2,\n title: _t('app.admin.tour.members.search.title'),\n content: _t('app.admin.tour.members.search.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.members-management .filter-members',\n stepId: 'filter',\n order: 3,\n title: _t('app.admin.tour.members.filter.title'),\n content: _t('app.admin.tour.members.filter.content'),\n placement: 'bottom'\n });\n if ($scope.members.length > 0) {\n uitour.createStep({\n selector: '.members-management .members-list .buttons',\n stepId: 'actions',\n order: 4,\n title: _t('app.admin.tour.members.actions.title'),\n content: _t('app.admin.tour.members.actions.content'),\n placement: 'left'\n });\n }\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: '.members-management .exports-buttons',\n stepId: 'exports',\n order: 5,\n title: _t('app.admin.tour.members.exports.title'),\n content: _t('app.admin.tour.members.exports.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.heading .import-members',\n stepId: 'import',\n order: 6,\n title: _t('app.admin.tour.members.import.title'),\n content: _t('app.admin.tour.members.import.content'),\n placement: 'left'\n });\n }\n uitour.createStep({\n selector: '.members-management .admins-tab',\n stepId: 'admins',\n order: 7,\n title: _t('app.admin.tour.members.admins.title'),\n content: _t('app.admin.tour.members.admins.content'),\n placement: 'bottom'\n });\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: '.members-management .groups-tab',\n stepId: 'groups',\n order: 8,\n title: _t('app.admin.tour.members.groups.title'),\n content: _t('app.admin.tour.members.groups.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.members-management .labels-tab',\n stepId: 'labels',\n order: 9,\n title: _t('app.admin.tour.members.labels.title'),\n content: _t('app.admin.tour.members.labels.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.members-management .sso-tab',\n stepId: 'sso',\n order: 10,\n title: _t('app.admin.tour.members.sso.title'),\n content: _t('app.admin.tour.members.sso.content'),\n placement: 'bottom',\n popupClass: 'shift-left-50'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 11,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on step change, change the active tab if needed\n uitour.on('stepChanged', function (nextStep) {\n if (nextStep.stepId === 'list' || nextStep.stepId === 'import') {\n $scope.tabs.active = 0;\n $scope.tabs.sub = 0;\n }\n if (nextStep.stepId === 'admins') {\n $scope.tabs.active = 0;\n $scope.tabs.sub = 1;\n }\n if (nextStep.stepId === 'groups') {\n $scope.tabs.active = 1;\n }\n if (nextStep.stepId === 'labels') {\n $scope.tabs.active = 2;\n }\n if (nextStep.stepId === 'sso') {\n $scope.tabs.active = 3;\n }\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('members') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'members' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('members') < 0) {\n uitour.start();\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if (!membersPromise[0] || (membersPromise[0].maxMembers <= $scope.members.length)) {\n return $scope.member.noMore = true;\n }\n };\n\n /**\n * Will temporize the search query to prevent overloading the API\n */\n let searchTimeout = null;\n\n /**\n * Iterate through the provided array and return the index of the requested item\n * @param items {Array} full list of users with the 'admin' role\n * @param id {Number} id of the item to retrieve in the list\n * @returns {Number} index of the requested item, in the provided array\n */\n const findItemIdxById = function (items, id) {\n return (items.map(function (item) { return item.id; })).indexOf(id);\n };\n\n /**\n * Reinitialize the context of the search to display new results set\n */\n const resetSearchMember = function () {\n $scope.member.noMore = false;\n $scope.member.page = 1;\n };\n\n /**\n * Run a search query with the current parameters set ($scope.member[searchText,order,page])\n * and affect or append the result in $scope.members, depending on the concat parameter\n * @param [concat] {boolean} if true, the result will be appended to $scope.members instead of being replaced\n */\n const memberSearch = function (concat) {\n Member.list({\n query: {\n search: $scope.member.searchText,\n order_by: $scope.member.order,\n filter: $scope.member.memberFilter,\n page: $scope.member.page,\n size: USERS_PER_PAGE\n }\n }, function (members) {\n if (concat) {\n $scope.members = $scope.members.concat(members);\n } else {\n $scope.members = members;\n }\n\n if (!members[0] || (members[0].maxMembers <= $scope.members.length)) {\n return $scope.member.noMore = true;\n }\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the member edition page\n */\nApplication.Controllers.controller('EditMemberController', ['$scope', '$state', '$transition$', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', 'settingsPromise', 'SupportingDocumentType',\n function ($scope, $state, $transition$, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet, settingsPromise, SupportingDocumentType) {\n /* PUBLIC SCOPE */\n\n // API URL where the form will be posted\n $scope.actionUrl = `/api/members/${$transition$.params().id}`;\n\n // Form action on the above URL\n $scope.method = 'patch';\n\n // List of tags joinable with user\n $scope.tags = tagsPromise;\n\n // The user to edit\n $scope.user = cleanUser(memberPromise);\n\n // Should the password be modified?\n $scope.password = { change: false };\n\n // is the phone number required in _member_form?\n $scope.phoneRequired = (settingsPromise.phone_required === 'true');\n\n // is the address required in _member_form?\n $scope.addressRequired = (settingsPromise.address_required === 'true');\n\n // is user validation required\n $scope.enableUserValidationRequired = (settingsPromise.user_validation_required === 'true');\n\n // the user subscription\n if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) {\n $scope.subscription = $scope.user.subscription;\n } else {\n Plan.query({ group_id: $scope.user.group_id }, function (plans) {\n $scope.plans = plans;\n return Array.from($scope.plans).map(function (plan) {\n return (plan.nameToDisplay = $filter('humanReadablePlanName')(plan));\n });\n });\n }\n\n // Available trainings list\n $scope.trainings = [];\n\n // Profiles types (student/standard/...)\n $scope.groups = [];\n\n // the user wallet\n $scope.wallet = walletPromise;\n\n // user wallet transactions\n $scope.transactions = transactionsPromise;\n\n // used in wallet partial template to identify parent view\n $scope.view = 'member_edit';\n\n // current active authentication provider\n $scope.activeProvider = activeProviderPromise;\n\n // modal dialog to extend the current subscription for free\n $scope.isOpenFreeExtendModal = false;\n\n // modal dialog to renew the current subscription\n $scope.isOpenRenewModal = false;\n\n // modal dialog to take a new subscription\n $scope.isOpenSubscribeModal = false;\n\n // modal dialog to change the user's role\n $scope.isOpenChangeRoleModal = false;\n\n // modal dialog to cancel the current subscription\n $scope.isOpenCancelModal = false;\n\n /**\n * Open a modal dialog asking for confirmation to change the role of the given user\n * @returns {*}\n */\n $scope.changeUserRole = function () {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/admin/members/change_role_modal.html',\n size: 'lg',\n resolve: {\n user () { return $scope.user; }\n },\n controller: ['$scope', '$uibModalInstance', 'Member', 'user', '_t', function ($scope, $uibModalInstance, Member, user, _t) {\n $scope.user = user;\n\n $scope.role = user.role;\n\n $scope.roles = [\n { key: 'admin', label: _t('app.admin.members_edit.admin') },\n { key: 'manager', label: _t('app.admin.members_edit.manager'), notAnOption: (user.role === 'admin') },\n { key: 'member', label: _t('app.admin.members_edit.member'), notAnOption: (user.role === 'admin' || user.role === 'manager') }\n ];\n\n $scope.ok = function () {\n Member.updateRole(\n { id: $scope.user.id },\n { role: $scope.role },\n function (_res) {\n growl.success(_t('app.admin.members_edit.role_changed', { OLD: _t(`app.admin.members_edit.${user.role}`), NEW: _t(`app.admin.members_edit.${$scope.role}`) }));\n return $uibModalInstance.close(_res);\n },\n function (error) {\n growl.error(_t('app.admin.members_edit.error_while_changing_role'));\n console.error(error);\n }\n );\n };\n\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }]\n });\n // once the form was validated successfully ...\n return modalInstance.result.then(function (user) {\n // remove the user for the old list add to the new\n });\n };\n\n /**\n * Opens/closes the modal dialog to freely extend the subscription\n */\n $scope.toggleFreeExtendModal = () => {\n setTimeout(() => {\n $scope.isOpenFreeExtendModal = !$scope.isOpenFreeExtendModal;\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Opens/closes the modal dialog to renew the subscription (with payment)\n */\n $scope.toggleRenewModal = () => {\n setTimeout(() => {\n $scope.isOpenRenewModal = !$scope.isOpenRenewModal;\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Opens/closes the modal dialog to cancel the current running subscription\n */\n $scope.toggleCancelModal = () => {\n setTimeout(() => {\n $scope.isOpenCancelModal = !$scope.isOpenCancelModal;\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Opens/closes the modal dialog to renew the subscription (with payment)\n */\n $scope.toggleSubscribeModal = () => {\n setTimeout(() => {\n $scope.isOpenSubscribeModal = !$scope.isOpenSubscribeModal;\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Opens/closes the modal dialog to change the user's role\n */\n $scope.toggleChangeRoleModal = () => {\n setTimeout(() => {\n $scope.isOpenChangeRoleModal = !$scope.isOpenChangeRoleModal;\n $scope.$apply();\n }, 0);\n };\n\n /**\n * Callback triggered if the subscription was successfully extended\n */\n $scope.onExtendSuccess = (message, newExpirationDate) => {\n growl.success(message);\n $scope.subscription.expired_at = newExpirationDate;\n };\n\n /**\n * Callback triggered when the subscription was successfully canceled\n */\n $scope.onCancelSuccess = (message) => {\n growl.success(message);\n $scope.user.subscribed_plan = null;\n $scope.user.subscription = null;\n $scope.subscription = null;\n };\n\n /**\n * Callback triggered if a new subscription was successfully taken\n */\n $scope.onSubscribeSuccess = (message, newSubscription) => {\n growl.success(message);\n $scope.subscription = newSubscription;\n };\n\n /**\n * Callback triggered if validate member was successfully taken\n */\n $scope.onValidateMemberSuccess = (_user, message) => {\n growl.success(message);\n setTimeout(() => {\n $scope.user = _user;\n $scope.user.statistic_profile_attributes.birthday = moment(_user.statistic_profile_attributes.birthday).toDate();\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered when the user was successfully updated\n */\n $scope.onUserSuccess = () => {\n growl.success(_t('app.admin.members_edit.update_success'));\n $state.go('app.admin.members');\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n $scope.createWalletCreditModal = function (user, wallet) {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/wallet/credit_modal.html',\n controller: ['$scope', '$uibModalInstance', 'Wallet', function ($scope, $uibModalInstance, Wallet) {\n // default: do not generate a refund invoice\n $scope.generate_avoir = false;\n\n // optional description shown on the refund invoice\n $scope.description = '';\n\n // default configuration for the avoir date selector widget\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false,\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Callback to open/close the date picker\n */\n $scope.toggleDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n return $scope.datePicker.opened = !$scope.datePicker.opened;\n };\n\n /**\n * Modal dialog validation callback\n */\n $scope.ok = function () {\n Wallet.credit(\n { id: wallet.id },\n {\n amount: $scope.amount,\n avoir: $scope.generate_avoir,\n avoir_description: $scope.description\n },\n function (_wallet) {\n growl.success(_t('app.shared.wallet.wallet_credit_successfully'));\n return $uibModalInstance.close(_wallet);\n },\n function (error) {\n growl.error(_t('app.shared.wallet.a_problem_occurred_for_wallet_credit'));\n console.error(error);\n }\n );\n };\n\n /**\n * Modal dialog cancellation callback\n */\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }\n ]\n });\n // once the form was validated successfully...\n return modalInstance.result.then(function (wallet) {\n $scope.wallet = wallet;\n return Wallet.transactions({ id: wallet.id }, function (transactions) { $scope.transactions = transactions; });\n });\n };\n\n /**\n * To use as callback in Array.prototype.filter to get only enabled plans\n */\n $scope.filterDisabledPlans = function (plan) { return !plan.disabled; };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n // the user subscription\n if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) {\n $scope.subscription = $scope.user.subscription;\n } else {\n Plan.query({ group_id: $scope.user.group_id }, function (plans) {\n $scope.plans = plans;\n return Array.from($scope.plans).map(function (plan) {\n return (plan.nameToDisplay = `${plan.base_name} - ${plan.interval}`);\n });\n });\n }\n\n SupportingDocumentType.query({ group_id: $scope.user.group_id }, function (supportingDocumentTypes) {\n $scope.hasProofOfIdentityTypes = supportingDocumentTypes.length > 0;\n });\n\n // Using the MembersController\n return new MembersController($scope, $state, Group, Training);\n };\n\n // prepare the user for the react-hook-form\n function cleanUser (user) {\n delete user.$promise;\n delete user.$resolved;\n return user;\n }\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the member's creation page (admin view)\n */\nApplication.Controllers.controller('NewMemberController', ['$scope', '$state', 'Member', 'Training', 'Group', 'CSRF', 'settingsPromise', 'growl', '_t',\n function ($scope, $state, Member, Training, Group, CSRF, settingsPromise, growl, _t) {\n CSRF.setMetaTags();\n\n /* PUBLIC SCOPE */\n\n // API URL where the form will be posted\n $scope.actionUrl = '/api/members';\n\n // Form action on the above URL\n $scope.method = 'post';\n\n // Should the password be set manually or generated?\n $scope.password = { change: false };\n\n // is the phone number required in _member_form?\n $scope.phoneRequired = (settingsPromise.phone_required === 'true');\n\n // is the address required to sign-up?\n $scope.addressRequired = (settingsPromise.address_required === 'true');\n\n // Default member's profile parameters\n $scope.user = {\n plan_interval: '',\n invoicing_profile_attributes: {},\n statistic_profile_attributes: {}\n };\n\n // Callback when the admin check/uncheck the box telling that the new user is an organization.\n // Disable or enable the organization fields in the form, accordingly\n $scope.toggleOrganization = function () {\n if ($scope.user.organization) {\n if (!$scope.user.invoicing_profile_attributes) { $scope.user.invoicing_profile_attributes = {}; }\n $scope.user.invoicing_profile_attributes.organization_attributes = {};\n } else {\n $scope.user.invoicing_profile_attributes.organization_attributes = undefined;\n }\n };\n\n /**\n * Callback triggered when the user was successfully updated\n */\n $scope.onUserSuccess = () => {\n growl.success(_t('app.admin.members_new.create_success'));\n $state.go('app.admin.members');\n };\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n // Using the MembersController\n return new MembersController($scope, $state, Group, Training);\n }\n]);\n\n/**\n * Controller used in the member's import page: import from CSV (admin view)\n */\nApplication.Controllers.controller('ImportMembersController', ['$scope', '$state', 'Group', 'Training', 'CSRF', 'tags', 'growl',\n function ($scope, $state, Group, Training, CSRF, tags, growl) {\n CSRF.setMetaTags();\n\n /* PUBLIC SCOPE */\n\n // API URL where the form will be posted\n $scope.actionUrl = '/api/imports/members';\n\n // Form action on the above URL\n $scope.method = 'post';\n\n // List of all tags\n $scope.tags = tags;\n\n /*\n * Callback run after the form was submitted\n * @param content {*} The result provided by the server, may be an Import object, or an error message\n */\n $scope.onImportResult = function (content) {\n if (content.id) {\n $state.go('app.admin.members_import_result', { id: content.id });\n } else {\n growl.error(JSON.stringify(content));\n }\n };\n\n // Using the MembersController\n return new MembersController($scope, $state, Group, Training);\n }\n]);\n\n/**\n * Controller used in the member's import results page (admin view)\n */\nApplication.Controllers.controller('ImportMembersResultController', ['$scope', '$state', 'Import', 'importItem',\n function ($scope, $state, Import, importItem) {\n /* PUBLIC SCOPE */\n\n // Current import as saved in database\n $scope.import = importItem;\n\n // Current import results\n $scope.results = null;\n\n /**\n * Changes the view of the admin to the members import page\n */\n $scope.cancel = function () { $state.go('app.admin.members_import'); };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n $scope.results = JSON.parse($scope.import.results);\n if (!$scope.results) {\n setTimeout(function () {\n Import.get({ id: $scope.import.id }, function (data) {\n $scope.import = data;\n initialize();\n });\n }, 5000);\n }\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n initialize();\n }\n]);\n\n/**\n * Controller used in the admin creation page (admin view)\n */\nApplication.Controllers.controller('NewAdminController', ['$state', '$scope', 'Admin', 'growl', '_t', 'settingsPromise', 'groupsPromise',\n function ($state, $scope, Admin, growl, _t, settingsPromise, groupsPromise) {\n // default admin profile\n let getGender;\n $scope.admin = {\n statistic_profile_attributes: {\n gender: true\n },\n profile_attributes: {},\n invoicing_profile_attributes: {}\n };\n\n // Default parameters for AngularUI-Bootstrap datepicker\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false,\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n // is the phone number required in _admin_form?\n $scope.phoneRequired = (settingsPromise.phone_required === 'true');\n\n // is the address required in _admin_form?\n $scope.addressRequired = (settingsPromise.address_required === 'true');\n\n // all available groups\n $scope.groups = groupsPromise;\n\n /**\n * Shows the birthday datepicker\n */\n $scope.openDatePicker = function () { $scope.datePicker.opened = true; };\n\n /**\n * Send the new admin, currently stored in $scope.admin, to the server for database saving\n */\n $scope.saveAdmin = function () {\n Admin.save(\n {},\n { admin: $scope.admin },\n function () {\n growl.success(_t('app.admin.admins_new.administrator_successfully_created_he_will_receive_his_connection_directives_by_email', { GENDER: getGender($scope.admin) }));\n return $state.go('app.admin.members');\n }\n , function (error) {\n growl.error(_t('app.admin.admins_new.failed_to_create_admin') + JSON.stringify(error.data ? error.data : error));\n console.error(error);\n }\n );\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Return an enumerable meaningful string for the gender of the provider user\n * @param user {Object} Database user record\n * @return {string} 'male' or 'female'\n */\n return getGender = function (user) {\n if (user.statistic_profile_attributes) {\n if (user.statistic_profile_attributes.gender) { return 'male'; } else { return 'female'; }\n } else { return 'other'; }\n };\n }\n\n]);\n\n/**\n * Controller used in the manager's creation page (admin view)\n */\nApplication.Controllers.controller('NewManagerController', ['$state', '$scope', 'User', 'groupsPromise', 'tagsPromise', 'growl', '_t', 'settingsPromise',\n function ($state, $scope, User, groupsPromise, tagsPromise, growl, _t, settingsPromise) {\n // default admin profile\n $scope.manager = {\n statistic_profile_attributes: {\n gender: true\n },\n profile_attributes: {},\n invoicing_profile_attributes: {}\n };\n\n // Default parameters for AngularUI-Bootstrap datepicker\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false,\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n // is the phone number required in _admin_form?\n $scope.phoneRequired = (settingsPromise.phone_required === 'true');\n\n // is the address required in _admin_form?\n $scope.addressRequired = (settingsPromise.address_required === 'true');\n\n // list of all groups\n $scope.groups = groupsPromise.filter(function (g) { return !g.disabled; });\n\n // list of all tags\n $scope.tags = tagsPromise;\n\n /**\n * Shows the birthday datepicker\n */\n $scope.openDatePicker = function () { $scope.datePicker.opened = true; };\n\n /**\n * Send the new manager, currently stored in $scope.manager, to the server for database saving\n */\n $scope.saveManager = function () {\n User.save(\n {},\n { manager: $scope.manager },\n function () {\n growl.success(_t('app.admin.manager_new.manager_successfully_created', { GENDER: getGender($scope.manager) }));\n return $state.go('app.admin.members');\n }\n , function (error) {\n growl.error(_t('app.admin.manager_new.failed_to_create_manager') + JSON.stringify(error.data ? error.data : error));\n console.error(error);\n }\n );\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Return an enumerable meaningful string for the gender of the provider user\n * @param user {Object} Database user record\n * @return {string} 'male' or 'female'\n */\n const getGender = function (user) {\n if (user.statistic_profile_attributes) {\n if (user.statistic_profile_attributes.gender) { return 'male'; } else { return 'female'; }\n } else { return 'other'; }\n };\n }\n\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Controllers.controller('OpenAPIClientsController', ['$scope', 'clientsPromise', 'settingsPromise', 'growl', 'OpenAPIClient', 'dialogs', '_t', 'Member', 'uiTourService',\n function ($scope, clientsPromise, settingsPromise, growl, OpenAPIClient, dialogs, _t, Member, uiTourService) {\n /* PUBLIC SCOPE */\n\n // clients list\n $scope.clients = clientsPromise;\n $scope.order = null;\n $scope.clientFormVisible = false;\n $scope.client = {};\n\n /**\n * Show the name edition form for a new client\n */\n $scope.createClient = function () {\n $scope.clientFormVisible = true;\n $scope.client = {};\n };\n\n /**\n * Change the order criterion to the one provided\n * @param orderBy {string} ordering criterion\n */\n $scope.setOrder = function (orderBy) {\n if ($scope.order === orderBy) {\n return $scope.order = `-${orderBy}`;\n } else {\n return $scope.order = orderBy;\n }\n };\n\n /**\n * Reset the name ot its original value and close the edition form\n */\n $scope.cancelEdit = function () {\n $scope.client.name = $scope.clientOriginalName;\n $scope.clientFormVisible = false;\n };\n\n $scope.saveClient = function (client) {\n if (client.id != null) {\n OpenAPIClient.update({ id: client.id }, { open_api_client: client }, function (clientResp) {\n client = clientResp;\n return growl.success(_t('app.admin.open_api_clients.client_successfully_updated'));\n });\n } else {\n OpenAPIClient.save({ open_api_client: client }, function (client) {\n $scope.clients.push(client);\n return growl.success(_t('app.admin.open_api_clients.client_successfully_created'));\n });\n }\n\n $scope.clientFormVisible = false;\n $scope.client = {};\n };\n\n $scope.editClient = function (client) {\n $scope.clientFormVisible = true;\n $scope.client = client;\n $scope.clientOriginalName = client.name;\n };\n\n $scope.deleteClient = index =>\n dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.open_api_clients.confirmation_required'),\n msg: _t('app.admin.open_api_clients.do_you_really_want_to_delete_this_open_api_client')\n };\n }\n }\n }\n , () =>\n OpenAPIClient.delete({ id: $scope.clients[index].id }, function () {\n $scope.clients.splice(index, 1);\n return growl.success(_t('app.admin.open_api_clients.client_successfully_deleted'));\n })\n );\n\n $scope.resetToken = client =>\n dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.open_api_clients.confirmation_required'),\n msg: _t('app.admin.open_api_clients.do_you_really_want_to_revoke_this_open_api_access')\n };\n }\n }\n }\n , () =>\n OpenAPIClient.resetToken({ id: client.id }, {}, function (clientResp) {\n client.token = clientResp.token;\n return growl.success(_t('app.admin.open_api_clients.access_successfully_revoked'));\n })\n );\n\n /**\n * Setup the feature-tour for the admin/open_api_clients page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupOpenAPITour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('open-api');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.open_api.welcome.title'),\n content: _t('app.admin.tour.open_api.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.heading .documentation-button',\n stepId: 'doc',\n order: 1,\n title: _t('app.admin.tour.open_api.doc.title'),\n content: _t('app.admin.tour.open_api.doc.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 2,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('open-api') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'open-api' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, and if the display behavior is not configured to manual triggering only, show the tour now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('open-api') < 0) {\n uitour.start();\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {};\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n'use strict';\n\nApplication.Controllers.controller('AdminShowOrdersController', ['$rootScope', '$scope', 'CSRF', 'growl', '$state', '$transition$',\n function ($rootScope, $scope, CSRF, growl, $state, $transition$) {\n /* PRIVATE SCOPE */\n\n /* PUBLIC SCOPE */\n $scope.orderId = $transition$.params().id;\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /**\n * Click Callback triggered in case of back orders list\n */\n $scope.backOrdersList = () => {\n $state.go('app.admin.store.orders');\n };\n\n // currently logged-in user\n $scope.currentUser = $rootScope.currentUser;\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","/* eslint-disable\n camelcase,\n handle-callback-err,\n no-return-assign,\n no-undef,\n no-unused-expressions,\n no-unused-vars,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS205: Consider reworking code to avoid use of IIFEs\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in the plan creation form\n */\nApplication.Controllers.controller('NewPlanController', ['$scope', '$uibModal', 'groups', 'prices', 'partners', 'CSRF', '$state', 'growl', '_t', '$uiRouter',\n function ($scope, $uibModal, groups, prices, partners, CSRF, $state, growl, _t, $uiRouter) {\n // protection against request forgery\n CSRF.setMetaTags();\n\n // the following item is used by the UnsavedFormAlert component to detect a page change\n $scope.uiRouter = $uiRouter;\n\n /**\n * Shows an error message forwarded from a child component\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Shows a success message forwarded from a child react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n }\n]);\n\n/**\n * Controller used in the plan edition form\n */\nApplication.Controllers.controller('EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'spaces', 'prices', 'partners', 'CSRF', '$state', '$transition$', 'growl', '$filter', '_t', '$uiRouter',\n function ($scope, groups, plans, planPromise, machines, spaces, prices, partners, CSRF, $state, $transition$, growl, $filter, _t, $uiRouter) {\n // protection against request forgery\n CSRF.setMetaTags();\n\n $scope.suscriptionPlan = cleanPlan(planPromise);\n\n // the following item is used by the UnsavedFormAlert component to detect a page change\n $scope.uiRouter = $uiRouter;\n\n /**\n * Shows an error message forwarded from a child component\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Shows a success message forwarded from a child react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n // prepare the plan for the react-hook-form\n function cleanPlan (plan) {\n delete plan.$promise;\n delete plan.$resolved;\n return plan;\n }\n }\n]);\n\n/**\n * Controller used the plan-categories administration page.\n * This is just a wrapper to integrate the React component in the angular app\n */\nApplication.Controllers.controller('PlanCategoriesController', ['$scope', 'growl',\n function ($scope, growl) {\n /* PUBLIC SCOPE */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n }\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in price category creation/edition form dialog\n */\nApplication.Controllers.controller('PriceCategoryController', ['$scope', '$uibModalInstance', 'category',\n function ($scope, $uibModalInstance, category) {\n // Price category to edit/empty object for new category\n $scope.category = category;\n\n /**\n * Callback for form validation\n */\n $scope.ok = () => $uibModalInstance.close($scope.category);\n\n /**\n * Do not validate the modifications, hide the modal\n */\n return $scope.cancel = () => $uibModalInstance.dismiss('cancel');\n }\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS205: Consider reworking code to avoid use of IIFEs\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in the prices edition page\n */\nApplication.Controllers.controller('EditPricingController', ['$scope', '$state', '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', 'spacesPromise', 'spacesPricesPromise', 'spacesCreditsPromise', 'settingsPromise', '_t', 'Member', 'uiTourService', 'planCategories',\n function ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, spacesPromise, spacesPricesPromise, spacesCreditsPromise, settingsPromise, _t, Member, uiTourService, planCategories) {\n /* PUBLIC SCOPE */\n\n // List of trainings pricing\n $scope.trainingsPricings = trainingsPricingsPromise;\n\n // List of available subscriptions plans (eg. student/month, PME/year ...)\n $scope.plans = plans;\n $scope.enabledPlans = plans.filter(function (p) { return !p.disabled; });\n\n // List of groups (eg. normal, student ...)\n $scope.groups = groups;\n $scope.enabledGroups = groups.filter(function (g) { return !g.disabled; });\n\n // List of all plan-categories\n $scope.planCategories = planCategories;\n\n // Associate free machine hours with subscriptions\n $scope.machineCredits = machineCreditsPromise;\n\n // Array of associations (plan <-> training)\n $scope.trainingCredits = trainingCreditsPromise;\n\n // Associate a plan with all its trainings ids\n $scope.trainingCreditsGroups = {};\n\n // List of trainings\n $scope.trainings = trainingsPromise.filter(function (t) { return !t.disabled; });\n\n // List of machines\n $scope.machines = machinesPromise;\n $scope.enabledMachines = machinesPromise.filter(function (m) { return !m.disabled; });\n\n // List of coupons\n $scope.coupons = couponsPromise;\n $scope.couponsPage = 1;\n\n // List of spaces\n $scope.spaces = spacesPromise;\n $scope.enabledSpaces = spacesPromise.filter(function (s) { return !s.disabled; });\n\n // Associate free space hours with subscriptions\n $scope.spaceCredits = spacesCreditsPromise;\n\n // List of spaces prices (not considering any plan)\n $scope.spacesPrices = spacesPricesPromise;\n\n // The plans list ordering. Default: by group\n $scope.orderPlans = 'group_id';\n\n // Status of the drop-down menu in Credits tab\n $scope.status =\n { isopen: false };\n\n // Default: we show only enabled plans\n $scope.planFiltering = 'enabled';\n\n // Default duration for the slots\n $scope.slotDuration = parseInt(settingsPromise.slot_duration, 10);\n\n // Available options for filtering plans by status\n $scope.filterDisabled = [\n 'enabled',\n 'disabled',\n 'all'\n ];\n\n // Default: we do not filter coupons\n $scope.filter = {\n coupon: 'all'\n };\n\n // Available status for filtering coupons\n $scope.couponStatus = [\n 'all',\n 'disabled',\n 'expired',\n 'sold_out',\n 'active'\n ];\n\n // default tab: plans list\n $scope.tabs = { active: 0 };\n\n /**\n * Retrieve a training price from all the trainings prices\n * @param trainingsPricings {Array} all trainings prices\n * @param trainingId {number}\n * @param groupId {number}\n * @returns {float}\n */\n $scope.findTrainingsPricing = function (trainingsPricings, trainingId, groupId) {\n for (const trainingsPricing of Array.from(trainingsPricings)) {\n if ((trainingsPricing.training_id === trainingId) && (trainingsPricing.group_id === groupId)) {\n return trainingsPricing;\n }\n }\n };\n\n /**\n * Update the price of a training for the given parameters\n * @param data {float} the new price\n * @param trainingsPricing {Object} the training pricing to update\n * @returns {Promise|string}\n */\n $scope.updateTrainingsPricing = function (data, trainingsPricing) {\n if (data != null) {\n return TrainingsPricing.update({ id: trainingsPricing.id }, { trainings_pricing: { amount: data } }).$promise;\n } else {\n return _t('app.admin.pricing.please_specify_a_number');\n }\n };\n\n /**\n * Retrieve a plan from its given identifier and returns it\n * @param id {number} plan ID\n * @returns {Object} Plan, inherits from $resource\n */\n $scope.getPlanFromId = function (id) {\n for (const plan of Array.from($scope.plans)) {\n if (plan.id === parseInt(id)) {\n return plan;\n }\n }\n };\n\n /**\n * Retrieve a group from its given identifier and returns it\n * @param id {number} group ID\n * @returns {Object} Group, inherits from $resource\n */\n $scope.getGroupFromId = function (groups, id) {\n for (const group of Array.from(groups)) {\n if (group.id === parseInt(id)) {\n return group;\n }\n }\n };\n\n /**\n * Returns a human readable string of named trainings, according to the provided array.\n * $scope.trainings may contains the full list of training. The returned string will only contains the trainings\n * whom ID are given in the provided parameter\n * @param trainings {Array} trainings IDs array\n */\n $scope.showTrainings = function (trainings) {\n if (!angular.isArray(trainings) || !(trainings.length > 0)) {\n return _t('app.admin.pricing.none');\n }\n\n const selected = [];\n angular.forEach($scope.trainings, function (t) {\n if (trainings.indexOf(t.id) >= 0) {\n return selected.push(t.name);\n }\n });\n if (selected.length) { return selected.join(' | '); } else { return _t('app.admin.pricing.none'); }\n };\n\n /**\n * Validation callback when editing training's credits. Save the changes.\n * @param newdata {Object} training and associated plans\n * @param planId {number|string} plan id\n */\n $scope.saveTrainingCredits = function (newdata, planId) {\n // save the number of credits\n Plan.update(\n { id: planId },\n { training_credit_nb: newdata.training_credits }\n , angular.noop() // do nothing in case of success\n , function (error) {\n growl.error(_t('app.admin.pricing.an_error_occurred_while_saving_the_number_of_credits'));\n console.error(error);\n }\n );\n\n // save the associated trainings\n return angular.forEach($scope.trainingCreditsGroups, function (original, key) {\n if (parseInt(key) === parseInt(planId)) { // we've got the original data\n if (original.join('_') !== newdata.training_ids.join('_')) { // if any changes\n // iterate through the previous credits to remove\n angular.forEach(original, function (oldTrainingId) {\n if (newdata.training_ids.indexOf(oldTrainingId) === -1) {\n const tc = findTrainingCredit(oldTrainingId, planId);\n if (tc) {\n return tc.$delete({}\n , function () {\n $scope.trainingCredits.splice($scope.trainingCredits.indexOf(tc), 1);\n return $scope.trainingCreditsGroups[planId].splice($scope.trainingCreditsGroups[planId].indexOf(tc.id), 1);\n }\n , function (error) {\n growl.error(_t('app.admin.pricing.an_error_occurred_while_deleting_credit_with_the_TRAINING', { TRAINING: tc.creditable.name }));\n console.error(error);\n });\n } else {\n return growl.error(_t('app.admin.pricing.an_error_occurred_unable_to_find_the_credit_to_revoke'));\n }\n }\n });\n\n // iterate through the new credits to add\n return angular.forEach(newdata.training_ids, function (newTrainingId) {\n if (original.indexOf(newTrainingId) === -1) {\n return Credit.save({\n credit: {\n creditable_id: newTrainingId,\n creditable_type: 'Training',\n plan_id: planId\n }\n }\n , function (newTc) { // success\n $scope.trainingCredits.push(newTc);\n return $scope.trainingCreditsGroups[newTc.plan_id].push(newTc.creditable_id);\n }\n , function (error) { // failed\n const training = getTrainingFromId(newTrainingId);\n growl.error(_t('app.admin.pricing.an_error_occurred_while_creating_credit_with_the_TRAINING', { TRAINING: training.name }));\n return console.error(error);\n });\n }\n });\n }\n }\n });\n };\n\n /**\n * Cancel the current training credit modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n */\n $scope.cancelTrainingCredit = function (rowform) { rowform.$cancel(); };\n\n /**\n * Create a new empty entry in the $scope.machineCredits array\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.addMachineCredit = function (e) {\n e.preventDefault();\n e.stopPropagation();\n $scope.inserted =\n { creditable_type: 'Machine' };\n $scope.machineCredits.push($scope.inserted);\n return $scope.status.isopen = !$scope.status.isopen;\n };\n\n /**\n * In the Credits tab, return the name of the machine/space associated with the given credit\n * @param credit {Object} credit object, inherited from $resource\n * @returns {String}\n */\n $scope.showCreditableName = function (credit) {\n let selected = _t('app.admin.pricing.not_set');\n if (credit && credit.creditable_id) {\n const object = $scope.getCreditable(credit);\n selected = object.name;\n if (credit.creditable_type === 'Machine') {\n selected += ` ( id. ${object.id} )`;\n }\n }\n return selected;\n };\n\n /**\n * In the Credits tab, return the machine/space associated with the given credit\n * @param credit {Object} credit object, inherited from $resource\n * @returns {Object}\n */\n $scope.getCreditable = function (credit) {\n let selected;\n if (credit && credit.creditable_id) {\n if (credit.creditable_type === 'Machine') {\n angular.forEach($scope.machines, function (m) {\n if (m.id === credit.creditable_id) {\n return selected = m;\n }\n });\n } else if (credit.creditable_type === 'Space') {\n angular.forEach($scope.spaces, function (s) {\n if (s.id === credit.creditable_id) {\n return selected = s;\n }\n });\n }\n }\n return selected;\n };\n\n /**\n * Validation callback when editing machine's credits. Save the changes.\n * This will prevent the creation of two credits associating the same machine and plan.\n * @param data {Object} machine, associated plan and number of credit hours.\n * @param [id] {number} credit id for edition, create a new credit object if not provided\n */\n $scope.saveMachineCredit = function (data, id) {\n for (const mc of Array.from($scope.machineCredits)) {\n if ((mc.plan_id === data.plan_id) && (mc.creditable_id === data.creditable_id) && ((id === null) || (mc.id !== id))) {\n growl.error(_t('app.admin.pricing.error_a_credit_linking_this_machine_with_that_subscription_already_exists'));\n if (!id) {\n $scope.machineCredits.pop();\n }\n return false;\n }\n }\n\n if (id != null) {\n return Credit.update({ id }, { credit: data }, function () { growl.success(_t('app.admin.pricing.changes_have_been_successfully_saved')); });\n } else {\n data.creditable_type = 'Machine';\n return Credit.save(\n { credit: data }\n , function (resp) {\n $scope.machineCredits[$scope.machineCredits.length - 1].id = resp.id;\n return growl.success(_t('app.admin.pricing.credit_was_successfully_saved'));\n }\n , function (err) {\n $scope.machineCredits.pop();\n growl.error(_t('app.admin.pricing.error_creating_credit'));\n console.error(err);\n });\n }\n };\n\n /**\n * Removes the newly inserted but not saved machine credit / Cancel the current machine credit modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} credit index in the $scope.machineCredits array\n */\n $scope.cancelMachineCredit = function (rowform, index) {\n if ($scope.machineCredits[index].id != null) {\n return rowform.$cancel();\n } else {\n return $scope.machineCredits.splice(index, 1);\n }\n };\n\n /**\n * Deletes the machine credit at the specified index\n * @param index {number} machine credit index in the $scope.machineCredits array\n */\n $scope.removeMachineCredit = function (index) {\n Credit.delete($scope.machineCredits[index]);\n $scope.machineCredits.splice(index, 1);\n };\n\n /**\n * Create a new empty entry in the $scope.spaceCredits array\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.addSpaceCredit = function (e) {\n e.preventDefault();\n e.stopPropagation();\n $scope.inserted =\n { creditable_type: 'Space' };\n $scope.spaceCredits.push($scope.inserted);\n $scope.status.isopen = !$scope.status.isopen;\n };\n\n /**\n * Validation callback when editing space's credits. Save the changes.\n * This will prevent the creation of two credits associated with the same space and plan.\n * @param data {Object} space, associated plan and number of credit hours.\n * @param [id] {number} credit id for edition, create a new credit object if not provided\n */\n $scope.saveSpaceCredit = function (data, id) {\n for (const sc of Array.from($scope.spaceCredits)) {\n if ((sc.plan_id === data.plan_id) && (sc.creditable_id === data.creditable_id) && ((id === null) || (sc.id !== id))) {\n growl.error(_t('app.admin.pricing.error_a_credit_linking_this_space_with_that_subscription_already_exists'));\n if (!id) {\n $scope.spaceCredits.pop();\n }\n return false;\n }\n }\n\n if (id != null) {\n return Credit.update({ id }, { credit: data }, function () { growl.success(_t('app.admin.pricing.changes_have_been_successfully_saved')); });\n } else {\n data.creditable_type = 'Space';\n return Credit.save(\n { credit: data }\n , function (resp) {\n $scope.spaceCredits[$scope.spaceCredits.length - 1].id = resp.id;\n return growl.success(_t('app.admin.pricing.credit_was_successfully_saved'));\n }\n , function () {\n $scope.spaceCredits.pop();\n return growl.error(_t('app.admin.pricing.error_creating_credit'));\n });\n }\n };\n\n /**\n * Removes the newly inserted but not saved space credit / Cancel the current space credit modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} credit index in the $scope.spaceCredits array\n */\n $scope.cancelSpaceCredit = function (rowform, index) {\n if ($scope.spaceCredits[index].id != null) {\n return rowform.$cancel();\n } else {\n return $scope.spaceCredits.splice(index, 1);\n }\n };\n\n /**\n * Deletes the space credit at the specified index\n * @param index {number} space credit index in the $scope.spaceCredits array\n */\n $scope.removeSpaceCredit = function (index) {\n Credit.delete($scope.spaceCredits[index]);\n return $scope.spaceCredits.splice(index, 1);\n };\n\n /**\n * Return the name of the plan-category, from its ID\n * @param id {number|undefined} plan-category's id\n * @returns {string} the name\n */\n $scope.getPlanCategory = function (id) {\n const cat = $scope.planCategories.find(c => c.id === id);\n if (cat) {\n return cat.name;\n }\n };\n\n /**\n * Change the plans ordering criterion to the one provided\n * @param orderBy {string} ordering criterion\n */\n $scope.setOrderPlans = function (orderBy) {\n if ($scope.orderPlans === orderBy) {\n return $scope.orderPlans = `-${orderBy}`;\n } else {\n return $scope.orderPlans = orderBy;\n }\n };\n\n /**\n * Retrieve a price from prices array by a machineId and a groupId\n */\n $scope.findPriceBy = function (prices, machineId, groupId) {\n for (const price of Array.from(prices)) {\n if ((price.priceable_id === machineId) && (price.group_id === groupId) && (price.duration === 60)) {\n return price;\n }\n }\n };\n\n /**\n * update a price for a machine and a group, not considering any plan\n */\n $scope.updatePrice = function (data, price) {\n if (data != null) {\n return Price.update({ id: price.id }, { price: { amount: data } }).$promise;\n } else {\n return _t('app.admin.pricing.please_specify_a_number');\n }\n };\n\n /**\n * Delete the specified subcription plan\n * @param id {number} plan id\n */\n $scope.deletePlan = function (plans, id) {\n if (typeof id !== 'number') {\n return console.error('[EditPricingController::deletePlan] Error: invalid id parameter');\n } else {\n // open a confirmation dialog\n return dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.pricing.confirmation_required'),\n msg: _t('app.admin.pricing.do_you_really_want_to_delete_this_subscription_plan')\n };\n }\n }\n },\n function () {\n // the admin has confirmed, delete the plan\n Plan.delete(\n { id },\n function (res) {\n growl.success(_t('app.admin.pricing.subscription_plan_was_successfully_deleted'));\n return $scope.plans.splice(findItemIdxById(plans, id), 1);\n },\n function (error) {\n if (error.statusText) { console.error(`[EditPricingController::deletePlan] Error: ${error.statusText}`); }\n growl.error(_t('app.admin.pricing.unable_to_delete_the_specified_subscription_an_error_occurred'));\n }\n );\n }\n );\n }\n };\n\n /**\n * Generate a string identifying the given plan by literal humain-readable name\n * @param plan {Object} Plan object, as recovered from GET /api/plan/:id\n * @param groups {Array} List of Groups objects, as recovered from GET /api/groups\n * @param short {boolean} If true, the generated name will contains the group slug, otherwise the group full name\n * will be included.\n * @returns {String}\n */\n $scope.humanReadablePlanName = function (plan, groups, short) { return `${$filter('humanReadablePlanName')(plan, groups, short)}`; };\n\n /**\n * Delete a coupon from the server's database and, in case of success, from the list in memory\n * @param coupons {Array} should be called with $scope.coupons\n * @param id {number} ID of the coupon to delete\n */\n $scope.deleteCoupon = function (coupons, id) {\n if (typeof id !== 'number') {\n return console.error('[EditPricingController::deleteCoupon] Error: invalid id parameter');\n } else {\n // open a confirmation dialog\n return dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.pricing.confirmation_required'),\n msg: _t('app.admin.pricing.do_you_really_want_to_delete_this_coupon')\n };\n }\n }\n }\n , function () {\n // the admin has confirmed, delete the coupon\n Coupon.delete({ id }, function (res) {\n growl.success(_t('app.admin.pricing.coupon_was_successfully_deleted'));\n return $scope.coupons.splice(findItemIdxById(coupons, id), 1);\n }\n\n , function (error) {\n if (error.statusText) { console.error(`[EditPricingController::deleteCoupon] Error: ${error.statusText}`); }\n if (error.status === 422) {\n return growl.error(_t('app.admin.pricing.unable_to_delete_the_specified_coupon_already_in_use'));\n } else {\n return growl.error(_t('app.admin.pricing.unable_to_delete_the_specified_coupon_an_unexpected_error_occurred'));\n }\n });\n });\n }\n };\n\n /**\n * Open a modal allowing to select an user and send him the details of the provided coupon\n * @param coupon {Object} The coupon to send\n */\n $scope.sendCouponToUser = function (coupon) {\n $uibModal.open({\n templateUrl: '/admin/pricing/sendCoupon.html',\n resolve: {\n coupon () { return coupon; },\n enableUserValidationRequired () { return settingsPromise.user_validation_required === 'true'; }\n },\n size: 'md',\n controller: ['$scope', '$uibModalInstance', 'Coupon', 'coupon', '_t', 'enableUserValidationRequired', function ($scope, $uibModalInstance, Coupon, coupon, _t, enableUserValidationRequired) {\n // Global config: is the user validation required ?\n $scope.enableUserValidationRequired = enableUserValidationRequired;\n\n // Member, receiver of the coupon\n $scope.ctrl =\n { member: null };\n\n // Details of the coupon to send\n $scope.coupon = coupon;\n\n // Callback to validate sending of the coupon\n $scope.ok = function () {\n Coupon.send({ coupon_code: coupon.code, user_id: $scope.ctrl.member.id }, function (res) {\n growl.success(_t('app.admin.pricing.coupon_successfully_sent_to_USER', { USER: $scope.ctrl.member.name }));\n return $uibModalInstance.close({ user_id: $scope.ctrl.member.id });\n }\n , function (err) {\n growl.error(_t('app.admin.pricing.an_error_occurred_unable_to_send_the_coupon'));\n console.error(err);\n });\n };\n // Callback to close the modal and cancel the sending process\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }]\n });\n };\n\n /**\n * Load the next 10 coupons\n */\n $scope.loadMore = function () {\n $scope.couponsPage++;\n Coupon.query({ page: $scope.couponsPage, filter: $scope.filter.coupon }, function (data) {\n $scope.coupons = $scope.coupons.concat(data);\n });\n };\n\n /**\n * Reset the list of coupons according to the newly selected filter\n */\n $scope.updateCouponFilter = function () {\n $scope.couponsPage = 1;\n Coupon.query({ page: $scope.couponsPage, filter: $scope.filter.coupon }, function (data) {\n $scope.coupons = data;\n });\n };\n\n /**\n * Return the exemple price based on the configuration of the default slot duration.\n * @param type {string} 'hourly_rate' | *\n * @returns {number} price for \"SLOT_DURATION\" minutes.\n */\n $scope.examplePrice = function (type) {\n const hourlyRate = 10;\n\n if (type === 'hourly_rate') {\n return $filter('currency')(hourlyRate);\n }\n\n const price = (hourlyRate / 60) * $scope.slotDuration;\n return $filter('currency')(price);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Setup the feature-tour for the admin/pricing page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupPricingTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('pricing');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.pricing.welcome.title'),\n content: _t('app.admin.tour.pricing.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.plans-pricing .new-plan-button',\n stepId: 'new_plan',\n order: 1,\n title: _t('app.admin.tour.pricing.new_plan.title'),\n content: _t('app.admin.tour.pricing.new_plan.content'),\n placement: 'bottom'\n });\n if ($scope.$root.modules.trainings) {\n uitour.createStep({\n selector: '.plans-pricing .trainings-tab',\n stepId: 'trainings',\n order: 2,\n title: _t('app.admin.tour.pricing.trainings.title'),\n content: _t('app.admin.tour.pricing.trainings.content'),\n placement: 'bottom'\n });\n }\n if ($scope.$root.modules.machines) {\n uitour.createStep({\n selector: '.plans-pricing .machines-tab',\n stepId: 'machines',\n order: 3,\n title: _t('app.admin.tour.pricing.machines.title'),\n content: _t('app.admin.tour.pricing.machines.content'),\n placement: 'bottom'\n });\n }\n if ($scope.$root.modules.spaces) {\n uitour.createStep({\n selector: '.plans-pricing .spaces-tab',\n stepId: 'spaces',\n order: 4,\n title: _t('app.admin.tour.pricing.spaces.title'),\n content: _t('app.admin.tour.pricing.spaces.content'),\n placement: 'bottom'\n });\n }\n uitour.createStep({\n selector: '.plans-pricing .credits-tab',\n stepId: 'credits',\n order: 5,\n title: _t('app.admin.tour.pricing.credits.title'),\n content: _t('app.admin.tour.pricing.credits.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.plans-pricing .coupons-tab',\n stepId: 'coupons',\n order: 6,\n title: _t('app.admin.tour.pricing.coupons.title'),\n content: _t('app.admin.tour.pricing.coupons.content'),\n placement: 'bottom',\n popupClass: 'shift-left-50'\n });\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 7,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on step change, change the active tab if needed\n uitour.on('stepChanged', function (nextStep) {\n if (nextStep.stepId === 'new_plan') { $scope.tabs.active = 0; }\n if (nextStep.stepId === 'trainings') { $scope.tabs.active = 1; }\n if (nextStep.stepId === 'machines') { $scope.tabs.active = 2; }\n if (nextStep.stepId === 'spaces') { $scope.tabs.active = 3; }\n if (nextStep.stepId === 'credits') { $scope.tabs.active = 4; }\n if (nextStep.stepId === 'coupons') { $scope.tabs.active = 5; }\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('pricing') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'pricing' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('pricing') < 0) {\n uitour.start();\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n $scope.trainingCreditsGroups = groupCreditsByPlan($scope.trainingCredits);\n\n // adds empty array for plan which hasn't any credits yet\n return (function () {\n const result = [];\n for (const plan of Array.from($scope.plans)) {\n if ($scope.trainingCreditsGroups[plan.id] == null) {\n result.push($scope.trainingCreditsGroups[plan.id] = []);\n } else {\n result.push(undefined);\n }\n }\n return result;\n })();\n };\n\n /**\n * Retrieve an item index by its ID from the given array of objects\n * @param items {Array<{id:number}>}\n * @param id {number}\n * @returns {number} item index in the provided array\n */\n const findItemIdxById = function (items, id) {\n return (items.map(function (item) { return item.id; })).indexOf(id);\n };\n\n /**\n * Group the given credits array into a map associating the plan ID with its associated trainings/machines\n * @return {Object} the association map\n */\n const groupCreditsByPlan = function (credits) {\n const creditsMap = {};\n angular.forEach(credits, function (c) {\n if (!creditsMap[c.plan_id]) {\n creditsMap[c.plan_id] = [];\n }\n return creditsMap[c.plan_id].push(c.creditable_id);\n });\n return creditsMap;\n };\n\n /**\n * Iterate through $scope.traininfCredits to find the credit matching the given criterion\n * @param trainingId {number|string} training ID\n * @param planId {number|string} plan ID\n */\n const findTrainingCredit = function (trainingId, planId) {\n trainingId = parseInt(trainingId);\n planId = parseInt(planId);\n\n for (const credit of Array.from($scope.trainingCredits)) {\n if ((credit.plan_id === planId) && (credit.creditable_id === trainingId)) {\n return credit;\n }\n }\n };\n\n /**\n * Retrieve a training from its given identifier and returns it\n * @param id {number} training ID\n * @returns {Object} Training inherited from $resource\n */\n const getTrainingFromId = function (id) {\n for (const training of Array.from($scope.trainings)) {\n if (training.id === parseInt(id)) {\n return training;\n }\n }\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Controllers.controller('AdminProjectsController', ['$scope', '$state', 'Component', 'Licence', 'Theme', 'componentsPromise', 'licencesPromise', 'themesPromise', '_t', 'Member', 'uiTourService', 'settingsPromise', 'growl',\n function ($scope, $state, Component, Licence, Theme, componentsPromise, licencesPromise, themesPromise, _t, Member, uiTourService, settingsPromise, growl) {\n // Materials list (plastic, wood ...)\n $scope.components = componentsPromise;\n\n // Licences list (Creative Common ...)\n $scope.licences = licencesPromise;\n\n // Themes list (cooking, sport ...)\n $scope.themes = themesPromise;\n\n // Application settings\n $scope.allSettings = settingsPromise;\n\n // default tab: materials\n $scope.tabs = { active: 0 };\n\n /**\n * Saves a new component / Update an existing material to the server (form validation callback)\n * @param data {Object} component name\n * @param [id] {number} component id, in case of update\n */\n $scope.saveComponent = function (data, id) {\n if (id != null) {\n return Component.update({ id }, data);\n } else {\n return Component.save(data, resp => $scope.components[$scope.components.length - 1].id = resp.id);\n }\n };\n\n /**\n * Deletes the component at the specified index\n * @param index {number} component index in the $scope.components array\n */\n $scope.removeComponent = function (index) {\n Component.delete($scope.components[index]);\n return $scope.components.splice(index, 1);\n };\n\n /**\n * Creates a new empty entry in the $scope.components array\n */\n $scope.addComponent = function () {\n $scope.inserted = { name: '' };\n $scope.components.push($scope.inserted);\n };\n\n /**\n * Removes the newly inserted but not saved component / Cancel the current component modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} component index in the $scope.components array\n */\n $scope.cancelComponent = function (rowform, index) {\n if ($scope.components[index].id != null) {\n return rowform.$cancel();\n } else {\n return $scope.components.splice(index, 1);\n }\n };\n\n /**\n * Saves a new theme / Update an existing theme to the server (form validation callback)\n * @param data {Object} theme name\n * @param [data] {number} theme id, in case of update\n */\n $scope.saveTheme = function (data, id) {\n if (id != null) {\n return Theme.update({ id }, data);\n } else {\n return Theme.save(data, resp => $scope.themes[$scope.themes.length - 1].id = resp.id);\n }\n };\n\n /**\n * Deletes the theme at the specified index\n * @param index {number} theme index in the $scope.themes array\n */\n $scope.removeTheme = function (index) {\n Theme.delete($scope.themes[index]);\n return $scope.themes.splice(index, 1);\n };\n\n /**\n * Creates a new empty entry in the $scope.themes array\n */\n $scope.addTheme = function () {\n $scope.inserted = { name: '' };\n $scope.themes.push($scope.inserted);\n };\n\n /**\n * Removes the newly inserted but not saved theme / Cancel the current theme modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} theme index in the $scope.themes array\n */\n $scope.cancelTheme = function (rowform, index) {\n if ($scope.themes[index].id != null) {\n rowform.$cancel();\n } else {\n $scope.themes.splice(index, 1);\n }\n };\n\n /**\n * Saves a new licence / Update an existing licence to the server (form validation callback)\n * @param data {Object} licence name and description\n * @param [id] {number} licence id, in case of update\n */\n $scope.saveLicence = function (data, id) {\n if (id != null) {\n return Licence.update({ id }, data);\n } else {\n return Licence.save(data, resp => $scope.licences[$scope.licences.length - 1].id = resp.id);\n }\n };\n\n /**\n * Deletes the licence at the specified index\n * @param index {number} licence index in the $scope.licences array\n */\n $scope.removeLicence = function (index) {\n Licence.delete($scope.licences[index]);\n return $scope.licences.splice(index, 1);\n };\n\n /**\n * Creates a new empty entry in the $scope.licences array\n */\n $scope.addLicence = function () {\n $scope.inserted = {\n name: '',\n description: ''\n };\n return $scope.licences.push($scope.inserted);\n };\n\n /**\n * Removes the newly inserted but not saved licence / Cancel the current licence modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} licence index in the $scope.licences array\n */\n $scope.cancelLicence = function (rowform, index) {\n if ($scope.licences[index].id != null) {\n return rowform.$cancel();\n } else {\n return $scope.licences.splice(index, 1);\n }\n };\n\n /**\n * When a file is sent to the server to test it against its MIME type,\n * handle the result of the test.\n */\n $scope.onTestFileComplete = function (res) {\n if (res) {\n growl.success(_t('app.admin.projects.settings.file_is_TYPE', { TYPE: res.type }));\n }\n };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n\n /**\n * Remove the initial dot from the given extension, if any\n * @param extension {String}\n * @returns {String}\n */\n $scope.removeInitialDot = function (extension) {\n if (extension.substr(0, 1) === '.') return $scope.lower(extension.substr(1));\n\n return $scope.lower(extension);\n };\n\n /**\n * Return the lowercase version of the provided string\n * @param text {String}\n * @returns {string}\n */\n $scope.lower = function (text) {\n return text.toLowerCase();\n };\n\n /**\n * Setup the feature-tour for the admin/projects page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupProjectElementsTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('projects');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.projects.welcome.title'),\n content: _t('app.admin.tour.projects.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.heading .abuses-button',\n stepId: 'abuses',\n order: 1,\n title: _t('app.admin.tour.projects.abuses.title'),\n content: _t('app.admin.tour.projects.abuses.content'),\n placement: 'bottom',\n popupClass: 'shift-left-40'\n });\n uitour.createStep({\n selector: '.projects .settings-tab',\n stepId: 'settings',\n order: 2,\n title: _t('app.admin.tour.projects.settings.title'),\n content: _t('app.admin.tour.projects.settings.content'),\n placement: 'bottom',\n popupClass: 'shift-left-50'\n });\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 3,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on step change, change the active tab if needed\n uitour.on('stepChanged', function (nextStep) {\n if (nextStep.stepId === 'settings') { $scope.tabs.active = 3; }\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('projects') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'projects' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('projects') < 0) {\n uitour.start();\n }\n };\n\n /**\n * Shows a success message forwarded from a child react component\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {};\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Controllers.controller('SettingsController', ['$scope', '$rootScope', '$filter', '$uibModal', 'dialogs', 'Setting', 'growl', 'settingsPromise', 'privacyDraftsPromise', 'cgvFile', 'cguFile', 'logoFile', 'logoBlackFile', 'faviconFile', 'profileImageFile', 'CSRF', '_t', 'Member', 'uiTourService',\n function ($scope, $rootScope, $filter, $uibModal, dialogs, Setting, growl, settingsPromise, privacyDraftsPromise, cgvFile, cguFile, logoFile, logoBlackFile, faviconFile, profileImageFile, CSRF, _t, Member, uiTourService) {\n /* PUBLIC SCOPE */\n\n // timepickers steps configuration\n $scope.timepicker = {\n hstep: 1,\n mstep: 15\n };\n\n // API URL where the upload forms will be posted\n $scope.actionUrl = {\n cgu: '/api/custom_assets',\n cgv: '/api/custom_assets',\n logo: '/api/custom_assets',\n logoBlack: '/api/custom_assets',\n favicon: '/api/custom_assets',\n profileImage: '/api/custom_assets'\n };\n\n // Form actions on the above URL\n $scope.methods = {\n cgu: 'post',\n cgv: 'post',\n logo: 'post',\n logoBlack: 'post',\n favicon: 'post',\n profileImage: 'post'\n };\n\n // Are we uploading the files currently (if so, display the loader)\n $scope.loader = {\n cgu: false,\n cgv: false\n };\n\n // default tab: general\n $scope.tabs = { active: 0 };\n\n // full history of privacy policy drafts\n $scope.privacyDraftsHistory = [];\n\n // all settings as retrieved from database\n $scope.allSettings = settingsPromise;\n\n // various configurable settings\n $scope.aboutTitleSetting = { name: 'about_title', value: settingsPromise.about_title };\n $scope.aboutBodySetting = { name: 'about_body', value: settingsPromise.about_body };\n $scope.privacyDpoSetting = { name: 'privacy_dpo', value: settingsPromise.privacy_dpo };\n $scope.aboutContactsSetting = { name: 'about_contacts', value: settingsPromise.about_contacts };\n $scope.homeBlogpostSetting = { name: 'home_blogpost', value: settingsPromise.home_blogpost };\n $scope.homeContent = { name: 'home_content', value: settingsPromise.home_content };\n $scope.homeCss = { name: 'home_css', value: settingsPromise.home_css };\n $scope.machineExplicationsAlert = { name: 'machine_explications_alert', value: settingsPromise.machine_explications_alert };\n $scope.trainingExplicationsAlert = { name: 'training_explications_alert', value: settingsPromise.training_explications_alert };\n $scope.trainingInformationMessage = { name: 'training_information_message', value: settingsPromise.training_information_message };\n $scope.subscriptionExplicationsAlert = { name: 'subscription_explications_alert', value: settingsPromise.subscription_explications_alert };\n $scope.eventExplicationsAlert = { name: 'event_explications_alert', value: settingsPromise.event_explications_alert };\n $scope.spaceExplicationsAlert = { name: 'space_explications_alert', value: settingsPromise.space_explications_alert };\n $scope.windowStart = { name: 'booking_window_start', value: settingsPromise.booking_window_start };\n $scope.windowEnd = { name: 'booking_window_end', value: settingsPromise.booking_window_end };\n $scope.mainColorSetting = { name: 'main_color', value: settingsPromise.main_color };\n $scope.secondColorSetting = { name: 'secondary_color', value: settingsPromise.secondary_color };\n $scope.nameGenre = { name: 'name_genre', value: settingsPromise.name_genre };\n $scope.cguFile = cguFile.custom_asset;\n $scope.cgvFile = cgvFile.custom_asset;\n $scope.customLogo = logoFile.custom_asset;\n $scope.customLogoBlack = logoBlackFile.custom_asset;\n $scope.customFavicon = faviconFile.custom_asset;\n $scope.profileImage = profileImageFile.custom_asset;\n\n // By default, we display the currently published privacy policy\n $scope.privacyPolicy = {\n version: null,\n bodyTemp: settingsPromise.privacy_body\n };\n\n // Extend the options for summernote editor, with special tools for home page\n $scope.summernoteOptsHomePage = angular.copy($rootScope.summernoteOpts);\n $scope.summernoteOptsHomePage.toolbar[5][1].push('nugget'); // toolbar -> insert -> nugget\n $scope.summernoteOptsHomePage.nugget = {\n label: '\\uF12E',\n tooltip: _t('app.admin.settings.home_items'),\n list: [\n `
${_t('app.admin.settings.item_news')}
`,\n `
${_t('app.admin.settings.item_projects')}
`,\n `
${_t('app.admin.settings.item_twitter')}
`,\n `
${_t('app.admin.settings.item_members')}
`,\n `
${_t('app.admin.settings.item_events')}
`\n ]\n };\n $scope.summernoteOptsHomePage.height = 400;\n\n // codemirror editor\n $scope.codeMirrorEditor = null;\n\n // Options for codemirror editor, used for custom css\n $scope.codemirrorOpts = {\n matchBrackets: true,\n lineNumbers: true,\n mode: 'sass'\n };\n\n // Show or hide advanced settings\n $scope.advancedSettings = {\n open: false\n };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n\n /**\n * Callback to save the setting value to the database\n * @param setting {{value:*, name:string}} note that the value will be stringified\n */\n $scope.save = function (setting) {\n // trim empty html\n let value;\n if ((setting.value === '
') || (setting.value === '


')) {\n setting.value = '';\n }\n // convert dates to ISO format\n if (setting.value instanceof Date) {\n setting.value = setting.value.toISOString();\n }\n\n if (setting.value !== null) {\n value = setting.value.toString();\n } else {\n ({ value } = setting);\n }\n\n Setting.update(\n { name: setting.name },\n { value },\n function () { growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) })); },\n function (error) {\n if (error.status === 304) return;\n\n growl.error(_t('app.admin.settings.an_error_occurred_saving_the_setting'));\n console.log(error);\n }\n );\n };\n\n /**\n * The privacy policy has its own special save function because updating the policy must notify all users\n */\n $scope.savePrivacyPolicy = function () {\n // open modal\n const modalInstance = $uibModal.open({\n templateUrl: '/admin/settings/save_policy.html',\n controller: 'SavePolicyController',\n resolve: {\n saveCb () { return $scope.save; },\n privacyPolicy () { return $scope.privacyPolicy; }\n }\n });\n\n // once done, update the client data\n modalInstance.result.then(function (type) {\n Setting.get({ name: 'privacy_draft', history: true }, function (data) {\n // reset history\n $scope.privacyDraftsHistory = [];\n data.setting.history.forEach(function (draft) {\n $scope.privacyDraftsHistory.push({ id: draft.id, name: _t('app.admin.settings.privacy.draft_from_USER_DATE', { USER: draft.user.name, DATE: draft.created_at }), content: draft.value });\n });\n if (type === 'privacy_draft') {\n const orderedHistory = $filter('orderBy')(data.setting.history, 'created_at');\n const last = orderedHistory[orderedHistory.length - 1];\n if (last) {\n $scope.privacyPolicy.version = last.id;\n }\n } else {\n $scope.privacyPolicy.version = null;\n }\n });\n });\n };\n\n /**\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when the upload is done: Any raised error will be displayed in a growl\n * message. If everything goes fine, a growl success message is shown.\n * @param content {Object} JSON - The upload's result\n */\n $scope.submited = function (content) {\n if ((content.custom_asset == null)) {\n $scope.alerts = [];\n return angular.forEach(content, function (v) {\n angular.forEach(v, function (err) { growl.error(err); });\n });\n } else {\n growl.success(_t('app.admin.settings.file_successfully_updated'));\n if (content.custom_asset.name === 'cgu-file') {\n $scope.cguFile = content.custom_asset;\n $scope.methods.cgu = 'put';\n if (!($scope.actionUrl.cgu.indexOf('/cgu-file') > 0)) { $scope.actionUrl.cgu += '/cgu-file'; }\n return $scope.loader.cgu = false;\n } else if (content.custom_asset.name === 'cgv-file') {\n $scope.cgvFile = content.custom_asset;\n $scope.methods.cgv = 'put';\n if (!($scope.actionUrl.cgv.indexOf('/cgv-file') > 0)) { $scope.actionUrl.cgv += '/cgv-file'; }\n return $scope.loader.cgv = false;\n } else if (content.custom_asset.name === 'logo-file') {\n $scope.customLogo = content.custom_asset;\n $scope.methods.logo = 'put';\n if (!($scope.actionUrl.logo.indexOf('/logo-file') > 0)) { return $scope.actionUrl.logo += '/logo-file'; }\n } else if (content.custom_asset.name === 'logo-black-file') {\n $scope.customLogoBlack = content.custom_asset;\n $scope.methods.logoBlack = 'put';\n if (!($scope.actionUrl.logoBlack.indexOf('/logo-black-file') > 0)) { return $scope.actionUrl.logoBlack += '/logo-black-file'; }\n } else if (content.custom_asset.name === 'favicon-file') {\n $scope.customFavicon = content.custom_asset;\n $scope.methods.favicon = 'put';\n if (!($scope.actionUrl.favicon.indexOf('/favicon-file') > 0)) { return $scope.actionUrl.favicon += '/favicon-file'; }\n } else if (content.custom_asset.name === 'profile-image-file') {\n $scope.profileImage = content.custom_asset;\n $scope.methods.profileImage = 'put';\n if (!($scope.actionUrl.profileImage.indexOf('/profile-image-file') > 0)) { return $scope.actionUrl.profileImage += '/profile-image-file'; }\n }\n }\n };\n\n /**\n * @param target {String} 'cgu' | 'cgv'\n */\n $scope.addLoader = function (target) {\n $scope.loader[target] = true;\n };\n\n /**\n * Change the revision of the displayed privacy policy, from drafts history\n */\n $scope.handlePolicyRevisionChange = function () {\n if ($scope.privacyPolicy.version === null) {\n $scope.privacyPolicy.bodyTemp = settingsPromise.privacy_body;\n return;\n }\n for (const draft of $scope.privacyDraftsHistory) {\n if (draft.id === $scope.privacyPolicy.version) {\n $scope.privacyPolicy.bodyTemp = draft.content;\n break;\n }\n }\n };\n\n /**\n * Open a modal showing a sample of the collected data if FabAnalytics is enabled\n */\n $scope.analyticsModal = function () {\n $uibModal.open({\n templateUrl: '/admin/settings/analyticsModal.html',\n controller: 'AnalyticsModalController',\n size: 'lg',\n resolve: {\n analyticsData: ['FabAnalytics', function (FabAnalytics) { return FabAnalytics.data().$promise; }]\n }\n });\n };\n\n /**\n * Reset the home page to its initial state (factory value)\n */\n $scope.resetHomePage = function () {\n dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.settings.confirmation_required'),\n msg: _t('app.admin.settings.confirm_reset_home_page')\n };\n }\n }\n }\n , function () { // confirmed\n Setting.reset({ name: 'home_content' }, function (data) {\n $scope.homeContent.value = data.value;\n growl.success(_t('app.admin.settings.home_content_reset'));\n });\n }\n );\n };\n\n /**\n * Callback triggered when the codemirror editor is loaded into the DOM\n * @param editor codemirror instance\n */\n $scope.codemirrorLoaded = function (editor) {\n $scope.codeMirrorEditor = editor;\n };\n\n /**\n * Shows a success message forwarded from a child react component\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Options for allow/prevent book overlapping slots: which kind of slots are used in the overlapping computation\n */\n $scope.availableOverlappingOptions = [\n ['training_reservations', _t('app.admin.settings.overlapping_options.training_reservations')],\n ['machine_reservations', _t('app.admin.settings.overlapping_options.machine_reservations')],\n ['space_reservations', _t('app.admin.settings.overlapping_options.space_reservations')],\n ['events_reservations', _t('app.admin.settings.overlapping_options.events_reservations')]\n ];\n\n /**\n * Setup the feature-tour for the admin/settings page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupSettingsTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('settings');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.settings.welcome.title'),\n content: _t('app.admin.tour.settings.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.admin-settings .general-page-tab',\n stepId: 'general',\n order: 1,\n title: _t('app.admin.tour.settings.general.title'),\n content: _t('app.admin.tour.settings.general.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.admin-settings .home-page-content h4',\n stepId: 'home',\n order: 2,\n title: _t('app.admin.tour.settings.home.title'),\n content: _t('app.admin.tour.settings.home.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.admin-settings .home-page-content .note-toolbar .note-insert div',\n stepId: 'components',\n order: 3,\n title: _t('app.admin.tour.settings.components.title'),\n content: _t('app.admin.tour.settings.components.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.admin-settings .home-page-content .note-toolbar .btn-codeview',\n stepId: 'codeview',\n order: 4,\n title: _t('app.admin.tour.settings.codeview.title'),\n content: _t('app.admin.tour.settings.codeview.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.admin-settings .reset-button',\n stepId: 'reset',\n order: 5,\n title: _t('app.admin.tour.settings.reset.title'),\n content: _t('app.admin.tour.settings.reset.content'),\n placement: 'left'\n });\n uitour.createStep({\n selector: '.admin-settings .home-page-style',\n stepId: 'css',\n order: 6,\n title: _t('app.admin.tour.settings.css.title'),\n content: _t('app.admin.tour.settings.css.content'),\n placement: 'top'\n });\n uitour.createStep({\n selector: '.admin-settings .about-page-tab',\n stepId: 'about',\n order: 7,\n title: _t('app.admin.tour.settings.about.title'),\n content: _t('app.admin.tour.settings.about.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.admin-settings .privacy-page-tab',\n stepId: 'privacy',\n order: 8,\n title: _t('app.admin.tour.settings.privacy.title'),\n content: _t('app.admin.tour.settings.privacy.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.admin-settings .history-select',\n stepId: 'draft',\n order: 9,\n title: _t('app.admin.tour.settings.draft.title'),\n content: _t('app.admin.tour.settings.draft.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.admin-settings .reservations-page-tab',\n stepId: 'reservations',\n order: 10,\n title: _t('app.admin.tour.settings.reservations.title'),\n content: _t('app.admin.tour.settings.reservations.content'),\n placement: 'bottom',\n popupClass: 'shift-left-50'\n });\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 11,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on step change, change the active tab if needed\n uitour.on('stepChanged', function (nextStep) {\n if (nextStep.stepId === 'general') { $scope.tabs.active = 0; }\n if (nextStep.stepId === 'home' || nextStep.stepId === 'css') { $scope.tabs.active = 2; }\n if (nextStep.stepId === 'about') { $scope.tabs.active = 3; }\n if (nextStep.stepId === 'privacy' || nextStep.stepId === 'draft') { $scope.tabs.active = 4; }\n if (nextStep.stepId === 'reservations') { $scope.tabs.active = 5; }\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('settings') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'settings' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if ($scope.allSettings.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('settings') < 0) {\n uitour.start();\n }\n };\n\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n\n // we prevent the admin from setting the closing time before the opening time\n $scope.$watch('windowEnd.value', function (newValue, oldValue, scope) {\n if ($scope.windowStart && moment($scope.windowStart.value).isAfter(newValue)) {\n return $scope.windowEnd.value = oldValue;\n }\n });\n\n // change form methods to PUT if items already exists\n if (cguFile.custom_asset) {\n $scope.methods.cgu = 'put';\n $scope.actionUrl.cgu += '/cgu-file';\n }\n if (cgvFile.custom_asset) {\n $scope.methods.cgv = 'put';\n $scope.actionUrl.cgv += '/cgv-file';\n }\n if (logoFile.custom_asset) {\n $scope.methods.logo = 'put';\n $scope.actionUrl.logo += '/logo-file';\n }\n if (logoBlackFile.custom_asset) {\n $scope.methods.logoBlack = 'put';\n $scope.actionUrl.logoBlack += '/logo-black-file';\n }\n if (faviconFile.custom_asset) {\n $scope.methods.favicon = 'put';\n $scope.actionUrl.favicon += '/favicon-file';\n }\n if (profileImageFile.custom_asset) {\n $scope.methods.profileImage = 'put';\n $scope.actionUrl.profileImage += '/profile-image-file';\n }\n\n privacyDraftsPromise.setting.history.forEach(function (draft) {\n $scope.privacyDraftsHistory.push({ id: draft.id, name: _t('app.admin.settings.privacy.draft_from_USER_DATE', { USER: draft.user.name, DATE: moment(draft.created_at).format('L LT') }), content: draft.value });\n });\n\n // refresh codemirror to display the fetched setting\n $scope.$watch('advancedSettings.open', function (newValue) {\n if (newValue) $scope.codeMirrorEditor.refresh();\n });\n\n // use the tours list, based on the selected value\n $scope.$watch('allSettings.feature_tour_display', function (newValue, oldValue, scope) {\n if (newValue === oldValue) return;\n\n if (newValue === 'session') {\n $scope.currentUser.profile_attributes.tours = Fablab.sessionTours;\n } else if (newValue === 'once') {\n Member.get({ id: $scope.currentUser.id }, function (user) {\n $scope.currentUser.profile_attributes.tours = user.profile_attributes.tours;\n });\n }\n });\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n\n/**\n * Controller used in the invoice refunding modal window\n */\nApplication.Controllers.controller('SavePolicyController', ['$scope', '$uibModalInstance', '_t', 'growl', 'saveCb', 'privacyPolicy',\n function ($scope, $uibModalInstance, _t, growl, saveCb, privacyPolicy) {\n /* PUBLIC SCOPE */\n\n /**\n * Save as draft the current text\n */\n $scope.save = function () {\n saveCb({ name: 'privacy_draft', value: privacyPolicy.bodyTemp });\n $uibModalInstance.close('privacy_draft');\n };\n\n /**\n * Publish the current text as the new privacy policy\n */\n $scope.publish = function () {\n saveCb({ name: 'privacy_body', value: privacyPolicy.bodyTemp });\n growl.info(_t('app.admin.settings.privacy.users_notified'));\n $uibModalInstance.close('privacy_body');\n };\n /**\n * Cancel the saving, dismiss the modal window\n */\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }\n]);\n\n/**\n * Controller used in the \"what do we collect?\" modal, about FabAnalytics\n */\nApplication.Controllers.controller('AnalyticsModalController', ['$scope', '$uibModalInstance', 'analyticsData',\n function ($scope, $uibModalInstance, analyticsData) {\n // analytics data sample\n $scope.data = analyticsData;\n\n // callback to close the modal\n $scope.close = function () {\n $uibModalInstance.dismiss();\n };\n }\n]);\n","/* eslint-disable\n no-constant-condition,\n no-return-assign,\n no-undef,\n n/no-callback-literal,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS205: Consider reworking code to avoid use of IIFEs\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Controllers.controller('StatisticsController', ['$scope', '$state', '$transitions', '$rootScope', '$uibModal', 'es', 'Member', '_t', 'membersPromise', 'statisticsPromise', 'uiTourService', 'settingsPromise',\n function ($scope, $state, $transitions, $rootScope, $uibModal, es, Member, _t, membersPromise, statisticsPromise, uiTourService, settingsPromise) {\n /* PRIVATE STATIC CONSTANTS */\n\n // search window size\n const RESULTS_PER_PAGE = 20;\n\n // keep search context for (delay in minutes) ...\n const ES_SCROLL_TIME = 1;\n\n /* PUBLIC SCOPE */\n\n // ui-view transitions optimization: if true, the stats will never be refreshed\n $scope.preventRefresh = false;\n\n // statistics structure in elasticSearch\n $scope.statistics = statisticsPromise;\n\n // fablab users list\n $scope.members = membersPromise;\n\n // statistics data recovered from elasticSearch\n $scope.data = null;\n\n // when did the search was triggered\n $scope.searchDate = null;\n\n // id of the elastic search context\n $scope.scrollId = null;\n\n // total number of results for the current query\n $scope.totalHits = null;\n\n // configuration of the widget allowing to pick the ages range\n $scope.agePicker = {\n show: false,\n start: null,\n end: null\n };\n\n // total CA for the current view\n $scope.sumCA = 0;\n\n // average users' age for the current view\n $scope.averageAge = 0;\n\n // total of the stat field for non simple types\n $scope.sumStat = 0;\n\n // Results of custom aggregations for the current type\n $scope.customAggs = {};\n\n // default: results are not sorted\n $scope.sorting = {\n ca: 'none',\n date: 'desc'\n };\n\n // active tab will be set here\n $scope.selectedIndex = null;\n\n // ui-bootstrap active tab index\n $scope.selectedTab = 0;\n\n // type filter binding\n $scope.type = {\n selected: null,\n active: null\n };\n\n // selected custom filter\n $scope.customFilter = {\n show: false,\n criterion: {},\n value: null,\n exclude: false,\n datePicker: {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: null,\n maxDate: moment().toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n }\n };\n\n // available custom filters\n $scope.filters = [];\n\n // default: we do not open the datepicker menu\n $scope.datePicker =\n { show: false };\n\n // datePicker parameters for interval beginning\n $scope.datePickerStart = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: null,\n maxDate: moment().subtract(1, 'day').toDate(),\n selected: moment().utc().subtract(1, 'months').subtract(1, 'day').startOf('day').toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n // datePicker parameters for interval ending\n $scope.datePickerEnd = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: null,\n maxDate: moment().subtract(1, 'day').toDate(),\n selected: moment().subtract(1, 'day').endOf('day').toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Return a localized name for the given field\n */\n $scope.customFieldName = function (field) {\n return _t(`app.admin.statistics.${field}`);\n };\n\n /**\n * Callback to open the datepicker (interval start)\n * @param $event {Object} jQuery event object\n */\n $scope.toggleStartDatePicker = function ($event) { toggleDatePicker($event, $scope.datePickerStart); };\n\n /**\n * Callback to open the datepicker (interval end)\n * @param $event {Object} jQuery event object\n */\n $scope.toggleEndDatePicker = function ($event) { toggleDatePicker($event, $scope.datePickerEnd); };\n\n /**\n * Callback to open the datepicker (custom filter)\n * @param $event {Object} jQuery event object\n */\n $scope.toggleCustomDatePicker = function ($event) { toggleDatePicker($event, $scope.customFilter.datePicker); };\n\n /**\n * Callback called when the active tab is changed.\n * recover the current tab and store its value in $scope.selectedIndex\n * @param tab {Object} elasticsearch statistic structure (from statistic_indices table)\n * @param index {number} index of the tab in the $scope.statistics array\n */\n $scope.setActiveTab = function (tab, index) {\n $scope.selectedIndex = tab;\n $scope.selectedTab = index;\n $scope.type.selected = tab.types[0];\n $scope.type.active = $scope.type.selected;\n $scope.customFilter.criterion = {};\n $scope.customFilter.value = null;\n $scope.customFilter.exclude = false;\n $scope.sorting.ca = 'none';\n $scope.sorting.date = 'desc';\n buildCustomFiltersList();\n return refreshStats();\n };\n\n /**\n * Returns true if the provided tab must be hidden due to some global or local configuration\n * @param tab {Object} elasticsearch statistic structure (from statistic_indices table)\n */\n $scope.hiddenTab = function (tab) {\n if (tab.table) {\n return ((tab.es_type_key === 'subscription' && !$rootScope.modules.plans) ||\n (tab.es_type_key === 'training' && !$rootScope.modules.trainings) ||\n (tab.es_type_key === 'space' && !$rootScope.modules.spaces) ||\n (tab.es_type_key === 'machine' && !$rootScope.modules.machines) ||\n (tab.es_type_key === 'order' && !$rootScope.modules.store)\n );\n } else {\n return true;\n }\n };\n\n /**\n * Callback to validate the filters and send a new request to elastic\n */\n $scope.validateFilterChange = function () {\n $scope.agePicker.show = false;\n $scope.customFilter.show = false;\n $scope.type.active = $scope.type.selected;\n buildCustomFiltersList();\n return refreshStats();\n };\n\n /**\n * Callback to validate the dates range and refresh the data from elastic\n */\n $scope.validateDateChange = function () {\n $scope.datePicker.show = false;\n return refreshStats();\n };\n\n /**\n * Parse the given date and return a user-friendly string\n * @param date {Date} JS date or ant moment.js compatible date string\n */\n $scope.formatDate = function (date) { return moment(date).format('LL'); };\n\n /**\n * Parse the sex and return a user-friendly string\n * @param sex {string} 'male' | 'female'\n */\n $scope.formatSex = function (sex) {\n if (sex === 'male') {\n return _t('app.admin.statistics.man');\n }\n if (sex === 'female') {\n return _t('app.admin.statistics.woman');\n }\n };\n\n /**\n * Return unique elements from the given array\n * @param elements {Array}\n */\n $scope.uniq = function (elements) {\n return [...new Set(elements)];\n };\n\n /**\n * Retrieve the label for the given subtype in the current type\n * @param key {string} statistic subtype key\n */\n $scope.formatSubtype = function (key) {\n let label = '';\n angular.forEach($scope.type.active.subtypes, function (subtype) {\n if (subtype.key === key) {\n return label = subtype.label;\n }\n });\n return label;\n };\n\n /**\n * Helper usable in ng-switch to determine the input type to display for custom filter value\n * @param filter {Object} custom filter criterion\n */\n $scope.getCustomValueInputType = function (filter) {\n if (filter && filter.values) {\n if (typeof (filter.values[0]) === 'string') {\n return filter.values[0];\n } else if (typeof (filter.values[0] === 'object')) {\n return 'input_select';\n }\n } else {\n return 'input_text';\n }\n };\n\n /**\n * Change the sorting order and refresh the results to match the new order\n * @param filter {Object} any filter\n */\n $scope.toggleSorting = function (filter) {\n switch ($scope.sorting[filter]) {\n case 'none': $scope.sorting[filter] = 'asc'; break;\n case 'asc': $scope.sorting[filter] = 'desc'; break;\n case 'desc': $scope.sorting[filter] = 'none'; break;\n }\n return refreshStats();\n };\n\n /**\n * Return the user's name from his given ID\n * @param id {number} user ID\n */\n $scope.getUserNameFromId = function (id) {\n const name = $scope.members[id];\n return (name || `ID ${id}`);\n };\n\n /**\n * Run a scroll query to elasticsearch to append the next packet of results to those displayed.\n * If the ES search context has expired when the user ask for more results, we re-run the whole query.\n */\n $scope.showMoreResults = function () {\n // if all results were retrieved, do nothing\n if ($scope.data.length >= $scope.totalHits) {\n return;\n }\n\n if (moment($scope.searchDate).add(ES_SCROLL_TIME, 'minutes').isBefore(moment())) {\n // elastic search context has expired, so we run again the whole query\n return refreshStats();\n } else {\n return es.scroll({\n scroll: ES_SCROLL_TIME + 'm',\n body: { scrollId: $scope.scrollId }\n }\n , function (error, response) {\n if (error) {\n return console.error(`Error: something unexpected occurred during elasticSearch scroll query: ${error}`);\n } else {\n $scope.scrollId = response._scroll_id;\n return $scope.data = $scope.data.concat(response.hits.hits);\n }\n });\n }\n };\n\n /**\n * Open a modal dialog asking the user for details about exporting the statistics tables to an excel file\n */\n $scope.exportToExcel = function () {\n const options = {\n templateUrl: '/admin/statistics/export.html',\n size: 'sm',\n controller: 'ExportStatisticsController',\n resolve: {\n dates () {\n return {\n start: $scope.datePickerStart.selected,\n end: $scope.datePickerEnd.selected\n };\n },\n query () {\n const custom = buildCustomFilterQuery();\n return buildElasticDataQuery($scope.type.active.key, custom, $scope.agePicker.start, $scope.agePicker.end, moment($scope.datePickerStart.selected), moment($scope.datePickerEnd.selected), $scope.sorting);\n },\n index () {\n return { key: $scope.selectedIndex.es_type_key };\n },\n type () {\n return { key: $scope.type.active.key };\n }\n }\n };\n\n return $uibModal.open(options)\n .result.finally(null).then(function (info) { console.log(info); });\n };\n\n /**\n * Setup the feature-tour for the admin/statistics page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupStatisticsTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('statistics');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.statistics.welcome.title'),\n content: _t('app.admin.tour.statistics.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.heading .export-button',\n stepId: 'export',\n order: 1,\n title: _t('app.admin.tour.statistics.export.title'),\n content: _t('app.admin.tour.statistics.export.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.heading .charts-button',\n stepId: 'trending',\n order: 2,\n title: _t('app.admin.tour.statistics.trending.title'),\n content: _t('app.admin.tour.statistics.trending.content'),\n placement: 'left'\n });\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 3,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('statistics') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'statistics' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('statistics') < 0) {\n uitour.start();\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected\n // which will cause every tabs to reload, one by one, when the view is closed\n $transitions.onStart({ to: 'app.admin.statistics' }, function (trans) {\n if (Object.keys(trans.from().params || {}).length === 0) {\n return $scope.preventRefresh = true;\n }\n });\n\n // set the default tab to \"machines\" if \"subscriptions\" are disabled\n if (!$rootScope.modules.plans) {\n const idx = $scope.statistics.findIndex(s => s.es_type_key === 'machine');\n $scope.setActiveTab($scope.statistics[idx], idx);\n } else {\n const idx = $scope.statistics.findIndex(s => s.es_type_key === 'subscription');\n $scope.setActiveTab($scope.statistics[idx], idx);\n }\n };\n\n /**\n * Generic function to toggle a bootstrap datePicker\n * @param $event {Object} jQuery event object\n * @param datePicker {Object} settings object of the concerned datepicker. Must have an 'opened' property\n */\n const toggleDatePicker = function ($event, datePicker) {\n $event.preventDefault();\n $event.stopPropagation();\n return datePicker.opened = !datePicker.opened;\n };\n\n /**\n * Force update the statistics table, querying elasticSearch according to the current config values\n */\n const refreshStats = function () {\n if ($scope.selectedIndex && !$scope.preventRefresh && $scope.type.active) {\n $scope.data = [];\n $scope.sumCA = 0;\n $scope.averageAge = 0;\n $scope.sumStat = 0;\n $scope.customAggs = {};\n $scope.totalHits = null;\n $scope.searchDate = new Date();\n let custom = buildCustomFilterQuery();\n return queryElasticStats($scope.selectedIndex.es_type_key, $scope.type.active.key, custom, function (res, err) {\n if (err) {\n return console.error(`[statisticsController::refreshStats] Unable to refresh due to ${err}`);\n } else {\n $scope.data = res.hits.hits;\n $scope.totalHits = res.hits.total;\n $scope.sumCA = res.aggregations.total_ca.value;\n $scope.averageAge = Math.round(res.aggregations.average_age.value * 100) / 100;\n $scope.sumStat = res.aggregations.total_stat.value;\n $scope.scrollId = res._scroll_id;\n return (function () {\n const result = [];\n for (custom of Array.from($scope.type.active.custom_aggregations)) {\n result.push($scope.customAggs[custom.field] = res.aggregations[custom.field].value);\n }\n return result;\n })();\n }\n });\n }\n };\n\n /**\n * Run the elasticSearch query to retrieve the /stats/type aggregations\n * @param index {String} elasticSearch document type (account|event|machine|project|subscription|training)\n * @param type {String} statistics type (month|year|booking|hour|user|project)\n * @param custom {{key:{string}, value:{string}}|null} custom filter property or null to disable this filter\n * @param callback {function} function be to run after results were retrieved, it will receive\n * two parameters : results {Object}, error {String} (if any)\n */\n const queryElasticStats = function (index, type, custom, callback) {\n // handle invalid callback\n if (typeof (callback) !== 'function') {\n console.error('[statisticsController::queryElasticStats] Error: invalid callback provided');\n return;\n }\n\n // run query\n return es.search({\n index: 'stats',\n type: index,\n size: RESULTS_PER_PAGE,\n scroll: ES_SCROLL_TIME + 'm',\n 'stat-type': type,\n 'custom-query': custom ? JSON.stringify(Object.assign({ exclude: custom.exclude }, buildElasticCustomCriterion(custom))) : '',\n 'start-date': moment($scope.datePickerStart.selected).format(),\n 'end-date': moment($scope.datePickerEnd.selected).format(),\n body: buildElasticDataQuery(type, custom, $scope.agePicker.start, $scope.agePicker.end, moment($scope.datePickerStart.selected), moment($scope.datePickerEnd.selected), $scope.sorting)\n }\n , function (error, response) {\n if (error) {\n return callback({}, `Error: something unexpected occurred during elasticSearch query: ${error}`);\n } else {\n return callback(response);\n }\n });\n };\n\n /**\n * Build an object representing the content of the REST-JSON query to elasticSearch,\n * based on the provided parameters for row data recovering.\n * @param type {String} statistics type (month|year|booking|hour|user|project)\n * @param custom {{key:{string}, value:{string}}|null} custom filter property or null to disable this filter\n * @param ageMin {Number|null} filter by age: range lower value OR null to do not filter\n * @param ageMax {Number|null} filter by age: range higher value OR null to do not filter\n * @param intervalBegin {moment} statitics interval beginning (moment.js type)\n * @param intervalEnd {moment} statitics interval ending (moment.js type)\n * @param sortings {Array|null} elasticSearch criteria for sorting the results\n */\n const buildElasticDataQuery = function (type, custom, ageMin, ageMax, intervalBegin, intervalEnd, sortings) {\n const q = {\n query: {\n bool: {\n must: [\n {\n term: { type }\n },\n {\n range: {\n date: {\n gte: intervalBegin.format(),\n lte: intervalEnd.format()\n }\n }\n }\n ]\n }\n }\n };\n // optional date range\n if ((typeof ageMin === 'number') && (typeof ageMax === 'number')) {\n q.query.bool.must.push({\n range: {\n age: {\n gte: ageMin,\n lte: ageMax\n }\n }\n });\n }\n // optional criterion\n if (custom) {\n const criterion = buildElasticCustomCriterion(custom);\n if (custom.exclude) {\n q.query.bool.must_not = [\n { term: criterion.match }\n ];\n } else {\n q.query.bool.must.push(criterion);\n }\n }\n\n if (sortings) {\n q.sort = buildElasticSortCriteria(sortings);\n }\n\n // aggregations (avg age & CA sum)\n q.aggs = {\n total_ca: {\n sum: {\n field: 'ca'\n }\n },\n average_age: {\n avg: {\n field: 'age'\n }\n },\n total_stat: {\n sum: {\n field: 'stat'\n }\n }\n };\n return q;\n };\n\n /**\n * Build the elasticSearch query DSL to match the selected cutom filter\n * @param custom {Object} if custom is empty or undefined, an empty string will be returned\n * @returns {{match:*}|string}\n */\n const buildElasticCustomCriterion = function (custom) {\n if (custom) {\n const criterion = {\n match: {}\n };\n switch ($scope.getCustomValueInputType($scope.customFilter.criterion)) {\n case 'input_date': criterion.match[custom.key] = moment(custom.value).format('YYYY-MM-DD'); break;\n case 'input_select': criterion.match[custom.key] = custom.value.key; break;\n case 'input_list': criterion.match[custom.key + '.name'] = custom.value; break;\n default: criterion.match[custom.key] = custom.value;\n }\n return criterion;\n } else {\n return '';\n }\n };\n\n /**\n * Parse the provided criteria array and return the corresponding elasticSearch syntax\n * @param criteria {Array} array of {key_to_sort:order}\n */\n const buildElasticSortCriteria = function (criteria) {\n const crits = [];\n angular.forEach(criteria, function (value, key) {\n if ((typeof value !== 'undefined') && (value !== null) && (value !== 'none')) {\n const c = {};\n c[key] = { order: value };\n return crits.push(c);\n }\n });\n return crits;\n };\n\n /**\n * Fulfill the list of available options in the custom filter panel. The list will be based on common\n * properties and on index-specific properties (additional_fields)\n */\n const buildCustomFiltersList = function () {\n $scope.filters = [\n { key: 'date', label: _t('app.admin.statistics.date'), values: ['input_date'] },\n { key: 'userId', label: _t('app.admin.statistics.user_id'), values: ['input_number'] },\n { key: 'gender', label: _t('app.admin.statistics.gender'), values: [{ key: 'male', label: _t('app.admin.statistics.man') }, { key: 'female', label: _t('app.admin.statistics.woman') }] },\n { key: 'age', label: _t('app.admin.statistics.age'), values: ['input_number'] },\n { key: 'ca', label: _t('app.admin.statistics.revenue'), values: ['input_number'] }\n ];\n\n // if no plans were created, there's no types for statisticIndex=subscriptions\n if ($scope.type.active) {\n $scope.filters.splice(4, 0, { key: 'subType', label: _t('app.admin.statistics.type'), values: $scope.type.active.subtypes });\n\n if (!$scope.type.active.simple) {\n const f = { key: 'stat', label: $scope.type.active.label, values: ['input_number'] };\n $scope.filters.push(f);\n }\n }\n\n angular.forEach($scope.selectedIndex.additional_fields, function (field) {\n const filter = { key: field.key, label: field.label, values: [] };\n switch (field.data_type) {\n case 'index': filter.values.push('input_number'); break;\n case 'number': filter.values.push('input_number'); break;\n case 'date': filter.values.push('input_date'); break;\n case 'list': filter.values.push('input_list'); break;\n default: filter.values.push('input_text');\n }\n\n return $scope.filters.push(filter);\n });\n };\n\n /**\n * Build and return an object according to the custom filter set by the user, used to request elasticsearch\n * @return {Object|null}\n */\n const buildCustomFilterQuery = function () {\n let custom = null;\n if (!angular.isUndefinedOrNull($scope.customFilter.criterion) &&\n !angular.isUndefinedOrNull($scope.customFilter.criterion.key) &&\n !angular.isUndefinedOrNull($scope.customFilter.value)) {\n custom = {};\n custom.key = $scope.customFilter.criterion.key;\n custom.value = $scope.customFilter.value;\n custom.exclude = $scope.customFilter.exclude;\n }\n return custom;\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n\nApplication.Controllers.controller('ExportStatisticsController', ['$scope', '$uibModalInstance', 'Export', 'dates', 'query', 'index', 'type', 'CSRF', 'growl', '_t',\n function ($scope, $uibModalInstance, Export, dates, query, index, type, CSRF, growl, _t) {\n // Retrieve Anti-CSRF tokens from cookies\n CSRF.setMetaTags();\n\n // Bindings for date range\n $scope.dates = dates;\n\n // Body of the query to export\n $scope.query = JSON.stringify(query);\n\n // API URL where the form will be posted\n $scope.actionUrl = `/stats/${index.key}/export`;\n\n // Key of the current search's statistic type\n $scope.typeKey = type.key;\n\n // Form action on the above URL\n $scope.method = 'post';\n\n // Anti-CSRF token to inject into the download form\n $scope.csrfToken = angular.element('meta[name=\"csrf-token\"]')[0].content;\n\n // Binding of the export type (global / current)\n $scope.export =\n { type: 'current' };\n\n // datePicker parameters for interval beginning\n $scope.exportStart = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: null,\n maxDate: moment().subtract(1, 'day').toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n // datePicker parameters for interval ending\n $scope.exportEnd = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n minDate: null,\n maxDate: moment().subtract(1, 'day').toDate(),\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Callback to open the datepicker (interval start)\n * @param $event {Object} jQuery event object\n */\n $scope.toggleStartDatePicker = function ($event) { $scope.exportStart.opened = !$scope.exportStart.opened; };\n\n /**\n * Callback to open the datepicker (interval end)\n * @param $event {Object} jQuery event object\n */\n $scope.toggleEndDatePicker = function ($event) { $scope.exportEnd.opened = !$scope.exportEnd.opened; };\n\n /**\n * Callback when exchanging the export type between 'global' and 'current view'\n * Adjust the query and the requesting url according to this type.\n */\n $scope.setRequest = function () {\n if ($scope.export.type === 'global') {\n $scope.actionUrl = '/stats/global/export';\n return $scope.query = JSON.stringify({\n query: {\n bool: {\n must: [\n {\n range: {\n date: {\n gte: moment($scope.dates.start).format(),\n lte: moment($scope.dates.end).format()\n }\n }\n }\n ]\n }\n }\n });\n } else {\n $scope.actionUrl = `/stats/${index.key}/export`;\n $scope.query = JSON.stringify(query);\n }\n };\n\n /**\n * Callback to close the modal, telling the caller what is exported\n */\n $scope.exportData = function () {\n const statusQry = { category: 'statistics', type: $scope.export.type, query: $scope.query };\n if ($scope.export.type !== 'global') {\n statusQry.type = index.key;\n statusQry.key = type.key;\n }\n\n Export.status(statusQry).then(function (res) {\n if (!res.data.exists) {\n return growl.success(_t('app.admin.statistics.export_is_running_you_ll_be_notified_when_its_ready'));\n }\n });\n\n return $uibModalInstance.close(statusQry);\n };\n\n /**\n * Callback to cancel the export and close the modal\n */\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n'use strict';\n\nApplication.Controllers.controller('AdminStoreController', ['$scope', 'CSRF', 'growl', '$state', '$uiRouter',\n function ($scope, CSRF, growl, $state, $uiRouter) {\n /* PRIVATE SCOPE */\n // Map of tab state and index\n const TABS = {\n 'app.admin.store.settings': 0,\n 'app.admin.store.products': 1,\n 'app.admin.store.categories': 2,\n 'app.admin.store.orders': 3\n };\n\n /* PUBLIC SCOPE */\n // default tab: products\n $scope.tabs = {\n active: TABS[$state.current.name]\n };\n\n // the following item is used by the Products component to save/restore filters in the URL\n $scope.uiRouter = $uiRouter;\n\n /**\n * Callback triggered in click tab\n */\n $scope.selectTab = () => {\n setTimeout(function () {\n const currentTab = _.keys(TABS)[$scope.tabs.active];\n if (currentTab !== $state.current.name) {\n $state.go(currentTab, { location: true, notify: false, reload: false });\n }\n });\n };\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n'use strict';\n\nApplication.Controllers.controller('AdminStoreProductController', ['$scope', 'CSRF', 'growl', '$state', '$transition$', '$uiRouter',\n function ($scope, CSRF, growl, $state, $transition$, $uiRouter) {\n /* PUBLIC SCOPE */\n $scope.productId = $transition$.params().id;\n\n // the following item is used by the UnsavedFormAlert component to detect a page change\n $scope.uiRouter = $uiRouter;\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /**\n * Click Callback triggered in case of back products list\n */\n $scope.backProductsList = (event) => {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '') {\n $state.prevState = 'app.admin.store.products';\n }\n window.history.back();\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Controllers.controller('TagsController', ['$scope', 'tagsPromise', 'Tag', 'dialogs', 'growl', '_t', function ($scope, tagsPromise, Tag, dialogs, growl, _t) {\n // List of users's tags\n $scope.tags = tagsPromise;\n\n /**\n * Removes the newly inserted but not saved tag / Cancel the current tag modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} tag index in the $scope.tags array\n */\n $scope.cancelTag = function (rowform, index) {\n if ($scope.tags[index].id != null) {\n return rowform.$cancel();\n } else {\n return $scope.tags.splice(index, 1);\n }\n };\n\n /**\n * Creates a new empty entry in the $scope.tags array\n */\n $scope.addTag = function () {\n $scope.inserted =\n { name: '' };\n return $scope.tags.push($scope.inserted);\n };\n\n /**\n * Saves a new tag / Update an existing tag to the server (form validation callback)\n * @param data {Object} tag name\n * @param [data] {number} tag id, in case of update\n */\n $scope.saveTag = function (data, id) {\n if (id != null) {\n return Tag.update({ id }, { tag: data }, response => growl.success(_t('app.admin.members.tag_form.changes_successfully_saved'))\n , () => growl.error(_t('app.admin.members.tag_form.an_error_occurred_while_saving_changes')));\n } else {\n return Tag.save({ tag: data }, function (resp) {\n growl.success(_t('app.admin.members.tag_form.new_tag_successfully_saved'));\n return $scope.tags[$scope.tags.length - 1].id = resp.id;\n }\n , function () {\n growl.error(_t('app.admin.members.tag_form.an_error_occurred_while_saving_the_new_tag'));\n return $scope.tags.splice($scope.tags.length - 1, 1);\n });\n }\n };\n\n /**\n * Deletes the tag at the specified index\n * @param index {number} tag index in the $scope.tags array\n */\n $scope.removeTag = index =>\n dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.admin.members.tag_form.confirmation_required'),\n msg: _t('app.admin.members.tag_form.confirm_delete_tag_html')\n };\n }\n }\n }\n , () => {\n Tag.delete({ id: $scope.tags[index].id }, function (resp) {\n growl.success(_t('app.admin.members.tag_form.tag_successfully_deleted'));\n return $scope.tags.splice(index, 1);\n }\n , () => growl.error(_t('app.admin.members.tag_form.an_error_occurred_and_the_tag_deletion_failed')));\n });\n}\n\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/* COMMON CODE */\n\n/**\n * Provides a set of common callback methods to the $scope parameter. These methods are used\n * in the various trainings' admin controllers.\n *\n * Provides :\n * - $scope.submited(content)\n * - $scope.fileinputClass(v)\n * - $scope.onDisableToggled\n *\n * Requires :\n * - $state (Ui-Router) [ 'app.admin.trainings' ]\n * - $scope.training\n */\nclass TrainingsController {\n constructor ($scope, $state) {\n /*\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when the upload is done: any raised error will be stacked in the\n * $scope.alerts array. If everything goes fine, the user is redirected to the trainings list.\n * @param content {Object} JSON - The upload's result\n */\n $scope.submited = function (content) {\n if ((content.id == null)) {\n $scope.alerts = [];\n return angular.forEach(content, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n } else {\n return $state.go('app.admin.trainings');\n }\n };\n\n /**\n * Changes the current user's view, redirecting him to the machines list\n */\n $scope.cancel = function () { $state.go('app.admin.trainings'); };\n\n /**\n * Force the 'public_page' attribute to false when the current training is disabled\n */\n $scope.onDisableToggled = function () { $scope.training.public_page = !$scope.training.disabled; };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n }\n}\n\n/**\n * Controller used in the training creation page (admin)\n */\nApplication.Controllers.controller('NewTrainingController', ['$scope', '$state', 'CSRF', 'growl',\n function ($scope, $state, CSRF, growl) {\n /* PUBLIC SCOPE */\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n // Using the TrainingsController\n return new TrainingsController($scope, $state);\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the training edition page (admin)\n */\nApplication.Controllers.controller('EditTrainingController', ['$scope', '$state', '$transition$', 'trainingPromise', 'CSRF', 'growl',\n function ($scope, $state, $transition$, trainingPromise, CSRF, growl) {\n /* PUBLIC SCOPE */\n\n // Details of the training to edit (id in URL)\n $scope.training = cleanTraining(trainingPromise);\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n // Using the TrainingsController\n return new TrainingsController($scope, $state);\n };\n\n // prepare the training for the react-hook-form\n function cleanTraining (training) {\n delete training.$promise;\n delete training.$resolved;\n return training;\n }\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the trainings management page, allowing admins users to see and manage the list of trainings and reservations.\n */\nApplication.Controllers.controller('TrainingsAdminController', ['$scope', '$state', '$uibModal', 'Training', 'trainingsPromise', 'machinesPromise', '_t', 'growl', 'dialogs', 'Member', 'uiTourService', 'settingsPromise', '$uiRouter',\n function ($scope, $state, $uibModal, Training, trainingsPromise, machinesPromise, _t, growl, dialogs, Member, uiTourService, settingsPromise, $uiRouter) {\n // the following item is used by the UnsavedFormAlert component to detect a page change\n $scope.uiRouter = $uiRouter;\n\n // list of trainings\n $scope.trainings = trainingsPromise;\n\n // simplified list of machines\n $scope.machines = machinesPromise;\n\n // Training to monitor, bound with drop-down selection\n $scope.monitoring = { training: null };\n\n // list of training availabilities, grouped by date\n $scope.groupedAvailabilities = {};\n\n // default: accordions are not open\n $scope.accordions = {};\n\n // Binding for the parseInt function\n $scope.parseInt = parseInt;\n\n // Default: we show only enabled trainings\n $scope.trainingFiltering = 'enabled';\n\n // Available options for filtering trainings by status\n $scope.filterDisabled = [\n 'enabled',\n 'disabled',\n 'all'\n ];\n\n // default tab: trainings list\n $scope.tabs = { active: 0 };\n\n $scope.enableMachinesModule = settingsPromise.machines_module === 'true';\n\n /**\n * In the trainings listing tab, return the stringified list of machines associated with the provided training\n * @param training {Object} Training object, inherited from $resource\n * @returns {string}\n */\n $scope.showMachines = function (training) {\n const selected = [];\n angular.forEach($scope.machines, function (m) {\n if (training.machine_ids.indexOf(m.id) >= 0) {\n return selected.push(m.name);\n }\n });\n if (selected.length) { return selected.join(', '); } else { return _t('app.admin.trainings.none'); }\n };\n\n /**\n * Removes the newly inserted but not saved training / Cancel the current training modification\n * @param rowform {Object} see http://vitalets.github.io/angular-xeditable/\n * @param index {number} training index in the $scope.trainings array\n */\n $scope.cancelTraining = function (rowform, index) {\n if ($scope.trainings[index].id != null) {\n return rowform.$cancel();\n } else {\n return $scope.trainings.splice(index, 1);\n }\n };\n\n /**\n * In the trainings monitoring tab, callback to open a modal window displaying the current bookings for the\n * provided training slot. The admin will be then able to validate the training for the users that followed\n * the training.\n * @param training {Object} Training object, inherited from $resource\n * @param availability {Object} time slot when the training occurs\n */\n $scope.showReservations = function (training, availability) {\n $uibModal.open({\n templateUrl: '/admin/trainings/validTrainingModal.html',\n controller: ['$scope', '$uibModalInstance', function ($scope, $uibModalInstance) {\n $scope.availability = availability;\n\n $scope.usersToValid = [];\n\n /**\n * Mark/unmark the provided user for training validation\n * @param user {Object} from the availability.reservation_users list\n */\n $scope.toggleSelection = function (user) {\n const index = $scope.usersToValid.indexOf(user);\n if (index > -1) {\n return $scope.usersToValid.splice(index, 1);\n } else {\n return $scope.usersToValid.push(user);\n }\n };\n\n /**\n * Validates the modifications (training validations) and save them to the server\n */\n $scope.ok = function () {\n const users = $scope.usersToValid.map(function (u) { return u.id; });\n return Training.update({ id: training.id }, {\n training: {\n users\n }\n }\n , function () { // success\n angular.forEach($scope.usersToValid, function (u) { u.is_valid = true; });\n $scope.usersToValid = [];\n return $uibModalInstance.close(training);\n });\n };\n\n /**\n * Cancel the modifications and close the modal window\n */\n return $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }\n ]\n });\n };\n\n /**\n * Delete the provided training and, in case of success, remove it from the trainings list afterwards\n * @param index {number} index of the provided training in $scope.trainings\n * @param training {Object} training to delete\n */\n $scope.removeTraining = function (index, training) {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.admin.trainings.confirmation_required'),\n msg: _t('app.admin.trainings.do_you_really_want_to_delete_this_training')\n };\n }\n }\n },\n function () { // deletion confirmed\n training.$delete(function () {\n $scope.trainings.splice(index, 1);\n growl.info(_t('app.admin.trainings.training_successfully_deleted'));\n },\n function (error) {\n growl.warning(_t('app.admin.trainings.unable_to_delete_the_training_because_some_users_already_booked_it'));\n console.error(error);\n });\n }\n );\n };\n\n /**\n * Takes a month number and return its localized literal name\n * @param number {Number} from 0 to 11\n * @returns {String} eg. 'janvier'\n */\n $scope.formatMonth = function (number) {\n number = parseInt(number);\n return moment().month(number).format('MMMM');\n };\n\n /**\n * Given a day, month and year, return a localized literal name for the day\n * @param day {Number} from 1 to 31\n * @param month {Number} from 0 to 11\n * @param year {Number} Gregorian's year number\n * @returns {String} eg. 'mercredi 12'\n */\n $scope.formatDay = function (day, month, year) {\n day = parseInt(day);\n month = parseInt(month);\n year = parseInt(year);\n\n return moment({ year, month, day }).format('dddd D');\n };\n\n /**\n * Callback when the drop-down selection is changed.\n * The selected training details will be loaded from the API and rendered into the accordions.\n */\n $scope.selectTrainingToMonitor = function () {\n Training.availabilities({ id: $scope.monitoring.training.id }, function (training) {\n $scope.groupedAvailabilities = groupAvailabilities([training]);\n // we open current year/month by default\n const now = moment();\n $scope.accordions[training.name] = {};\n $scope.accordions[training.name][now.year()] = { isOpenFirst: true };\n $scope.accordions[training.name][now.year()][now.month()] = { isOpenFirst: true };\n });\n };\n\n /**\n * Shows a success message forwarded from a child react component\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n growl.error(message);\n };\n\n /**\n * Setup the feature-tour for the admin/trainings page.\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupTrainingsTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('trainings');\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.admin.tour.trainings.welcome.title'),\n content: _t('app.admin.tour.trainings.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.trainings-monitoring .manage-trainings',\n stepId: 'trainings',\n order: 1,\n title: _t('app.admin.tour.trainings.trainings.title'),\n content: _t('app.admin.tour.trainings.trainings.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.trainings-monitoring .filter-trainings',\n stepId: 'filter',\n order: 2,\n title: _t('app.admin.tour.trainings.filter.title'),\n content: _t('app.admin.tour.trainings.filter.content'),\n placement: 'left'\n });\n uitour.createStep({\n selector: '.trainings-monitoring .post-tracking',\n stepId: 'tracking',\n order: 3,\n title: _t('app.admin.tour.trainings.tracking.title'),\n content: _t('app.admin.tour.trainings.tracking.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 4,\n title: _t('app.admin.tour.conclusion.title'),\n content: _t('app.admin.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on step change, change the active tab if needed\n uitour.on('stepChanged', function (nextStep) {\n if (nextStep.stepId === 'filter' || nextStep.stepId === 'machines') { $scope.tabs.active = 0; }\n if (nextStep.stepId === 'tracking') { $scope.tabs.active = 1; }\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('trainings') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'trainings' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('trainings') < 0) {\n uitour.start();\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {};\n\n /**\n * Group the trainings availabilities by trainings and by dates and return the resulting tree\n * @param trainings {Array} $scope.trainings is expected here\n * @returns {Object} Tree constructed as /training_name/year/month/day/[availabilities]\n */\n const groupAvailabilities = function (trainings) {\n const tree = {};\n for (const training of Array.from(trainings)) {\n tree[training.name] = {};\n tree[training.name].training = training;\n for (const availability of Array.from(training.availabilities)) {\n const start = moment(availability.start_at);\n\n // init the tree structure\n if (typeof tree[training.name][start.year()] === 'undefined') {\n tree[training.name][start.year()] = {};\n }\n if (typeof tree[training.name][start.year()][start.month()] === 'undefined') {\n tree[training.name][start.year()][start.month()] = {};\n }\n if (typeof tree[training.name][start.year()][start.month()][start.date()] === 'undefined') {\n tree[training.name][start.year()][start.month()][start.date()] = [];\n }\n\n // add the availability at its right place\n tree[training.name][start.year()][start.month()][start.date()].push(availability);\n }\n }\n return tree;\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n\n]);\n","\nApplication.Controllers.controller('ApplicationController', ['$rootScope', '$scope', '$transitions', '$window', '$locale', '$timeout', 'Session', 'AuthService', 'Auth', '$uibModal', '$state', 'growl', 'Notification', '$interval', 'Setting', '_t', 'Version', 'Help', '$cookies',\n function ($rootScope, $scope, $transitions, $window, $locale, $timeout, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version, Help, $cookies) {\n /* PRIVATE STATIC CONSTANTS */\n\n // User's notifications will get refreshed every 30s\n const NOTIFICATIONS_CHECK_PERIOD = 30000;\n\n /* PUBLIC SCOPE */\n\n // Fab-manager's version\n $scope.version =\n { current: '' };\n\n // currency symbol for the current locale (cf. angular-i18n)\n $rootScope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;\n\n /**\n * Set the current user to the provided value and initialize the session\n * @param user {Object} Rails/Devise user\n */\n $scope.setCurrentUser = function (user) {\n if (!angular.isUndefinedOrNull(user)) {\n $rootScope.currentUser = user;\n Session.create(user);\n getNotifications();\n // Fab-manager's app-version\n if (user.role === 'admin') {\n // get the version\n $scope.version = Version.get({ origin: window.location.origin });\n } else {\n $scope.version = { current: '' };\n }\n }\n };\n\n /**\n * Login callback\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n * @param callback {function}\n */\n $scope.login = function (e, callback) {\n if (e) { e.preventDefault(); }\n return openLoginModal(null, null, callback);\n };\n\n /**\n * Logout callback\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.logout = function (e) {\n e.preventDefault();\n return Auth.logout().then(function () {\n Session.destroy();\n $rootScope.currentUser = null;\n $rootScope.toCheckNotifications = false;\n $scope.notifications = {\n total: 0,\n unread: 0\n };\n $cookies.remove('fablab_cart_token');\n return $state.go('app.public.home');\n }, function (error) {\n console.error(`An error occurred logging out: ${error}`);\n });\n };\n\n /**\n * Open the modal window allowing the user to create an account.\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.signup = function (e) {\n if (e) { e.preventDefault(); }\n if (Fablab.activeProviderType !== 'DatabaseProvider') {\n $window.location.href = '/sso-redirect';\n } else {\n const signupModal = $uibModal.open({\n templateUrl: '/shared/signupModal.html',\n backdrop: 'static',\n keyboard: false,\n size: 'xl',\n resolve: {\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({ names: \"['phone_required', 'recaptcha_site_key', 'confirmation_required', 'address_required']\" }).$promise;\n }],\n profileCustomFieldsPromise: ['ProfileCustomField', function (ProfileCustomField) { return ProfileCustomField.query({}).$promise; }],\n proofOfIdentityTypesPromise: ['SupportingDocumentType', function (SupportingDocumentType) { return SupportingDocumentType.query({}).$promise; }]\n },\n controller: ['$scope', '$uibModalInstance', 'Group', 'CustomAsset', 'settingsPromise', 'growl', '_t', 'profileCustomFieldsPromise', 'proofOfIdentityTypesPromise', 'BrazillianData', function ($scope, $uibModalInstance, Group, CustomAsset, settingsPromise, growl, _t, profileCustomFieldsPromise, proofOfIdentityTypesPromise, BrazillianData) {\n // default parameters for the date picker in the account creation modal\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false,\n options: {\n startingDay: Fablab.weekStartingDay,\n maxDate: new Date()\n }\n };\n\n $scope.datePickerRg = {\n format: Fablab.uibDateFormat,\n opened: false,\n options: {\n startingDay: Fablab.weekStartingDay,\n maxDate: new Date()\n }\n };\n\n // disabled city origin\n $scope.city_origin_enabled = false;\n\n // is the phone number required to sign-up?\n $scope.phoneRequired = (settingsPromise.phone_required === 'true');\n\n // is the address required to sign-up?\n $scope.addressRequired = (settingsPromise.address_required === 'true');\n\n // reCaptcha v2 site key (or undefined)\n $scope.recaptchaSiteKey = settingsPromise.recaptcha_site_key;\n\n // callback to open the date picker (account creation modal)\n $scope.openDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n $scope.datePicker.opened = true;\n };\n\n $scope.openDatePickerRg = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n $scope.datePickerRg.opened = true;\n };\n\n $scope.profileCustomFields = profileCustomFieldsPromise.filter(f => f.actived);\n\n // retrieve the groups (standard, student ...)\n Group.query(function (groups) {\n $scope.groups = groups;\n $scope.enabledGroups = groups.filter(g => !g.disabled);\n $scope.user.group_id = $scope.enabledGroups.find(g => g.name === 'Outros').id;\n });\n\n // retrieve all brazillian states\n BrazillianData.all_states({}, function (states) {\n $scope.brazillianStates = states;\n });\n\n // retrieve the CGU\n CustomAsset.get({ name: 'cgu-file' }, function (cgu) {\n $scope.cgu = cgu.custom_asset;\n });\n\n // default user's parameters\n $scope.user = {\n is_allow_contact: true,\n is_allow_newsletter: false,\n // reCaptcha response, received from Google (through AJAX) and sent to server for validation\n recaptcha: undefined,\n invoicing_profile_attributes: {\n user_profile_custom_fields_attributes: $scope.profileCustomFields.map(f => {\n return { profile_custom_field_id: f.id };\n })\n }\n };\n\n $scope.showFinacialResponsible = false;\n\n $scope.verifyAge = function () {\n if ($scope.isUnder18($scope.user.statistic_profile_attributes.birthday)) {\n $scope.showFinacialResponsible = true;\n /* eslint-disable */\n Inputmask({'mask': '999.999.999-99', 'clearMaskOnLostFocus': true }).mask('[name=\"financial_responsible_cpf\"]');\n } else {\n $scope.showFinacialResponsible = false;\n }\n };\n\n $scope.resetZipcodeReadonly = function () {\n $scope.zipcodeReadonly = {\n state: true,\n city: true,\n neighborhood: true,\n street: true\n };\n };\n\n $scope.resetZipcodeReadonly();\n\n $scope.hasProofOfIdentityTypes = function (groupId) {\n return proofOfIdentityTypesPromise.filter(t => t.group_ids.includes(groupId)).length > 0;\n };\n\n $scope.groupName = function (groupId) {\n if (!$scope.enabledGroups || groupId === undefined || groupId === null) {\n return '';\n }\n return $scope.enabledGroups.find(g => g.id === groupId).name;\n };\n\n $scope.isUnder18 = function (dateString) {\n const currentDate = new Date();\n const birthDate = new Date(dateString);\n const ageDifference = currentDate.getFullYear() - birthDate.getFullYear();\n if (ageDifference < 18) {\n return true;\n }\n if (\n ageDifference === 18 &&\n (birthDate.getMonth() > currentDate.getMonth() ||\n (birthDate.getMonth() === currentDate.getMonth() &&\n birthDate.getDate() > currentDate.getDate()))\n ) {\n return true;\n }\n return false;\n };\n\n // Errors display\n $scope.alerts = [];\n $scope.closeAlert = function (index) {\n $scope.alerts.splice(index, 1);\n };\n\n // retrieve cities by uf\n $scope.loadCities = function () {\n $scope.city_origin_enabled = false;\n const uf = $scope.user.profile_attributes.origin_state;\n BrazillianData.cities({ uf }, function (cities) {\n $scope.brazillianCities = cities;\n $scope.city_origin_enabled = true;\n });\n }; \n\n $scope.ocupacional_status = [\n { id: 1, name: 'Empregado' },\n { id: 2, name: 'Desempregado' },\n { id: 3, name: 'Empregador' },\n { id: 4, name: 'Autônomo/Conta Própria' },\n { id: 5, name: 'Profissional Liberal' },\n { id: 6, name: '1º Emprego' },\n { id: 7, name: 'Aposentado' },\n { id: 8, name: 'Microempreendedor Individual - MEI' },\n { id: 9, name: 'Aprendiz com contrato' }\n ];\n\n $scope.educational_levels = [\n { id: '1', name: 'Analfabeto' },\n { id: '2', name: 'Até o 5º ano incompleto do ensino fundamental' },\n { id: '3', name: '5º ano completo do ensino fundamental' },\n { id: '4', name: 'Do 6º ao 9º ano do ensino fundamental' },\n { id: '5', name: 'Ensino fundamental completo' },\n { id: '6', name: 'Ensino médio incompleto' },\n { id: '7', name: 'Ensino médio completo' },\n { id: '8', name: 'Educação superior incompleto' },\n { id: '9', name: 'Educação superior completo' },\n { id: 'A', name: 'Pós Grad. incompleto' },\n { id: 'B', name: 'Pós Grad. completo' },\n { id: 'C', name: 'Mestrado incompleto' },\n { id: 'D', name: 'Mestrado completo' },\n { id: 'E', name: 'Doutorado incompleto' },\n { id: 'F', name: 'Doutorado completo' },\n { id: 'G', name: 'Pós Dout. incompleto' },\n { id: 'H', name: 'Pós Dout. completo' }\n ];\n\n // retrieve cep of zipcode\n $scope.searchZipcode = function () {\n const zip = $scope.user.profile_attributes.zipcode.replace(/\\D/g, '');\n if (zip.length < 8) return;\n $scope.resetZipcodeReadonly();\n BrazillianData.zipcode({ zip }, function (r) {\n if (r.logradouro && r.logradouro !== '') {\n $scope.zipcodeReadonly.street = true;\n $scope.user.profile_attributes.street = r.logradouro;\n } else $scope.zipcodeReadonly.street = false;\n if (r.bairro && r.bairro !== '') {\n $scope.zipcodeReadonly.neighborhood = true;\n $scope.user.profile_attributes.neighborhood = r.bairro;\n } else $scope.zipcodeReadonly.neighborhood = false;\n if (r.localidade && r.localidade !== '') {\n $scope.zipcodeReadonly.city = true;\n $scope.user.profile_attributes.city = r.localidade;\n } else $scope.zipcodeReadonly.city = false;\n if (r.uf && r.uf !== '') {\n $scope.zipcodeReadonly.state = true;\n $scope.user.profile_attributes.state = r.uf;\n } else $scope.zipcodeReadonly.state = false;\n });\n };\n\n // callback for form validation\n $scope.ok = function () {\n // try to create the account\n $scope.alerts = [];\n // remove 'organization' attribute\n const orga = $scope.user.organization;\n delete $scope.user.organization;\n // register on server\n return Auth.register($scope.user).then(function (user) {\n if (user.id) {\n // creation successful\n $uibModalInstance.close({\n user,\n settings: settingsPromise\n });\n } else {\n // the user was not saved in database, something wrong occurred\n growl.error(_t('app.public.common.unexpected_error_occurred'));\n }\n }, function (error) {\n // creation failed...\n // restore organization param\n $scope.user.organization = orga;\n // display errors\n angular.forEach(error.data.errors, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n });\n };\n\n $scope.dismiss = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }]\n });\n signupModal.result.finally(null).then(function (res) {\n // when the account was created successfully, set the session to the newly created account\n if (res.settings.confirmation_required === 'true') {\n Auth._currentUser = null;\n growl.info(_t('app.public.common.you_will_receive_confirmation_instructions_by_email_detailed'));\n } else {\n $scope.setCurrentUser(res.user);\n }\n });\n signupModal.rendered.then(function () {\n /* eslint-disable */\n Inputmask({'mask': '999.999.999-99', 'clearMaskOnLostFocus': true }).mask('[name=\"cpf\"]');\n /* eslint-disable */\n Inputmask({'mask': '99999-999', 'clearMaskOnLostFocus': true }).mask('[name=\"zipcode\"]'); \n });\n return signupModal;\n }\n };\n\n /**\n * Open the modal window allowing the user to change his password.\n * @param token {string} security token for password changing. The user should have recieved it by mail\n */\n $scope.editPassword = function (token) {\n $uibModal.open({\n templateUrl: '/shared/passwordEditModal.html',\n size: 'md',\n controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) {\n $scope.user = { reset_password_token: token };\n $scope.alerts = [];\n $scope.closeAlert = function (index) {\n $scope.alerts.splice(index, 1);\n };\n\n $scope.changePassword = function () {\n $scope.alerts = [];\n return $http.put('/users/password.json', { user: $scope.user }).then(function () { $uibModalInstance.close(); }).catch(function (data) {\n angular.forEach(data.data.errors, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n });\n };\n }]\n }).result.finally(null).then(function () {\n growl.success(_t('app.public.common.your_password_was_successfully_changed'));\n return Auth.login().then(function (user) {\n $scope.setCurrentUser(user);\n }, function (error) {\n console.error(`Authentication failed: ${JSON.stringify(error)}`);\n }\n );\n });\n };\n\n /**\n * Compact/Expend the width of the left navigation bar\n * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.toggleNavSize = function (event) {\n let $classes, $targets;\n if (typeof event === 'undefined') {\n console.error('[ApplicationController::toggleNavSize] Missing event parameter');\n return;\n }\n\n let toggler = $(event.target);\n if (!toggler.data('toggle')) { toggler = toggler.closest('[data-toggle^=\"class\"]'); }\n\n const $class = toggler.data().toggle;\n const $target = toggler.data('target') || toggler.attr('data-link');\n\n if ($class) {\n const $tmp = $class.split(':')[1];\n if ($tmp) { $classes = $tmp.split(','); }\n }\n\n if ($target) {\n $targets = $target.split(',');\n }\n\n if ($classes && $classes.length) {\n $.each($targets, function (index) {\n if ($classes[index].indexOf('*') !== -1) {\n const patt = new RegExp('\\\\s',\n +$classes[index].replace(/\\*/g, '[A-Za-z0-9-_]+').split(' ').join('\\\\s|\\\\s'),\n +'\\\\s', 'g');\n $(toggler).each(function (i, it) {\n let cn = ` ${it.className} `;\n while (patt.test(cn)) {\n cn = cn.replace(patt, ' ');\n }\n it.className = $.trim(cn);\n });\n }\n\n return (($targets[index] !== '#') && $($targets[index]).toggleClass($classes[index])) || toggler.toggleClass($classes[index]);\n });\n }\n\n toggler.toggleClass('active');\n };\n\n /**\n * Open the modal dialog showing that an upgrade is available\n */\n $scope.versionModal = function () {\n if ($scope.version.up_to_date) return;\n if ($rootScope.currentUser.role !== 'admin') return;\n\n $uibModal.open({\n templateUrl: '/admin/versions/upgradeModal.html',\n controller: 'VersionModalController',\n resolve: {\n version () { return $scope.version; }\n }\n });\n };\n\n /**\n * Trigger the contextual help \"feature tour\".\n * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.help = function (event) {\n event.preventDefault();\n\n // we wrap the event triggering into a $timeout to prevent conflicting with current $apply\n $timeout(function () {\n const evt = new KeyboardEvent('keydown', { key: 'F1' });\n window.dispatchEvent(evt);\n });\n };\n\n /* PRIVATE SCOPE */\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // try to retrieve any currently logged user\n Auth.login().then(function (user) {\n $scope.setCurrentUser(user);\n // force users to complete their profile if they are not\n if (user.need_completion) {\n return $state.transitionTo('app.logged.profileCompletion');\n }\n }, function () {\n console.info('No users currently logged');\n $rootScope.toCheckNotifications = false;\n });\n\n // bind to the $transitions.onStart event (UI-Router)\n $transitions.onStart({}, function (trans) {\n if (!trans.$to().data) { return; }\n\n const { authorizedRoles } = trans.$to().data;\n if (!AuthService.isAuthorized(authorizedRoles)) {\n if (AuthService.isAuthenticated()) {\n // user is not allowed\n console.error('[ApplicationController::initialize] user is not allowed');\n return false;\n } else {\n // user is not logged in\n openLoginModal(trans.$to().name, trans.$to().params);\n return false;\n }\n }\n });\n\n // we stop polling notifications when the page is not in foreground\n onPageVisible(function (state) { $rootScope.toCheckNotifications = (state === 'visible'); });\n\n Setting.query({ names: \"['fablab_name', 'name_genre', 'link_name']\" }, function (settings) {\n $scope.fablabName = settings.fablab_name;\n $scope.nameGenre = settings.name_genre;\n $scope.linkName = settings.link_name;\n });\n\n // shorthands\n $scope.isAuthenticated = Auth.isAuthenticated;\n $scope.isAuthorized = AuthService.isAuthorized;\n $rootScope.login = $scope.login;\n\n // handle F1 key to trigger help\n window.addEventListener('keydown', Help);\n };\n\n /**\n * Retrieve once the notifications from the server and display a message popup for each new one.\n * Then, periodically check for new notifications.\n */\n const getNotifications = function () {\n $rootScope.toCheckNotifications = true;\n if (!$rootScope.checkNotificationsIsInit && !!$rootScope.currentUser) {\n setTimeout(function () {\n // we request the most recent notifications\n Notification.last_unread(function (notifications) {\n $rootScope.lastCheck = new Date();\n $scope.notifications = notifications.totals;\n\n const toDisplay = [];\n angular.forEach(notifications.notifications, function (n) { toDisplay.push(n); });\n\n if (toDisplay.length < notifications.totals.unread) {\n toDisplay.push({ message: { description: _t('app.public.common.and_NUMBER_other_notifications', { NUMBER: notifications.totals.unread - toDisplay.length }) } });\n }\n\n angular.forEach(toDisplay, function (notification) { growl.info(notification.message.description); });\n });\n }, 2000);\n\n const checkNotifications = function () {\n if ($rootScope.toCheckNotifications) {\n return Notification.polling({ last_poll: $rootScope.lastCheck }).$promise.then(function (data) {\n $rootScope.lastCheck = new Date();\n $scope.notifications = data.totals;\n\n angular.forEach(data.notifications, function (notification) { growl.info(notification.message.description); });\n }).catch(function (error) {\n console.error('Error while polling notifications', error);\n });\n }\n };\n\n $interval(checkNotifications, NOTIFICATIONS_CHECK_PERIOD);\n $rootScope.checkNotificationsIsInit = true;\n }\n };\n\n /**\n * Open the modal window allowing the user to log in.\n */\n const openLoginModal = function (toState, toParams, callback) {\n if (Fablab.activeProviderType !== 'DatabaseProvider') {\n $window.location.href = '/sso-redirect';\n } else {\n return $uibModal.open({\n templateUrl: '/shared/deviseModal.html',\n backdrop: 'static',\n size: 'sm',\n resolve: {\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({ names: \"['confirmation_required', 'public_registrations']\" }).$promise;\n }]\n },\n controller: ['$scope', '$uibModalInstance', '_t', 'settingsPromise', function ($scope, $uibModalInstance, _t, settingsPromise) {\n const user = ($scope.user = {});\n\n // email confirmation required before user sign-in?\n $scope.confirmationRequired = settingsPromise.confirmation_required;\n\n // is public registrations allowed?\n $scope.publicRegistrations = (settingsPromise.public_registrations !== 'false');\n\n $scope.login = function () {\n Auth.login(user).then(function (user) {\n // Authentication succeeded ...\n $uibModalInstance.close(user);\n if (callback && (typeof callback === 'function')) {\n return callback(user);\n }\n }\n , function (error) {\n console.error(`Authentication failed: ${JSON.stringify(error)}`);\n $scope.alerts = [];\n return $scope.alerts.push({\n msg: error.data.error,\n type: 'danger'\n });\n });\n };\n // handle modal behaviors. The provided reason will be used to define the following actions\n $scope.dismiss = function () {\n $uibModalInstance.dismiss('cancel');\n };\n\n $scope.openSignup = function (e) {\n e.preventDefault();\n return $uibModalInstance.dismiss('signup');\n };\n\n $scope.openConfirmationNewModal = function (e) {\n e.preventDefault();\n return $uibModalInstance.dismiss('confirmationNew');\n };\n\n $scope.openResetPassword = function (e) {\n e.preventDefault();\n return $uibModalInstance.dismiss('resetPassword');\n };\n }]\n }).result.finally(null).then(function (user) {\n // what to do when the modal is closed\n\n // authentication succeeded, set the session, gather the notifications and redirect\n GTM.trackLogin();\n $scope.setCurrentUser(user);\n\n if ((toState !== null) && (toParams !== null)) {\n return $state.go(toState, toParams);\n }\n }, function (reason) {\n // authentication did not end successfully\n if (reason === 'signup') {\n // open sign-up modal\n $scope.signup();\n } else if (reason === 'resetPassword') {\n // open the 'reset password' modal\n return $uibModal.open({\n templateUrl: '/shared/passwordNewModal.html',\n size: 'sm',\n controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) {\n $scope.user = { email: '' };\n $scope.sendReset = function () {\n return $http.post('/users/password.json', { user: $scope.user }).then(function () {\n $uibModalInstance.close();\n });\n };\n }]\n }).result.finally(null).then(function () {\n growl.info(_t('app.public.common.you_will_receive_in_a_moment_an_email_with_instructions_to_reset_your_password'));\n });\n } else if (reason === 'confirmationNew') {\n // open the 'reset password' modal\n return $uibModal.open({\n templateUrl: '/shared/ConfirmationNewModal.html',\n size: 'sm',\n controller: ['$scope', '$uibModalInstance', '$http', function ($scope, $uibModalInstance, $http) {\n $scope.user = { email: '' };\n $scope.submitConfirmationNewForm = function () {\n return $http.post('/users/confirmation.json', { user: $scope.user }).then(function () {\n $uibModalInstance.close();\n });\n };\n }]\n }).result.finally(null).then(function () {\n growl.info(_t('app.public.common.you_will_receive_confirmation_instructions_by_email_detailed'));\n });\n }\n });\n // otherwise the user just closed the modal\n }\n };\n\n /**\n * Detect if the current page (tab/window) is active of put as background.\n * When the status changes, the callback is triggered with the new status as parameter\n * Inspired by http://stackoverflow.com/questions/1060008/is-there-a-way-to-detect-if-a-browser-window-is-not-currently-active#answer-1060034\n */\n const onPageVisible = function (callback) {\n let hidden = 'hidden';\n\n const onchange = function (evt) {\n const v = 'visible';\n const h = 'hidden';\n const evtMap = {\n focus: v,\n focusin: v,\n pageshow: v,\n blur: h,\n focusout: h,\n pagehide: h\n };\n evt = evt || window.event;\n if (evt.type in evtMap) {\n if (typeof callback === 'function') { callback(evtMap[evt.type]); }\n } else {\n const visibility = this[hidden] ? 'hidden' : 'visible';\n if (typeof callback === 'function') { callback(visibility); }\n }\n };\n\n // Standards:\n if (hidden in document) {\n document.addEventListener('visibilitychange', onchange);\n } else if ((hidden = 'mozHidden') in document) {\n document.addEventListener('mozvisibilitychange', onchange);\n } else if ((hidden = 'webkitHidden') in document) {\n document.addEventListener('webkitvisibilitychange', onchange);\n } else if ((hidden = 'msHidden') in document) {\n document.addEventListener('msvisibilitychange', onchange);\n // IE 9 and lower\n } else if ('onfocusin' in document) {\n document.onfocusin = (document.onfocusout = onchange);\n // All others\n } else {\n window.onpageshow = (window.onpagehide = (window.onfocus = (window.onblur = onchange)));\n }\n // set the initial state (but only if browser supports the Page Visibility API)\n if (document[hidden] !== undefined) {\n return onchange({ type: document[hidden] ? 'blur' : 'focus' });\n }\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the modal showing details about the version and the upgrades\n */\nApplication.Controllers.controller('VersionModalController', ['$scope', '$uibModalInstance', 'version', function ($scope, $uibModalInstance, version) {\n // version infos (current version + upgrade infos from hub)\n $scope.version = version;\n\n // callback to close the modal\n $scope.close = function () {\n $uibModalInstance.dismiss();\n };\n}]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in the public calendar global\n */\n\nApplication.Controllers.controller('CalendarController', ['$scope', '$state', '$aside', '$uibModal', 'moment', 'Availability', 'Setting', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', '_t', 'uiCalendarConfig', 'CalendarConfig', 'trainingsPromise', 'machinesPromise', 'spacesPromise', 'iCalendarPromise', 'machineCategoriesPromise',\n function ($scope, $state, $aside, $uibModal, moment, Availability, Setting, growl, dialogs, bookingWindowStart, bookingWindowEnd, _t, uiCalendarConfig, CalendarConfig, trainingsPromise, machinesPromise, spacesPromise, iCalendarPromise, machineCategoriesPromise) {\n /* PRIVATE STATIC CONSTANTS */\n let currentMachineEvent = null;\n machinesPromise.forEach(m => m.checked = true);\n trainingsPromise.forEach(t => t.checked = true);\n spacesPromise.forEach(s => s.checked = true);\n\n // check all formation/machine is select in filter\n const isSelectAll = (type, scope) => scope[type].length === scope[type].filter(t => t.checked).length;\n\n /* PUBLIC SCOPE */\n\n // List of trainings\n $scope.trainings = trainingsPromise.filter(t => !t.disabled);\n\n // List of machines\n $scope.machines = machinesPromise.filter(t => !t.disabled);\n\n // List of machine categories\n $scope.machineCategories = machineCategoriesPromise;\n\n // List of machines group by category\n $scope.machinesGroupByCategory = [];\n\n // List of spaces\n $scope.spaces = spacesPromise.filter(t => !t.disabled);\n\n // List of external iCalendar sources\n $scope.externals = iCalendarPromise.map(e => Object.assign(e, { checked: true }));\n\n // add availabilities source to event sources\n $scope.eventSources = [];\n\n // filter availabilities if have change\n $scope.filterAvailabilities = function (filter, scope) {\n if (!scope) { scope = $scope; }\n scope.filter = ($scope.filter = {\n trainings: isSelectAll('trainings', scope),\n machines: isSelectAll('machines', scope),\n spaces: isSelectAll('spaces', scope),\n externals: isSelectAll('externals', scope),\n evt: filter.evt,\n dispo: filter.dispo,\n reserved: filter.reserved\n });\n scope.machinesGroupByCategory.forEach(c => c.checked = _.every(c.machines, 'checked'));\n // remove all\n $scope.eventSources.splice(0, $scope.eventSources.length);\n // recreate source for trainings/machines/events with new filters\n $scope.eventSources.push({\n url: availabilitySourceUrl()\n });\n // external iCalendar events sources\n $scope.externals.forEach(e => {\n if (e.checked) {\n if (!$scope.eventSources.some(evt => evt.id === e.id)) {\n $scope.eventSources.push({\n id: e.id,\n url: `/api/i_calendar/${e.id}/events`,\n textColor: e.text_color || '#000',\n color: e.color\n });\n }\n } else {\n if ($scope.eventSources.some(evt => evt.id === e.id)) {\n const idx = $scope.eventSources.findIndex(evt => evt.id === e.id);\n $scope.eventSources.splice(idx, 1);\n }\n }\n });\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n };\n\n /**\n * Return a CSS-like style of the given calendar configuration\n * @param calendar\n */\n $scope.calendarStyle = function (calendar) {\n return {\n 'border-color': calendar.color,\n color: calendar.text_color\n };\n };\n\n // a variable for formation/machine/event/dispo checkbox is or not checked\n $scope.filter = {\n trainings: isSelectAll('trainings', $scope),\n machines: isSelectAll('machines', $scope),\n spaces: isSelectAll('spaces', $scope),\n externals: isSelectAll('externals', $scope),\n evt: true,\n dispo: true\n };\n\n // toggle to select all formation/machine\n $scope.toggleFilter = function (type, filter, machineCategoryId) {\n if (type === 'machineCategory') {\n const category = _.find($scope.machinesGroupByCategory, (c) => (c.id).toString() === machineCategoryId);\n if (category) {\n category.machines.forEach(m => m.checked = category.checked);\n }\n filter.machines = isSelectAll('machines', $scope);\n } else {\n $scope[type].forEach(t => t.checked = filter[type]);\n if (type === 'machines') {\n $scope.machinesGroupByCategory.forEach(t => t.checked = filter[type]);\n }\n }\n $scope.filterAvailabilities(filter, $scope);\n };\n\n $scope.openFilterAside = () =>\n $aside.open({\n templateUrl: '/calendar/filterAside.html',\n placement: 'right',\n size: 'md',\n backdrop: false,\n resolve: {\n trainings () {\n return $scope.trainings;\n },\n machines () {\n return $scope.machines;\n },\n machinesGroupByCategory () {\n return $scope.machinesGroupByCategory;\n },\n spaces () {\n return $scope.spaces;\n },\n externals () {\n return $scope.externals;\n },\n filter () {\n return $scope.filter;\n },\n toggleFilter () {\n return $scope.toggleFilter;\n },\n filterAvailabilities () {\n return $scope.filterAvailabilities;\n }\n },\n controller: ['$scope', '$uibModalInstance', 'trainings', 'machines', 'machinesGroupByCategory', 'spaces', 'externals', 'filter', 'toggleFilter', 'filterAvailabilities', 'AuthService', function ($scope, $uibModalInstance, trainings, machines, machinesGroupByCategory, spaces, externals, filter, toggleFilter, filterAvailabilities, AuthService) {\n $scope.trainings = trainings;\n $scope.machines = machines;\n $scope.machinesGroupByCategory = machinesGroupByCategory;\n $scope.hasMachineCategory = _.some(machines, 'machine_category_id');\n $scope.spaces = spaces;\n $scope.externals = externals;\n $scope.filter = filter;\n $scope.accordion = {\n trainings: false,\n machines: false,\n spaces: false\n };\n $scope.machinesGroupByCategory.forEach(c => $scope.accordion[c.name] = false);\n\n $scope.toggleAccordion = (type) => $scope.accordion[type] = !$scope.accordion[type];\n\n $scope.toggleFilter = (type, filter, machineCategoryId) => toggleFilter(type, filter, machineCategoryId);\n\n $scope.filterAvailabilities = filter => filterAvailabilities(filter, $scope);\n\n $scope.isAuthorized = AuthService.isAuthorized;\n\n return $scope.close = function (e) {\n $uibModalInstance.dismiss();\n return e.stopPropagation();\n };\n }]\n });\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = () => {\n // fullCalendar (v2) configuration\n $scope.calendarConfig = CalendarConfig({\n slotEventOverlap: true,\n header: {\n left: 'month agendaWeek agendaDay today prev,next',\n center: 'title',\n right: ''\n },\n minTime: moment.duration(moment(bookingWindowStart.setting.value).format('HH:mm:ss')),\n maxTime: moment.duration(moment(bookingWindowEnd.setting.value).format('HH:mm:ss')),\n defaultView: window.innerWidth <= 480 ? 'agendaDay' : 'agendaWeek',\n eventClick (event, jsEvent, view) {\n return calendarEventClickCb(event, jsEvent, view);\n },\n viewRender (view, element) {\n return viewRenderCb(view, element);\n },\n eventRender (event, element) {\n return eventRenderCb(event, element);\n }\n });\n $scope.eventSources = [{\n url: availabilitySourceUrl()\n }];\n $scope.externals.forEach(e => {\n if (e.checked) {\n $scope.eventSources.push({\n id: e.id,\n url: `/api/i_calendar/${e.id}/events`,\n textColor: e.text_color || '#000',\n color: e.color\n });\n }\n });\n\n // group machines by category\n _.forIn(_.groupBy($scope.machines, 'machine_category_id'), (ms, categoryId) => {\n const category = _.find($scope.machineCategories, (c) => (c.id).toString() === categoryId);\n $scope.machinesGroupByCategory.push({\n id: categoryId,\n name: category ? category.name : _t('app.shared.machine.machine_uncategorized'),\n checked: true,\n machine_ids: category ? category.machine_ids : [],\n machines: ms\n });\n });\n };\n\n /**\n * Callback triggered when an event object is clicked in the fullCalendar view\n */\n const calendarEventClickCb = function (event) {\n // current calendar object\n const { calendar } = uiCalendarConfig.calendars;\n if (event.available_type === 'machines') {\n currentMachineEvent = event;\n calendar.fullCalendar('changeView', 'agendaDay');\n calendar.fullCalendar('gotoDate', event.start);\n } else if (event.available_type === 'space') {\n calendar.fullCalendar('changeView', 'agendaDay');\n calendar.fullCalendar('gotoDate', event.start);\n } else if (event.available_type === 'event') {\n $state.go('app.public.events_show', { id: event.event_id });\n } else if (event.available_type === 'training') {\n $state.go('app.public.training_show', { id: event.training_id });\n } else {\n if (event.machine_ids) {\n if (event.machine_ids.length === 1) {\n $state.go('app.public.machines_show', { id: event.machine_ids[0] });\n } else {\n // open a modal to ask the user to select the machine to show\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/calendar/chooseMachine.html',\n size: 'md',\n controller: ['$scope', 'machinesPromise', '$uibModalInstance', function ($scope, machinesPromise, $uibModalInstance) {\n $scope.machines = machinesPromise.filter(m => event.machine_ids.includes(m.id));\n $scope.selectMachine = function (machineId) {\n $uibModalInstance.close(machineId);\n };\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }],\n resolve: {\n machinesPromise: ['Machine', function (Machine) {\n return Machine.query().$promise;\n }]\n }\n });\n modalInstance.result.then(function (res) {\n $state.go('app.public.machines_show', { id: res });\n });\n }\n } else if (event.space_id) {\n $state.go('app.public.space_show', { id: event.space_id });\n }\n }\n };\n\n // agendaDay view: disable slotEventOverlap\n // agendaWeek view: enable slotEventOverlap\n const toggleSlotEventOverlap = function (view) {\n // set defaultView, because when we change slotEventOverlap\n // ui-calendar will trigger rerender calendar\n $scope.calendarConfig.defaultView = view.type;\n const today = currentMachineEvent ? currentMachineEvent.start : moment().utc().startOf('day');\n if ((today > view.intervalStart) && (today < view.intervalEnd) && (today !== view.intervalStart)) {\n $scope.calendarConfig.defaultDate = today;\n } else {\n $scope.calendarConfig.defaultDate = view.intervalStart;\n }\n if (view.type === 'agendaDay') {\n return $scope.calendarConfig.slotEventOverlap = false;\n } else {\n return $scope.calendarConfig.slotEventOverlap = true;\n }\n };\n\n /**\n * This function is called when calendar view is rendered or changed\n * @see https://fullcalendar.io/docs/v3/viewRender#v2\n */\n const viewRenderCb = function (view) {\n toggleSlotEventOverlap(view);\n if (view.type === 'agendaDay') {\n // get availabilties by 1 day for show machine slots\n return uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n }\n };\n\n /**\n * Callback triggered by fullCalendar when it is about to render an event.\n * @see https://fullcalendar.io/docs/v3/eventRender#v2\n */\n const eventRenderCb = function (event, element) {\n if (event.tags && event.tags.length > 0) {\n let html = '';\n for (const tag of Array.from(event.tags)) {\n html += `${tag.name} `;\n }\n element.find('.fc-title').append(`
${html}`);\n }\n };\n\n const getFilter = function () {\n const t = $scope.trainings.filter(t => t.checked).map(t => t.id);\n const m = $scope.machines.filter(m => m.checked).map(m => m.id);\n const s = $scope.spaces.filter(s => s.checked).map(s => s.id);\n return { t, m, s, evt: $scope.filter.evt, dispo: $scope.filter.dispo, reserved: $scope.filter.reserved };\n };\n\n const availabilitySourceUrl = () => `/api/availabilities/public?${$.param(getFilter())}`;\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n'use strict';\n\nApplication.Controllers.controller('CartController', ['$scope', 'CSRF', 'growl', '$state',\n function ($scope, CSRF, growl, $state) {\n /* PRIVATE SCOPE */\n\n /* PUBLIC SCOPE */\n\n /**\n * Open the modal dialog allowing the user to log into the system\n */\n $scope.userLogin = function () {\n setTimeout(() => {\n if (!$scope.isAuthenticated()) {\n $scope.login();\n $scope.$apply();\n }\n }, 50);\n };\n\n /**\n * Overlap global function to allow the user to navigate to the previous screen\n * If no previous $state were recorded, navigate to the project list page\n */\n $scope.backPrevLocation = function (event) {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '') {\n $state.prevState = 'app.public.store';\n }\n window.history.back();\n };\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","'use strict';\n\n/**\n * Controller used for the cookies consent modal\n */\nApplication.Controllers.controller('CookiesController', ['$scope', '$cookies', 'Setting',\n function ($scope, $cookies, Setting) {\n /* PUBLIC SCOPE */\n\n // the acceptation state (undefined if no decision was made until now)\n $scope.cookiesState = undefined;\n\n // link pointed by \"learn more\"\n $scope.learnMoreUrl = 'https://www.cookiesandyou.com/';\n\n // add a cookie to the browser, saving the user choice to refuse cookies\n $scope.declineCookies = function () {\n const expires = moment().add(13, 'months').toDate();\n $cookies.put('fab-manager-cookies-consent', 'decline', { expires });\n readCookie();\n };\n\n // add a cookie to the browser, saving the user choice to accept cookies.\n // Then enable the analytics\n $scope.acceptCookies = function () {\n const expires = moment().add(13, 'months').toDate();\n $cookies.put('fab-manager-cookies-consent', 'accept', { expires });\n readCookie();\n GTM.enableAnalytics(Fablab.trackingId);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n readCookie();\n // if the privacy policy was defined, redirect the user to it when clicking on \"read more\"\n Setting.get({ name: 'privacy_body' }, data => {\n if (data.setting.value) {\n $scope.learnMoreUrl = '#!/privacy-policy';\n }\n });\n // if the tracking ID was not set in the settings, only functional cookies will be set, so user consent is not required\n if (!Fablab.trackingId) $scope.cookiesState = 'ignore';\n };\n\n const readCookie = function () {\n $scope.cookiesState = $cookies.get('fab-manager-cookies-consent');\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Controllers.controller('DashboardController', ['$scope', 'memberPromise', 'trainingsPromise', 'SocialNetworks', 'growl', 'proofOfIdentityTypesPromise',\n function ($scope, memberPromise, trainingsPromise, SocialNetworks, growl, proofOfIdentityTypesPromise) {\n // Current user's profile\n $scope.user = memberPromise;\n\n // List of social networks associated with this user and toggle 'show all' state\n $scope.social = {\n showAllLinks: false,\n networks: SocialNetworks\n };\n\n $scope.hasProofOfIdentityTypes = proofOfIdentityTypesPromise.length > 0;\n\n /**\n * Check if the member has used his training credits for the given credit\n * @param trainingCredits array of credits used by the member\n * @param trainingId id of the training to find\n */\n $scope.hasUsedTrainingCredit = function (trainingCredits, trainingId) {\n return trainingCredits.find(tc => tc.training_id === trainingId);\n };\n\n /**\n * Return the name associated with the provided training ID\n * @param trainingId training identifier\n * @return {string}\n */\n $scope.getTrainingName = function (trainingId) {\n return trainingsPromise.find(t => t.id === trainingId).name;\n };\n\n /**\n * Callback used in PaymentScheduleDashboard, in case of error\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback used to display a success message\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered when the user has successfully updated his card\n */\n $scope.onCardUpdateSuccess = function (message) {\n growl.success(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = () => {\n $scope.social.networks = filterNetworks();\n };\n\n /**\n * Filter the social networks or websites that are associated with the profile of the user provided in promise\n * and return the filtered networks\n * @return {Array}\n */\n const filterNetworks = function () {\n const networks = [];\n for (const network of Array.from(SocialNetworks)) {\n if ($scope.user.profile_attributes[network] && ($scope.user.profile_attributes[network].length > 0)) {\n networks.push(network);\n }\n }\n return networks;\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n\n]);\n","'use strict';\n\nApplication.Controllers.controller('HeaderController', ['$scope', '$transitions', '$state', 'settingsPromise', 'SupportingDocumentType', 'AuthService',\n function ($scope, $transitions, $state, settingsPromise, SupportingDocumentType, AuthService) {\n $scope.aboutPage = ($state.current.name === 'app.public.about');\n\n $transitions.onStart({}, function (trans) {\n $scope.aboutPage = (trans.$to().name === 'app.public.about');\n });\n\n /**\n * Returns the current state of the public registration setting (allowed/blocked).\n */\n $scope.registrationEnabled = function () {\n return settingsPromise.public_registrations === 'true';\n };\n\n $scope.dropdownOnToggled = function (open) {\n if (open) {\n SupportingDocumentType.query({ group_id: $scope.currentUser.group_id }, function (proofOfIdentityTypes) {\n $scope.hasProofOfIdentityTypes = proofOfIdentityTypes.length > 0;\n });\n }\n };\n }\n]);\n","'use strict';\n\nApplication.Controllers.controller('HomeController', ['$scope', '$transition$', '$translatePartialLoader', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', '_t',\n function ($scope, $transition$, $translatePartialLoader, AuthService, settingsPromise, Member, uiTourService, _t) {\n /* PUBLIC SCOPE */\n\n // Home page HTML content\n $scope.homeContent = null;\n\n // Status of the components in the home page (exists or not?)\n $scope.status = {\n news: false,\n projects: false,\n twitter: false,\n members: false,\n events: false\n };\n\n /**\n * Setup the feature-tour for the home page. (admins only)\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupHomeTour = function () {\n if (AuthService.isAuthorized(['admin', 'manager'])) {\n // Workaround for the following bug: sometimes, when the feature tour is shown, the translations keys are not\n // interpreted. This is an ugly hack, but we can't do better for now because angular-ui-tour does not support\n // removing steps (this would allow us to recreate the steps when the translations are loaded), and we can't use\n // promises with _t's translations (this would be a very big refactoring)\n setTimeout(setupWelcomeTour, 1000);\n }\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // if we receive a token to reset the password as GET parameter, trigger the\n // changePassword modal from the parent controller\n if ($transition$.params().reset_password_token) {\n return $scope.$parent.editPassword($transition$.params().reset_password_token);\n }\n\n // We set the home page content, with the directives replacing the placeholders\n $scope.homeContent = insertDirectives(settingsPromise.home_content);\n\n // for admins, setup the tour on login\n $scope.$watch('currentUser', function (newValue, oldValue) {\n if (!oldValue && newValue && newValue.role === 'admin') {\n const uitour = uiTourService.getTourByName('welcome');\n if (!uitour.hasStep()) {\n setupWelcomeTour();\n }\n }\n });\n };\n\n /**\n * Parse the provided html and replace the elements with special IDs (#news, #projects, #twitter, #members, #events)\n * by their respective angular directives\n * @param html {String} a valid html string, as defined by the summernote editor in admin/settings/home_page\n * @returns {string} a valid html string containing angular directives for the specified plugins\n */\n const insertDirectives = function (html) {\n const node = document.createElement('div');\n node.innerHTML = html.trim();\n\n node.querySelectorAll('div#news').forEach((newsNode) => {\n const news = document.createElement('news');\n newsNode.parentNode.replaceChild(news, newsNode);\n $scope.status.news = true;\n });\n\n node.querySelectorAll('div#projects').forEach((projectsNode) => {\n const projects = document.createElement('projects');\n projectsNode.parentNode.replaceChild(projects, projectsNode);\n $scope.status.projects = true;\n });\n\n node.querySelectorAll('div#twitter').forEach((twitterNode) => {\n const twitter = document.createElement('twitter');\n twitterNode.parentNode.replaceChild(twitter, twitterNode);\n $scope.status.twitter = true;\n });\n\n node.querySelectorAll('div#members').forEach((membersNode) => {\n const members = document.createElement('members');\n membersNode.parentNode.replaceChild(members, membersNode);\n $scope.status.members = true;\n });\n\n node.querySelectorAll('div#events').forEach((eventsNode) => {\n const events = document.createElement('events');\n eventsNode.parentNode.replaceChild(events, eventsNode);\n $scope.status.events = true;\n });\n\n return node.outerHTML;\n };\n\n /**\n * Setup the feature-tour for the home page that will present an overview of the whole app.\n * This is intended as a contextual help.\n */\n const setupWelcomeTour = function () {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('welcome');\n if (!uitour) return;\n // add the steps\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.public.tour.welcome.welcome.title'),\n content: _t('app.public.tour.welcome.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n uitour.createStep({\n selector: '.nav-primary li.home-link',\n stepId: 'home',\n order: 1,\n title: _t('app.public.tour.welcome.home.title'),\n content: _t('app.public.tour.welcome.home.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.nav-primary li.public-calendar-link',\n stepId: 'calendar',\n order: 2,\n title: _t('app.public.tour.welcome.calendar.title'),\n content: _t('app.public.tour.welcome.calendar.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.nav-primary li.reserve-machine-link',\n stepId: 'machines',\n order: 3,\n title: _t('app.public.tour.welcome.machines.title'),\n content: _t('app.public.tour.welcome.machines.content'),\n placement: 'right'\n });\n if ($scope.$root.modules.spaces) {\n uitour.createStep({\n selector: '.nav-primary li.reserve-space-link',\n stepId: 'spaces',\n order: 4,\n title: _t('app.public.tour.welcome.spaces.title'),\n content: _t('app.public.tour.welcome.spaces.content'),\n placement: 'right'\n });\n }\n uitour.createStep({\n selector: '.nav-primary li.reserve-training-link',\n stepId: 'trainings',\n order: 5,\n title: _t('app.public.tour.welcome.trainings.title'),\n content: _t('app.public.tour.welcome.trainings.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.nav-primary li.reserve-event-link',\n stepId: 'events',\n order: 6,\n title: _t('app.public.tour.welcome.events.title'),\n content: _t('app.public.tour.welcome.events.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.nav-primary li.projects-gallery-link',\n stepId: 'projects',\n order: 7,\n title: _t('app.public.tour.welcome.projects.title'),\n content: _t('app.public.tour.welcome.projects.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.nav-primary li.plans-link',\n stepId: 'plans',\n order: 8,\n title: _t('app.public.tour.welcome.plans.title'),\n content: _t('app.public.tour.welcome.plans.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.nav-primary .admin-section',\n stepId: 'admin',\n order: 9,\n title: _t('app.public.tour.welcome.admin.title', { ROLE: _t(`app.public.common.${$scope.currentUser.role}`) }),\n content: _t('app.public.tour.welcome.admin.content'),\n placement: 'right'\n });\n uitour.createStep({\n selector: '.navbar.header li.about-page-link',\n stepId: 'about',\n order: 10,\n title: _t('app.public.tour.welcome.about.title'),\n content: _t('app.public.tour.welcome.about.content'),\n placement: 'bottom',\n popupClass: 'shift-right-40'\n });\n uitour.createStep({\n selector: '.navbar.header li.notification-center-link',\n stepId: 'notifications',\n order: 11,\n title: _t('app.public.tour.welcome.notifications.title'),\n content: _t('app.public.tour.welcome.notifications.content'),\n placement: 'bottom'\n });\n uitour.createStep({\n selector: '.navbar.header li.user-menu-dropdown',\n stepId: 'profile',\n order: 12,\n title: _t('app.public.tour.welcome.profile.title'),\n content: _t('app.public.tour.welcome.profile.content'),\n placement: 'bottom',\n popupClass: 'shift-left-80'\n });\n if ($scope.status.news && settingsPromise.home_blogpost) {\n uitour.createStep({\n selector: 'news',\n stepId: 'news',\n order: 13,\n title: _t('app.public.tour.welcome.news.title'),\n content: _t('app.public.tour.welcome.news.content'),\n placement: 'bottom'\n });\n }\n if ($scope.status.projects) {\n uitour.createStep({\n selector: 'projects',\n stepId: 'last_projects',\n order: 14,\n title: _t('app.public.tour.welcome.last_projects.title'),\n content: _t('app.public.tour.welcome.last_projects.content'),\n placement: 'right'\n });\n }\n if ($scope.status.twitter) {\n uitour.createStep({\n selector: 'twitter',\n stepId: 'last_tweet',\n order: 15,\n title: _t('app.public.tour.welcome.last_tweet.title'),\n content: _t('app.public.tour.welcome.last_tweet.content'),\n placement: 'left'\n });\n }\n if ($scope.status.members) {\n uitour.createStep({\n selector: 'members',\n stepId: 'last_members',\n order: 16,\n title: _t('app.public.tour.welcome.last_members.title'),\n content: _t('app.public.tour.welcome.last_members.content'),\n placement: 'left'\n });\n }\n if ($scope.status.events) {\n uitour.createStep({\n selector: 'events',\n stepId: 'next_events',\n order: 17,\n title: _t('app.public.tour.welcome.next_events.title'),\n content: _t('app.public.tour.welcome.next_events.content'),\n placement: 'top'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'customize',\n order: 18,\n title: _t('app.public.tour.welcome.customize.title'),\n content: _t('app.public.tour.welcome.customize.content'),\n placement: 'bottom',\n orphan: 'true'\n });\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: '.app-generator .app-version',\n stepId: 'version',\n order: 19,\n title: _t('app.public.tour.welcome.version.title'),\n content: _t('app.public.tour.welcome.version.content'),\n placement: 'top'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 20,\n title: _t('app.public.tour.conclusion.title'),\n content: _t('app.public.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('welcome') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'welcome' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('welcome') < 0) {\n uitour.start();\n }\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Navigation controller. List the links availables in the left navigation pane and their icon.\n */\nApplication.Controllers.controller('MainNavController', ['$scope', 'settingsPromise', function ($scope, settingsPromise) {\n /**\n * Returns the current state of the public registration setting (allowed/blocked).\n */\n $scope.registrationEnabled = function () {\n return settingsPromise.public_registrations === 'true';\n };\n\n /**\n * Check if the store should be hidden to members/visitors\n */\n $scope.storeHidden = function () {\n return settingsPromise.store_hidden === 'true';\n };\n\n // Common links (public application)\n $scope.navLinks = [\n {\n state: 'app.public.home',\n linkText: 'app.public.common.home',\n linkIcon: 'home',\n class: 'home-link'\n },\n { class: 'menu-spacer' },\n $scope.$root.modules.publicAgenda && {\n state: 'app.public.calendar',\n linkText: 'app.public.common.public_calendar',\n linkIcon: 'calendar',\n class: 'public-calendar-link'\n },\n $scope.$root.modules.machines && {\n state: 'app.public.machines_list',\n linkText: 'app.public.common.reserve_a_machine',\n linkIcon: 'cogs',\n class: 'reserve-machine-link'\n },\n $scope.$root.modules.trainings && {\n state: 'app.public.trainings_list',\n linkText: 'app.public.common.trainings_registrations',\n linkIcon: 'graduation-cap',\n class: 'reserve-training-link'\n },\n $scope.$root.modules.spaces && {\n state: 'app.public.spaces_list',\n linkText: 'app.public.common.reserve_a_space',\n linkIcon: 'rocket',\n class: 'reserve-space-link'\n },\n {\n state: 'app.public.events_list',\n linkText: 'app.public.common.events_registrations',\n linkIcon: 'tags',\n class: 'reserve-event-link'\n },\n $scope.$root.modules.store && {\n state: 'app.public.store',\n linkText: 'app.public.common.fablab_store',\n linkIcon: 'cart-plus',\n class: 'store-link',\n authorizedRoles: $scope.storeHidden() ? ['admin', 'manager'] : undefined\n },\n { class: 'menu-spacer' },\n {\n state: 'app.public.projects_list',\n linkText: 'app.public.common.projects_gallery',\n linkIcon: 'th',\n class: 'projects-gallery-link'\n },\n $scope.$root.modules.plans && { class: 'menu-spacer' },\n $scope.$root.modules.plans && {\n state: 'app.public.plans',\n linkText: 'app.public.common.subscriptions',\n linkIcon: 'credit-card',\n class: 'plans-link'\n }\n ].filter(Boolean);\n\n Fablab.adminNavLinks = Fablab.adminNavLinks || [];\n $scope.adminNavLinks = [\n {\n state: 'app.admin.calendar',\n linkText: 'app.public.common.manage_the_calendar',\n linkIcon: 'calendar',\n authorizedRoles: ['admin', 'manager']\n },\n $scope.$root.modules.machines && {\n state: 'app.admin.machines_list',\n linkText: 'app.public.common.manage_the_machines',\n linkIcon: 'cogs',\n authorizedRoles: ['admin', 'manager']\n },\n $scope.$root.modules.trainings && {\n state: 'app.admin.trainings',\n linkText: 'app.public.common.trainings_monitoring',\n linkIcon: 'graduation-cap',\n authorizedRoles: ['admin', 'manager']\n },\n $scope.$root.modules.spaces && {\n state: 'app.public.spaces_list',\n linkText: 'app.public.common.manage_the_spaces',\n linkIcon: 'rocket'\n },\n {\n state: 'app.admin.events',\n linkText: 'app.public.common.manage_the_events',\n linkIcon: 'tags',\n authorizedRoles: ['admin', 'manager']\n },\n $scope.$root.modules.store && {\n state: 'app.admin.store.products',\n linkText: 'app.public.common.manage_the_store',\n linkIcon: 'cart-plus',\n authorizedRoles: ['admin', 'manager']\n },\n { class: 'menu-spacer' },\n {\n state: 'app.admin.members',\n linkText: 'app.public.common.manage_the_users',\n linkIcon: 'users',\n authorizedRoles: ['admin', 'manager']\n },\n {\n state: 'app.admin.pricing',\n linkText: 'app.public.common.subscriptions_and_prices',\n linkIcon: 'money',\n authorizedRoles: ['admin']\n },\n {\n state: 'app.admin.invoices',\n linkText: 'app.public.common.manage_the_invoices',\n linkIcon: 'file-pdf-o',\n authorizedRoles: ['admin', 'manager']\n },\n $scope.$root.modules.statistics && {\n state: 'app.admin.statistics',\n linkText: 'app.public.common.statistics',\n linkIcon: 'bar-chart-o',\n authorizedRoles: ['admin']\n },\n {\n class: 'menu-spacer',\n authorizedRoles: ['admin']\n },\n {\n state: 'app.admin.settings',\n linkText: 'app.public.common.customization',\n linkIcon: 'gear',\n authorizedRoles: ['admin']\n },\n {\n state: 'app.admin.projects',\n linkText: 'app.public.common.projects',\n linkIcon: 'tasks',\n authorizedRoles: ['admin']\n },\n {\n state: 'app.admin.open_api_clients',\n linkText: 'app.public.common.open_api_clients',\n linkIcon: 'cloud',\n authorizedRoles: ['admin']\n }\n ].filter(Boolean).concat(Fablab.adminNavLinks);\n}\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in the members listing page\n */\nApplication.Controllers.controller('MembersController', ['$scope', 'Member', 'membersPromise', function ($scope, Member, membersPromise) {\n /* PRIVATE STATIC CONSTANTS */\n\n // number of invoices loaded each time we click on 'load more...'\n const MEMBERS_PER_PAGE = 10;\n\n /* PUBLIC SCOPE */\n\n // currently displayed page of members\n $scope.page = 1;\n\n // members list\n $scope.members = membersPromise;\n\n // true when all members are loaded\n $scope.noMoreResults = false;\n\n /**\n * Callback for the 'load more' button.\n * Will load the next results of the current search, if any\n */\n $scope.showNextMembers = function () {\n $scope.page += 1;\n return Member.query({\n requested_attributes: '[profile]',\n page: $scope.page,\n size: MEMBERS_PER_PAGE\n }, function (members) {\n $scope.members = $scope.members.concat(members);\n\n if (!members[0] || (members[0].maxMembers <= $scope.members.length)) {\n return $scope.noMoreResults = true;\n }\n });\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if (!membersPromise[0] || (membersPromise[0].maxMembers <= $scope.members.length)) {\n return $scope.noMoreResults = true;\n }\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n}\n\n]);\n\n/**\n * Controller used when editing the current user's profile (in dashboard)\n */\nApplication.Controllers.controller('EditProfileController', ['$scope', '$rootScope', '$state', '$window', '$sce', '$cookies', '$injector', 'Member', 'Auth', 'Session', 'activeProviderPromise', 'settingsPromise', 'growl', 'dialogs', 'CSRF', 'memberPromise', 'groups', '_t', 'proofOfIdentityTypesPromise', 'SupportingDocumentType',\n function ($scope, $rootScope, $state, $window, $sce, $cookies, $injector, Member, Auth, Session, activeProviderPromise, settingsPromise, growl, dialogs, CSRF, memberPromise, groups, _t, proofOfIdentityTypesPromise, SupportingDocumentType) {\n /* PUBLIC SCOPE */\n\n // API URL where the form will be posted\n $scope.actionUrl = `/api/members/${$scope.currentUser.id}`;\n\n // list of groups\n $scope.groups = groups.filter(g => !g.disabled);\n\n // Form action on the above URL\n $scope.method = 'patch';\n\n // Current user's profile\n $scope.user = cleanUser(memberPromise);\n\n // default : do not show the group changing form\n $scope.group =\n { change: false };\n\n // group ID of the current/selected user\n $scope.userGroup = memberPromise.group_id;\n\n // active authentication provider parameters\n $scope.activeProvider = activeProviderPromise;\n\n // allow the user to change his password except if he connects from an SSO\n $scope.preventPassword = false;\n\n // get the status of cookies acceptance\n $scope.cookiesStatus = $cookies.get('fab-manager-cookies-consent');\n\n // mapping of fields to disable\n $scope.preventField = {};\n\n // Should the passord be modified?\n $scope.password = { change: false };\n\n // is the phone number required in _member_form?\n $scope.phoneRequired = (settingsPromise.phone_required === 'true');\n\n // is the address required in _member_form?\n $scope.addressRequired = (settingsPromise.address_required === 'true');\n\n // Angular-Bootstrap datepicker configuration for birthday\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n // This boolean value will tell if the current user is the system admin\n $scope.isAdminSys = memberPromise.id === Fablab.adminSysId;\n\n $scope.hasProofOfIdentityTypes = proofOfIdentityTypesPromise.length > 0;\n\n /**\n * Return the group object, identified by the ID set in $scope.userGroup\n */\n $scope.getUserGroup = function () {\n for (const group of Array.from($scope.groups)) {\n if (group.id === $scope.userGroup) {\n return group;\n }\n }\n };\n\n /**\n * Callback triggered when the user has successfully changed his group\n */\n $scope.onGroupUpdateSuccess = function (message, user) {\n growl.success(message);\n setTimeout(() => {\n $scope.user = _.cloneDeep(user);\n $scope.$apply();\n }, 50);\n $rootScope.currentUser.group_id = user.group_id;\n Auth._currentUser.group_id = user.group_id;\n SupportingDocumentType.query({ group_id: user.group_id }, function (supportingDocumentTypes) {\n $scope.hasProofOfIdentityTypes = supportingDocumentTypes.length > 0;\n });\n };\n\n /**\n * Check if it is allowed the change the group of the current user\n */\n $scope.isAllowedChangingGroup = function () {\n return !$scope.user.subscribed_plan?.name;\n };\n\n /**\n * Callback to diplay the datepicker as a dropdown when clicking on the input field\n * @param $event {Object} jQuery event object\n */\n $scope.openDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n return $scope.datePicker.opened = true;\n };\n\n /**\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when the upload is done: any raised error will be stacked in the\n * $scope.alerts array. If everything goes fine, the user's profile is updated and the user is\n * redirected to the home page\n * @param content {Object} JSON - The upload's result\n */\n $scope.submited = function (content) {\n if ((content.id == null)) {\n $scope.alerts = [];\n return angular.forEach(content, (v, k) =>\n angular.forEach(v, err =>\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n })\n )\n );\n } else {\n $scope.currentUser.profile_attributes.user_avatar_attributes = content.profile_attributes.user_avatar_attributes;\n Auth._currentUser.profile_attributes.user_avatar_attributes = content.profile_attributes.user_avatar_attributes;\n $scope.currentUser.name = content.name;\n Auth._currentUser.name = content.name;\n $scope.currentUser = content;\n Auth._currentUser = content;\n $rootScope.currentUser = content;\n return $state.go('app.public.home');\n }\n };\n\n /**\n * Ask for confirmation then delete the current user's account\n * @param user {Object} the current user (to delete)\n */\n $scope.deleteUser = user =>\n dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.logged.dashboard.settings.confirmation_required'),\n msg: $sce.trustAsHtml(\n _t('app.logged.dashboard.settings.confirm_delete_your_account') + '
' +\n '' + _t('app.logged.dashboard.settings.all_data_will_be_lost') + '

' +\n _t('app.logged.dashboard.settings.invoicing_data_kept') + '
' +\n _t('app.logged.dashboard.settings.statistic_data_anonymized') + '
' +\n _t('app.logged.dashboard.settings.no_further_access_to_projects')\n )\n };\n }\n }\n }\n , () => // cancel confirmed\n Member.remove({ id: user.id }, () =>\n Auth.logout().then(function () {\n $state.go('app.public.home');\n return growl.success(_t('app.logged.dashboard.settings.your_user_account_has_been_successfully_deleted_goodbye'));\n })\n\n , function (error) {\n console.log(error);\n return growl.error(_t('app.logged.dashboard.settings.an_error_occured_preventing_your_account_from_being_deleted'));\n })\n );\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n\n /**\n * Check if the of the properties editable by the user are linked to the SSO\n * @return {boolean} true if some editable fields are mapped with the SSO, false otherwise\n */\n $scope.hasSsoFields = () =>\n // if check if keys > 1 because there's a minimum of 1 mapping (id <-> provider-uid)\n // so the user may want to edit his profile on the SSO if at least 2 mappings exists\n Object.keys($scope.preventField).length > 1;\n\n /**\n * Disconnect and re-connect the user to the SSO to force the synchronisation of the profile's data\n */\n $scope.syncProfile = () =>\n Auth.logout().then(function (oldUser) {\n Session.destroy();\n $rootScope.currentUser = null;\n $rootScope.toCheckNotifications = false;\n $scope.notifications = {\n total: 0,\n unread: 0\n };\n return $window.location.href = $scope.activeProvider.link_to_sso_connect;\n });\n\n /**\n * Destroy the cookie used to save the user's preference, this will trigger the choice popup again\n */\n $scope.resetCookies = function () {\n $cookies.remove('fab-manager-cookies-consent');\n $scope.cookiesStatus = undefined;\n $injector.get('$state').reload();\n };\n\n /**\n * Callback triggered when an error is raised on a lower-level component\n * @param message {string}\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered when the user was successfully updated\n * @param user {object} the updated user\n */\n $scope.onSuccess = function (user) {\n $scope.currentUser = _.cloneDeep(user);\n Auth._currentUser = _.cloneDeep(user);\n $rootScope.currentUser = _.cloneDeep(user);\n growl.success(_t('app.logged.dashboard.settings.your_profile_has_been_successfully_updated'));\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n if ($scope.activeProvider.providable_type !== 'DatabaseProvider') {\n $scope.preventPassword = true;\n }\n\n // bind fields protection with sso fields\n return angular.forEach(activeProviderPromise.mapping, map => $scope.preventField[map] = true);\n };\n\n // prepare the user for the react-hook-form\n function cleanUser (user) {\n delete user.$promise;\n delete user.$resolved;\n return user;\n }\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used on the public user's profile page (seeing another user's profile)\n */\nApplication.Controllers.controller('ShowProfileController', ['$scope', 'memberPromise', 'SocialNetworks', function ($scope, memberPromise, SocialNetworks) {\n // Selected user's information\n $scope.user = memberPromise; // DEPENDENCY WITH NAVINUM GAMIFICATION PLUGIN !!!!\n\n // List of social networks associated with this user and toggle 'show all' state\n $scope.social = {\n showAllLinks: false,\n networks: SocialNetworks\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = () => $scope.social.networks = filterNetworks();\n\n /**\n * Filter social network or website that are associated with the profile of the user provided in promise\n * and return the filtered networks\n * @return {Array}\n */\n const filterNetworks = function () {\n const networks = [];\n for (const network of Array.from(SocialNetworks)) {\n if ($scope.user.profile_attributes[network] && ($scope.user.profile_attributes[network].length > 0)) {\n networks.push(network);\n }\n }\n return networks;\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n}\n\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n no-unused-vars,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Controller used in notifications page\n */\nApplication.Controllers.controller('NotificationsController', ['$scope', 'growl', function ($scope, growl) {\n /* PUBLIC SCOPE */\n\n /**\n * Shows an error message forwarded from a child react component\n */\n $scope.onError = function (message) {\n growl.error(message);\n };\n}\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n'use strict';\n\nApplication.Controllers.controller('ShowOrdersController', ['$rootScope', '$scope', 'CSRF', 'growl', '$state', '$transition$',\n function ($rootScope, $scope, CSRF, growl, $state, $transition$) {\n /* PRIVATE SCOPE */\n\n /* PUBLIC SCOPE */\n $scope.orderId = $transition$.params().id;\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /**\n * Click Callback triggered in case of back orders list\n */\n $scope.backOrdersList = () => {\n $state.go('app.logged.dashboard.orders');\n };\n\n // currently logged-in user\n $scope.currentUser = $rootScope.currentUser;\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Controllers.controller('PlansIndexController', ['$scope', '$rootScope', '$state', '$uibModal', 'Auth', 'AuthService', 'dialogs', 'growl', 'Subscription', 'Member', 'subscriptionExplicationsPromise', '_t', 'Wallet', 'helpers', 'settingsPromise', 'Price',\n function ($scope, $rootScope, $state, $uibModal, Auth, AuthService, dialogs, growl, Subscription, Member, subscriptionExplicationsPromise, _t, Wallet, helpers, settingsPromise, Price) {\n /* PUBLIC SCOPE */\n\n // user to deal with\n $scope.ctrl = {\n member: null,\n member_id: null\n };\n\n // already subscribed plan of the current user\n $scope.paid =\n { plan: null };\n\n // plan to subscribe (shopping cart)\n $scope.selectedPlan = null;\n\n // the moment when the plan selection changed for the last time, used to trigger changes in the cart\n $scope.planSelectionTime = null;\n\n // the application global settings\n $scope.settings = settingsPromise;\n\n // Global config: is the user validation required ?\n $scope.enableUserValidationRequired = settingsPromise.user_validation_required === 'true';\n\n // Discount coupon to apply to the basket, if any\n $scope.coupon =\n { applied: null };\n\n // text that appears in the bottom-right box of the page (subscriptions rules details)\n $scope.subscriptionExplicationsAlert = subscriptionExplicationsPromise.setting.value;\n\n /**\n * Callback to deal with the subscription of the user selected in the dropdown list instead of the current user's\n * subscription. (admins and managers only)\n */\n $scope.updateMember = function () {\n $scope.selectedPlan = null;\n $scope.paid.plan = null;\n Member.get({ id: $scope.ctrl.member.id }, function (member) {\n $scope.ctrl.member = member;\n });\n };\n\n /**\n * Add the provided plan to the shopping basket\n * @param plan {Object} The plan to subscribe to\n */\n $scope.selectPlan = function (plan) {\n setTimeout(() => {\n if ($scope.isAuthenticated()) {\n if (!AuthService.isAuthorized(['admin', 'manager']) && (helpers.isUserValidationRequired($scope.settings, 'subscription') && !helpers.isUserValidated($scope.ctrl.member))) {\n return;\n }\n if ($scope.selectedPlan !== plan) {\n $scope.selectedPlan = plan;\n $scope.planSelectionTime = new Date();\n }\n } else {\n $scope.login();\n }\n $scope.$apply();\n }, 50);\n };\n\n $scope.canSelectPlan = function () {\n return helpers.isUserValidatedByType($scope.ctrl.member, $scope.settings, 'subscription');\n };\n\n /**\n * Open the modal dialog allowing the user to log into the system\n */\n $scope.userLogin = function () {\n setTimeout(() => {\n if (!$scope.isAuthenticated()) {\n $scope.login();\n $scope.$apply();\n }\n }, 50);\n };\n\n /**\n * Callback triggered when an error is raised on a lower-level component\n * @param message {string}\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Test if the provided date is in the future\n * @param dateTime {Date}\n * @return {boolean}\n */\n $scope.isInFuture = function (dateTime) {\n return (moment().diff(moment(dateTime)) < 0);\n };\n\n /**\n * To use as callback in Array.prototype.filter to get only enabled plans\n */\n $scope.filterDisabledPlans = function (plan) { return !plan.disabled; };\n\n /**\n * Once the subscription has been confirmed (payment process successfully completed), mark the plan as subscribed,\n * and update the user's subscription\n */\n $scope.afterPayment = function () {\n $scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);\n if ($scope.ctrl.member.id === Auth._currentUser.id) {\n Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);\n }\n $scope.paid.plan = angular.copy($scope.selectedPlan);\n $scope.selectedPlan = null;\n $scope.coupon.applied = null;\n };\n\n /**\n * Callback triggered when the user has successfully changed his group\n */\n $scope.onGroupUpdateSuccess = function (message, user) {\n growl.success(message);\n setTimeout(() => {\n $scope.ctrl.member = _.cloneDeep(user);\n $scope.$apply();\n }, 50);\n if (AuthService.isAuthorized('member') ||\n (AuthService.isAuthorized('manager') && $scope.currentUser.id !== $scope.ctrl.member.id)) {\n $rootScope.currentUser.group_id = user.group_id;\n Auth._currentUser.group_id = user.group_id;\n }\n };\n\n /**\n * Check if it is allowed the change the group of the selected user\n */\n $scope.isAllowedChangingGroup = function () {\n return $scope.ctrl.member && !$scope.selectedPlan && !$scope.paid.plan;\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if ($scope.currentUser) {\n if (!AuthService.isAuthorized('admin')) {\n $scope.ctrl.member = $scope.currentUser;\n $scope.paid.plan = $scope.currentUser.subscribed_plan;\n }\n }\n\n $scope.$on('devise:new-session', function (event, user) { if (user.role !== 'admin') { $scope.ctrl.member = user; } });\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","'use strict';\n\nApplication.Controllers.controller('PrivacyController', ['$scope', 'Setting', function ($scope, Setting) {\n /* PUBLIC SCOPE */\n\n Setting.get({ name: 'privacy_body' }, data => { $scope.privacyBody = data.setting; });\n\n Setting.get({ name: 'privacy_dpo' }, data => { $scope.privacyDpo = data.setting; });\n}\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n'use strict';\n\nApplication.Controllers.controller('ShowProductController', ['$scope', 'CSRF', 'growl', '$transition$', '$state',\n function ($scope, CSRF, growl, $transition$, $state) {\n /* PRIVATE SCOPE */\n\n /* PUBLIC SCOPE */\n $scope.productSlug = $transition$.params().slug;\n\n /**\n * Overlap global function to allow the user to navigate to the previous screen\n * If no previous $state were recorded, navigate to the project list page\n */\n $scope.backPrevLocation = function (event) {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '') {\n $state.prevState = 'app.public.store';\n }\n window.history.back();\n };\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n\n'use strict';\n\nApplication.Controllers.controller('CompleteProfileController', ['$scope', '$rootScope', '$state', '$window', '_t', 'growl', 'CSRF', 'Auth', 'Member', 'settingsPromise', 'activeProviderPromise', 'groupsPromise', 'cguFile', 'memberPromise', 'Session', 'dialogs', 'AuthProvider',\n function ($scope, $rootScope, $state, $window, _t, growl, CSRF, Auth, Member, settingsPromise, activeProviderPromise, groupsPromise, cguFile, memberPromise, Session, dialogs, AuthProvider) {\n /* PUBLIC SCOPE */\n\n // API URL where the form will be posted\n $scope.actionUrl = `/api/members/${memberPromise.id}`;\n\n // Form action on the above URL\n $scope.method = 'patch';\n\n // genre of the application name (eg. \"_le_ Fablab\" or \"_la_ Fabrique\")\n $scope.nameGenre = settingsPromise.name_genre;\n\n // name of the current fablab application (eg. \"Fablab de la Casemate\")\n $scope.fablabName = settingsPromise.fablab_name;\n\n // information from the current SSO provider\n $scope.activeProvider = activeProviderPromise;\n\n // list of user's groups (student/standard/...)\n $scope.groups = groupsPromise;\n\n // current user, contains information retrieved from the SSO\n $scope.user = cleanUser(memberPromise);\n\n // disallow the user to change his password as he connect from SSO\n $scope.preventPassword = true;\n\n // mapping of fields to disable\n $scope.preventField = {};\n\n // CGU\n $scope.cgu = cguFile.custom_asset;\n\n // is the phone number required in _member_form?\n $scope.phoneRequired = (settingsPromise.phone_required === 'true');\n\n // is the address required in _member_form?\n $scope.addressRequired = (settingsPromise.address_required === 'true');\n\n // Angular-Bootstrap datepicker configuration for birthday\n $scope.datePicker = {\n format: Fablab.uibDateFormat,\n opened: false, // default: datePicker is not shown\n options: {\n startingDay: Fablab.weekStartingDay\n }\n };\n\n /**\n * Callback to diplay the datepicker as a dropdown when clicking on the input field\n * @param $event {Object} jQuery event object\n */\n $scope.openDatePicker = function ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n return $scope.datePicker.opened = true;\n };\n\n /**\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when the upload is done: any raised error will be stacked in the\n * $scope.alerts array. If everything goes fine, the user's profile is updated and the user is\n * redirected to the home page\n * @param content {Object} JSON - The upload's result\n */\n $scope.submited = function (content) {\n if ((content.id == null)) {\n $scope.alerts = [];\n angular.forEach(content, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n } else {\n $scope.user.profile_attributes.user_avatar_attributes = content.profile_attributes.user_avatar_attributes;\n Auth._currentUser.profile_attributes.user_avatar_attributes = content.profile_attributes.user_avatar_attributes;\n $scope.user.name = content.name;\n Auth._currentUser.name = content.name;\n $scope.user = content;\n Auth._currentUser = content;\n $rootScope.currentUser = content;\n return $state.go('app.public.home');\n }\n };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n\n /**\n * Merge the current user into the account with the given auth_token\n */\n $scope.registerAuthToken = function () {\n Member.merge({ id: $rootScope.currentUser.id }, { user: { auth_token: $scope.user.auth_token } }, function (user) {\n $scope.user = user;\n Auth._currentUser = user;\n $rootScope.currentUser = user;\n $state.go('app.public.home');\n }\n , function (err) {\n if (err.data.error) {\n growl.error(err.data.error);\n } else {\n growl.error(_t('app.logged.profile_completion.an_unexpected_error_occurred_check_your_authentication_code'));\n console.error(err);\n }\n });\n };\n\n /**\n * Return the email given by the SSO provider, parsed if needed\n * @return {String} E-mail of the current user\n */\n $scope.ssoEmail = function () {\n const { email } = memberPromise;\n if (email) {\n const duplicate = email.match(/^<([^>]+)>.{20}-duplicate$/);\n if (duplicate) {\n return duplicate[1];\n }\n }\n return email;\n };\n\n /**\n * Test if the user's mail is marked as duplicate\n * @return {boolean}\n */\n $scope.hasDuplicate = function () {\n const { email } = memberPromise;\n if (email) {\n return !(email.match(/^<([^>]+)>.{20}-duplicate$/) === null);\n }\n };\n\n /**\n * Ask for email confirmation and send the SSO merging token again\n * @param event {Object} jQuery event object\n */\n $scope.resendCode = function (event) {\n event.preventDefault();\n event.stopPropagation();\n dialogs.confirm(\n {\n templateUrl: '/profile/resend_code_modal.html',\n resolve: {\n object () {\n return { email: memberPromise.email };\n }\n }\n },\n function (email) {\n // Request the server to send an auth-migration email to the current user\n AuthProvider.send_code({ email },\n function (res) { growl.info(_t('app.logged.profile_completion.code_successfully_sent_again')); },\n function (err) { growl.error(err.data.error); }\n );\n }\n );\n };\n\n /**\n * Disconnect and re-connect the user to the SSO to force the synchronisation of the profile's data\n */\n $scope.syncProfile = function () {\n Auth.logout().then(function (oldUser) {\n Session.destroy();\n $rootScope.currentUser = null;\n $rootScope.toCheckNotifications = false;\n $scope.notifications = {\n total: 0,\n unread: 0\n };\n $window.location.href = activeProviderPromise.link_to_sso_connect;\n });\n };\n\n /**\n * Hide the new account messages.\n * If hidden, the page will be used only to complete the current user's profile.\n */\n $scope.hideNewAccountConfirmation = function () {\n return !$scope.activeProvider.previous_provider || $scope.activeProvider.previous_provider.id === $scope.activeProvider.id;\n };\n\n /**\n * Callback triggered when an error is raised on a lower-level component\n * @param message {string}\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered when the user was successfully updated\n * @param user {object} the updated user\n */\n $scope.onSuccess = function (user) {\n $scope.currentUser = _.cloneDeep(user);\n Auth._currentUser = _.cloneDeep(user);\n $rootScope.currentUser = _.cloneDeep(user);\n growl.success(_t('app.logged.profile_completion.your_profile_has_been_successfully_updated'));\n $state.go('app.public.home');\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n // init the birth date to JS object\n $scope.user.statistic_profile_attributes.birthday = $scope.user.statistic_profile_attributes.birthday ? moment($scope.user.statistic_profile_attributes.birthday).toDate() : undefined;\n\n // bind fields protection with sso fields\n angular.forEach(activeProviderPromise.mapping, function (map) { $scope.preventField[map] = true; });\n };\n\n // prepare the user for the react-hook-form\n function cleanUser (user) {\n delete user.$promise;\n delete user.$resolved;\n return user;\n }\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS205: Consider reworking code to avoid use of IIFEs\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/* COMMON CODE */\n\n/**\n * Provides a set of common properties and methods to the $scope parameter. They are used\n * in the various projects' admin controllers.\n *\n * Provides :\n * - $scope.summernoteOptsProject\n * - $scope.totalSteps\n * - $scope.machines = [{Machine}]\n * - $scope.components = [{Component}]\n * - $scope.themes = [{Theme}]\n * - $scope.licences = [{Licence}]\n * - $scope.allowedExtensions = [{String}]\n * - $scope.submited(content)\n * - $scope.cancel()\n * - $scope.addFile()\n * - $scope.deleteFile(file)\n * - $scope.addStep()\n * - $scope.deleteStep(step)\n * - $scope.changeStepIndex(step, newIdx)\n *\n * Requires :\n * - $scope.project.project_caos_attributes = []\n * - $scope.project.project_steps_attributes = []\n * - $state (Ui-Router) [ 'app.public.projects_show', 'app.public.projects_list' ]\n */\nclass ProjectsController {\n constructor ($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, Status, $document, Diacritics, dialogs, allowedExtensions, _t) {\n // remove codeview from summernote editor\n $scope.summernoteOptsProject = angular.copy($rootScope.summernoteOpts);\n $scope.summernoteOptsProject.toolbar[6][1].splice(1, 1);\n\n // Retrieve the list of machines from the server\n Machine.query().$promise.then(function (data) {\n $scope.machines = data.map(function (d) {\n return ({\n id: d.id,\n name: d.name\n });\n });\n });\n\n // Retrieve the list of components from the server\n Component.query().$promise.then(function (data) {\n $scope.components = data.map(function (d) {\n return ({\n id: d.id,\n name: d.name\n });\n });\n });\n\n // Retrieve the list of themes from the server\n Theme.query().$promise.then(function (data) {\n $scope.themes = data.map(function (d) {\n return ({\n id: d.id,\n name: d.name\n });\n });\n });\n\n // Retrieve the list of licences from the server\n Licence.query().$promise.then(function (data) {\n $scope.licences = data.map(function (d) {\n return ({\n id: d.id,\n name: d.name\n });\n });\n });\n\n // Retrieve the list of statuses from the server\n Status.query().$promise.then(function (data) {\n $scope.statuses = data.map(function (d) {\n return ({\n id: d.id,\n name: d.name\n });\n });\n });\n\n // Total number of documentation steps for the current project\n $scope.totalSteps = $scope.project.project_steps_attributes.length;\n\n // List of extensions allowed for CAD attachements upload\n $scope.allowedExtensions = allowedExtensions.setting.value.split(' ');\n\n /**\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when an upload is done: any raised error will be stacked in the\n * $scope.alerts array. If everything goes fine, the user is redirected to the project page.\n * @param content {Object} JSON - The upload's result\n */\n $scope.submited = function (content) {\n if ((content.id == null)) {\n $scope.alerts = [];\n angular.forEach(content, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n // using https://github.com/oblador/angular-scroll\n $('section[ui-view=main]').scrollTop(0, 200);\n } else {\n return $state.go('app.public.projects_show', { id: content.slug });\n }\n };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n\n /**\n * This will create a single new empty entry into the project's CAO attachements list.\n */\n $scope.addFile = function () { $scope.project.project_caos_attributes.push({}); };\n\n /**\n * This will remove the given file from the project's CAO attachements list. If the file was previously uploaded\n * to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from\n * the CAO attachements array.\n * @param file {Object} the file to delete\n */\n $scope.deleteFile = function (file) {\n const index = $scope.project.project_caos_attributes.indexOf(file);\n if (file.id != null) {\n return file._destroy = true;\n } else {\n return $scope.project.project_caos_attributes.splice(index, 1);\n }\n };\n\n /**\n * This will create a single new empty entry into the project's steps list.\n */\n $scope.addStep = function () {\n $scope.totalSteps += 1;\n return $scope.project.project_steps_attributes.push({ step_nb: $scope.totalSteps, project_step_images_attributes: [] });\n };\n\n /**\n * This will remove the given step from the project's steps list. If the step was previously saved\n * on the server, it will be marked for deletion for the next saving. Otherwise, it will be simply truncated from\n * the steps array.\n * @param step {Object} the step to delete\n */\n $scope.deleteStep = function (step) {\n dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.shared.project.confirmation_required'),\n msg: _t('app.shared.project.do_you_really_want_to_delete_this_step')\n };\n }\n }\n }\n , function () { // deletion confirmed\n const index = $scope.project.project_steps_attributes.indexOf(step);\n if (step.id != null) {\n step._destroy = true;\n } else {\n $scope.project.project_steps_attributes.splice(index, 1);\n }\n\n // update the new total number of steps\n $scope.totalSteps -= 1;\n // reindex the remaining steps\n return (function () {\n const result = [];\n for (const s of Array.from($scope.project.project_steps_attributes)) {\n if (s.step_nb > step.step_nb) {\n result.push(s.step_nb -= 1);\n } else {\n result.push(undefined);\n }\n }\n return result;\n })();\n });\n };\n\n /**\n * Change the step_nb property of the given step to the new value provided. The step that was previously at this\n * index will be assigned to the old position of the provided step.\n * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-\n * @param step {Object} the project's step to reindex\n * @param newIdx {number} the new index to assign to the step\n */\n $scope.changeStepIndex = function (event, step, newIdx) {\n if (event) { event.preventDefault(); }\n for (const s of Array.from($scope.project.project_steps_attributes)) {\n if (s.step_nb === newIdx) {\n s.step_nb = step.step_nb;\n step.step_nb = newIdx;\n break;\n }\n }\n return false;\n };\n\n /**\n * This function will query the API to autocomplete the typed user's name\n * @param nameLookup {string}\n */\n $scope.autoCompleteName = function (nameLookup) {\n if (!nameLookup) {\n return;\n }\n const asciiName = Diacritics.remove(nameLookup);\n\n Member.search(\n { query: asciiName },\n function (users) { $scope.matchingMembers = users; },\n function (error) { console.error(error); }\n );\n };\n\n /**\n * This will create a single new empty entry into the project's step image list.\n */\n $scope.addProjectStepImage = function (step) { step.project_step_images_attributes.push({}); };\n\n /**\n * This will remove the given image from the project's step image list.\n * @param step {Object} the project step has images\n * @param image {Object} the image to delete\n */\n $scope.deleteProjectStepImage = function (step, image) {\n const index = step.project_step_images_attributes.indexOf(image);\n if (image.id != null) {\n return image._destroy = true;\n } else {\n return step.project_step_images_attributes.splice(index, 1);\n }\n };\n\n /**\n * Returns the text to display on the save button, depending on the current state of the project\n */\n $scope.saveButtonValue = function () {\n if (!$scope.project.state || $scope.project.state === 'draft') {\n return _t('app.shared.project.save_as_draft');\n }\n return _t('app.shared.buttons.save');\n };\n }\n}\n\n/**\n * Controller used on projects listing page\n */\nApplication.Controllers.controller('ProjectsController', ['$scope', '$state', 'Project', 'machinesPromise', 'themesPromise', 'componentsPromise', 'paginationService', 'OpenlabProject', '$window', 'growl', '_t', '$location', '$timeout', 'settingsPromise', 'openLabActive',\n function ($scope, $state, Project, machinesPromise, themesPromise, componentsPromise, paginationService, OpenlabProject, $window, growl, _t, $location, $timeout, settingsPromise, openLabActive) {\n /* PRIVATE STATIC CONSTANTS */\n\n // Number of projects added to the page when the user clicks on 'load more projects'\n // -- dependency in app/models/project.rb\n const PROJECTS_PER_PAGE = 16;\n\n /* PUBLIC SCOPE */\n\n // Fab-manager's instance ID in the openLab network\n $scope.openlabAppId = settingsPromise.openlab_app_id;\n\n // Is openLab enabled on the instance?\n $scope.openlab = {\n projectsActive: openLabActive.isPresent,\n searchOverWholeNetwork: settingsPromise.openlab_default === 'true'\n };\n\n // default search parameters\n $scope.search = {\n q: ($location.$$search.q || ''),\n from: ($location.$$search.from || undefined),\n machine_id: (parseInt($location.$$search.machine_id) || undefined),\n component_id: (parseInt($location.$$search.component_id) || undefined),\n theme_id: (parseInt($location.$$search.theme_id) || undefined),\n status_id: (parseInt($location.$$search.status_id) || undefined)\n };\n\n // list of projects to display\n $scope.projects = [];\n\n // list of machines / used for filtering\n $scope.machines = machinesPromise;\n\n // list of themes / used for filtering\n $scope.themes = themesPromise;\n\n // list of components / used for filtering\n $scope.components = componentsPromise;\n\n $scope.onStatusChange = function (status) {\n if (status) {\n $scope.search.status_id = status.id;\n } else {\n $scope.search.status_id = undefined;\n }\n $scope.setUrlQueryParams($scope.search);\n $scope.triggerSearch();\n };\n\n /**\n * Callback triggered when the button \"search from the whole network\" is toggled\n */\n $scope.searchOverWholeNetworkChanged = function () {\n $scope.resetFiltersAndTriggerSearch();\n };\n\n /**\n * Callback to load the next projects of the result set, for the current search\n */\n $scope.loadMore = function () {\n if ($scope.openlab.searchOverWholeNetwork === true) {\n return $scope.projectsPagination.loadMore({ q: $scope.search.q });\n } else {\n return $scope.projectsPagination.loadMore({ search: $scope.search });\n }\n };\n\n /**\n * Reinitialize the search filters (used by the projects from the instance DB) and trigger a new search query\n */\n $scope.resetFiltersAndTriggerSearch = function () {\n setTimeout(() => {\n $scope.search.q = '';\n $scope.search.from = undefined;\n $scope.search.machine_id = undefined;\n $scope.search.component_id = undefined;\n $scope.search.theme_id = undefined;\n $scope.search.status_id = undefined;\n $scope.$apply();\n $scope.setUrlQueryParams($scope.search);\n $scope.triggerSearch();\n }, 50);\n };\n\n /**\n * Query the list of projects. Depending on $scope.openlab.searchOverWholeNetwork, the resulting list\n * will be fetched from OpenLab or from the instance DB\n */\n $scope.triggerSearch = function () {\n const currentPage = parseInt($location.$$search.page) || 1;\n if ($scope.openlab.searchOverWholeNetwork === true) {\n updateUrlParam('whole_network', 't');\n $scope.projectsPagination = new paginationService.Instance(OpenlabProject, currentPage, PROJECTS_PER_PAGE, null, { }, loadMoreOpenlabCallback);\n OpenlabProject.query({ q: $scope.search.q, page: currentPage, per_page: PROJECTS_PER_PAGE }, function (projectsPromise) {\n if (projectsPromise.errors) {\n growl.error(_t('app.public.projects_list.openlab_search_not_available_at_the_moment'));\n $scope.openlab.searchOverWholeNetwork = false;\n $scope.triggerSearch();\n } else {\n $scope.projectsPagination.totalCount = projectsPromise.meta.total;\n $scope.projects = normalizeProjectsAttrs(projectsPromise.projects);\n }\n });\n } else {\n updateUrlParam('whole_network', 'f');\n $scope.projectsPagination = new paginationService.Instance(Project, currentPage, PROJECTS_PER_PAGE, null, { }, loadMoreCallback, 'search');\n Project.search({ search: $scope.search, page: currentPage, per_page: PROJECTS_PER_PAGE }, function (projectsPromise) {\n $scope.projectsPagination.totalCount = projectsPromise.meta.total;\n $scope.projects = projectsPromise.projects;\n });\n }\n };\n\n /**\n * Callback to switch the user's view to the detailed project page\n * @param project {{slug:string}} The project to display\n */\n $scope.showProject = function (project) {\n if (($scope.openlab.searchOverWholeNetwork === true) && (project.app_id !== Fablab.openlabAppId)) {\n $window.open(project.project_url, '_blank');\n return true;\n } else {\n return $state.go('app.public.projects_show', { id: project.slug });\n }\n };\n\n /**\n * function to set all url query search parameters from search object\n */\n $scope.setUrlQueryParams = function (search) {\n updateUrlParam('page', 1);\n updateUrlParam('q', search.q);\n updateUrlParam('from', search.from);\n updateUrlParam('theme_id', search.theme_id);\n updateUrlParam('component_id', search.component_id);\n updateUrlParam('machine_id', search.machine_id);\n updateUrlParam('status_id', search.status_id);\n return true;\n };\n\n /**\n * Overlap global function to allow the user to navigate to the previous screen\n * If no previous $state were recorded, navigate to the project list page\n */\n $scope.backPrevLocation = function (event) {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '' || $state.prevState === 'app.public.projects_list') {\n $state.prevState = 'app.public.home';\n return $state.go($state.prevState, {});\n }\n window.history.back();\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if ($location.$$search.whole_network === 'f') {\n $scope.openlab.searchOverWholeNetwork = false;\n } else if ($location.$$search.whole_network === undefined) {\n $scope.openlab.searchOverWholeNetwork = $scope.openlab.projectsActive && settingsPromise.openlab_default === 'true';\n } else {\n $scope.openlab.searchOverWholeNetwork = $scope.openlab.projectsActive;\n }\n return $scope.triggerSearch();\n };\n\n /**\n * function to update url query param, little hack to turn off reloadOnSearch and re-enable it after we set the params.\n * params example: 'q' , 'presse-purée'\n */\n const updateUrlParam = function (name, value) {\n $state.current.reloadOnSearch = false;\n $location.search(name, value);\n $timeout(function () { $state.current.reloadOnSearch = undefined; });\n };\n\n /**\n * Callback triggered when the next projects were loaded from the result set (from the instance DB)\n * @param projectsPromise {{projects: []}}\n */\n const loadMoreCallback = function (projectsPromise) {\n $scope.projects = $scope.projects.concat(projectsPromise.projects);\n updateUrlParam('page', $scope.projectsPagination.currentPage);\n };\n\n /**\n * Callback triggered when the next projects were loaded from the result set (from OpenLab)\n * @param projectsPromise {{projects: []}}\n */\n const loadMoreOpenlabCallback = function (projectsPromise) {\n $scope.projects = $scope.projects.concat(normalizeProjectsAttrs(projectsPromise.projects));\n updateUrlParam('page', $scope.projectsPagination.currentPage);\n };\n\n const normalizeProjectsAttrs = function (projects) {\n return projects.map(function (project) {\n project.project_image = project.image_url;\n return project;\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the project creation page\n */\nApplication.Controllers.controller('NewProjectController', ['$rootScope', '$scope', '$state', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', 'Status', '$document', 'CSRF', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',\n function ($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, Status, $document, CSRF, Diacritics, dialogs, allowedExtensions, _t) {\n CSRF.setMetaTags();\n\n // API URL where the form will be posted\n $scope.actionUrl = '/api/projects/';\n\n // Form action on the above URL\n $scope.method = 'post';\n\n // Default project parameters\n $scope.project = {\n project_steps_attributes: [],\n project_caos_attributes: []\n };\n\n $scope.matchingMembers = [];\n\n /*\n * Overlap global function to allow the user to navigate to the previous screen\n * If no previous $state were recorded, navigate to the project list page\n */\n $scope.backPrevLocation = function (event) {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '') {\n $state.prevState = 'app.public.projects_list';\n return $state.go($state.prevState, {});\n }\n window.history.back();\n };\n\n // Using the ProjectsController\n return new ProjectsController($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, Status, $document, Diacritics, dialogs, allowedExtensions, _t);\n }\n]);\n\n/**\n * Controller used in the project edition page\n */\nApplication.Controllers.controller('EditProjectController', ['$rootScope', '$scope', '$state', '$transition$', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', 'Status', '$document', 'CSRF', 'projectPromise', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',\n function ($rootScope, $scope, $state, $transition$, Project, Machine, Member, Component, Theme, Licence, Status, $document, CSRF, projectPromise, Diacritics, dialogs, allowedExtensions, _t) {\n /* PUBLIC SCOPE */\n\n // API URL where the form will be posted\n $scope.actionUrl = `/api/projects/${$transition$.params().id}`;\n\n // Form action on the above URL\n $scope.method = 'put';\n\n // Retrieve the project's details, if an error occurred, redirect the user to the projects list page\n $scope.project = projectPromise;\n\n $scope.matchingMembers = $scope.project.project_users.map(function (u) {\n return ({\n id: u.id,\n name: u.full_name\n });\n });\n\n /**\n * Overlap global function to allow the user to navigate to the previous screen\n * If no previous $state were recorded, navigate to the project show page\n */\n $scope.backPrevLocation = function (event) {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '') {\n $state.prevState = 'app.public.projects_show';\n }\n $state.go($state.prevState, { id: $transition$.params().id });\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n if ($scope.project.author_id !== $rootScope.currentUser.id && $scope.project.user_ids.indexOf($rootScope.currentUser.id) === -1 && $scope.currentUser.role !== 'admin') {\n $state.go('app.public.projects_show', { id: $scope.project.slug });\n console.error('[EditProjectController::initialize] user is not allowed');\n }\n\n // Using the ProjectsController\n return new ProjectsController($rootScope, $scope, $state, Project, Machine, Member, Component, Theme, Licence, Status, $document, Diacritics, dialogs, allowedExtensions, _t);\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the public project's details page\n */\nApplication.Controllers.controller('ShowProjectController', ['$scope', '$state', 'projectPromise', 'shortnamePromise', '$location', '$uibModal', 'dialogs', '_t',\n function ($scope, $state, projectPromise, shortnamePromise, $location, $uibModal, dialogs, _t) {\n /* PUBLIC SCOPE */\n\n // Store the project's details\n $scope.project = projectPromise;\n $scope.projectUrl = $location.absUrl();\n $scope.disqusShortname = shortnamePromise.setting.value;\n\n /**\n * Test if the provided user has the edition rights on the current project\n * @param [user] {{id:number}} (optional) the user to check rights\n * @returns boolean\n */\n $scope.projectEditableBy = function (user) {\n if ((user == null)) { return false; }\n if ($scope.project.author_id === user.id) { return true; }\n let canEdit = false;\n angular.forEach($scope.project.project_users, function (u) {\n if ((u.id === user.id) && u.is_valid) { return canEdit = true; }\n });\n return canEdit;\n };\n\n /**\n * Test if the provided user has the deletion rights on the current project\n * @param [user] {{id:number}} (optional) the user to check rights\n * @returns boolean\n */\n $scope.projectDeletableBy = function (user) {\n if ((user == null)) { return false; }\n if ($scope.project.author_id === user.id) { return true; }\n };\n\n /**\n * Callback to delete the current project. Then, the user is redirected to the projects list page,\n * which is refreshed. Admins and project owner only are allowed to delete a project\n */\n $scope.deleteProject = function () {\n // check the permissions\n if (($scope.currentUser.role === 'admin') || $scope.projectDeletableBy($scope.currentUser)) {\n // delete the project then refresh the projects list\n return dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.public.projects_show.confirmation_required'),\n msg: _t('app.public.projects_show.do_you_really_want_to_delete_this_project')\n };\n }\n }\n }\n , function () { // cancel confirmed\n $scope.project.$delete(function () { $state.go('app.public.projects_list', {}, { reload: true }); });\n });\n } else {\n return console.error(_t('app.public.projects_show.unauthorized_operation'));\n }\n };\n\n /**\n * Open a modal box containg a form that allow the end-user to signal an abusive content\n * @param e {Object} jQuery event\n */\n $scope.signalAbuse = function (e) {\n if (e) { e.preventDefault(); }\n\n $uibModal.open({\n templateUrl: '/shared/signalAbuseModal.html',\n size: 'md',\n resolve: {\n project () { return $scope.project; }\n },\n controller: ['$scope', '$uibModalInstance', '_t', 'growl', 'Abuse', 'project', function ($scope, $uibModalInstance, _t, growl, Abuse, project) {\n // signaler's profile & signalement infos\n $scope.signaler = {\n signaled_type: 'Project',\n signaled_id: project.id\n };\n\n // callback for signaling cancellation\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n\n // callback for form validation\n return $scope.ok = function () {\n Abuse.save(\n {},\n { abuse: $scope.signaler },\n function (res) {\n // creation successful\n growl.success(_t('app.public.projects_show.your_report_was_successful_thanks'));\n return $uibModalInstance.close(res);\n }\n , function () {\n // creation failed...\n growl.error(_t('app.public.projects_show.an_error_occured_while_sending_your_report'));\n }\n );\n };\n }]\n });\n };\n\n /**\n * Return the URL allowing to share the current project on the Facebook social network\n */\n $scope.shareOnFacebook = function () { return `https://www.facebook.com/share.php?u=${$state.href('app.public.projects_show', { id: $scope.project.slug }, { absolute: true }).replace('#', '%23')}`; };\n\n /**\n * Return the URL allowing to share the current project on the Twitter social network\n */\n $scope.shareOnTwitter = function () { return `https://twitter.com/intent/tweet?url=${encodeURIComponent($state.href('app.public.projects_show', { id: $scope.project.slug }, { absolute: true }))}&text=${encodeURIComponent($scope.project.name)}`; };\n\n /**\n * Overlap global function to allow the user to navigate to the previous screen\n * If no previous $state were recorded, navigate to the project list page\n */\n $scope.backPrevLocation = function (event) {\n event.preventDefault();\n event.stopPropagation();\n if ($state.prevState === '') {\n $state.prevState = 'app.public.projects_list';\n return $state.go($state.prevState, {});\n }\n window.history.back();\n };\n }\n]);\n","'use strict';\n\nApplication.Controllers.controller('StoreController', ['$scope', 'CSRF', 'growl', '$uiRouter',\n function ($scope, CSRF, growl, $uiRouter) {\n /* PUBLIC SCOPE */\n\n // the following item is used by the Store component to store the filters in the URL\n $scope.uiRouter = $uiRouter;\n\n /**\n * Callback triggered in case of error\n */\n $scope.onError = (message) => {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Callback triggered in case of success\n */\n $scope.onSuccess = (message) => {\n growl.success(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the authenticity tokens in the forms\n CSRF.setMetaTags();\n };\n\n // init the controller (call at the end !)\n return initialize();\n }\n\n]);\n","'use strict';\n\nApplication.Controllers.controller('WalletController', ['$scope', 'walletPromise', 'transactionsPromise', 'proofOfIdentityTypesPromise',\n function ($scope, walletPromise, transactionsPromise, proofOfIdentityTypesPromise) {\n /* PUBLIC SCOPE */\n\n // current user wallet\n $scope.wallet = walletPromise;\n\n // current wallet transactions\n $scope.transactions = transactionsPromise;\n\n $scope.hasProofOfIdentityTypes = proofOfIdentityTypesPromise.length > 0;\n }\n]);\n","'use strict';\n\nApplication.Directives.directive('bsJasnyFileinput', [function () {\n return {\n require: ['ngModel'],\n link: function ($scope, elm, attrs, requiredCtrls) {\n const ngModelCtrl = requiredCtrls[0];\n const fileinput = elm.parents('[data-provides=fileinput]');\n const filetypeRegex = attrs.bsJasnyFileinput;\n fileinput.on('clear.bs.fileinput', function (e) {\n if (ngModelCtrl) {\n ngModelCtrl.$setViewValue(null);\n ngModelCtrl.$setPristine();\n $scope.$apply();\n }\n });\n fileinput.on('change.bs.fileinput', function (e, files) {\n if (ngModelCtrl) {\n if (files) {\n ngModelCtrl.$setViewValue(files.result);\n } else {\n ngModelCtrl.$setPristine();\n }\n\n // TODO: ne marche pas pour filetype\n if (filetypeRegex) {\n if (files && typeof files.type !== 'undefined' && files.type.match(new RegExp(filetypeRegex))) { ngModelCtrl.$setValidity('filetype', true); } else { ngModelCtrl.$setValidity('filetype', false); }\n };\n }\n $scope.$apply();\n });\n }\n };\n}]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs', 'growl', 'Auth', 'Price', 'Wallet', 'CustomAsset', 'SlotsReservation', 'AuthService', 'Payment', 'helpers', '_t',\n function ($rootScope, $uibModal, dialogs, growl, Auth, Price, Wallet, CustomAsset, SlotsReservation, AuthService, Payment, helpers, _t) {\n return ({\n restrict: 'E',\n scope: {\n slot: '=',\n slotSelectionTime: '=',\n events: '=',\n user: '=',\n modePlans: '=',\n plan: '=',\n planSelectionTime: '=',\n settings: '=',\n plans: '=',\n groups: '=',\n onSlotAddedToCart: '=',\n onSlotRemovedFromCart: '=',\n onSlotStartToModify: '=',\n onSlotModifySuccess: '=',\n onSlotModifyCancel: '=',\n onSlotModifyUnselect: '=',\n onSlotCancelSuccess: '=',\n afterPayment: '=',\n reservableId: '@',\n reservableType: '@',\n reservableName: '@',\n limitToOneSlot: '@'\n },\n templateUrl: '/shared/_cart.html',\n link ($scope, element, attributes) {\n // will store the user's plan if he chose to buy one\n $scope.selectedPlan = null;\n\n // total amount of the bill to pay\n $scope.amountTotal = 0;\n\n // total amount of the elements in the cart, without considering any coupon\n $scope.totalNoCoupon = 0;\n\n // once the cart was paid, retain the total amount paid by the customer\n $scope.amountPaid = 0;\n\n // Discount coupon to apply to the basket, if any\n $scope.coupon = { applied: null };\n\n // Global config: is the user authorized to change his bookings slots?\n $scope.enableBookingMove = ($scope.settings.booking_move_enable === 'true');\n\n // Global config: delay in hours before a booking while changing the booking slot is forbidden\n $scope.moveBookingDelay = parseInt($scope.settings.booking_move_delay);\n\n // Global config: is the user authorized to cancel his bookings?\n $scope.enableBookingCancel = ($scope.settings.booking_cancel_enable === 'true');\n\n // Global config: delay in hours before a booking while the cancellation is forbidden\n $scope.cancelBookingDelay = parseInt($scope.settings.booking_cancel_delay);\n\n // Payment schedule\n $scope.schedule = {\n requested_schedule: false, // does the user requests a payment schedule for his subscription\n payment_schedule: undefined // the effective computed payment schedule\n };\n\n // online payments (by card)\n $scope.onlinePayment = {\n showModal: false,\n cartItems: undefined\n };\n\n // offline payments (at the fablab's reception)\n $scope.localPayment = {\n showModal: false,\n cartItems: undefined\n };\n\n // currently logged-in user\n $scope.currentUser = $rootScope.currentUser;\n\n /**\n * Add the provided slot to the shopping cart (state transition from free to 'about to be reserved')\n * and increment the total amount of the cart if needed.\n * @param slot {Object} fullCalendar event object\n */\n $scope.validateSlot = function (slot) {\n validateTags(slot, function () {\n validateSameTimeReservations(slot, function () {\n slot.isValid = true;\n updateCartPrice();\n });\n });\n };\n\n /**\n * Remove the provided slot from the shopping cart (state transition from 'about to be reserved' to free)\n * and decrement the total amount of the cart if needed.\n * @param slot {Object} fullCalendar event object\n * @param index {number} index of the slot in the reservation array\n * @param [event] {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.removeSlot = function (slot, index, event) {\n if (event) { event.preventDefault(); }\n $scope.events.reserved.splice(index, 1);\n // if is was the last slot, we remove any plan from the cart\n if ($scope.events.reserved.length === 0) {\n $scope.selectedPlan = null;\n $scope.plan = null;\n $scope.modePlans = false;\n }\n if (typeof $scope.onSlotRemovedFromCart === 'function') { $scope.onSlotRemovedFromCart(slot); }\n return updateCartPrice();\n };\n\n /**\n * Checks that every selected slots were added to the shopping cart. Ie. will return false if\n * any checked slot was not validated by the user.\n */\n $scope.isSlotsValid = function () {\n let isValid = true;\n if ($scope.events) {\n angular.forEach($scope.events.reserved, function (m) {\n if (!m.isValid) {\n return isValid = false;\n }\n });\n }\n return isValid;\n };\n\n /**\n * Switch the user's view from the reservation agenda to the plan subscription\n */\n $scope.showPlans = function () {\n // first, we ensure that a user was selected (admin/manager) or logged (member)\n const isSelectedUser = Object.keys($scope.user).length > 0;\n // all slots are in future\n const areFutureSlots = _.every($scope.events.reserved, function (s) {\n return s.start.isAfter();\n });\n if (isSelectedUser && areFutureSlots) {\n return $scope.modePlans = true;\n } else if (!isSelectedUser) {\n // otherwise we alert, this error musn't occur when the current user hasn't the admin role\n return growl.error(_t('app.shared.cart.please_select_a_member_first'));\n } else if (!areFutureSlots) {\n return growl.error(_t('app.shared.cart.unable_to_select_plan_if_slots_in_the_past'));\n }\n };\n\n /**\n * Validates the shopping chart and redirect the user to the payment step\n */\n $scope.payCart = function () {\n // first, we check that a user was selected\n if (Object.keys($scope.user).length > 0) {\n // check selected user has a subscription, if any slot is restricted for subscriptions\n const slotValidations = [];\n let slotNotValid;\n let slotNotValidError;\n if ($scope.events.reserved) {\n $scope.events.reserved.forEach(function (slot) {\n if (slot.plan_ids.length > 0) {\n if (\n ($scope.selectedPlan && _.includes(slot.plan_ids, $scope.selectedPlan.id)) ||\n ($scope.user.subscribed_plan && _.includes(slot.plan_ids, $scope.user.subscribed_plan.id))\n ) {\n slotValidations.push(true);\n } else {\n slotNotValid = slot;\n if ($scope.selectedPlan && !_.includes(slot.plan_ids, $scope.selectedPlan.id)) {\n slotNotValidError = 'selectedPlanError';\n }\n if ($scope.user.subscribed_plan && !_.includes(slot.plan_ids, $scope.user.subscribed_plan.id)) {\n slotNotValidError = 'userPlanError';\n }\n if (!$scope.selectedPlan || !$scope.user.subscribed_plan) {\n slotNotValidError = 'noPlanError';\n }\n slotValidations.push(false);\n }\n }\n });\n const hasPlanForSlot = slotValidations.every(function (a) {\n return a;\n });\n if (!hasPlanForSlot) {\n if (!AuthService.isAuthorized(['admin', 'manager'])) {\n return growl.error(_t('app.shared.cart.slot_restrict_subscriptions_must_select_plan'));\n } else {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/shared/_reserve_slot_without_plan.html',\n size: 'md',\n controller: 'ReserveSlotWithoutPlanController',\n resolve: {\n slot: function () {\n return slotNotValid;\n },\n slotNotValidError: function () {\n return slotNotValidError;\n }\n }\n });\n modalInstance.result.then(function (res) {\n return paySlots();\n });\n }\n } else {\n return paySlots();\n }\n } else if ($scope.selectedPlan) {\n return paySlots();\n }\n } else {\n // otherwise we alert, this error musn't occur when the current user is not admin or manager\n return growl.error(_t('app.shared.cart.please_select_a_member_first'));\n }\n };\n\n /**\n * When modifying an already booked reservation, confirm the modification.\n */\n $scope.modifySlot = function () {\n SlotsReservation.update({ id: $scope.events.modifiable.slots_reservations_ids[0] }, {\n slots_reservation: {\n slot_id: $scope.events.placable.slot_id\n }\n }\n , function (slotReservation) { // success\n // -> run the callback\n if (typeof $scope.onSlotModifySuccess === 'function') { $scope.onSlotModifySuccess(); }\n // -> set the events as successfully moved (to display a summary)\n $scope.events.moved = {\n newSlot: Object.assign($scope.events.placable, { slots_reservations_ids: [slotReservation.id] }),\n oldSlot: $scope.events.modifiable\n };\n // -> reset the 'moving' status\n $scope.events.placable = null;\n $scope.events.modifiable = null;\n }\n , function (err) { // failure\n growl.error(_t('app.shared.cart.unable_to_change_the_reservation'));\n console.error(err);\n });\n };\n\n /**\n * Cancel the current booking modification, reseting the whole process\n * @param [event] {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.cancelModifySlot = function (event) {\n if (event) { event.preventDefault(); }\n if (typeof $scope.onSlotModifyCancel === 'function') { $scope.onSlotModifyCancel(); }\n $scope.events.placable = null;\n $scope.events.modifiable = null;\n };\n\n /**\n * When modifying an already booked reservation, cancel the choice of the new slot\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.removeSlotToPlace = function (e) {\n e.preventDefault();\n if (typeof $scope.onSlotModifyUnselect === 'function') { $scope.onSlotModifyUnselect(); }\n $scope.events.placable = null;\n };\n\n /**\n * Checks if $scope.events.modifiable and $scope.events.placable have tag incompatibilities\n * @returns {boolean} true in case of incompatibility\n */\n $scope.tagMissmatch = function () {\n if ($scope.events.placable.tag_ids.length === 0) { return false; }\n for (const tag of Array.from($scope.events.modifiable.tags)) {\n if (!Array.from($scope.events.placable.tag_ids).includes(tag.id)) {\n return true;\n }\n }\n return false;\n };\n\n /**\n * Check if the currently logged user has the 'admin' OR 'manager' role, but is not taking reseravtion for himself\n * @returns {boolean}\n */\n $scope.isAuthorized = function () {\n if (AuthService.isAuthorized(['admin', 'manager'])) {\n return ($rootScope.currentUser.id !== $scope.user.id);\n }\n\n return false;\n };\n\n /**\n * This will update the payment_schedule setting when the user toggles the switch button\n * @param checked {Boolean}\n */\n $scope.togglePaymentSchedule = (checked) => {\n setTimeout(() => {\n $scope.schedule.requested_schedule = checked;\n updateCartPrice();\n $scope.$apply();\n }, 50);\n };\n\n /**\n * This will open/close the online payment modal\n */\n $scope.toggleOnlinePaymentModal = (beforeApply) => {\n setTimeout(() => {\n $scope.onlinePayment.showModal = !$scope.onlinePayment.showModal;\n if (typeof beforeApply === 'function') {\n beforeApply();\n }\n $scope.$apply();\n }, 50);\n };\n\n /**\n * This will open/close the local payment modal\n */\n $scope.toggleLocalPaymentModal = (beforeApply) => {\n setTimeout(() => {\n $scope.localPayment.showModal = !$scope.localPayment.showModal;\n if (typeof beforeApply === 'function') {\n beforeApply();\n }\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Invoked atfer a successful card payment\n * @param invoice {*} may be an Invoice or a paymentSchedule\n */\n $scope.afterOnlinePaymentSuccess = (invoice) => {\n $scope.toggleOnlinePaymentModal();\n afterPayment(invoice);\n };\n\n /**\n * Invoked atfer a successful offline payment\n * @param invoice {*} may be an Invoice or a paymentSchedule\n */\n $scope.afterLocalPaymentSuccess = (invoice) => {\n $scope.toggleLocalPaymentModal();\n afterPayment(invoice);\n };\n\n /**\n * Invoked when something wrong occurred after the payment dialog has been closed\n * @param message {string}\n */\n $scope.onLocalPaymentError = (message) => {\n growl.error(message);\n };\n\n /**\n * Invoked when something wrong occurred during the payment dialog initialization\n * @param message {string}\n */\n $scope.onOnlinePaymentError = (message) => {\n growl.error(message);\n };\n\n /**\n * Callback triggered when a child component (LocalPaymentModal) requires to update the cart content\n * @param cart {ShoppingCart}\n */\n $scope.updateCart = (cart) => {\n setTimeout(() => {\n $scope.localPayment.cartItems = cart;\n $scope.$apply();\n }, 50);\n };\n\n $scope.isUserValidatedByType = (type) => {\n return AuthService.isAuthorized(['admin', 'manager']) || (!helpers.isUserValidationRequired($scope.settings, type) || (\n helpers.isUserValidationRequired($scope.settings, type) && helpers.isUserValidated($scope.user)));\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the directive is loaded\n */\n const initialize = function () {\n // What the bound slot\n $scope.$watch('slotSelectionTime', function (newValue, oldValue) {\n if (newValue !== oldValue) {\n slotSelectionChanged();\n }\n });\n $scope.$watch('user', function (newValue, oldValue) {\n if (newValue !== oldValue) {\n resetCartState();\n updateCartPrice();\n }\n });\n $scope.$watch('planSelectionTime', function (newValue, oldValue) {\n if (newValue !== oldValue) {\n planSelectionChanged();\n }\n });\n // watch when a coupon is applied to re-compute the total price\n $scope.$watch('coupon.applied', function (newValue, oldValue) {\n if (newValue !== oldValue) {\n updateCartPrice();\n }\n });\n };\n\n /**\n * Validates that the current slot is reserved by a member with an authorized tag. Admin and managers can overpass\n * the mismatch.\n * @param slot {Object} fullCalendar event object.\n * @param callback {function}\n */\n const validateTags = function (slot, callback) {\n const interTags = _.intersection.apply(null, [slot.tag_ids, $scope.user.tag_ids]);\n if (slot.tag_ids.length === 0 || interTags.length > 0) {\n if (typeof callback === 'function') callback();\n } else {\n // ask confirmation\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/shared/_reserve_slot_tags_mismatch.html',\n size: 'md',\n controller: 'ReserveSlotTagsMismatchController',\n resolve: {\n slotTags: function () { return slot.tags; },\n userTags: function () { return $scope.user.tags; },\n userName: function () { return $scope.user.name; }\n }\n });\n modalInstance.result.then(function (res) {\n if (typeof callback === 'function') callback(res);\n });\n }\n };\n\n /**\n * Validates that no other reservations were made that conflict the current slot and alert the user about the conflict.\n * If the user is an administrator or a manager, he can overpass the conflict.\n * @param slot {Object} fullCalendar event object.\n * @param callback {function}\n */\n const validateSameTimeReservations = function (slot, callback) {\n let sameTimeReservations = $scope.settings.overlapping_categories.split(',').map(function (k) {\n return _.filter($scope.user[k], function (sr) {\n return !sr.canceled_at && (\n slot.start.isSame(sr.start_at) ||\n (slot.end.isAfter(sr.start_at) && slot.end.isBefore(sr.end_at)) ||\n (slot.start.isAfter(sr.start_at) && slot.start.isBefore(sr.end_at)) ||\n (slot.start.isBefore(sr.start_at) && slot.end.isAfter(sr.end_at))\n );\n });\n });\n sameTimeReservations = _.union.apply(null, sameTimeReservations);\n if (sameTimeReservations.length > 0) {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/shared/_reserve_slot_same_time.html',\n size: 'md',\n controller: 'ReserveSlotSameTimeController',\n resolve: {\n sameTimeReservations: function () { return sameTimeReservations; },\n bookOverlappingSlotsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'book_overlapping_slots' }).$promise; }]\n }\n });\n modalInstance.result.then(function (res) {\n if (typeof callback === 'function') callback(res);\n });\n } else {\n if (typeof callback === 'function') callback();\n }\n };\n\n /**\n * Callback triggered when the selected slot changed\n */\n const slotSelectionChanged = function () {\n if ($scope.slot) {\n // if this slot is restricted for subscribers...\n if ($scope.slot.plan_ids.length > 0) {\n // ... we select all the plans matching these restrictions...\n const _plans = _.filter($scope.plans, function (p) { return _.includes($scope.slot.plan_ids, p.id); });\n // ... and we group these plans, by Group...\n $scope.slot.plansGrouped = [];\n $scope.slot.group_ids = [];\n for (const group of Array.from($scope.groups)) {\n const groupObj = { id: group.id, name: group.name, plans: [] };\n for (const plan of Array.from(_plans)) {\n if (plan.group_id === group.id) { groupObj.plans.push(plan); }\n }\n if (groupObj.plans.length > 0) {\n // ... Finally, we only keep the plans matching the group of the current user\n // OR all plans if the current user is admin or manager\n if (AuthService.isAuthorized(['admin', 'manager'])) {\n $scope.slot.plansGrouped.push(groupObj);\n } else if ($scope.user.group_id === groupObj.id) {\n $scope.slot.plansGrouped.push(groupObj);\n }\n }\n }\n $scope.slot.group_ids = $scope.slot.plansGrouped.map(function (g) { return g.id; });\n }\n\n if (!$scope.slot.is_completed && $scope.slot.slots_reservations_ids.length === 0 && !$scope.events.modifiable) {\n // slot is not fully reserved, and not reserved by the current user, and we are not currently modifying a slot\n // -> can be added to cart or removed if already present\n const index = _.findIndex($scope.events.reserved, (e) => e.slot_id === $scope.slot.slot_id);\n if (index === -1) {\n if (($scope.limitToOneSlot === 'true') && $scope.events.reserved[0]) {\n // if we limit the number of slots in the cart to 1, and there is already\n // a slot in the cart, we remove it before adding the new one\n $scope.removeSlot($scope.events.reserved[0], 0);\n }\n // slot is not in the cart, so we add it\n $scope.events.reserved.push($scope.slot);\n if (typeof $scope.onSlotAddedToCart === 'function') { $scope.onSlotAddedToCart($scope.slot); }\n } else {\n // slot is in the cart, remove it\n $scope.removeSlot($scope.slot, index);\n }\n // in every cases, because a new reservation has started, we reset the cart content\n resetCartState();\n // finally, we update the prices\n return updateCartPrice();\n } else if (!$scope.slot.is_completed && $scope.slot.slots_reservations_ids.length === 0 && $scope.events.modifiable) {\n // slot is not fully reserved, not reserved by the current user, and we are currently modifying a slot\n // -> we request the calendar to change the rendering\n if (typeof $scope.onSlotModifyUnselect === 'function') {\n // if the callback return false, cancel the selection for the current modification\n const res = $scope.onSlotModifyUnselect();\n if (!res) return;\n }\n // -> then, we re-affect the destination slot\n if (!$scope.events.placable || ($scope.events.placable.slot_id !== $scope.slot.slot_id)) {\n return $scope.events.placable = $scope.slot;\n } else {\n return $scope.events.placable = null;\n }\n } else if ($scope.slot.slots_reservations_ids.length > 0 &&\n $scope.events.modifiable &&\n ($scope.slot._id === $scope.events.modifiable._id)) {\n // slot is reserved and currently modified\n // -> we cancel the modification\n $scope.cancelModifySlot();\n } else if ($scope.slot.slots_reservations_ids.length > 0 &&\n (slotCanBeModified($scope.slot) || slotCanBeCanceled($scope.slot)) &&\n !$scope.events.modifiable &&\n $scope.events.reserved.length === 0) {\n // slot is reserved and is ok to be modified or cancelled\n // but we are not currently running a modification or having any slots in the cart\n // -> first affect the modification/cancellation rights attributes to the current slot\n resetCartState();\n $scope.slot.movable = slotCanBeModified($scope.slot);\n $scope.slot.cancelable = slotCanBeCanceled($scope.slot);\n // -> then, we open a dialog to ask to the user to choose an action\n return dialogs.confirm({\n templateUrl: '/shared/confirm_modify_slot_modal.html',\n resolve: {\n object () {\n if ($scope.slot.user && !$scope.slot.user.name) {\n $scope.slot.user.name = _t('app.shared.confirm_modify_slot_modal.deleted_user');\n }\n return $scope.slot;\n }\n }\n }\n , function (type) {\n // the user has chosen an action, so we proceed\n if (type === 'move') {\n if (typeof $scope.onSlotStartToModify === 'function') { $scope.onSlotStartToModify(); }\n $scope.events.modifiable = $scope.slot;\n } else if (type === 'cancel') {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.shared.cart.confirmation_required'),\n msg: _t('app.shared.cart.do_you_really_want_to_cancel_this_reservation_html')\n };\n }\n }\n },\n function () { // cancel confirmed\n SlotsReservation.cancel({ id: $scope.slot.slots_reservations_ids[0] }, function () { // successfully canceled\n growl.success(_t('app.shared.cart.reservation_was_cancelled_successfully'));\n if (typeof $scope.onSlotCancelSuccess === 'function') { return $scope.onSlotCancelSuccess(); }\n }\n , function () { // error while canceling\n growl.error(_t('app.shared.cart.cancellation_failed'));\n });\n }\n );\n }\n });\n }\n }\n };\n\n /**\n * Reset the parameters that may lead to a wrong price but leave the content (events added to cart)\n */\n const resetCartState = function () {\n $scope.selectedPlan = null;\n $scope.paidPlan = null;\n $scope.coupon.applied = null;\n $scope.events.moved = null;\n $scope.events.paid = [];\n $scope.events.modifiable = null;\n $scope.events.placable = null;\n $scope.schedule.requested_schedule = false;\n $scope.schedule.payment_schedule = null;\n };\n\n /**\n * Determines if the provided booked slot is able to be modified by the user.\n * @param slot {Object} fullCalendar event object\n */\n const slotCanBeModified = function (slot) {\n if (AuthService.isAuthorized(['admin', 'manager'])) { return true; }\n const slotStart = moment(slot.start);\n const now = moment();\n return (slot.can_modify && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay));\n };\n\n /**\n * Determines if the provided booked slot is able to be canceled by the user.\n * @param slot {Object} fullCalendar event object\n */\n const slotCanBeCanceled = function (slot) {\n if (AuthService.isAuthorized(['admin', 'manager'])) { return true; }\n const slotStart = moment(slot.start);\n const now = moment();\n return (slot.can_modify && $scope.enableBookingCancel && (slotStart.diff(now, 'hours') >= $scope.cancelBookingDelay));\n };\n\n /**\n * Callback triggered when the selected slot changed\n */\n const planSelectionChanged = function () {\n if (Auth.isAuthenticated()) {\n if ($scope.selectedPlan !== $scope.plan) {\n $scope.selectedPlan = $scope.plan;\n $scope.schedule.requested_schedule = $scope.plan.monthly_payment;\n } else {\n $scope.selectedPlan = null;\n }\n return updateCartPrice();\n } else {\n return $rootScope.login(null, function () {\n $scope.selectedPlan = $scope.plan;\n return updateCartPrice();\n });\n }\n };\n\n /**\n * Update the total price of the current selection/reservation\n */\n const updateCartPrice = function () {\n if (Object.keys($scope.user).length > 0) {\n const items = [];\n if ($scope.events.reserved && $scope.events.reserved.length > 0) {\n items.push(mkReservation($scope.events.reserved));\n }\n if ($scope.selectedPlan) {\n items.push(mkSubscription($scope.selectedPlan.id));\n }\n\n return Price.compute(mkCartItems(items), function (res) {\n $scope.amountTotal = res.price;\n $scope.schedule.payment_schedule = res.schedule;\n $scope.totalNoCoupon = res.price_without_coupon;\n if (res.errors && Object.keys(res.errors).length > 0) {\n for (const error in res.errors) {\n for (const message of res.errors[error]) {\n growl.error(message);\n }\n }\n }\n setSlotsDetails(res.details);\n });\n } else {\n // otherwise we alert, this error musn't occur when the current user is not admin\n growl.warning(_t('app.shared.cart.please_select_a_member_first'));\n $scope.amountTotal = null;\n }\n };\n\n const setSlotsDetails = function (details) {\n angular.forEach($scope.events.reserved, function (slot) {\n angular.forEach(details.slots, function (s) {\n if (moment(s.start_at).isSame(slot.start)) {\n slot.promo = s.promo;\n slot.price = s.price;\n }\n });\n });\n };\n\n /**\n * Create a hash map implementing the Reservation specs\n * @param slots {Array} Array of fullCalendar events: slots selected on the calendar\n * @return {{reservation: Reservation}}\n */\n const mkReservation = function (slots) {\n const reservation = {\n reservable_id: $scope.reservableId,\n reservable_type: $scope.reservableType,\n slots_reservations_attributes: []\n };\n angular.forEach(slots, function (slot) {\n reservation.slots_reservations_attributes.push({\n offered: slot.offered || false,\n slot_id: slot.slot_id\n });\n });\n\n return { reservation };\n };\n\n /**\n * Create a hash map implementing the Subscription specs\n * @param planId {number}\n * @return {{subscription: SubscriptionRequest}}\n */\n const mkSubscription = function (planId) {\n return {\n subscription: {\n plan_id: planId\n }\n };\n };\n\n /**\n * Build the ShoppingCart object, from the current reservation\n * @param items {Array}\n * @param paymentMethod {string}\n * @return {ShoppingCart}\n */\n const mkCartItems = function (items, paymentMethod = '') {\n return {\n customer_id: $scope.user.id,\n items,\n payment_schedule: $scope.schedule.requested_schedule,\n payment_method: paymentMethod,\n coupon_code: (($scope.coupon.applied ? $scope.coupon.applied.code : undefined))\n };\n };\n\n /**\n * Open a modal window that allows the user to process a credit card payment for his current shopping cart.\n */\n const payOnline = function (items) {\n // check that the online payment is enabled\n if ($scope.settings.online_payment_module !== 'true') {\n growl.error(_t('app.shared.cart.online_payment_disabled'));\n } else {\n $scope.toggleOnlinePaymentModal(() => {\n $scope.onlinePayment.cartItems = mkCartItems(items, 'card');\n });\n }\n };\n\n /**\n * Open a modal window that allows the user to process a local payment for his current shopping cart (admin only).\n */\n const payOnSite = function (items) {\n $scope.toggleLocalPaymentModal(() => {\n $scope.localPayment.cartItems = mkCartItems(items);\n });\n };\n\n /**\n * Actions to run after the payment was successful\n * @param paymentDocument {*} may be an Invoice or a PaymentSchedule\n */\n const afterPayment = function (paymentDocument) {\n // we set the cart content as 'paid' to display a summary of the transaction\n $scope.events.paid = $scope.events.reserved;\n $scope.amountPaid = $scope.amountTotal;\n // we call the external callback if present\n if (typeof $scope.afterPayment === 'function') { $scope.afterPayment(paymentDocument); }\n // we reset the coupon, and the cart content, and we unselect the slot\n $scope.coupon.applied = undefined;\n if ($scope.slot) {\n // reservation (+ subscription)\n $scope.slot = undefined;\n $scope.events.reserved = [];\n } else {\n // subscription only\n $scope.events = {};\n }\n $scope.paidPlan = $scope.selectedPlan;\n $scope.selectedPlan = undefined;\n $scope.schedule.requested_schedule = false;\n $scope.schedule.payment_schedule = undefined;\n };\n\n /**\n * Actions to pay slots (or subscription)\n */\n const paySlots = function () {\n const items = [];\n if ($scope.events.reserved && $scope.events.reserved.length > 0) {\n items.push(mkReservation($scope.events.reserved));\n }\n if ($scope.selectedPlan) {\n items.push(mkSubscription($scope.selectedPlan.id));\n }\n\n return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) {\n const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount);\n if ((AuthService.isAuthorized(['member']) && (amountToPay > 0 || (amountToPay === 0 && hasOtherDeadlines()))) ||\n ($scope.user.id === $rootScope.currentUser.id && amountToPay > 0)) {\n return payOnline(items);\n } else {\n if ((AuthService.isAuthorized(['admin', 'manager']) && $scope.user.id !== $rootScope.currentUser.id) ||\n (amountToPay === 0 && !hasOtherDeadlines())) {\n return payOnSite(items);\n }\n }\n });\n };\n\n /**\n * Check if the later deadlines of the payment schedule exists and are not equal to zero\n * @return {boolean}\n */\n const hasOtherDeadlines = function () {\n if (!$scope.schedule.payment_schedule) return false;\n if ($scope.schedule.payment_schedule.items.length < 2) return false;\n return $scope.schedule.payment_schedule.items[1].amount !== 0;\n };\n\n // !!! MUST BE CALLED AT THE END of the directive\n return initialize();\n }\n });\n }\n]);\n\n/**\n * Controller of the modal showing the reservations the same date at the same time\n */\nApplication.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '$uibModalInstance', 'AuthService', 'sameTimeReservations', 'bookOverlappingSlotsPromise',\n function ($scope, $uibModalInstance, AuthService, sameTimeReservations, bookOverlappingSlotsPromise) {\n $scope.sameTimeReservations = sameTimeReservations;\n $scope.bookSlotAtSameTime = (bookOverlappingSlotsPromise.setting.value === 'true');\n $scope.isAuthorized = AuthService.isAuthorized;\n /**\n * Confirmation callback\n */\n $scope.ok = function () {\n $uibModalInstance.close({});\n };\n /**\n * Cancellation callback\n */\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }\n]);\n\n/**\n * Controller of the modal showing the slot tags\n */\nApplication.Controllers.controller('ReserveSlotTagsMismatchController', ['$scope', '$uibModalInstance', 'AuthService', 'slotTags', 'userTags', 'userName',\n function ($scope, $uibModalInstance, AuthService, slotTags, userTags, userName) {\n $scope.slotTags = slotTags;\n $scope.userTags = userTags;\n $scope.userName = userName;\n $scope.isAuthorized = AuthService.isAuthorized;\n /**\n * Confirmation callback\n */\n $scope.ok = function () {\n $uibModalInstance.close({});\n };\n /**\n * Cancellation callback\n */\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }\n]);\n\n/**\n * Controller used to alert admin reserve slot without plan\n */\nApplication.Controllers.controller('ReserveSlotWithoutPlanController', ['$scope', '$uibModalInstance', 'slot', 'slotNotValidError', 'growl', '_t',\n function ($scope, $uibModalInstance, slot, slotNotValidError, growl, _t) {\n $scope.slot = slot;\n $scope.slotNotValidError = slotNotValidError;\n /**\n * Confirmation callback\n */\n $scope.ok = function () {\n $uibModalInstance.close({});\n };\n /**\n * Cancellation callback\n */\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }\n]);\n","Application.Directives.directive('compile', ['$compile', function ($compile) {\n return function (scope, element, attrs) {\n scope.$watch(\n function (scope) {\n // watch the 'compile' expression for changes\n return scope.$eval(attrs.compile);\n },\n function (value) {\n // when the 'compile' expression changes\n // assign it into the current DOM\n element.html(value);\n\n // compile the new DOM and link it to the current\n // scope.\n // NOTE: we only compile .childNodes so that\n // we don't get into infinite loop compiling ourselves\n $compile(element.contents())(scope);\n }\n );\n };\n}]);\n","/* eslint-disable\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Directives.directive('confirmationNeeded', [() =>\n ({\n priority: 1,\n terminal: true,\n link (scope, element, attrs) {\n const msg = attrs.confirmationNeeded || 'Are you sure?';\n const clickAction = attrs.ngClick;\n return element.bind('click', function () {\n if (attrs.confirmationNeededIf != null) {\n const confirmNeededIf = scope.$eval(attrs.confirmationNeededIf);\n if (confirmNeededIf === true) {\n if (window.confirm(msg)) {\n return scope.$eval(clickAction);\n }\n } else {\n return scope.$eval(clickAction);\n }\n } else {\n if (window.confirm(msg)) {\n return scope.$eval(clickAction);\n }\n }\n });\n }\n })\n\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Directives.directive('coupon', ['$rootScope', 'Coupon', '_t', function ($rootScope, Coupon, _t) {\n return ({\n restrict: 'E',\n scope: {\n show: '=',\n coupon: '=',\n total: '=',\n userId: '@'\n },\n templateUrl: '/shared/_coupon.html',\n link ($scope, element, attributes) {\n // Whether code input is shown or not (ie. the link 'I have a coupon' is shown)\n $scope.code =\n { input: false };\n\n // Available status are: 'pending', 'valid', 'invalid'\n $scope.status = 'pending';\n\n // Binding for the code inputed (see the attached template)\n $scope.couponCode = null;\n\n // Code validation messages\n $scope.messages = [];\n\n // Re-compute if the code can be applied when the total of the cart changes\n $scope.$watch('total', function (newValue, oldValue) {\n if (newValue && (newValue !== oldValue) && $scope.couponCode) {\n return $scope.validateCode();\n }\n });\n\n /**\n * Callback to validate the code\n */\n $scope.validateCode = function () {\n $scope.messages = [];\n if ($scope.couponCode === '') {\n $scope.status = 'pending';\n $scope.coupon = null;\n } else {\n Coupon.validate({ code: $scope.couponCode, user_id: $scope.userId, amount: $scope.total }, function (res) {\n $scope.status = 'valid';\n $scope.coupon = res;\n if (res.type === 'percent_off') {\n $scope.messages.push({ type: 'success', message: _t('app.shared.coupon_input.the_coupon_has_been_applied_you_get_PERCENT_discount', { PERCENT: res.percent_off }) });\n } else {\n $scope.messages.push({ type: 'success', message: _t('app.shared.coupon_input.the_coupon_has_been_applied_you_get_AMOUNT_CURRENCY', { AMOUNT: res.amount_off, CURRENCY: $rootScope.currencySymbol }) });\n }\n if (res.validity_per_user === 'once') {\n $scope.messages.push({ type: 'warning', message: _t('app.shared.coupon_input.coupon_validity_once') });\n }\n }\n , function (err) {\n $scope.status = 'invalid';\n $scope.coupon = null;\n return $scope.messages.push({ type: 'danger', message: _t(`app.shared.coupon_input.unable_to_apply_the_coupon_because_${err.data.status}`) });\n });\n }\n };\n\n /**\n * Callback to remove the message at provided index from the displayed list\n */\n $scope.closeMessage = function (index) { $scope.messages.splice(index, 1); };\n }\n });\n}]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Directives.directive('fileread', [() =>\n ({\n scope: {\n fileread: '='\n },\n\n link (scope, element, attributes) {\n return element.bind('change', changeEvent =>\n scope.$apply(() => scope.fileread = changeEvent.target.files[0])\n );\n }\n })\n\n]);\n\n// This `bsHolder` angular directive is a workaround for\n// an incompatability between angular and the holder.js\n// image placeholder library.\n//\n// To use, simply define `bs-holder` on any element\nApplication.Directives.directive('bsHolder', [() =>\n ({\n link (scope, element, attrs) {\n Holder.addTheme('icon', { background: 'white', foreground: '#ebebeb', size: 60, font: 'FontAwesome' })\n .addTheme('icon-xs', { background: 'white', foreground: '#ebebeb', size: 20, font: 'FontAwesome' })\n .addTheme('icon-black-xs', { background: 'black', foreground: 'white', size: 20, font: 'FontAwesome' })\n .addTheme('avatar', { background: '#eeeeee', foreground: '#555555', size: 16, font: 'FontAwesome' })\n .run(element[0]);\n }\n })\n\n]);\n\nApplication.Directives.directive('match', [() =>\n ({\n require: 'ngModel',\n restrict: 'A',\n scope: {\n match: '='\n },\n link (scope, elem, attrs, ctrl) {\n return scope.$watch(() => (ctrl.$pristine && angular.isUndefined(ctrl.$modelValue)) || (scope.match === ctrl.$modelValue)\n , currentValue => ctrl.$setValidity('match', currentValue));\n }\n })\n\n]);\n\nApplication.Directives.directive('publishProject', [() =>\n ({\n restrict: 'A',\n link (scope, elem, attrs, ctrl) {\n return elem.bind('click', function ($event) {\n if ($event) {\n $event.preventDefault();\n $event.stopPropagation();\n }\n\n if (elem.attr('disabled')) { return; }\n const input = angular.element('');\n const form = angular.element('form');\n form.append(input);\n form.triggerHandler('submit');\n return form[0].submit();\n });\n }\n })\n\n]);\n\nApplication.Directives.directive('disableAnimation', ['$animate', ($animate) =>\n ({\n restrict: 'A',\n link (scope, elem, attrs) {\n return attrs.$observe('disableAnimation', value => $animate.enabled(elem, !value));\n }\n })\n]);\n\n/**\n * Isolate a form's scope from its parent : no nested validation\n * @see https://stackoverflow.com/a/37481846/1039377\n */\nApplication.Directives.directive('isolateForm', [() =>\n ({\n restrict: 'A',\n require: '?form',\n link (scope, elm, attrs, ctrl) {\n if (!ctrl) { return; }\n\n const parentForm = ctrl.$$parentForm; // Note this uses private API\n if (!parentForm) {\n return;\n }\n\n // Remove this form from parent controller\n parentForm.$removeControl(ctrl);\n }\n\n })\n\n]);\n","/* eslint-disable\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Directives.directive('fabUserAvatar', [function () {\n return ({\n restrict: 'E',\n scope: {\n userAvatar: '=ngModel',\n avatarClass: '@'\n },\n templateUrl: '/shared/_user_avatar.html'\n });\n}]);\n","Application.Directives.directive('events', ['Event',\n function (Event) {\n return ({\n restrict: 'E',\n templateUrl: '/home/events.html',\n link ($scope, element, attributes) {\n // The closest upcoming events\n $scope.upcomingEvents = null;\n\n /**\n * Test if the provided event run on a single day or not\n * @param event {Object} single event from the $scope.upcomingEvents array\n * @returns {boolean} false if the event runs on more that 1 day\n */\n $scope.isOneDayEvent = function (event) {\n return moment(event.start_date).isSame(event.end_date, 'day');\n };\n\n // constructor\n const initialize = function () {\n Event.upcoming({ limit: 3 }, function (data) {\n $scope.upcomingEvents = data;\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the directive\n return initialize();\n }\n });\n }\n]);\n","Application.Directives.directive('news', ['Setting',\n function (Setting) {\n return ({\n restrict: 'E',\n templateUrl: '/home/news.html',\n link ($scope, element, attributes) {\n // The admin blogpost\n $scope.homeBlogpost = null;\n\n // constructor\n const initialize = function () {\n Setting.get({ name: 'home_blogpost' }, function (data) {\n $scope.homeBlogpost = data.setting.value;\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the directive\n return initialize();\n }\n });\n }\n]);\n","Application.Directives.directive('projects', ['Project',\n function (Project) {\n return ({\n restrict: 'E',\n templateUrl: '/home/projects.html',\n link ($scope, element, attributes) {\n // The last projects published/documented on the platform\n $scope.lastProjects = null;\n\n // The default slide shown in the carousel\n $scope.activeSlide = 0;\n\n // constructor\n const initialize = function () {\n Project.lastPublished(function (data) {\n $scope.lastProjects = data;\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the directive\n return initialize();\n }\n });\n }\n]);\n","/* global twitterFetcher */\n\n/**\n * This directive will show the last tweet.\n * Usage: \n */\nApplication.Directives.directive('twitter', ['Setting',\n function (Setting) {\n return ({\n restrict: 'E',\n templateUrl: '/home/twitter.html',\n link ($scope, element, attributes) {\n // Twitter username\n $scope.twitterName = null;\n\n // constructor\n const initialize = function () {\n Setting.get({ name: 'twitter_name' }, function (data) {\n $scope.twitterName = data.setting.value;\n if ($scope.twitterName) {\n const configProfile = {\n profile: { screenName: $scope.twitterName },\n domId: 'twitter',\n maxTweets: 1,\n enableLinks: true,\n showUser: false,\n showTime: true,\n showImages: false,\n showRetweet: true,\n showInteraction: false,\n lang: Fablab.locale\n };\n twitterFetcher.fetch(configProfile);\n }\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the directive\n return initialize();\n }\n });\n }\n]);\n","Application.Directives.directive('members', ['Member', 'Setting',\n function (Member, Setting) {\n return ({\n restrict: 'E',\n resolve: {\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({ names: \"['public_registrations']\" }).$promise;\n }]\n },\n templateUrl: '/home/members.html',\n link ($scope, element, attributes) {\n // The last registered members who confirmed their addresses\n $scope.lastMembers = null;\n\n // constructor\n const initialize = function () {\n Member.lastSubscribed({ limit: 4 }, function (data) {\n $scope.lastMembers = data;\n });\n Setting.query({ names: \"['public_registrations']\" }, function (data) {\n // is public registrations allowed?\n $scope.publicRegistrations = (data.public_registrations !== 'false');\n });\n };\n\n // !!! MUST BE CALLED AT THE END of the directive\n return initialize();\n }\n });\n }\n]);\n","Application.Directives.directive('postRender', ['$timeout',\n function ($timeout) {\n return ({\n restrict: 'A',\n terminal: false,\n transclude: false,\n link: function (scope, element, attrs) {\n $timeout(scope[attrs.postRender], 0);\n }\n });\n }\n]);\n","'use strict';\n\n/**\n * This directive will allow to select a member.\n * Please surround it with a ng-if directive to prevent it from being used by a non-admin user.\n * The resulting member will be set into the parent $scope (=> $scope.ctrl.member).\n * The directive takes an optional parameter \"subscription\" as a \"boolean string\" that will filter the user\n * which have a valid running subscription or not.\n * Usage: \n */\nApplication.Directives.directive('selectMember', ['Diacritics', 'Member', function (Diacritics, Member) {\n return ({\n restrict: 'E',\n templateUrl: '/shared/_member_select.html',\n link (scope, element, attributes) {\n scope.autoCompleteName = function (nameLookup) {\n if (!nameLookup) {\n return;\n }\n scope.isLoadingMembers = true;\n const asciiName = Diacritics.remove(nameLookup);\n\n const q = { query: asciiName };\n if (attributes.subscription) {\n q.subscription = attributes.subscription;\n }\n\n Member.search(q, function (users) {\n scope.matchingMembers = users;\n scope.isLoadingMembers = false;\n }\n , function (error) { console.error(error); });\n };\n }\n\n });\n}]);\n","Application.Directives.directive('numberSetting', ['Setting', 'growl', '_t',\n function (Setting, growl, _t) {\n return ({\n restrict: 'E',\n scope: {\n name: '@',\n label: '@',\n settings: '=',\n classes: '@',\n faIcon: '@',\n helperText: '@',\n min: '@',\n step: '@',\n required: '<'\n },\n templateUrl: '/admin/settings/number.html',\n link ($scope, element, attributes) {\n // The setting\n $scope.setting = {\n name: $scope.name,\n value: parseFloat($scope.settings[$scope.name])\n };\n\n /**\n * Callback to save the setting value to the database\n * @param setting {{value:*, name:string}} note that the value will be stringified\n */\n $scope.save = function (setting) {\n let value;\n if (typeof setting.value === 'number') {\n value = setting.value.toString();\n } else {\n ({ value } = setting);\n }\n\n Setting.update(\n { name: setting.name },\n { value },\n function () {\n growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n $scope.settings[$scope.name] = value;\n },\n function (error) {\n if (error.status === 304) return;\n\n if (error.status === 423) {\n growl.error(_t('app.admin.settings.error_SETTING_locked', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n return;\n }\n\n growl.error(_t('app.admin.settings.an_error_occurred_saving_the_setting'));\n console.log(error);\n }\n );\n };\n }\n });\n }\n]);\n","Application.Directives.directive('selectMultipleSetting', ['Setting', 'growl', '_t', '$uibModal',\n function (Setting, growl, _t, $uibModal) {\n return ({\n restrict: 'E',\n scope: {\n name: '@',\n label: '@',\n settings: '=',\n classes: '@',\n required: '<',\n titleNew: '@',\n descriptionNew: '@',\n beforeAdd: '='\n },\n templateUrl: '/admin/settings/select-multiple.html',\n link ($scope, element, attributes) {\n // The setting\n $scope.setting = {\n name: $scope.name,\n value: $scope.settings[$scope.name]\n };\n\n // the options\n $scope.options = $scope.settings[$scope.name].split(' ').sort();\n\n // the selected options\n $scope.selection = [];\n\n /**\n * Remove the items in the selection from the options and update setting.value\n */\n $scope.removeItem = function () {\n const options = $scope.options.filter(function (opt) {\n return $scope.selection.indexOf(opt) < 0;\n });\n $scope.options = options;\n $scope.setting.value = options.join(' ');\n growl.success(_t('app.admin.settings.COUNT_items_removed', { COUNT: $scope.selection.length }));\n $scope.selection = [];\n };\n\n /**\n * Open a modal dialog asking for the value of a new item to add\n */\n $scope.addItem = function () {\n $uibModal.open({\n templateUrl: '/admin/settings/newSelectOption.html',\n resolve: {\n titleNew: function () { return $scope.titleNew; },\n descriptionNew: function () { return $scope.descriptionNew; }\n },\n controller: ['$scope', '$uibModalInstance', 'titleNew', 'descriptionNew',\n function ($scope, $uibModalInstance, titleNew, descriptionNew) {\n $scope.value = undefined;\n $scope.titleNew = titleNew;\n $scope.descriptionNew = descriptionNew;\n $scope.ok = function () {\n $uibModalInstance.close($scope.value);\n };\n $scope.dismiss = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }]\n }).result.finally(null).then(function (val) {\n const options = Array.from($scope.options);\n if (typeof $scope.beforeAdd === 'function') { val = $scope.beforeAdd(val); }\n options.push(val);\n $scope.options = options;\n $scope.setting.value = options.join(' ');\n growl.success(_t('app.admin.settings.item_added'));\n });\n };\n\n /**\n * Callback to save the setting value to the database\n * @param setting {{value:*, name:string}} note that the value will be stringified\n */\n $scope.save = function (setting) {\n const { value } = setting;\n\n Setting.update(\n { name: setting.name },\n { value },\n function () {\n growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n $scope.settings[$scope.name] = value;\n },\n function (error) {\n if (error.status === 304) return;\n\n if (error.status === 423) {\n growl.error(_t('app.admin.settings.error_SETTING_locked', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n return;\n }\n\n growl.error(_t('app.admin.settings.an_error_occurred_saving_the_setting'));\n console.log(error);\n }\n );\n };\n }\n });\n }\n]);\n","Application.Directives.directive('selectSetting', ['Setting', 'growl', '_t',\n function (Setting, growl, _t) {\n return ({\n restrict: 'E',\n scope: {\n name: '@',\n label: '@',\n settings: '=',\n classes: '@',\n required: '<',\n option1: '<',\n option2: '<',\n option3: '<',\n option4: '<',\n option5: '<'\n },\n templateUrl: '/admin/settings/select.html',\n link ($scope, element, attributes) {\n // The setting\n $scope.setting = {\n name: $scope.name,\n value: $scope.settings[$scope.name]\n };\n\n /**\n * Callback to save the setting value to the database\n * @param setting {{value:*, name:string}} note that the value will be stringified\n */\n $scope.save = function (setting) {\n const { value } = setting;\n\n Setting.update(\n { name: setting.name },\n { value },\n function () {\n growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n $scope.settings[$scope.name] = value;\n },\n function (error) {\n if (error.status === 304) return;\n\n if (error.status === 423) {\n growl.error(_t('app.admin.settings.error_SETTING_locked', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n return;\n }\n\n growl.error(_t('app.admin.settings.an_error_occurred_saving_the_setting'));\n console.log(error);\n }\n );\n };\n }\n });\n }\n]);\n","Application.Directives.directive('textSetting', ['Setting', 'growl', '_t',\n function (Setting, growl, _t) {\n return ({\n restrict: 'E',\n scope: {\n name: '@',\n label: '@',\n settings: '=',\n classes: '@',\n faIcon: '@',\n placeholder: '@',\n required: '<',\n type: '@',\n maxLength: '@',\n minLength: '@',\n readOnly: '<'\n },\n templateUrl: '/admin/settings/text.html',\n link ($scope, element, attributes) {\n // if type is not specified, use text as default\n if (typeof $scope.type === 'undefined') {\n $scope.type = 'text';\n }\n // 'required' default to true\n if (typeof $scope.required === 'undefined') {\n $scope.required = true;\n }\n // The setting\n $scope.setting = {\n name: $scope.name,\n value: $scope.settings[$scope.name]\n };\n\n $scope.$watch(`settings.${$scope.name}`, function (newValue, oldValue, scope) {\n if (newValue !== oldValue) {\n $scope.setting.value = newValue;\n }\n });\n\n /**\n * Callback to save the setting value to the database\n * @param setting {{value:*, name:string}} note that the value will be stringified\n */\n $scope.save = function (setting) {\n const { value } = setting;\n\n Setting.update(\n { name: setting.name },\n { value },\n function () {\n growl.success(_t('app.admin.settings.customization_of_SETTING_successfully_saved', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n $scope.settings[$scope.name] = value;\n },\n function (error) {\n if (error.status === 304) return;\n\n if (error.status === 423) {\n growl.error(_t('app.admin.settings.error_SETTING_locked', { SETTING: _t(`app.admin.settings.${setting.name}`) }));\n return;\n }\n\n growl.error(_t('app.admin.settings.an_error_occurred_saving_the_setting'));\n console.log(error);\n }\n );\n };\n }\n });\n }\n]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\nApplication.Directives.directive('socialLink', [function () {\n return ({\n restrict: 'E',\n scope: {\n network: '@?',\n user: '='\n },\n templateUrl: '/shared/_social_link.html',\n link (scope, element, attributes) {\n if (scope.network === 'dailymotion') {\n scope.image = 'social/dailymotion.png';\n return scope.altText = 'd';\n } else if (scope.network === 'echosciences') {\n scope.image = 'social/echosciences.png';\n return scope.altText = 'E)';\n } else {\n if (scope.network === 'website') {\n return scope.faClass = 'fa-globe';\n } else {\n return scope.faClass = `fa-${scope.network.replace('_', '-')}`;\n }\n }\n }\n });\n}]);\n","/* eslint-disable\n no-return-assign,\n no-undef,\n no-useless-escape,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Directives.directive('url', [function () {\n const URL_REGEXP = /^(https?:\\/\\/)([\\da-z\\.-]+)\\.([-a-z0-9\\.]{2,30})([\\/\\w \\.-]*)*\\/?$/;\n return {\n require: 'ngModel',\n link (scope, element, attributes, ctrl) {\n return ctrl.$validators.url = function (modelValue, viewValue) {\n if (ctrl.$isEmpty(modelValue)) {\n return true;\n }\n if (URL_REGEXP.test(viewValue)) {\n return true;\n }\n\n // otherwise, this is invalid\n return false;\n };\n }\n };\n}\n]);\n\nApplication.Directives.directive('endpoint', [function () {\n const ENDPOINT_REGEXP = /^\\/?([-._~:?#\\[\\]@!$&'()*+,;=%\\w]+\\/?)*$/;\n return {\n require: 'ngModel',\n link (scope, element, attributes, ctrl) {\n return ctrl.$validators.endpoint = function (modelValue, viewValue) {\n if (ctrl.$isEmpty(modelValue)) {\n return true;\n }\n if (ENDPOINT_REGEXP.test(viewValue)) {\n return true;\n }\n\n // otherwise, this is invalid\n return false;\n };\n }\n };\n}\n]);\n\nApplication.Directives.directive('cpf', [function () {\n return {\n require: 'ngModel',\n link: function (scope, element, attributes, ctrl) {\n ctrl.$validators.cpf = function (modelValue, viewValue) {\n if (ctrl.$isEmpty(modelValue)) {\n return true;\n }\n\n const cpf = modelValue.replace(/[^\\d]/g, '');\n if (cpf.length !== 11) {\n return false;\n }\n\n if (/^(\\d)\\1{10}$/.test(cpf)) {\n return false;\n }\n\n let sum = 0;\n for (let i = 0; i < 9; i++) {\n sum += parseInt(cpf.charAt(i)) * (10 - i);\n }\n let remainder = 11 - (sum % 11);\n if (remainder === 10 || remainder === 11) {\n remainder = 0;\n }\n if (remainder !== parseInt(cpf.charAt(9))) {\n return false;\n }\n\n sum = 0;\n for (let j = 0; j < 10; j++) {\n sum += parseInt(cpf.charAt(j)) * (11 - j);\n }\n remainder = 11 - (sum % 11);\n if (remainder === 10 || remainder === 11) {\n remainder = 0;\n }\n return remainder === parseInt(cpf.charAt(10));\n };\n }\n };\n}]);\n","/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS202: Simplify dynamic range loops\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\nApplication.Filters.filter('array', [function () {\n return function (arrayLength) {\n if (arrayLength) {\n arrayLength = Math.ceil(arrayLength);\n const arr = new Array(arrayLength);\n\n for (let i = 0, end = arrayLength, asc = end >= 0; asc ? i < end : i > end; asc ? i++ : i--) {\n arr[i] = i;\n }\n\n return arr;\n }\n };\n}]);\n\n// filter for projects and trainings\nApplication.Filters.filter('machineFilter', [function () {\n return function (elements, selectedMachine) {\n if (!angular.isUndefined(elements) && !angular.isUndefined(selectedMachine) && (elements != null) && (selectedMachine != null)) {\n const filteredElements = [];\n angular.forEach(elements, function (element) {\n if (element.machine_ids.indexOf(selectedMachine) !== -1) {\n return filteredElements.push(element);\n }\n });\n return filteredElements;\n } else {\n return elements;\n }\n };\n}]);\n\nApplication.Filters.filter('projectMemberFilter', ['Auth', function (Auth) {\n return function (projects, selectedMember) {\n if (!angular.isUndefined(projects) && angular.isDefined(selectedMember) && (projects != null) && (selectedMember != null) && (selectedMember !== '')) {\n const filteredProject = [];\n // Mes projets\n if (selectedMember === '0') {\n angular.forEach(projects, function (project) {\n if (project.author_id === Auth._currentUser.id) {\n return filteredProject.push(project);\n }\n });\n // les projets auxquels je collabore\n } else {\n angular.forEach(projects, function (project) {\n if (project.user_ids.indexOf(Auth._currentUser.id) !== -1) {\n return filteredProject.push(project);\n }\n });\n }\n return filteredProject;\n } else {\n return projects;\n }\n };\n}]);\n\nApplication.Filters.filter('themeFilter', [function () {\n return function (projects, selectedTheme) {\n if (!angular.isUndefined(projects) && !angular.isUndefined(selectedTheme) && (projects != null) && (selectedTheme != null)) {\n const filteredProjects = [];\n angular.forEach(projects, function (project) {\n if (project.theme_ids.indexOf(selectedTheme) !== -1) {\n return filteredProjects.push(project);\n }\n });\n return filteredProjects;\n } else {\n return projects;\n }\n };\n}]);\n\nApplication.Filters.filter('componentFilter', [function () {\n return function (projects, selectedComponent) {\n if (!angular.isUndefined(projects) && !angular.isUndefined(selectedComponent) && (projects != null) && (selectedComponent != null)) {\n const filteredProjects = [];\n angular.forEach(projects, function (project) {\n if (project.component_ids.indexOf(selectedComponent) !== -1) {\n return filteredProjects.push(project);\n }\n });\n return filteredProjects;\n } else {\n return projects;\n }\n };\n}]);\n\nApplication.Filters.filter('projectsByAuthor', [function () {\n return function (projects, authorId) {\n if (!angular.isUndefined(projects) && angular.isDefined(authorId) && (projects != null) && (authorId != null) && (authorId !== '')) {\n const filteredProject = [];\n angular.forEach(projects, function (project) {\n if (project.author_id === authorId) {\n return filteredProject.push(project);\n }\n });\n return filteredProject;\n } else {\n return projects;\n }\n };\n}]);\n\nApplication.Filters.filter('projectsCollabored', [function () {\n return function (projects, memberId) {\n if (!angular.isUndefined(projects) && angular.isDefined(memberId) && (projects != null) && (memberId != null) && (memberId !== '')) {\n const filteredProject = [];\n angular.forEach(projects, function (project) {\n if (project.user_ids.indexOf(memberId) !== -1) {\n return filteredProject.push(project);\n }\n });\n return filteredProject;\n } else {\n return projects;\n }\n };\n}]);\n\n// depend on app/frontend/src/javascript/lib/humanize.js\nApplication.Filters.filter('humanize', [function () {\n return (element, param) => Humanize.truncate(element, param, null);\n}]);\n\n/**\n * This filter will convert ASCII carriage-return character to the HTML break-line tag\n */\nApplication.Filters.filter('breakFilter', [function () {\n return function (text) {\n if (text != null) {\n return text.replace(/\\n+/g, '
');\n }\n };\n}]);\n\n/**\n * This filter will take a HTML text as input and will return it without the html tags\n */\nApplication.Filters.filter('simpleText', [function () {\n return function (text) {\n if (text != null) {\n // add a line break after specific closing tags\n text = text.replace(/(<\\/p>|<\\/h4>|<\\/h5>|<\\/h6>|<\\/pre>|<\\/blockquote>)/g, '\\n');\n text = text.replace(//g, '\\n');\n return text.replace(/<\\/?\\w+[^>]*>/g, '');\n } else {\n return '';\n }\n };\n}]);\n\nApplication.Filters.filter('toTrusted', ['$sce', function ($sce) {\n return text => $sce.trustAsHtml(text);\n}]);\n\nApplication.Filters.filter('planIntervalFilter', [function () {\n return (interval, intervalCount) => moment.duration(intervalCount, interval).humanize();\n}]);\n\nApplication.Filters.filter('humanReadablePlanName', ['$filter', function ($filter) {\n return function (plan, groups, short) {\n if (plan != null) {\n let result = plan.base_name;\n if (groups != null) {\n for (const group of Array.from(groups)) {\n if (group.id === plan.group_id) {\n if (short != null) {\n result += ` - ${group.slug}`;\n } else {\n result += ` - ${group.name}`;\n }\n }\n }\n }\n result += ` - ${$filter('planIntervalFilter')(plan.interval, plan.interval_count)}`;\n return result;\n }\n };\n}]);\n\nApplication.Filters.filter('canceledReservationsFilter', [function () {\n return function (elements) {\n if (!angular.isUndefined(elements) && (elements != null)) {\n return elements.filter(e => e.canceled_at === null);\n }\n };\n}]);\n\nApplication.Filters.filter('trainingReservationsFilter', [function () {\n return function (elements, selectedScope) {\n if (!angular.isUndefined(elements) && !angular.isUndefined(selectedScope) && (elements != null) && (selectedScope != null)) {\n const filteredElements = [];\n angular.forEach(elements, function (element) {\n switch (selectedScope) {\n case 'future':\n if (new Date(element.start_at) > new Date()) {\n return filteredElements.push(element);\n }\n break;\n case 'passed':\n if ((new Date(element.start_at) <= new Date()) && !element.is_valid) {\n return filteredElements.push(element);\n }\n break;\n case 'valided':\n if ((new Date(element.start_at) <= new Date()) && element.is_valid) {\n return filteredElements.push(element);\n }\n break;\n default:\n return [];\n }\n });\n return filteredElements;\n } else {\n return elements;\n }\n };\n}]);\n\nApplication.Filters.filter('eventsReservationsFilter', [function () {\n return function (elements, selectedScope) {\n if (!angular.isUndefined(elements) && !angular.isUndefined(selectedScope) && (elements != null) && (selectedScope != null) && (selectedScope !== '')) {\n const filteredElements = [];\n angular.forEach(elements, function (element) {\n if (angular.isUndefined(element.start_at)) { element.start_at = element.availability.start_at; }\n if (angular.isUndefined(element.end_at)) { element.end_at = element.availability.end_at; }\n switch (selectedScope) {\n case 'future':\n if (new Date(element.end_at) >= new Date()) {\n return filteredElements.push(element);\n }\n break;\n case 'future_asc':\n if (new Date(element.end_at) >= new Date()) {\n return filteredElements.push(element);\n }\n break;\n case 'passed':\n if (new Date(element.end_at) <= new Date()) {\n return filteredElements.push(element);\n }\n break;\n default:\n return [];\n }\n });\n switch (selectedScope) {\n case 'future_asc':\n return filteredElements.reverse();\n default:\n return filteredElements;\n }\n } else {\n return elements;\n }\n };\n}]);\n\nApplication.Filters.filter('groupFilter', [function () {\n return function (elements, member) {\n if (!angular.isUndefined(elements) && !angular.isUndefined(member) && (elements != null) && (member != null)) {\n const filteredElements = [];\n angular.forEach(elements, function (element) {\n if (member.group_id === element.id) {\n return filteredElements.push(element);\n }\n });\n return filteredElements;\n } else {\n return elements;\n }\n };\n}]);\n\nApplication.Filters.filter('groupByFilter', [function () {\n return _.memoize((elements, field) => _.groupBy(elements, field));\n}]);\n\nApplication.Filters.filter('capitalize', [() =>\n text => `${text.charAt(0).toUpperCase()}${text.slice(1).toLowerCase()}`\n\n]);\n\nApplication.Filters.filter('reverse', [function () {\n return function (items) {\n if (!angular.isArray(items)) {\n return items;\n }\n\n return items.slice().reverse();\n };\n}]);\n\nApplication.Filters.filter('toArray', [function () {\n return function (obj) {\n if (!(obj instanceof Object)) { return obj; }\n return _.map(obj, function (val, key) {\n if (angular.isObject(val)) {\n return Object.defineProperty(val, '$key', { __proto__: null, value: key });\n }\n });\n };\n}]);\n\nApplication.Filters.filter('toIsoDate', [function () {\n return function (date) {\n if (!(date instanceof Date) && !moment.isMoment(date)) { return date; }\n return moment(date).format('YYYY-MM-DD');\n };\n}]);\n\nApplication.Filters.filter('booleanFormat', ['_t', function (_t) {\n return function (boolean) {\n if (((typeof boolean === 'boolean') && boolean) || ((typeof boolean === 'string') && (boolean === 'true'))) {\n return _t('app.shared.buttons.yes');\n } else {\n return _t('app.shared.buttons.no');\n }\n };\n}]);\n\nApplication.Filters.filter('maxCount', ['_t', function (_t) {\n return function (max) {\n if ((typeof max === 'undefined') || (max === null) || ((typeof max === 'number') && (max === 0))) {\n return _t('app.admin.pricing.unlimited');\n } else {\n return max;\n }\n };\n}]);\n\nApplication.Filters.filter('filterDisabled', [function () {\n return function (list, filter) {\n if (angular.isArray(list)) {\n return list.filter(function (e) {\n switch (filter) {\n case 'disabled': return e.disabled;\n case 'enabled': return !e.disabled;\n default: return true;\n }\n });\n } else {\n return list;\n }\n };\n}]);\n\nApplication.Filters.filter('currency', [function ($locale) {\n return function (amount) {\n // if null or undefined pass it through\n return (amount == null)\n ? amount\n : new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).format(amount);\n };\n}]);\n","import { useState, useEffect } from 'react';\nimport { emitCustomEvent } from 'react-custom-events';\nimport { Order } from '../models/order';\nimport CartAPI from '../api/cart';\nimport { getCartToken, setCartToken } from '../lib/cart-token';\nimport { User } from '../models/user';\n\nexport default function useCart (user?: User) {\n const [cart, setCart] = useState(null);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(null);\n\n useEffect(() => {\n async function createCart () {\n const currentCartToken = getCartToken();\n const data = await CartAPI.create(currentCartToken);\n _setCart(data);\n setLoading(false);\n setCartToken(data.token);\n }\n setLoading(true);\n try {\n createCart();\n } catch (e) {\n setLoading(false);\n setError(e);\n }\n }, []);\n\n const reloadCart = async () => {\n setLoading(true);\n const currentCartToken = getCartToken();\n const data = await CartAPI.create(currentCartToken);\n _setCart(data);\n setLoading(false);\n };\n\n useEffect(() => {\n if (user && cart && (!cart.statistic_profile_id || !cart.operator_profile_id)) {\n reloadCart();\n }\n }, [user]);\n\n const _setCart = (data: Order) => {\n setCart(data);\n emitCustomEvent('CartUpdate', data);\n };\n\n return { loading, cart, error, setCart: _setCart, reloadCart };\n}\n","import _ from 'lodash';\nimport { ApiFilter } from '../models/api';\nimport { serialize } from 'object-to-formdata-tz';\n\nexport default class ApiLib {\n static filtersToQuery (filters?: ApiFilter, keepNullValues = true): string {\n if (!filters || Object.keys(filters).length < 1) return '';\n\n return '?' + Object.entries(filters)\n .filter(filter => keepNullValues || !_.isNil(filter[1]))\n .map(filter => `${filter[0]}=${filter[1]}`)\n .join('&');\n }\n\n static serializeAttachments (object: TObject, name: string, attachmentAttributes: Array): FormData {\n const data = serialize({\n [name]: {\n ...object,\n ...attachmentAttributes.reduce((a, name) => { return { ...a, [name]: null }; }, {})\n }\n }, { dateWithTimezone: true });\n attachmentAttributes.forEach((attr) => {\n data.delete(`${name}[${attr}]`);\n if (Array.isArray(object[attr])) {\n object[attr]?.forEach((file, i) => {\n if (file?.attachment_files && file?.attachment_files[0]) {\n data.set(`${name}[${attr}][${i}][attachment]`, file.attachment_files[0]);\n }\n if (file?.id) {\n data.set(`${name}[${attr}][${i}][id]`, file.id.toString());\n }\n if (file?._destroy) {\n data.set(`${name}[${attr}][${i}][_destroy]`, file._destroy.toString());\n }\n if (file?.is_main) {\n data.set(`${name}[${attr}][${i}][is_main]`, file.is_main.toString());\n }\n });\n } else {\n if (object[attr]?.attachment_files && object[attr]?.attachment_files[0]) {\n data.set(`${name}[${attr}][attachment]`, object[attr]?.attachment_files[0]);\n }\n if (object[attr]?.id) {\n data.set(`${name}[${attr}][id]`, object[attr].id.toString());\n }\n if (object[attr]?._destroy) {\n data.set(`${name}[${attr}][_destroy]`, object[attr]._destroy.toString());\n }\n }\n });\n return data;\n }\n}\n","import Cookies from 'js-cookie';\n\nexport const cartCookieName = 'fablab_cart_token';\nexport const cartCookieExpire = 7;\n\nexport const getCartToken = () =>\n Cookies.get(cartCookieName);\n\nexport const setCartToken = (cartToken: string) => {\n const cookieOptions = {\n expires: cartCookieExpire\n };\n\n Cookies.set(\n cartCookieName,\n cartToken,\n cookieOptions\n );\n};\n\nexport const removeCartToken = () => {\n Cookies.remove(cartCookieName);\n};\n","import { Coupon } from '../models/coupon';\n\nexport const computePriceWithCoupon = (price: number, coupon?: Coupon): number => {\n if (!coupon) {\n return price;\n }\n if (coupon.type === 'percent_off') {\n return (Math.round(price * 100) - (Math.round(price * 100) * coupon.percent_off / 100)) / 100;\n } else if (coupon.type === 'amount_off' && price > coupon.amount_off) {\n return (Math.round(price * 100) - Math.round(coupon.amount_off * 100)) / 100;\n }\n return price;\n};\n","// This is a kind of promise you can resolve from outside the function callback.\n// Credits to https://stackoverflow.com/a/71158892/1039377\nexport default class Deferred {\n public readonly promise: Promise;\n private resolveFn!: (value: T | PromiseLike) => void;\n private rejectFn!: (reason?: unknown) => void;\n\n public constructor () {\n this.promise = new Promise((resolve, reject) => {\n this.resolveFn = resolve;\n this.rejectFn = reject;\n });\n }\n\n public reject (reason?: unknown): void {\n this.rejectFn(reason);\n }\n\n public resolve (param: T): void {\n this.resolveFn(param);\n }\n}\n","'use strict';\n// TODO remove unused?\n(function (angular) {\n const deviseModal = angular.module('DeviseModal', [\n 'Devise',\n 'ui.bootstrap'\n ]);\n deviseModal.run([\n '$uibModal',\n '$http',\n 'Auth',\n '$rootScope',\n function ($uibModal, $http, Auth, $rootScope) {\n let promise = null;\n function reset () {\n promise = null;\n }\n function partial (fn, arg) {\n return function () {\n return fn.call(this, arg);\n };\n }\n $rootScope.$on('devise:unauthorized', function (event, response, deferred) {\n function retryRequestAfterLogin () {\n return promise.then(function () {\n return $http(response.config);\n }).then(deferred.resolve, partial(deferred.reject, response));\n }\n if (!promise) {\n promise = $uibModal.open({\n templateUrl: '/shared/deviseModal.html',\n controller: ['$scope', '$uibModalInstance', function ($scope, $uibModalInstance) {\n const user = $scope.user = {};\n $scope.login = function () {\n $uibModalInstance.close(user);\n };\n $scope.dismiss = function () {\n $uibModalInstance.dismiss('cancel');\n };\n }]\n }).result.finally(reset).then(Auth.login);\n }\n retryRequestAfterLogin();\n });\n }\n ]);\n deviseModal.run([\n '$templateCache',\n function ($templateCache) {\n 'use strict';\n $templateCache.put('deviseModal.html', '
');\n }\n ]);\n}(angular));\n","/**\n * A directive to embed a Disqus comments widget on your AngularJS page.\n *\n * For documentation, see the README.md file in this directory\n *\n * Created by Michael on 22/01/14.\n * Copyright Michael Bromley 2014\n * Available under the MIT license.\n */\nangular.module('angularUtils.directives.dirDisqus', [])\n\n .directive('dirDisqus', ['$window', function ($window) {\n return {\n restrict: 'E',\n scope: {\n disqus_shortname: '@disqusShortname',\n disqus_identifier: '@disqusIdentifier',\n disqus_title: '@disqusTitle',\n disqus_url: '@disqusUrl',\n disqus_category_id: '@disqusCategoryId',\n disqus_disable_mobile: '@disqusDisableMobile',\n readyToBind: '@'\n },\n template: '
comments powered by Disqus',\n link: function (scope) {\n // ensure that the disqus_identifier and disqus_url are both set, otherwise we will run in to identifier conflicts when using URLs with \"#\" in them\n // see http://help.disqus.com/customer/portal/articles/662547-why-are-the-same-comments-showing-up-on-multiple-pages-\n if (typeof scope.disqus_identifier === 'undefined' || typeof scope.disqus_url === 'undefined') {\n throw new Error('Please ensure that the `disqus-identifier` and `disqus-url` attributes are both set.');\n }\n\n scope.$watch('readyToBind', function (isReady) {\n // If the directive has been called without the 'ready-to-bind' attribute, we\n // set the default to \"true\" so that Disqus will be loaded straight away.\n if (!angular.isDefined(isReady)) {\n isReady = 'true';\n }\n if (scope.$eval(isReady)) {\n // put the config variables into separate global vars so that the Disqus script can see them\n $window.disqus_shortname = scope.disqus_shortname;\n $window.disqus_identifier = scope.disqus_identifier;\n $window.disqus_title = scope.disqus_title;\n $window.disqus_url = scope.disqus_url;\n $window.disqus_category_id = scope.disqus_category_id;\n $window.disqus_disable_mobile = scope.disqus_disable_mobile;\n\n // get the remote Disqus script and insert it into the DOM, but only if it not already loaded (as that will cause warnings)\n if (!$window.DISQUS) {\n const dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;\n dsq.src = '//' + scope.disqus_shortname + '.disqus.com/embed.js';\n (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);\n } else {\n $window.DISQUS.reset({\n reload: true,\n config: function () {\n this.page.identifier = scope.disqus_identifier;\n this.page.url = scope.disqus_url;\n this.page.title = scope.disqus_title;\n }\n });\n }\n }\n });\n }\n };\n }]);\n","import { Path } from 'react-hook-form';\nimport { UnpackNestedValue, UseFormSetValue } from 'react-hook-form/dist/types/form';\nimport { FieldPathValue } from 'react-hook-form/dist/types/path';\nimport { FieldValues } from 'react-hook-form/dist/types/fields';\nimport { FileType } from '../models/file';\nimport { Dispatch, SetStateAction } from 'react';\n\nexport default class FileUploadLib {\n public static onRemoveFile (file: FileType, id: string, setFile: Dispatch>, setValue: UseFormSetValue, onFileRemove: () => void) {\n if (file?.id) {\n setValue(\n `${id}._destroy` as Path,\n true as UnpackNestedValue>>\n );\n }\n setValue(\n `${id}.attachment_files` as Path,\n null as UnpackNestedValue>>\n );\n setFile(null);\n if (typeof onFileRemove === 'function') {\n onFileRemove();\n }\n }\n\n public static hasFile (file: FileType): boolean {\n return file?.attachment_name && !file?._destroy;\n }\n}\n","import moment, { unitOfTime } from 'moment-timezone';\nimport { IFablab } from '../models/fablab';\nimport { TDateISO, TDateISODate, TDateISOShortTime } from '../typings/date-iso';\n\ndeclare let Fablab: IFablab;\n\nexport default class FormatLib {\n /**\n * Check if the provided variable is a JS Date oject\n */\n static isDate = (value: unknown): boolean => {\n return (value != null) && !isNaN(value as number) && (typeof (value as Date).getDate !== 'undefined');\n };\n\n /**\n * Check if the provided variable is an ISO 8601 representation of a date\n */\n static isDateISO = (value: string): boolean => {\n if (typeof value !== 'string') return false;\n return !!value?.match(/^\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d/);\n };\n\n /**\n * Check if the provided variable is string representing a short date, according to ISO 8601 (e.g. 2023-01-12)\n */\n static isShortDateISO = (value: string): boolean => {\n if (typeof value !== 'string') return false;\n return !!value.match(/^\\d\\d\\d\\d-\\d\\d-\\d\\d$/);\n };\n\n /**\n * Check if the provided variable is string representing a short time, according to ISO 8601 (e.g. 14:21)\n */\n static isShortTimeISO = (value: string): boolean => {\n if (typeof value !== 'string') return false;\n return !!value?.match(/^\\d\\d:\\d\\d$/);\n };\n\n /**\n * Return the formatted localized date for the given date\n */\n static date = (date: Date|TDateISO|TDateISODate): string => {\n let tempDate: Date;\n if (FormatLib.isShortDateISO(date as string) || FormatLib.isDateISO(date as string)) {\n tempDate = FormatLib.parseISOdate(date as TDateISO);\n } else {\n tempDate = moment(date).toDate();\n }\n return Intl.DateTimeFormat(Fablab.intl_locale, { timeZone: Fablab.timezone }).format(tempDate);\n };\n\n /**\n * Parse the provided datetime or date string (as ISO8601 format) and return the equivalent Date object\n */\n private static parseISOdate = (date: TDateISO|TDateISODate): Date => {\n const isoDateMatch = (date as string)?.match(/^(\\d\\d\\d\\d-\\d\\d-\\d\\d)/);\n return new Date(`${isoDateMatch[1]}T12:00:00${Fablab.timezone_offset}`);\n };\n\n /**\n * Parse the provided datetime or time string (as ISO8601 format) and return the equivalent Date object\n */\n private static parseISOtime = (date: TDateISO|TDateISOShortTime): Date => {\n const isoTimeMatch = (date as string)?.match(/(^|T)(\\d\\d:\\d\\d)/);\n return new Date(`1970-01-01T${isoTimeMatch[2]}:00${Fablab.timezone_offset}`);\n };\n\n /**\n * Return a date formatted for use within a filename\n */\n static dateFilename = (date: Date|TDateISO|TDateISODate): string => {\n return moment(date).format('DDMMYYYY');\n };\n\n /**\n * Return the formatted localized time for the given date\n */\n static time = (date: Date|TDateISO|TDateISOShortTime): string => {\n let tempDate: Date;\n if (FormatLib.isShortTimeISO(date as string) || FormatLib.isDateISO(date as string)) {\n tempDate = FormatLib.parseISOtime(date as TDateISOShortTime);\n } else {\n tempDate = moment(date).toDate();\n }\n return Intl.DateTimeFormat(Fablab.intl_locale, { hour: 'numeric', minute: 'numeric', timeZone: Fablab.timezone }).format(tempDate);\n };\n\n /**\n * Return the formatted localized duration\n */\n static duration = (interval: unitOfTime.DurationConstructor, intervalCount: number): string => {\n return moment.duration(intervalCount, interval).locale(Fablab.moment_locale).humanize();\n };\n\n /**\n * Return the formatted localized amount for the given price (eg. 20.5 => \"20,50 €\")\n */\n static price = (price: number): string => {\n return new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).format(price);\n };\n\n /**\n * Return currency symbol for currency setting\n */\n static currencySymbol = (): string => {\n return new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).formatToParts().filter(p => p.type === 'currency')[0].value;\n };\n}\n","// this script loads the google tag manager, used by Google Analytics V4\n(function () {\n const GTM = {};\n\n window.dataLayer = window.dataLayer || [];\n function gtag () { window.dataLayer.push(arguments); }\n\n GTM.enableAnalytics = function (trackingId) {\n gtag('js', new Date());\n gtag('config', trackingId);\n\n const node = document.createElement('script');\n const firstScript = document.getElementsByTagName('script')[0];\n node.async = true;\n node.src = `//www.googletagmanager.com/gtag/js?id=${trackingId}`;\n firstScript.parentNode.insertBefore(node, firstScript);\n };\n\n GTM.trackPage = function (url, title) {\n gtag('event', 'page_view', {\n page_location: url,\n page_title: title\n });\n };\n\n GTM.trackLogin = function () {\n gtag('event', 'login');\n };\n\n GTM.trackPurchase = function (transactionId, value) {\n gtag('event', 'purchase', {\n transaction_id: transactionId,\n value,\n currency: Fablab.intl_currency\n });\n };\n\n this.GTM = GTM;\n\n if (typeof module !== 'undefined' && module !== null) {\n module.exports = GTM;\n }\n}).call(this);\n","(function () {\n const objectRef = new function () {}();\n\n const toString = objectRef.toString;\n\n const isNaN = function (value) {\n return Number.isNaN(value);\n };\n\n const isFinite = function (value) {\n return ((typeof window !== 'undefined' && window !== null ? window.isFinite : undefined) || global.isFinite)(value) && !isNaN(parseFloat(value));\n };\n\n const isArray = function (value) {\n return toString.call(value) === '[object Array]';\n };\n\n const timeFormats = [\n {\n name: 'second',\n value: 1e3\n }, {\n name: 'minute',\n value: 6e4\n }, {\n name: 'hour',\n value: 36e5\n }, {\n name: 'day',\n value: 864e5\n }, {\n name: 'week',\n value: 6048e5\n }\n ];\n\n const Humanize = {};\n\n Humanize.intword = function (number, charWidth, decimals) {\n if (decimals == null) {\n decimals = 2;\n }\n /*\n # This method is deprecated. Please use compactInteger instead.\n # intword will be going away in the next major version.\n */\n\n return Humanize.compactInteger(number, decimals);\n };\n\n Humanize.compactInteger = function (input, decimals) {\n let decimalPart, length, output, outputNumber, unsignedNumberString, _i, _len, _length;\n if (decimals == null) {\n decimals = 0;\n }\n decimals = Math.max(decimals, 0);\n const number = parseInt(input, 10);\n const signString = number < 0 ? '-' : '';\n const unsignedNumber = Math.abs(number);\n unsignedNumberString = '' + unsignedNumber;\n const numberLength = unsignedNumberString.length;\n const numberLengths = [13, 10, 7, 4];\n const bigNumPrefixes = ['T', 'B', 'M', 'k'];\n if (unsignedNumber < 1000) {\n if (decimals > 0) {\n unsignedNumberString += '.' + (Array(decimals + 1).join('0'));\n }\n return '' + signString + unsignedNumberString;\n }\n if (numberLength > numberLengths[0] + 3) {\n return number.toExponential(decimals).replace('e+', 'x10^');\n }\n for (_i = 0, _len = numberLengths.length; _i < _len; _i++) {\n _length = numberLengths[_i];\n if (numberLength >= _length) {\n length = _length;\n break;\n }\n }\n const decimalIndex = numberLength - length + 1;\n const unsignedNumberCharacterArray = unsignedNumberString.split('');\n const wholePartArray = unsignedNumberCharacterArray.slice(0, decimalIndex);\n const decimalPartArray = unsignedNumberCharacterArray.slice(decimalIndex, decimalIndex + decimals + 1);\n const wholePart = wholePartArray.join('');\n decimalPart = decimalPartArray.join('');\n if (decimalPart.length < decimals) {\n decimalPart += '' + (Array(decimals - decimalPart.length + 1).join('0'));\n }\n if (decimals === 0) {\n output = '' + signString + wholePart + bigNumPrefixes[numberLengths.indexOf(length)];\n } else {\n outputNumber = (+('' + wholePart + '.' + decimalPart)).toFixed(decimals);\n output = '' + signString + outputNumber + bigNumPrefixes[numberLengths.indexOf(length)];\n }\n return output;\n };\n\n Humanize.intcomma = Humanize.intComma = function (number, decimals) {\n if (decimals == null) {\n decimals = 0;\n }\n return Humanize.formatNumber(number, decimals);\n };\n\n Humanize.filesize = Humanize.fileSize = function (filesize) {\n let sizeStr;\n if (filesize >= 1073741824) {\n sizeStr = Humanize.formatNumber(filesize / 1073741824, 2, '') + ' GB';\n } else if (filesize >= 1048576) {\n sizeStr = Humanize.formatNumber(filesize / 1048576, 2, '') + ' MB';\n } else if (filesize >= 1024) {\n sizeStr = Humanize.formatNumber(filesize / 1024, 0) + ' KB';\n } else {\n sizeStr = Humanize.formatNumber(filesize, 0) + Humanize.pluralize(filesize, ' byte');\n }\n return sizeStr;\n };\n\n Humanize.formatNumber = function (number, precision, thousand, decimal) {\n if (precision == null) {\n precision = 0;\n }\n if (thousand == null) {\n thousand = ',';\n }\n if (decimal == null) {\n decimal = '.';\n }\n const firstComma = function (number, thousand, position) {\n if (position) {\n return number.substr(0, position) + thousand;\n } else {\n return '';\n }\n };\n const commas = function (number, thousand, position) {\n return number.substr(position).replace(/(\\d{3})(?=\\d)/g, '$1' + thousand);\n };\n const decimals = function (number, decimal, usePrecision) {\n if (usePrecision) {\n return decimal + Humanize.toFixed(Math.abs(number), usePrecision).split('.')[1];\n } else {\n return '';\n }\n };\n const usePrecision = Humanize.normalizePrecision(precision);\n const negative = number < 0 ? '-' : '';\n const base = parseInt(Humanize.toFixed(Math.abs(number || 0), usePrecision), 10) + '';\n const mod = base.length > 3 ? base.length % 3 : 0;\n return negative + firstComma(base, thousand, mod) + commas(base, thousand, mod) + decimals(number, decimal, usePrecision);\n };\n\n Humanize.toFixed = function (value, precision) {\n if (precision == null) {\n precision = Humanize.normalizePrecision(precision, 0);\n }\n const power = Math.pow(10, precision);\n return (Math.round(value * power) / power).toFixed(precision);\n };\n\n Humanize.normalizePrecision = function (value, base) {\n value = Math.round(Math.abs(value));\n if (isNaN(value)) {\n return base;\n } else {\n return value;\n }\n };\n\n Humanize.ordinal = function (value) {\n let end;\n const number = parseInt(value, 10);\n if (number === 0) {\n return value;\n }\n const specialCase = number % 100;\n if (specialCase === 11 || specialCase === 12 || specialCase === 13) {\n return '' + number + 'th';\n }\n const leastSignificant = number % 10;\n switch (leastSignificant) {\n case 1:\n end = 'st';\n break;\n case 2:\n end = 'nd';\n break;\n case 3:\n end = 'rd';\n break;\n default:\n end = 'th';\n }\n return '' + number + end;\n };\n\n Humanize.times = function (value, overrides) {\n let number, smallTimes, _ref;\n if (overrides == null) {\n overrides = {};\n }\n if (isFinite(value) && value >= 0) {\n number = parseFloat(value);\n smallTimes = ['never', 'once', 'twice'];\n if (overrides[number] != null) {\n return '' + overrides[number];\n } else {\n return '' + (((_ref = smallTimes[number]) != null ? _ref.toString() : undefined) || number.toString() + ' times');\n }\n }\n };\n\n Humanize.pluralize = function (number, singular, plural) {\n if (!((number != null) && (singular != null))) {\n return;\n }\n if (plural == null) {\n plural = singular + 's';\n }\n if (parseInt(number, 10) === 1) {\n return singular;\n } else {\n return plural;\n }\n };\n\n Humanize.truncate = function (str, length, ending) {\n if (length == null) {\n length = 100;\n }\n if (ending == null) {\n ending = '...';\n }\n if (str && str.length > length) {\n return str.substring(0, length - ending.length) + ending;\n } else {\n return str;\n }\n };\n\n Humanize.truncatewords = Humanize.truncateWords = function (string, length) {\n let i, result;\n const array = string.split(' ');\n result = '';\n i = 0;\n while (i < length) {\n if (array[i] != null) {\n result += '' + array[i] + ' ';\n }\n i++;\n }\n if (array.length > length) {\n return result + '...';\n }\n };\n\n Humanize.truncatenumber = Humanize.boundedNumber = function (num, bound, ending) {\n let result;\n if (bound == null) {\n bound = 100;\n }\n if (ending == null) {\n ending = '+';\n }\n result = null;\n if (isFinite(num) && isFinite(bound)) {\n if (num > bound) {\n result = bound + ending;\n }\n }\n return (result || num).toString();\n };\n\n Humanize.oxford = function (items, limit, limitStr) {\n let extra, limitIndex;\n const numItems = items.length;\n if (numItems < 2) {\n return '' + items;\n } else if (numItems === 2) {\n return items.join(' and ');\n } else if ((limit != null) && numItems > limit) {\n extra = numItems - limit;\n limitIndex = limit;\n if (limitStr == null) {\n limitStr = ', and ' + extra + ' ' + (Humanize.pluralize(extra, 'other'));\n }\n } else {\n limitIndex = -1;\n limitStr = ', and ' + items[numItems - 1];\n }\n return items.slice(0, limitIndex).join(', ') + limitStr;\n };\n\n Humanize.dictionary = function (object, joiner, separator) {\n let defs, key, result, val;\n if (joiner == null) {\n joiner = ' is ';\n }\n if (separator == null) {\n separator = ', ';\n }\n result = '';\n if ((object != null) && typeof object === 'object' && Object.prototype.toString.call(object) !== '[object Array]') {\n defs = [];\n for (key in object) {\n val = object[key];\n defs.push('' + key + joiner + val);\n }\n result = defs.join(separator);\n }\n return result;\n };\n\n Humanize.frequency = function (list, verb) {\n let str;\n if (!isArray(list)) {\n return;\n }\n const len = list.length;\n const times = Humanize.times(len);\n if (len === 0) {\n str = '' + times + ' ' + verb;\n } else {\n str = '' + verb + ' ' + times;\n }\n return str;\n };\n\n Humanize.pace = function (value, intervalMs, unit) {\n let f, prefix, relativePace, timeUnit, _i, _len;\n if (unit == null) {\n unit = 'time';\n }\n if (value === 0 || intervalMs === 0) {\n return 'No ' + (Humanize.pluralize(unit));\n }\n prefix = 'Approximately';\n timeUnit = null;\n const rate = value / intervalMs;\n for (_i = 0, _len = timeFormats.length; _i < _len; _i++) {\n f = timeFormats[_i];\n relativePace = rate * f.value;\n if (relativePace > 1) {\n timeUnit = f.name;\n break;\n }\n }\n if (!timeUnit) {\n prefix = 'Less than';\n relativePace = 1;\n timeUnit = timeFormats[timeFormats.length - 1].name;\n }\n const roundedPace = Math.round(relativePace);\n unit = Humanize.pluralize(roundedPace, unit);\n return '' + prefix + ' ' + roundedPace + ' ' + unit + ' per ' + timeUnit;\n };\n\n Humanize.nl2br = function (string, replacement) {\n if (replacement == null) {\n replacement = '
';\n }\n return string.replace(/\\n/g, replacement);\n };\n\n Humanize.br2nl = function (string, replacement) {\n if (replacement == null) {\n replacement = '\\r\\n';\n }\n return string.replace(//g, replacement);\n };\n\n Humanize.capitalize = function (string, downCaseTail) {\n if (downCaseTail == null) {\n downCaseTail = false;\n }\n return '' + (string.charAt(0).toUpperCase()) + (downCaseTail ? string.slice(1).toLowerCase() : string.slice(1));\n };\n\n Humanize.capitalizeAll = function (string) {\n return string.replace(/(?:^|\\s)\\S/g, function (a) {\n return a.toUpperCase();\n });\n };\n\n Humanize.titlecase = Humanize.titleCase = function (string) {\n const smallWords = /\\b(a|an|and|at|but|by|de|en|for|if|in|of|on|or|the|to|via|vs?\\.?)\\b/i;\n const internalCaps = /\\S+[A-Z]+\\S*/;\n const splitOnWhiteSpaceRegex = /\\s+/;\n const splitOnHyphensRegex = /-/;\n const doTitleCase = function (_string, hyphenated, firstOrLast) {\n let index, word, _i, _len;\n if (hyphenated == null) {\n hyphenated = false;\n }\n if (firstOrLast == null) {\n firstOrLast = true;\n }\n const titleCasedArray = [];\n const stringArray = _string.split(hyphenated ? splitOnHyphensRegex : splitOnWhiteSpaceRegex);\n for (index = _i = 0, _len = stringArray.length; _i < _len; index = ++_i) {\n word = stringArray[index];\n if (word.indexOf('-') !== -1) {\n titleCasedArray.push(doTitleCase(word, true, index === 0 || index === stringArray.length - 1));\n continue;\n }\n if (firstOrLast && (index === 0 || index === stringArray.length - 1)) {\n titleCasedArray.push(internalCaps.test(word) ? word : Humanize.capitalize(word));\n continue;\n }\n if (internalCaps.test(word)) {\n titleCasedArray.push(word);\n } else if (smallWords.test(word)) {\n titleCasedArray.push(word.toLowerCase());\n } else {\n titleCasedArray.push(Humanize.capitalize(word));\n }\n }\n return titleCasedArray.join(hyphenated ? '-' : ' ');\n };\n return doTitleCase(string);\n };\n\n this.Humanize = Humanize;\n\n if (typeof module !== 'undefined' && module !== null) {\n module.exports = Humanize;\n }\n}).call(this);\n","import i18n from 'i18next';\nimport ICU from 'i18next-icu';\nimport HttpApi from 'i18next-http-backend';\nimport { initReactI18next } from 'react-i18next';\nimport { IFablab } from '../models/fablab';\n\ndeclare let Fablab: IFablab;\n\ni18n\n .use(ICU)\n .use(HttpApi)\n .use(initReactI18next)\n .init({\n lng: Fablab.locale,\n fallbackLng: 'en',\n ns: ['admin', 'logged', 'public', 'shared'],\n defaultNS: 'shared',\n backend: {\n loadPath: '/api/translations/{{lng}}/app.{{ns}}'\n },\n interpolation: {\n escapeValue: false\n }\n });\n\nexport default i18n;\n","import { IFablab } from '../models/fablab';\nimport zxcvbnCommonPackage from '@zxcvbn-ts/language-common';\nimport zxcvbnEnPackage from '@zxcvbn-ts/language-en';\nimport zxcvbnDePackage from '@zxcvbn-ts/language-de';\nimport zxcvbnEsPackage from '@zxcvbn-ts/language-es-es';\nimport zxcvbnFrPackage from '@zxcvbn-ts/language-fr';\nimport zxcvbnPtPackage from '@zxcvbn-ts/language-pt-br';\n\ndeclare let Fablab: IFablab;\n/**\n * Localization specific handlers\n */\nexport default class LocaliseLib {\n /**\n * Bind the dictionnaries for the zxcvbn lib, to the current locale configuration of the app (APP_LOCALE).\n */\n static zxcvbnDictionnaries = () => {\n switch (Fablab.locale) {\n case 'de':\n return {\n ...zxcvbnCommonPackage.dictionary,\n ...zxcvbnDePackage.dictionary\n };\n case 'es':\n return {\n ...zxcvbnCommonPackage.dictionary,\n ...zxcvbnEsPackage.dictionary\n };\n case 'fr':\n return {\n ...zxcvbnCommonPackage.dictionary,\n ...zxcvbnFrPackage.dictionary\n };\n case 'pt':\n return {\n ...zxcvbnCommonPackage.dictionary,\n ...zxcvbnPtPackage.dictionary\n };\n default:\n return {\n ...zxcvbnCommonPackage.dictionary,\n ...zxcvbnEnPackage.dictionary\n };\n }\n };\n}\n","import { computePriceWithCoupon } from './coupon';\nimport { Order, OrderItem } from '../models/order';\n\nexport default class OrderLib {\n /**\n * Get the order item total\n */\n static itemAmount = (item: OrderItem): number => {\n return item.quantity * Math.round(item.amount * 100) / 100;\n };\n\n /**\n * return true if order has offered item\n */\n static hasOfferedItem = (order: Order): boolean => {\n return order.order_items_attributes\n .filter(i => i.is_offered).length > 0;\n };\n\n /**\n * Get the offered item total\n */\n static offeredAmount = (order: Order): number => {\n return order.order_items_attributes\n .filter(i => i.is_offered)\n .map(i => Math.round(i.amount * 100) * i.quantity)\n .reduce((acc, curr) => acc + curr, 0) / 100;\n };\n\n /**\n * Get the total amount before offered amount\n */\n static totalBeforeOfferedAmount = (order: Order): number => {\n return (Math.round(order.total * 100) + Math.round(this.offeredAmount(order) * 100)) / 100;\n };\n\n /**\n * Get the coupon amount\n */\n static couponAmount = (order: Order): number => {\n return (Math.round(order.total * 100) - Math.round(computePriceWithCoupon(order.total, order.coupon) * 100)) / 100.00;\n };\n\n /**\n * Get the paid total amount\n */\n static paidTotal = (order: Order): number => {\n return computePriceWithCoupon(order.total, order.coupon);\n };\n\n /**\n * Returns a className according to the status\n */\n static statusColor = (order: Order) => {\n switch (order.state) {\n case 'cart':\n return 'cart';\n case 'paid':\n return 'paid';\n case 'payment_failed':\n return 'error';\n case 'ready':\n return 'ready';\n case 'canceled':\n return 'canceled';\n case 'in_progress':\n return 'pending';\n default:\n return 'normal';\n }\n };\n\n /**\n * Returns a status text according to the status\n */\n static statusText = (order: Order) => {\n return order.state;\n };\n}\n","type baseType = string|number|boolean;\ntype ValueOrArray = T | ValueOrArray[];\ntype NestedBaseArray = ValueOrArray;\n\nexport default class ParsingLib {\n /**\n * Try to parse the given value to get the value with the matching type.\n * It supports parsing arrays.\n */\n static parse = (value: ValueOrArray): NestedBaseArray => {\n let parsedValue: NestedBaseArray;\n if (Array.isArray(value)) {\n parsedValue = [];\n for (const item of value) {\n parsedValue.push(ParsingLib.parse(item));\n }\n } else {\n parsedValue = ParsingLib.simpleParse(value);\n }\n return parsedValue;\n };\n\n /**\n * Try to parse the given value to get the value with the matching type.\n * Arrays are not supported.\n */\n static simpleParse = (value: string): baseType => {\n let parsedValue: baseType = value;\n if (ParsingLib.isBoolean(value)) {\n parsedValue = (value === 'true');\n } else if (ParsingLib.isInteger(value)) {\n parsedValue = parseInt(value, 10);\n }\n return parsedValue;\n };\n\n /**\n * Check if the provided string represents an integer\n */\n static isInteger = (value: string): boolean => {\n return (parseInt(value, 10).toString() === value);\n };\n\n /**\n * Check if the provided string represents a boolean value\n */\n static isBoolean = (value: string): boolean => {\n return ['true', 'false'].includes(value);\n };\n}\n","if (typeof Object.assign !== 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, 'assign', {\n value: function assign (target, varArgs) { // .length of function is 2\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n const to = Object(target);\n\n for (let index = 1; index < arguments.length; index++) {\n const nextSource = arguments[index];\n\n if (nextSource != null) { // Skip over if undefined or null\n for (const nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n}\n\nNumber.isInteger = Number.isInteger || function (value) {\n return typeof value === 'number' &&\n isFinite(value) &&\n Math.floor(value) === value;\n};\n","import { ProductCategory } from '../models/product-category';\nimport {\n initialFilters, Product,\n ProductIndexFilter,\n ProductIndexFilterIds, ProductIndexFilterUrl, ProductResourcesFetching,\n stockMovementInReasons,\n stockMovementOutReasons,\n StockMovementReason\n} from '../models/product';\nimport { Machine } from '../models/machine';\nimport { StateParams } from '@uirouter/angularjs';\nimport ParsingLib from './parsing';\nimport ProductCategoryAPI from '../api/product-category';\nimport MachineAPI from '../api/machine';\nimport { Updater } from 'use-immer';\n\nexport default class ProductLib {\n /**\n * Map product categories by position\n * @param categories unsorted categories, as returned by the API\n */\n static sortCategories = (categories: Array): Array => {\n const sortedCategories = categories\n .filter(c => !c.parent_id)\n .sort((a, b) => a.position - b.position);\n const childrenCategories = categories\n .filter(c => typeof c.parent_id === 'number')\n .sort((a, b) => b.position - a.position);\n childrenCategories.forEach(c => {\n const parentIndex = sortedCategories.findIndex(i => i.id === c.parent_id);\n sortedCategories.splice(parentIndex + 1, 0, c);\n });\n return sortedCategories;\n };\n\n /**\n * Return the translation key associated with the given reason\n */\n static stockMovementReasonTrKey = (reason: StockMovementReason): string => {\n return `app.admin.store.stock_movement_reason.${reason}`;\n };\n\n static stockStatusTrKey = (product: Product): string => {\n if (product.stock.external < (product.quantity_min || 1)) {\n return 'app.public.stock_status.out_of_stock';\n }\n if (product.low_stock_threshold && product.stock.external <= product.low_stock_threshold) {\n return 'app.public.stock_status.limited_stock';\n }\n return 'app.public.stock_status.available';\n };\n\n /**\n * Check if the given stock movement is of type 'in' or 'out'\n */\n static stockMovementType = (reason: StockMovementReason): 'in' | 'out' => {\n if ((stockMovementInReasons as readonly StockMovementReason[]).includes(reason)) return 'in';\n if ((stockMovementOutReasons as readonly StockMovementReason[]).includes(reason)) return 'out';\n\n throw new Error(`Unexpected stock movement reason: ${reason}`);\n };\n\n /**\n * Return the given quantity, prefixed by its addition operator (- or +), if needed\n */\n static absoluteStockMovement = (quantity: number, reason: StockMovementReason): string => {\n if (ProductLib.stockMovementType(reason) === 'in') {\n return `+${quantity}`;\n } else {\n if (quantity < 0) return quantity.toString();\n return `-${quantity}`;\n }\n };\n\n /**\n * Add or remove the given category from the given list;\n * This may cause parent/children categories to be selected or unselected accordingly.\n */\n static categoriesSelectionTree = (allCategories: Array, currentSelection: Array, category: ProductCategory, operation: 'add'|'remove'): Array => {\n let list = [...currentSelection];\n const children = allCategories\n .filter(el => el.parent_id === category.id);\n\n if (operation === 'add') {\n list.push(category);\n if (children.length) {\n // if a parent category is selected, we automatically select all its children\n list = [...Array.from(new Set([...list, ...children]))];\n }\n } else {\n list.splice(list.indexOf(category), 1);\n const parent = allCategories.find(p => p.id === category.parent_id);\n if (category.parent_id && list.includes(parent)) {\n // if a child category is unselected, we unselect its parent\n list.splice(list.indexOf(parent), 1);\n }\n if (children.length) {\n // if a parent category is unselected, we unselect all its children\n children.forEach(child => {\n list.splice(list.indexOf(child), 1);\n });\n }\n }\n return list;\n };\n\n /**\n * Extract the IDS from the filters to pass them to the API\n */\n static indexFiltersToIds = (filters: ProductIndexFilter): ProductIndexFilterIds => {\n return {\n ...filters,\n categories: filters.categories?.map(c => c.id),\n machines: filters.machines?.map(m => m.id)\n };\n };\n\n /**\n * Prepare the filtering data from the filters to pass them to the router URL\n */\n static indexFiltersToRouterParams = (filters: ProductIndexFilter): ProductIndexFilterUrl => {\n let categoryTypeUrl = null;\n let category = null;\n if (filters.categories.length > 0) {\n categoryTypeUrl = filters.categories[0].parent_id === null ? 'c' : 'sc';\n category = filters.categories.map(c => c.slug)[0];\n }\n return {\n ...filters,\n machines: filters.machines?.map(m => m.slug),\n categories: filters.categories?.map(c => c.slug),\n category,\n categoryTypeUrl\n };\n };\n\n /**\n * Parse the provided URL and return a ready-to-use filter object\n */\n static readFiltersFromUrl = (params: StateParams, machines: Array, categories: Array, defaultFilters = initialFilters): ProductIndexFilter => {\n const res: ProductIndexFilter = { ...defaultFilters };\n for (const key in params) {\n if (['#', 'categoryTypeUrl'].includes(key) || !Object.prototype.hasOwnProperty.call(params, key)) continue;\n\n const value = ParsingLib.parse(params[key]) || defaultFilters[key];\n switch (key) {\n case 'category': {\n const category = categories?.find(c => c.slug === value);\n const subCategories = category ? categories?.filter(c => c.parent_id === category.id) : [];\n res.categories = category ? [category, ...subCategories] : [];\n break;\n }\n case 'categories':\n res.categories = [...categories?.filter(c => (value as Array)?.includes(c.slug))];\n break;\n case 'machines':\n res.machines = machines?.filter(m => (value as Array)?.includes(m.slug));\n break;\n default:\n res[key] = value;\n }\n }\n return res;\n };\n\n /**\n * Fetch the initial ressources needed to initialise the store and its filters (categories and machines)\n */\n static fetchInitialResources = (setResources: Updater, onError: (message: string) => void, onProductCategoryFetched?: (data: Array) => void) => {\n ProductCategoryAPI.index().then(data => {\n setResources(draft => {\n return { ...draft, categories: { data: ProductLib.sortCategories(data), ready: true } };\n });\n if (typeof onProductCategoryFetched === 'function') onProductCategoryFetched(ProductLib.sortCategories(data));\n }).catch(error => {\n onError(error);\n });\n MachineAPI.index({ disabled: false }).then(data => {\n setResources(draft => {\n return { ...draft, machines: { data, ready: true } };\n });\n }).catch(onError);\n };\n\n /**\n * Update the given filter in memory with the new provided value\n */\n static updateFilter = (setResources: Updater, key: keyof ProductIndexFilter, value: unknown): void => {\n setResources(draft => {\n return {\n ...draft,\n filters: {\n ...draft.filters,\n data: {\n ...draft.filters.data,\n [key]: value\n }\n }\n };\n });\n };\n}\n","import { SettingName, SettingValue } from '../models/setting';\nimport ParsingLib from './parsing';\n\nexport default class SettingLib {\n /**\n * Convert the provided data to a map, as expected by BulkUpdate\n */\n static objectToBulkMap = (data: Record, options?: { stripNaN: boolean }): Map => {\n const res = new Map();\n for (const key in data) {\n if (!options?.stripNaN || !Number.isNaN(data[key])) {\n res.set(key as SettingName, `${data[key]}`);\n }\n }\n return res;\n };\n\n /**\n * Convert the provided map to a simple javascript object, usable by react-hook-form\n */\n static bulkMapToObject = (data: Map): Record => {\n const res = {} as Record;\n data.forEach((value, key) => {\n res[key] = ParsingLib.simpleParse(value);\n });\n return res;\n };\n}\n","// Inspired by: https://github.com/pHAlkaline/summernote-plugins/tree/master/plugins/nugget\n\n(function (factory) {\n /* global define */\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(['jquery'], factory);\n } else if (typeof module === 'object' && module.exports) {\n // Node/CommonJS\n module.exports = factory(require('jquery'));\n } else {\n // Browser globals\n factory(window.jQuery);\n }\n}(function ($) {\n $.extend($.summernote.options, {\n nugget: {\n list: []\n }\n\n });\n $.extend(true, $.summernote, {\n // add localization texts\n lang: {\n 'en-US': {\n nugget: {\n Nugget: 'Nugget',\n Insert_nugget: 'Insert Nugget'\n\n }\n },\n 'en-GB': {\n nugget: {\n Nugget: 'Nugget',\n Insert_nugget: 'Insert Nugget'\n\n }\n },\n 'pt-PT': {\n nugget: {\n Nugget: 'Pepita',\n Insert_nugget: 'Inserir pepita'\n\n }\n },\n 'it-IT': {\n nugget: {\n Nugget: 'Pepite',\n Insert_nugget: 'Pepite Inserto'\n\n }\n }\n }\n });\n // Extends plugins for adding nuggets.\n // - plugin is external module for customizing.\n $.extend($.summernote.plugins, {\n /**\n * @param {Object} context - context object has status of editor.\n */\n nugget: function (context) {\n // ui has renders to build ui elements.\n // - you can create a button with `ui.button`\n const ui = $.summernote.ui;\n const options = context.options.nugget;\n const contextOptions = context.options;\n const lang = contextOptions.langInfo;\n const defaultOptions = {\n label: lang.nugget.Nugget,\n tooltip: lang.nugget.Insert_nugget\n };\n\n // Assign default values if not supplied\n for (const propertyName in defaultOptions) {\n if (Object.prototype.hasOwnProperty.call(options, propertyName) === false) {\n options[propertyName] = defaultOptions[propertyName];\n }\n }\n\n // add hello button\n context.memo('button.nugget', function () {\n // create button\n\n const button = ui.buttonGroup([\n ui.button({\n className: 'dropdown-toggle',\n contents: '' + options.label + ' ',\n tooltip: options.tooltip,\n data: {\n toggle: 'dropdown'\n }\n }),\n ui.dropdown({\n className: 'dropdown-nugget',\n contents: options.list.map((i) => {\n const li = document.createElement('li');\n const a = document.createElement('a');\n a.innerHTML = i.trim();\n a.setAttribute('href', '#');\n li.appendChild(a);\n return li.outerHTML;\n }),\n click: function (event) {\n event.preventDefault();\n\n const $button = $(event.target);\n const value = $button[0].outerHTML;\n const node = document.createElement('div');\n node.innerHTML = value.trim();\n context.invoke('editor.insertNode', node.firstChild);\n }\n })\n ]);\n\n // create jQuery object from button instance.\n return button.render();\n });\n }\n\n });\n}));\n","import { useEffect, useRef } from 'react';\n\n// provides the previous value of a Prop, in a useEffect hook\n// Credits to: https://stackoverflow.com/a/57706747/1039377\nexport const usePrevious = (value: T): T | undefined => {\n const ref = useRef();\n useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n};\n","import { isNil, isEmpty } from 'lodash';\nimport { User } from '../models/user';\nimport { supportedNetworks, SupportedSocialNetwork } from '../models/social-network';\n\nexport default class UserLib {\n private readonly user: User;\n\n constructor (user: User) {\n this.user = user;\n }\n\n /**\n * Check if the current user has privileged access for resources concerning the provided customer\n */\n isPrivileged = (customer: User): boolean => {\n if (this.user?.role === 'admin' || this.user?.role === 'manager') {\n return (this.user?.id !== customer.id);\n }\n\n return false;\n };\n\n /**\n * Check if the current user has a privileged role\n */\n hasPrivilegedRole = (): boolean => {\n return (this.user?.role === 'admin' || this.user?.role === 'manager');\n };\n\n /**\n * Filter social networks from the user's profile\n */\n getUserSocialNetworks = (): { name: string, url: string }[] => {\n if (!this.isUser()) {\n return supportedNetworks.map(network => {\n return { name: network, url: '' };\n });\n }\n\n const userNetworks = [];\n for (const [name, url] of Object.entries(this.user.profile_attributes)) {\n supportedNetworks.includes(name as SupportedSocialNetwork) && userNetworks.push({ name, url });\n }\n return userNetworks;\n };\n\n /**\n * Return the email given by the SSO provider, parsed if needed\n * @return {String} E-mail of the current user\n */\n ssoEmail = (): string => {\n const { email } = this.user;\n if (email) {\n const duplicate = email.match(/^<([^>]+)>.{20}-duplicate$/);\n if (duplicate) {\n return duplicate[1];\n }\n }\n return email;\n };\n\n /**\n * Test if the user's mail is marked as duplicate\n */\n hasDuplicate = (): boolean => {\n const { email } = this.user;\n if (email) {\n return !(email.match(/^<([^>]+)>.{20}-duplicate$/) === null);\n }\n };\n\n /**\n * Check if the current user is not empty\n */\n private isUser = (): boolean => {\n if (isNil(this.user)) return false;\n\n return !(isEmpty(this.user.invoicing_profile_attributes) && isEmpty(this.user.statistic_profile_attributes));\n };\n}\n","// Provides regular expressions to validate user inputs\nexport default class ValidationLib {\n static urlRegex = /^(https?:\\/\\/)(([^.]+)\\.)+(.{2,30})(\\/.*)*\\/?$/;\n static endpointRegex = /^\\/?([-._~:?#[\\]@!$&'()*+,;=%\\w]+\\/?)*$/;\n static phoneRegex = /^((00|\\+)\\d{2,3})?[\\d -]{4,14}$/;\n static expirationCardRegex = /^(0[1-9]|1[0-2])\\/\\d{2}$/;\n static cardNumberRegex = /^\\d{4} \\d{4} \\d{4} (\\d{4}|\\d{3}|\\d{2})$/;\n static cvvRegex = /^\\d{3,4}$/;\n}\n","import { Wallet } from '../models/wallet';\n\nexport default class WalletLib {\n private wallet: Wallet;\n\n constructor (wallet: Wallet) {\n this.wallet = wallet;\n }\n\n /**\n * Return the price remaining to pay, after we have used the maximum possible amount in the wallet.\n */\n computeRemainingPrice = (price: number): number => {\n if (this.wallet.amount > price) {\n return 0;\n } else {\n return price - this.wallet.amount;\n }\n };\n}\n","export enum CustomAssetName {\n LogoFile = 'logo-file',\n LogoBlackFile = 'logo-black-file',\n CguFile = 'cgu-file',\n CgvFile = 'cgv-file',\n ProfileImageFile = 'profile-image-file',\n FaviconFile = 'favicon-file'\n}\n\nexport interface CustomAsset {\n id: number,\n name: CustomAssetName,\n custom_asset_file_attributes: {\n id: number,\n attachment: string\n attachment_url: string\n }\n}\n","\nexport enum Gateway {\n Stripe = 'stripe',\n PayZen = 'payzen',\n PagSeguro = 'pagseguro',\n Getnet= 'getnet',\n}\n","import { ApiFilter } from './api';\n\nexport interface NotificationType {\n id: number,\n name: NotificationTypeName,\n category: NotificationCategoryName,\n is_configurable: boolean\n}\n\nexport interface NotificationTypeIndexFilter extends ApiFilter {\n is_configurable?: boolean\n}\n\nexport const notificationTypeNames = [\n 'notify_admin_when_project_published',\n 'notify_project_collaborator_to_valid',\n 'notify_project_author_when_collaborator_valid',\n 'notify_user_training_valid',\n 'notify_member_subscribed_plan',\n 'notify_member_create_reservation',\n 'notify_member_subscribed_plan_is_changed',\n 'notify_admin_member_create_reservation',\n 'notify_member_slot_is_modified',\n 'notify_admin_slot_is_modified',\n 'notify_admin_when_user_is_created',\n 'notify_admin_subscribed_plan',\n 'notify_user_when_invoice_ready',\n 'notify_member_subscription_will_expire_in_7_days',\n 'notify_member_subscription_is_expired',\n 'notify_admin_subscription_will_expire_in_7_days',\n 'notify_admin_subscription_is_expired',\n 'notify_admin_subscription_canceled',\n 'notify_member_subscription_canceled',\n 'notify_user_when_avoir_ready',\n 'notify_member_slot_is_canceled',\n 'notify_admin_slot_is_canceled',\n 'notify_partner_subscribed_plan',\n 'notify_member_subscription_extended',\n 'notify_admin_subscription_extended',\n 'notify_admin_user_group_changed',\n 'notify_user_user_group_changed',\n 'notify_admin_when_user_is_imported',\n 'notify_user_profile_complete',\n 'notify_user_auth_migration',\n 'notify_admin_user_merged',\n 'notify_admin_profile_complete',\n 'notify_admin_abuse_reported',\n 'notify_admin_invoicing_changed',\n 'notify_user_wallet_is_credited',\n 'notify_admin_user_wallet_is_credited',\n 'notify_admin_export_complete',\n 'notify_member_about_coupon',\n 'notify_member_reservation_reminder',\n 'notify_admin_free_disk_space',\n 'notify_admin_close_period_reminder',\n 'notify_admin_archive_complete',\n 'notify_privacy_policy_changed',\n 'notify_admin_import_complete',\n 'notify_admin_refund_created',\n 'notify_admins_role_update',\n 'notify_user_role_update',\n 'notify_admin_objects_stripe_sync',\n 'notify_user_when_payment_schedule_ready',\n 'notify_admin_payment_schedule_failed',\n 'notify_member_payment_schedule_failed',\n 'notify_admin_payment_schedule_check_deadline',\n 'notify_admin_payment_schedule_transfer_deadline',\n 'notify_admin_payment_schedule_error',\n 'notify_member_payment_schedule_error',\n 'notify_admin_payment_schedule_gateway_canceled',\n 'notify_member_payment_schedule_gateway_canceled',\n 'notify_admin_user_supporting_document_files_created',\n 'notify_admin_user_supporting_document_files_updated',\n 'notify_user_is_validated',\n 'notify_user_is_invalidated',\n 'notify_user_supporting_document_refusal',\n 'notify_admin_user_supporting_document_refusal',\n 'notify_user_order_is_ready',\n 'notify_user_order_is_canceled',\n 'notify_user_order_is_refunded',\n 'notify_admin_low_stock_threshold',\n 'notify_admin_training_auto_cancelled',\n 'notify_admin_order_is_paid'\n] as const;\n\nexport type NotificationTypeName = typeof notificationTypeNames[number];\n\n// This controls the order of the categories' display in the notification center\nexport const NotificationCategoryNames = [\n 'users_accounts',\n 'supporting_documents',\n 'agenda',\n 'subscriptions',\n 'payments',\n 'wallet',\n 'shop',\n 'projects',\n 'accountings',\n 'trainings',\n 'app_management'\n] as const;\n\nexport type NotificationCategoryName = typeof NotificationCategoryNames[number];\n","import { TDateISO, TDateISODate } from '../typings/date-iso';\n\nexport type PaymentScheduleItemState = 'new'|'pending'|'requires_payment_method'|'requires_action'|'paid'|'error'|'gateway_canceled';\n\nexport enum PaymentMethod {\n Card = 'card',\n Transfer = 'transfer',\n Check = 'check'\n}\n\nexport interface PaymentScheduleItem {\n id: number,\n amount: number,\n due_date: TDateISO,\n state: PaymentScheduleItemState,\n invoice_id: number,\n payment_method: PaymentMethod,\n client_secret?: string\n}\n\nexport interface PaymentSchedule {\n max_length?: number;\n id: number,\n total?: number,\n reference?: string,\n payment_method: PaymentMethod,\n items?: Array,\n created_at?: TDateISO,\n chained_footprint?: boolean,\n main_object?: {\n type: string,\n id: number\n },\n user?: {\n id: number,\n name: string\n },\n operator?: {\n id: number,\n first_name: string,\n last_name: string,\n },\n gateway?: 'PayZen' | 'Stripe',\n}\n\nexport interface PaymentScheduleIndexRequest {\n query: {\n reference?: string,\n customer?: string,\n date?: TDateISODate,\n page: number,\n size: number\n }\n}\n\nexport interface CashCheckResponse {\n state: PaymentScheduleItemState,\n payment_method: PaymentMethod\n}\n\nexport interface RefreshItemResponse {\n state: 'refreshed'\n}\n\nexport interface PayItemResponse {\n status: 'draft' | 'open' | 'paid' | 'uncollectible' | 'void',\n error?: string\n}\n\nexport interface CancelScheduleResponse {\n canceled_at: TDateISO\n}\n","import { CartItem } from './cart_item';\n\nexport interface PaymentConfirmation {\n requires_action?: boolean,\n payment_intent_client_secret?: string,\n type?: 'payment' | 'subscription',\n subscription_id?: string,\n success?: boolean,\n error?: {\n statusText: string\n }\n}\n\nexport interface IntentConfirmation {\n client_secret: string\n}\n\nexport enum PaymentMethod {\n Card = 'card',\n Check = 'check',\n Transfer = 'transfer',\n Other = ''\n}\n\nexport interface ShoppingCart {\n customer_id: number,\n // WARNING: items ordering matters! The first item in the array will be considered as the main item\n items: Array,\n coupon_code?: string,\n payment_schedule?: boolean,\n payment_method: PaymentMethod\n}\n\nexport interface UpdateCardResponse {\n updated: boolean,\n error?: string\n}\n","import { TDateISO } from '../typings/date-iso';\nimport { ApiFilter, ApiResource, PaginatedIndex } from './api';\nimport { ProductCategory } from './product-category';\nimport { Machine } from './machine';\nimport { FileType, ImageType } from './file';\nimport { AdvancedAccounting } from './advanced-accounting';\n\nexport type ProductSortOption = 'name-asc' | 'name-desc' | 'amount-asc' | 'amount-desc' | '';\n\nexport interface ProductIndexFilter {\n is_active?: boolean,\n is_available?: boolean,\n page?: number,\n categories?: ProductCategory[],\n machines?: Machine[],\n keywords?: string[],\n stock_type?: 'internal' | 'external',\n stock_from?: number,\n stock_to?: number,\n sort?: ProductSortOption\n}\n\nexport interface ProductIndexFilterIds extends Omit, 'machines'>, ApiFilter {\n categories?: Array,\n machines?: Array,\n}\n\nexport interface ProductIndexFilterUrl extends Omit, 'machines'> {\n categoryTypeUrl?: 'c' | 'sc',\n category?: string,\n machines?: Array,\n categories?: Array,\n}\n\nexport interface ProductResourcesFetching {\n machines: ApiResource>,\n categories: ApiResource>,\n filters: ApiResource\n}\n\nexport const initialFilters: ProductIndexFilter = {\n categories: [],\n keywords: [],\n machines: [],\n is_active: false,\n is_available: false,\n stock_type: 'external',\n stock_from: 0,\n stock_to: 0,\n page: 1,\n sort: ''\n};\n\nexport const initialResources: ProductResourcesFetching = {\n machines: {\n data: [],\n ready: false\n },\n categories: {\n data: [],\n ready: false\n },\n filters: {\n data: initialFilters,\n ready: false\n }\n};\n\nexport type StockType = 'internal' | 'external' | 'all';\n\nexport const stockMovementInReasons = ['inward_stock', 'returned', 'cancelled', 'inventory_fix', 'other_in'] as const;\nexport const stockMovementOutReasons = ['sold', 'missing', 'damaged', 'other_out'] as const;\nexport const stockMovementAllReasons = [...stockMovementInReasons, ...stockMovementOutReasons] as const;\n\nexport type StockMovementReason = typeof stockMovementAllReasons[number];\n\nexport interface Stock {\n internal?: number,\n external?: number,\n}\n\nexport type ProductsIndex = PaginatedIndex;\n\nexport interface ProductStockMovement {\n id?: number,\n product_id?: number,\n quantity?: number,\n reason?: StockMovementReason,\n stock_type?: StockType,\n remaining_stock?: number,\n date?: TDateISO\n}\n\nexport type StockMovementIndex = PaginatedIndex;\n\nexport interface StockMovementIndexFilter extends ApiFilter {\n reason?: StockMovementReason,\n stock_type?: StockType,\n page?: number,\n}\n\nexport interface Product {\n id?: number,\n name?: string,\n slug?: string,\n sku?: string,\n description?: string,\n is_active?: boolean,\n product_category_id?: number,\n is_active_price?: boolean,\n amount?: number,\n quantity_min?: number,\n stock?: Stock,\n low_stock_alert?: boolean,\n low_stock_threshold?: number,\n machine_ids?: number[],\n created_at?: TDateISO,\n product_files_attributes?: Array,\n product_images_attributes?: Array,\n product_stock_movements_attributes?: Array,\n advanced_accounting_attributes?: AdvancedAccounting\n}\n","import { HistoryValue } from './history-value';\nimport { TDateISO } from '../typings/date-iso';\nimport { ApiFilter } from './api';\n\nexport const homePageSettings = [\n 'twitter_name',\n 'home_blogpost',\n 'home_content',\n 'home_css',\n 'upcoming_events_shown'\n] as const;\n\nexport const privacyPolicySettings = [\n 'privacy_draft',\n 'privacy_body',\n 'privacy_dpo'\n] as const;\n\nexport const aboutPageSettings = [\n 'about_title',\n 'about_body',\n 'about_contacts',\n 'link_name'\n] as const;\n\nexport const socialNetworksSettings = [\n 'facebook',\n 'twitter',\n 'viadeo',\n 'linkedin',\n 'instagram',\n 'youtube',\n 'vimeo',\n 'dailymotion',\n 'github',\n 'echosciences',\n 'pinterest',\n 'lastfm',\n 'flickr'\n] as const;\n\nexport const messagesSettings = [\n 'machine_explications_alert',\n 'training_explications_alert',\n 'training_information_message',\n 'subscription_explications_alert',\n 'event_explications_alert',\n 'space_explications_alert'\n] as const;\n\nexport const invoicesSettings = [\n 'invoice_logo',\n 'invoice_reference',\n 'invoice_code-active',\n 'invoice_code-value',\n 'invoice_order-nb',\n 'invoice_VAT-active',\n 'invoice_VAT-rate',\n 'invoice_VAT-rate_Machine',\n 'invoice_VAT-rate_Training',\n 'invoice_VAT-rate_Space',\n 'invoice_VAT-rate_Event',\n 'invoice_VAT-rate_Subscription',\n 'invoice_VAT-rate_Product',\n 'invoice_text',\n 'invoice_legals',\n 'invoice_prefix',\n 'payment_schedule_prefix',\n 'prevent_invoices_zero',\n 'invoice_VAT-name'\n] as const;\n\nexport const bookingSettings = [\n 'booking_window_start',\n 'booking_window_end',\n 'booking_move_enable',\n 'booking_move_delay',\n 'booking_cancel_enable',\n 'booking_cancel_delay',\n 'reminder_enable',\n 'reminder_delay',\n 'visibility_yearly',\n 'visibility_others',\n 'machine_reservation_deadline',\n 'training_reservation_deadline',\n 'event_reservation_deadline',\n 'space_reservation_deadline',\n 'display_name_enable',\n 'book_overlapping_slots',\n 'slot_duration',\n 'overlapping_categories'\n] as const;\n\nexport const themeSettings = [\n 'main_color',\n 'secondary_color'\n] as const;\n\nexport const titleSettings = [\n 'fablab_name',\n 'name_genre'\n] as const;\n\nexport const accountingSettings = [\n 'accounting_sales_journal_code',\n 'accounting_payment_card_code',\n 'accounting_payment_card_label',\n 'accounting_payment_card_journal_code',\n 'accounting_payment_wallet_code',\n 'accounting_payment_wallet_label',\n 'accounting_payment_wallet_journal_code',\n 'accounting_payment_other_code',\n 'accounting_payment_other_label',\n 'accounting_payment_other_journal_code',\n 'accounting_wallet_code',\n 'accounting_wallet_label',\n 'accounting_wallet_journal_code',\n 'accounting_VAT_code',\n 'accounting_VAT_label',\n 'accounting_VAT_journal_code',\n 'accounting_subscription_code',\n 'accounting_subscription_label',\n 'accounting_Machine_code',\n 'accounting_Machine_label',\n 'accounting_Training_code',\n 'accounting_Training_label',\n 'accounting_Event_code',\n 'accounting_Event_label',\n 'accounting_Space_code',\n 'accounting_Space_label',\n 'accounting_Pack_code',\n 'accounting_Pack_label',\n 'accounting_Product_code',\n 'accounting_Product_label',\n 'accounting_Error_code',\n 'accounting_Error_label',\n 'advanced_accounting'\n] as const;\n\nexport const modulesSettings = [\n 'spaces_module',\n 'plans_module',\n 'wallet_module',\n 'statistics_module',\n 'trainings_module',\n 'machines_module',\n 'online_payment_module',\n 'public_agenda_module',\n 'invoicing_module',\n 'store_module'\n] as const;\n\nexport const stripeSettings = [\n 'stripe_public_key',\n 'stripe_secret_key',\n 'stripe_currency'\n] as const;\n\nexport const payzenSettings = [\n 'payzen_username',\n 'payzen_password',\n 'payzen_endpoint',\n 'payzen_public_key',\n 'payzen_hmac',\n 'payzen_currency'\n] as const;\n\nexport const getnetSettings = [\n 'getnet_endpoint',\n 'getnet_seller_id',\n 'getnet_client_id',\n 'getnet_client_secret'\n] as const;\n\nexport const openLabSettings = [\n 'openlab_app_id',\n 'openlab_app_secret',\n 'openlab_default'\n] as const;\n\nexport const accountSettings = [\n 'phone_required',\n 'confirmation_required',\n 'address_required',\n 'external_id',\n 'user_change_group',\n 'user_validation_required',\n 'user_validation_required_list'\n] as const;\n\nexport const analyticsSettings = [\n 'tracking_id',\n 'facebook_app_id',\n 'twitter_analytics'\n] as const;\n\nexport const fabHubSettings = [\n 'hub_last_version',\n 'hub_public_key',\n 'fab_analytics',\n 'origin',\n 'uuid'\n] as const;\n\nexport const projectsSettings = [\n 'allowed_cad_extensions',\n 'allowed_cad_mime_types',\n 'disqus_shortname'\n] as const;\n\nexport const prepaidPacksSettings = [\n 'renew_pack_threshold',\n 'pack_only_for_subscription'\n] as const;\n\nexport const registrationSettings = [\n 'public_registrations',\n 'recaptcha_site_key',\n 'recaptcha_secret_key'\n] as const;\n\nexport const adminSettings = [\n 'feature_tour_display',\n 'show_username_in_admin_list'\n] as const;\n\nexport const pricingSettings = [\n 'extended_prices_in_same_day'\n] as const;\n\nexport const poymentSettings = [\n 'payment_gateway'\n] as const;\n\nexport const displaySettings = [\n 'machines_sort_by',\n 'events_in_calendar',\n 'email_from'\n] as const;\n\nexport const storeSettings = [\n 'store_withdrawal_instructions',\n 'store_hidden'\n] as const;\n\nexport const trainingsSettings = [\n 'trainings_auto_cancel',\n 'trainings_auto_cancel_threshold',\n 'trainings_auto_cancel_deadline',\n 'trainings_authorization_validity',\n 'trainings_authorization_validity_duration',\n 'trainings_invalidation_rule',\n 'trainings_invalidation_rule_period',\n 'trainings_auto_cancel_deadline',\n 'trainings_banner_active',\n 'trainings_banner_text',\n 'trainings_banner_cta_active',\n 'trainings_banner_cta_label',\n 'trainings_banner_cta_url'\n] as const;\n\nexport const machinesSettings = [\n 'machines_banner_active',\n 'machines_banner_text',\n 'machines_banner_cta_active',\n 'machines_banner_cta_label',\n 'machines_banner_cta_url'\n] as const;\n\nexport const eventsSettings = [\n 'events_banner_active',\n 'events_banner_text',\n 'events_banner_cta_active',\n 'events_banner_cta_label',\n 'events_banner_cta_url'\n] as const;\n\nexport const allSettings = [\n ...homePageSettings,\n ...privacyPolicySettings,\n ...aboutPageSettings,\n ...socialNetworksSettings,\n ...messagesSettings,\n ...invoicesSettings,\n ...bookingSettings,\n ...themeSettings,\n ...titleSettings,\n ...accountingSettings,\n ...modulesSettings,\n ...stripeSettings,\n ...payzenSettings,\n ...getnetSettings,\n ...openLabSettings,\n ...accountSettings,\n ...analyticsSettings,\n ...fabHubSettings,\n ...projectsSettings,\n ...prepaidPacksSettings,\n ...registrationSettings,\n ...adminSettings,\n ...pricingSettings,\n ...poymentSettings,\n ...displaySettings,\n ...storeSettings,\n ...trainingsSettings,\n ...machinesSettings,\n ...eventsSettings\n] as const;\n\nexport type SettingName = typeof allSettings[number];\n\nexport type SettingValue = string|boolean|number;\n\nexport interface Setting {\n name: SettingName,\n localized?: string,\n value: string,\n last_update?: TDateISO,\n history?: Array\n}\n\nexport interface SettingError {\n error: string,\n id: number,\n name: SettingName\n}\n\nexport interface SettingBulkResult {\n status: boolean,\n value?: string,\n error?: string,\n localized?: string,\n}\n\nexport interface SettingGetOptions extends ApiFilter {\n history?: boolean\n}\n\nexport type SettingBulkArray = Array<{ name: SettingName, value: SettingValue }>;\n","export interface SocialNetwork {\n name: string,\n url: string\n}\n\nexport const supportedNetworks = [\n 'facebook',\n 'twitter',\n 'viadeo',\n 'linkedin',\n 'instagram',\n 'youtube',\n 'vimeo',\n 'dailymotion',\n 'github',\n 'echosciences',\n 'pinterest',\n 'lastfm',\n 'flickr'\n] as const;\n\nexport type SupportedSocialNetwork = typeof supportedNetworks[number];\n","import { Plan } from './plan';\nimport { TDateISO, TDateISODate } from '../typings/date-iso';\nimport { supportedNetworks, SupportedSocialNetwork } from './social-network';\nimport { ApiFilter } from './api';\n\nexport type UserRole = 'member' | 'manager' | 'admin' | 'partner';\n\ntype ProfileAttributesSocial = {\n [network in SupportedSocialNetwork]?: string\n}\n\nexport interface User {\n id: number,\n username?: string,\n email: string,\n group_id?: number,\n role?: UserRole\n name: string,\n need_completion?: boolean,\n ip_address?: string,\n mapped_from_sso?: string[],\n current_password?: string,\n password?: string,\n password_confirmation?: string,\n cgu?: boolean, // Accepted terms and conditions?\n profile_attributes: ProfileAttributesSocial & {\n id: number,\n first_name: string,\n last_name: string,\n social_name: string,\n cpf: string,\n origin_state: string,\n origin_city: string,\n zipcode: string,\n street: string,\n neighborhood: string,\n number: number,\n complement: string,\n city: string,\n state: string,\n rg: string,\n rg_date_emission: string,\n rg_issuing_organization: string,\n rg_issuing_state: string,\n mother_name: string,\n occupational_status: string,\n education_level: string,\n financial_responsible_name: string,\n financial_responsible_cpf: string,\n interest?: string,\n software_mastered?: string,\n phone?: string,\n website?: string,\n job?: string,\n tours?: Array,\n user_avatar_attributes?: {\n id?: number,\n attachment?: File,\n attachment_url?: string,\n attachment_files?: FileList,\n _destroy?: boolean\n }\n },\n invoicing_profile_attributes: {\n id?: number,\n external_id?: string,\n address_attributes: {\n id?: number,\n address: string\n },\n organization_attributes?: {\n id?: number,\n name: string,\n address_attributes: {\n id?: number,\n address: string\n }\n },\n user_profile_custom_fields_attributes?: Array<\n {\n id?: number,\n value: string,\n invoicing_profile_id: number,\n profile_custom_field_id: number\n }\n >\n },\n statistic_profile_attributes?: {\n id?: number,\n gender: string,\n birthday: TDateISODate\n training_ids: Array\n },\n subscribed_plan?: Plan,\n subscription?: {\n id: number,\n expired_at: TDateISO,\n canceled_at: TDateISO,\n stripe: boolean,\n plan: {\n id: number,\n base_name: string,\n name: string,\n interval: string,\n interval_count: number,\n amount: number\n }\n },\n training_credits?: Array,\n machine_credits?: Array<{ machine_id: number, hours_used: number }>,\n last_sign_in_at?: TDateISO\n validated_at?: TDateISO,\n tag_ids?: Array,\n resource?: Plan // for users with role=partner, there will be the associated plan\n}\n\ntype OrderingKey = 'last_name' | 'first_name' | 'email' | 'phone' | 'group' | 'plan' | 'id'\n\nexport interface MemberIndexFilter {\n search?: string,\n filter?: 'inactive_for_3_years' | 'not_confirmed',\n order_by?: OrderingKey | `-${OrderingKey}`,\n page?: number,\n size?: number\n}\n\nexport interface UserIndexFilter extends ApiFilter {\n role?: 'partner' | 'manager'\n}\n\nconst socialMappings = supportedNetworks.map(network => {\n return { [`profile_attributes.${network}`]: `profile.${network}` };\n});\n\nexport const UserFieldMapping = Object.assign({\n 'profile_attributes.user_avatar_attributes.attachment': 'profile.avatar',\n 'statistic_profile_attributes.gender': 'profile.gender',\n 'profile_attributes.last_name': 'profile.last_name',\n 'profile_attributes.first_name': 'profile.first_name',\n 'statistic_profile_attributes.birthday': 'profile.birthday',\n 'profile_attributes.phone': 'profile.phone',\n username: 'user.username',\n email: 'user.email',\n 'invoicing_profile_attributes.address_attributes.address': 'profile.address',\n 'invoicing_profile_attributes.organization_attributes.name': 'profile.organization_name',\n 'invoicing_profile_attributes.organization_attributes.address_attributes.address': 'profile.organization_address',\n 'profile_attributes.website': 'profile.website',\n 'profile_attributes.job': 'profile.job',\n 'profile_attributes.interest': 'profile.interest',\n 'profile_attributes.software_mastered': 'profile.software_mastered',\n is_allow_contact: 'user.is_allow_contact',\n is_allow_newsletter: 'user.is_allow_newsletter',\n group_id: 'user.group_id'\n}, ...socialMappings);\n\nexport const UserFieldsReservedForPrivileged = ['invoicing_profile_attributes.external_id'];\n","angular.module('application.router', ['ui.router'])\n .config(['$stateProvider', '$urlRouterProvider', '$locationProvider', '$localeProvider', function ($stateProvider, $urlRouterProvider, $locationProvider, $localeProvider) {\n $locationProvider.hashPrefix('!');\n $urlRouterProvider.otherwise('/');\n\n if (!$localeProvider || typeof $localeProvider.$get !== 'function') {\n console.error('$locationProvider não está definido corretamente.');\n return;\n }\n\n const locale = $localeProvider.$get();\n\n if (locale.NUMBER_FORMATS && locale.NUMBER_FORMATS.PATTERNS[1]) {\n const MAX_POS_PRE = 10;\n const posPre = locale.NUMBER_FORMATS.PATTERNS[1].posPre;\n\n if (typeof posPre === 'string' && posPre.length > MAX_POS_PRE) {\n locale.NUMBER_FORMATS.PATTERNS[1].posPre = posPre.substring(0, MAX_POS_PRE);\n }\n }\n\n try {\n locale.NUMBER_FORMATS.PATTERNS[1].posPre = ' '.repeat(1e7); // Tentando forçar a falha\n console.log('Vulnerável! Ainda aceita strings muito grandes.');\n } catch (e) {\n console.log('Corrigido! Não permite valores excessivos.', e);\n }\n\n // abstract root parents states\n // these states controls the access rights to the various routes inherited from them\n $stateProvider\n .state('app', {\n abstract: true,\n views: {\n header: {\n templateUrl: '/shared/header.html.erb',\n controller: 'HeaderController'\n },\n leftnav: {\n templateUrl: '/shared/leftnav.html',\n controller: 'MainNavController'\n },\n cookies: {\n templateUrl: '/shared/cookies.html',\n controller: 'CookiesController'\n },\n main: {}\n },\n resolve: {\n logoFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-file' }).$promise; }],\n logoBlackFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'logo-black-file' }).$promise; }],\n sharedTranslations: ['Translations', function (Translations) { return Translations.query(['app.shared', 'app.public.common']).$promise; }],\n modulesPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['machines_module', 'spaces_module', 'plans_module', 'invoicing_module', 'wallet_module', 'statistics_module', 'trainings_module', 'public_agenda_module', 'store_module']\" }).$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['public_registrations', 'store_hidden']\" }).$promise; }]\n },\n onEnter: ['$rootScope', 'logoFile', 'logoBlackFile', 'modulesPromise', 'CSRF', function ($rootScope, logoFile, logoBlackFile, modulesPromise, CSRF) {\n // Retrieve Anti-CSRF tokens from cookies\n CSRF.setMetaTags();\n // Application logo\n $rootScope.logo = logoFile.custom_asset;\n $rootScope.logoBlack = logoBlackFile.custom_asset;\n $rootScope.modules = {\n machines: (modulesPromise.machines_module === 'true'),\n spaces: (modulesPromise.spaces_module === 'true'),\n plans: (modulesPromise.plans_module === 'true'),\n trainings: (modulesPromise.trainings_module === 'true'),\n store: (modulesPromise.store_module === 'true'),\n invoicing: (modulesPromise.invoicing_module === 'true'),\n wallet: (modulesPromise.wallet_module === 'true'),\n publicAgenda: (modulesPromise.public_agenda_module === 'true'),\n statistics: (modulesPromise.statistics_module === 'true')\n };\n }]\n })\n .state('app.public', {\n abstract: true,\n resolve: {\n publicTranslations: ['Translations', function (Translations) { return Translations.query(['app.public']).$promise; }]\n }\n })\n .state('app.logged', {\n abstract: true,\n data: {\n authorizedRoles: ['member', 'admin', 'manager']\n },\n resolve: {\n currentUser: ['Auth', function (Auth) { return Auth.currentUser(); }],\n loggedTranslations: ['Translations', function (Translations) { return Translations.query(['app.logged']).$promise; }]\n },\n onEnter: ['$state', '$timeout', 'currentUser', '$rootScope', function ($state, $timeout, currentUser, $rootScope) {\n $rootScope.currentUser = currentUser;\n }]\n })\n .state('app.admin', {\n abstract: true,\n data: {\n authorizedRoles: ['admin', 'manager']\n },\n resolve: {\n currentUser: ['Auth', function (Auth) { return Auth.currentUser(); }],\n adminTranslations: ['Translations', function (Translations) { return Translations.query(['app.admin']).$promise; }]\n },\n onEnter: ['$state', '$timeout', 'currentUser', '$rootScope', function ($state, $timeout, currentUser, $rootScope) {\n $rootScope.currentUser = currentUser;\n }]\n })\n\n // main pages\n .state('app.public.about', {\n url: '/about',\n views: {\n 'content@': {\n templateUrl: '/shared/about.html',\n controller: 'AboutController'\n }\n }\n })\n .state('app.public.home', {\n url: '/?reset_password_token',\n views: {\n 'main@': {\n templateUrl: '/home.html',\n controller: 'HomeController'\n }\n },\n resolve: {\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['home_content', 'home_blogpost', 'spaces_module', 'feature_tour_display']\" }).$promise; }]\n }\n })\n .state('app.public.privacy', {\n url: '/privacy-policy',\n views: {\n 'content@': {\n templateUrl: '/shared/privacy.html',\n controller: 'PrivacyController'\n }\n }\n })\n\n // profile completion (SSO import passage point)\n .state('app.logged.profileCompletion', {\n url: '/profile_completion',\n views: {\n 'main@': {\n templateUrl: '/profile/complete.html',\n controller: 'CompleteProfileController'\n }\n },\n resolve: {\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['fablab_name', 'name_genre', 'phone_required', 'address_required']\" }).$promise; }],\n activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n cguFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgu-file' }).$promise; }],\n memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }]\n }\n })\n\n // dashboard\n .state('app.logged.dashboard', {\n abstract: true,\n url: '/dashboard',\n resolve: {\n memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }],\n trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }],\n proofOfIdentityTypesPromise: ['SupportingDocumentType', 'currentUser', function (SupportingDocumentType, currentUser) { return SupportingDocumentType.query({ group_id: currentUser.group_id }).$promise; }]\n }\n })\n .state('app.logged.dashboard.profile', {\n url: '/profile',\n views: {\n 'main@': {\n templateUrl: '/dashboard/profile.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.settings', {\n url: '/settings',\n views: {\n 'main@': {\n templateUrl: '/dashboard/settings.html',\n controller: 'EditProfileController'\n }\n },\n resolve: {\n groups: ['Group', function (Group) { return Group.query().$promise; }],\n activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['phone_required', 'address_required']\" }).$promise; }]\n }\n })\n .state('app.logged.dashboard.supporting_document_files', {\n url: '/supporting_document_files',\n views: {\n 'main@': {\n templateUrl: '/dashboard/supporting_document_files.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.projects', {\n url: '/projects',\n views: {\n 'main@': {\n templateUrl: '/dashboard/projects.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.trainings', {\n url: '/trainings',\n views: {\n 'main@': {\n templateUrl: '/dashboard/trainings.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.reservations_dashboard', {\n url: '/reservations',\n views: {\n 'main@': {\n templateUrl: '/dashboard/reservations.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.events', {\n url: '/events',\n views: {\n 'main@': {\n templateUrl: '/dashboard/events.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.invoices', {\n url: '/invoices',\n views: {\n 'main@': {\n templateUrl: '/dashboard/invoices.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.payment_schedules', {\n url: '/payment_schedules',\n views: {\n 'main@': {\n templateUrl: '/dashboard/payment_schedules.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.orders', {\n url: '/orders',\n views: {\n 'main@': {\n templateUrl: '/dashboard/orders.html',\n controller: 'DashboardController'\n }\n }\n })\n .state('app.logged.dashboard.order_show', {\n url: '/orders/:id',\n views: {\n 'main@': {\n templateUrl: '/orders/show.html',\n controller: 'ShowOrdersController'\n }\n }\n })\n .state('app.logged.dashboard.wallet', {\n url: '/wallet',\n abstract: !Fablab.walletModule,\n views: {\n 'main@': {\n templateUrl: '/dashboard/wallet.html',\n controller: 'WalletController'\n }\n },\n resolve: {\n walletPromise: ['Wallet', 'currentUser', function (Wallet, currentUser) { return Wallet.getWalletByUser({ user_id: currentUser.id }).$promise; }],\n transactionsPromise: ['Wallet', 'walletPromise', function (Wallet, walletPromise) { return Wallet.transactions({ id: walletPromise.id }).$promise; }]\n }\n })\n\n // members\n .state('app.logged.members_show', {\n url: '/members/:id',\n views: {\n 'main@': {\n templateUrl: '/members/show.html',\n controller: 'ShowProfileController'\n }\n },\n resolve: {\n memberPromise: ['$transition$', 'Member', function ($transition$, Member) { return Member.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n .state('app.logged.members', {\n url: '/members',\n views: {\n 'main@': {\n templateUrl: '/members/index.html',\n controller: 'MembersController'\n }\n },\n resolve: {\n membersPromise: ['Member', function (Member) { return Member.query({ requested_attributes: '[profile]', page: 1, size: 10 }).$promise; }]\n }\n })\n\n // projects\n .state('app.public.projects_list', {\n url: '/projects?q&page&theme_id&component_id&machine_id&from&whole_network&status_id',\n reloadOnSearch: false,\n views: {\n 'main@': {\n templateUrl: '/projects/index.html',\n controller: 'ProjectsController'\n }\n },\n resolve: {\n themesPromise: ['Theme', function (Theme) { return Theme.query().$promise; }],\n componentsPromise: ['Component', function (Component) { return Component.query().$promise; }],\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['openlab_app_id', 'openlab_default']\" }).$promise; }],\n openLabActive: ['Setting', function (Setting) { return Setting.isPresent({ name: 'openlab_app_secret' }).$promise; }]\n }\n })\n .state('app.logged.projects_new', {\n url: '/projects/new',\n views: {\n 'main@': {\n templateUrl: '/projects/new.html',\n controller: 'NewProjectController'\n }\n },\n resolve: {\n allowedExtensions: ['Setting', function (Setting) { return Setting.get({ name: 'allowed_cad_extensions' }).$promise; }]\n }\n })\n .state('app.public.projects_show', {\n url: '/projects/:id',\n views: {\n 'main@': {\n templateUrl: '/projects/show.html',\n controller: 'ShowProjectController'\n }\n },\n resolve: {\n projectPromise: ['$transition$', 'Project', function ($transition$, Project) { return Project.get({ id: $transition$.params().id }).$promise; }],\n shortnamePromise: ['Setting', function (Setting) { return Setting.get({ name: 'disqus_shortname' }).$promise; }]\n }\n })\n .state('app.logged.projects_edit', {\n url: '/projects/:id/edit',\n views: {\n 'main@': {\n templateUrl: '/projects/edit.html',\n controller: 'EditProjectController'\n }\n },\n resolve: {\n projectPromise: ['$transition$', 'Project', function ($transition$, Project) { return Project.get({ id: $transition$.params().id }).$promise; }],\n allowedExtensions: ['Setting', function (Setting) { return Setting.get({ name: 'allowed_cad_extensions' }).$promise; }]\n }\n })\n\n // machines\n .state('app.public.machines_list', {\n url: '/machines',\n abstract: !Fablab.machinesModule,\n views: {\n 'main@': {\n templateUrl: '/machines/index.html',\n controller: 'MachinesController'\n }\n },\n resolve: {\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display', 'user_validation_required', 'user_validation_required_list']\" }).$promise; }]\n }\n })\n .state('app.admin.machines_list', {\n url: '/admin/machines',\n abstract: !Fablab.machinesModule,\n views: {\n 'main@': {\n templateUrl: '/admin/machines/index.html',\n controller: 'AdminMachinesController'\n }\n },\n resolve: {\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display', 'user_validation_required', 'user_validation_required_list']\" }).$promise; }]\n }\n })\n .state('app.admin.machines_new', {\n url: '/machines/new',\n abstract: !Fablab.machinesModule,\n views: {\n 'main@': {\n templateUrl: '/machines/new.html',\n controller: 'NewMachineController'\n }\n }\n })\n .state('app.public.machines_show', {\n url: '/machines/:id',\n abstract: !Fablab.machinesModule,\n views: {\n 'main@': {\n templateUrl: '/machines/show.html',\n controller: 'ShowMachineController'\n }\n },\n resolve: {\n machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n .state('app.logged.machines_reserve', {\n url: '/machines/:id/reserve',\n abstract: !Fablab.machinesModule,\n views: {\n 'main@': {\n templateUrl: '/machines/reserve.html',\n controller: 'ReserveMachineController'\n }\n },\n resolve: {\n plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }],\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({\n names: \"['machine_explications_alert', 'booking_window_start', 'booking_window_end', 'booking_move_enable', \" +\n \"'booking_move_delay', 'booking_cancel_enable', 'booking_cancel_delay', 'subscription_explications_alert', \" +\n \"'online_payment_module', 'payment_gateway', 'overlapping_categories', 'user_validation_required', 'user_validation_required_list']\"\n }).$promise;\n }]\n }\n })\n .state('app.admin.machines_edit', {\n url: '/machines/:id/edit',\n abstract: !Fablab.machinesModule,\n views: {\n 'main@': {\n templateUrl: '/machines/edit.html',\n controller: 'EditMachineController'\n }\n },\n resolve: {\n machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }],\n machineCategoriesPromise: ['MachineCategory', function (MachineCategory) { return MachineCategory.query().$promise; }]\n }\n })\n\n // spaces\n .state('app.public.spaces_list', {\n url: '/spaces',\n abstract: !Fablab.spacesModule,\n views: {\n 'main@': {\n templateUrl: '/spaces/index.html',\n controller: 'SpacesController'\n }\n },\n resolve: {\n spacesPromise: ['Space', function (Space) { return Space.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display']\" }).$promise; }]\n }\n })\n .state('app.admin.space_new', {\n url: '/spaces/new',\n abstract: !Fablab.spacesModule,\n views: {\n 'main@': {\n templateUrl: '/spaces/new.html',\n controller: 'NewSpaceController'\n }\n }\n })\n .state('app.public.space_show', {\n url: '/spaces/:id',\n abstract: !Fablab.spacesModule,\n views: {\n 'main@': {\n templateUrl: '/spaces/show.html',\n controller: 'ShowSpaceController'\n }\n },\n resolve: {\n spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n .state('app.admin.space_edit', {\n url: '/spaces/:id/edit',\n abstract: !Fablab.spacesModule,\n views: {\n 'main@': {\n templateUrl: '/spaces/edit.html',\n controller: 'EditSpaceController'\n }\n },\n resolve: {\n spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n .state('app.logged.space_reserve', {\n url: '/spaces/:id/reserve',\n abstract: !Fablab.spacesModule,\n views: {\n 'main@': {\n templateUrl: '/spaces/reserve.html',\n controller: 'ReserveSpaceController'\n }\n },\n resolve: {\n spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }],\n plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({\n names: \"['booking_window_start', 'booking_window_end', 'booking_move_enable', 'booking_move_delay', \" +\n \"'booking_cancel_enable', 'booking_cancel_delay', 'subscription_explications_alert', \" +\n \"'space_explications_alert', 'online_payment_module', 'payment_gateway', 'overlapping_categories', \" +\n \"'user_validation_required', 'user_validation_required_list']\"\n }).$promise;\n }]\n }\n })\n\n // trainings\n .state('app.public.trainings_list', {\n url: '/trainings',\n abstract: !Fablab.trainingsModule,\n views: {\n 'main@': {\n templateUrl: '/trainings/index.html',\n controller: 'TrainingsController'\n }\n },\n resolve: {\n trainingsPromise: ['Training', function (Training) { return Training.query({ public_page: true, disabled: false }).$promise; }]\n }\n })\n .state('app.public.training_show', {\n url: '/trainings/:id',\n abstract: !Fablab.trainingsModule,\n views: {\n 'main@': {\n templateUrl: '/trainings/show.html',\n controller: 'ShowTrainingController'\n }\n },\n resolve: {\n trainingPromise: ['Training', '$transition$', function (Training, $transition$) { return Training.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n .state('app.logged.trainings_reserve', {\n url: '/trainings/:id/reserve',\n abstract: !Fablab.trainingsModule,\n views: {\n 'main@': {\n templateUrl: '/trainings/reserve.html',\n controller: 'ReserveTrainingController'\n }\n },\n resolve: {\n explicationAlertPromise: ['Setting', function (Setting) { return Setting.get({ name: 'training_explications_alert' }).$promise; }],\n plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n trainingPromise: ['Training', '$transition$', function (Training, $transition$) {\n if ($transition$.params().id !== 'all') { return Training.get({ id: $transition$.params().id }).$promise; }\n }],\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({\n names: \"['booking_window_start', 'booking_window_end', 'booking_move_enable', 'booking_move_delay', \" +\n \"'booking_cancel_enable', 'booking_cancel_delay', 'subscription_explications_alert', \" +\n \"'training_explications_alert', 'training_information_message', 'online_payment_module', \" +\n \"'payment_gateway', 'overlapping_categories', 'user_validation_required', 'user_validation_required_list']\"\n }).$promise;\n }]\n }\n })\n // notifications\n .state('app.logged.notifications', {\n url: '/notifications',\n views: {\n 'main@': {\n templateUrl: '/notifications/index.html',\n controller: 'NotificationsController'\n }\n }\n })\n\n // pricing\n .state('app.public.plans', {\n url: '/plans',\n abstract: !Fablab.plansModule,\n views: {\n 'main@': {\n templateUrl: '/plans/index.html',\n controller: 'PlansIndexController'\n }\n },\n resolve: {\n subscriptionExplicationsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'subscription_explications_alert' }).$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['online_payment_module', 'payment_gateway', 'overlapping_categories', 'user_validation_required', 'user_validation_required_list']\" }).$promise; }]\n }\n })\n\n // events\n .state('app.public.events_list', {\n url: '/events',\n views: {\n 'main@': {\n templateUrl: '/events/index.html',\n controller: 'EventsController'\n }\n },\n resolve: {\n categoriesPromise: ['Category', function (Category) { return Category.query().$promise; }],\n themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }],\n ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }]\n }\n })\n .state('app.public.events_show', {\n url: '/events/:id',\n views: {\n 'main@': {\n templateUrl: '/events/show.html',\n controller: 'ShowEventController'\n }\n },\n resolve: {\n eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],\n priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', 'booking_cancel_delay', 'event_explications_alert', 'online_payment_module', 'user_validation_required', 'user_validation_required_list']\" }).$promise; }]\n }\n })\n\n // global calendar (trainings, machines and events)\n .state('app.public.calendar', {\n url: '/calendar',\n abstract: !Fablab.publicAgendaModule,\n views: {\n 'main@': {\n templateUrl: '/calendar/calendar.html',\n controller: 'CalendarController'\n }\n },\n resolve: {\n bookingWindowStart: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_start' }).$promise; }],\n bookingWindowEnd: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_end' }).$promise; }],\n trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }],\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n spacesPromise: ['Space', function (Space) { return Space.query().$promise; }],\n iCalendarPromise: ['ICalendar', function (ICalendar) { return ICalendar.query().$promise; }],\n machineCategoriesPromise: ['MachineCategory', function (MachineCategory) { return MachineCategory.query().$promise; }]\n }\n })\n\n // store\n .state('app.public.store', {\n url: '/store/:categoryTypeUrl/:category?{machines:string}{keywords:string}{is_active:string}{is_available:string}{page:string}{sort:string}',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/store/index.html',\n controller: 'StoreController'\n }\n },\n params: {\n categoryTypeUrl: { raw: true, type: 'path', value: null, squash: true },\n category: { type: 'path', raw: true, value: null, squash: true },\n machines: { array: true, dynamic: true, type: 'query', raw: true },\n keywords: { dynamic: true, type: 'query' },\n is_active: { dynamic: true, type: 'query', value: 'true', squash: true },\n is_available: { dynamic: true, type: 'query', value: 'false', squash: true },\n page: { dynamic: true, type: 'query', value: '1', squash: true },\n sort: { dynamic: true, type: 'query' },\n authorizedRoles: { dynamic: true, raw: true }\n }\n })\n\n // show product\n .state('app.public.product_show', {\n url: '/store/p/:slug',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/products/show.html',\n controller: 'ShowProductController'\n }\n }\n })\n\n // cart\n .state('app.public.store_cart', {\n url: '/store/cart',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/cart/index.html',\n controller: 'CartController'\n }\n }\n })\n\n // --- namespace /admin/... ---\n // calendar\n .state('app.admin.calendar', {\n url: '/admin/calendar',\n views: {\n 'main@': {\n templateUrl: '/admin/calendar/calendar.html',\n controller: 'AdminCalendarController'\n }\n },\n resolve: {\n bookingWindowStart: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_start' }).$promise; }],\n bookingWindowEnd: ['Setting', function (Setting) { return Setting.get({ name: 'booking_window_end' }).$promise; }],\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['slot_duration', 'events_in_calendar', 'feature_tour_display']\" }).$promise; }],\n trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }],\n spacesPromise: ['Space', function (Space) { return Space.query().$promise; }],\n machineCategoriesPromise: ['MachineCategory', function (MachineCategory) { return MachineCategory.query().$promise; }]\n }\n })\n .state('app.admin.calendar.icalendar', {\n url: '/admin/calendar/icalendar',\n views: {\n 'main@': {\n templateUrl: '/admin/calendar/icalendar.html',\n controller: 'AdminICalendarController'\n }\n },\n resolve: {\n iCalendars: ['ICalendar', function (ICalendar) { return ICalendar.query().$promise; }]\n }\n })\n\n // project's settings\n .state('app.admin.projects', {\n url: '/admin/projects',\n views: {\n 'main@': {\n templateUrl: '/admin/projects/index.html',\n controller: 'AdminProjectsController'\n }\n },\n resolve: {\n componentsPromise: ['Component', function (Component) { return Component.query().$promise; }],\n licencesPromise: ['Licence', function (Licence) { return Licence.query().$promise; }],\n themesPromise: ['Theme', function (Theme) { return Theme.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({\n names: \"['feature_tour_display', 'disqus_shortname', 'allowed_cad_extensions', \" +\n \"'allowed_cad_mime_types', 'openlab_app_id', 'openlab_app_secret', 'openlab_default']\"\n }).$promise;\n }]\n }\n })\n .state('app.admin.manage_abuses', {\n url: '/admin/abuses',\n views: {\n 'main@': {\n templateUrl: '/admin/abuses/index.html',\n controller: 'AbusesController'\n }\n },\n resolve: {\n abusesPromise: ['Abuse', function (Abuse) { return Abuse.query().$promise; }]\n }\n })\n\n // trainings\n .state('app.admin.trainings', {\n url: '/admin/trainings',\n abstract: !Fablab.trainingsModule,\n views: {\n 'main@': {\n templateUrl: '/admin/trainings/index.html',\n controller: 'TrainingsAdminController'\n }\n },\n resolve: {\n trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }],\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display', 'machines_module']\" }).$promise; }]\n }\n })\n .state('app.admin.trainings_new', {\n url: '/admin/trainings/new',\n abstract: !Fablab.trainingsModule,\n views: {\n 'main@': {\n templateUrl: '/admin/trainings/new.html',\n controller: 'NewTrainingController'\n }\n }\n })\n .state('app.admin.trainings_edit', {\n url: '/admin/trainings/:id/edit',\n abstract: !Fablab.trainingsModule,\n views: {\n 'main@': {\n templateUrl: '/admin/trainings/edit.html',\n controller: 'EditTrainingController'\n }\n },\n resolve: {\n trainingPromise: ['Training', '$transition$', function (Training, $transition$) { return Training.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n // events\n .state('app.admin.events', {\n url: '/admin/events',\n views: {\n 'main@': {\n templateUrl: '/admin/events/index.html',\n controller: 'AdminEventsController'\n }\n },\n resolve: {\n eventsPromise: ['Event', function (Event) { return Event.query({ page: 1 }).$promise; }],\n categoriesPromise: ['Category', function (Category) { return Category.query().$promise; }],\n themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }],\n ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }],\n priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display']\" }).$promise; }]\n }\n })\n .state('app.admin.events_new', {\n url: '/admin/events/new',\n views: {\n 'main@': {\n templateUrl: '/events/new.html',\n controller: 'NewEventController'\n }\n }\n })\n .state('app.admin.events_edit', {\n url: '/admin/events/:id/edit',\n views: {\n 'main@': {\n templateUrl: '/events/edit.html',\n controller: 'EditEventController'\n }\n },\n resolve: {\n eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n .state('app.admin.event_reservations', {\n url: '/admin/events/:id/reservations',\n views: {\n 'main@': {\n templateUrl: '/admin/events/reservations.html',\n controller: 'ShowEventReservationsController'\n }\n },\n resolve: {\n eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],\n reservationsPromise: ['Reservation', '$transition$', function (Reservation, $transition$) { return Reservation.query({ reservable_id: $transition$.params().id, reservable_type: 'Event' }).$promise; }]\n }\n })\n\n // pricing\n .state('app.admin.pricing', {\n url: '/admin/pricing',\n views: {\n 'main@': {\n templateUrl: '/admin/pricing/index.html',\n controller: 'EditPricingController'\n }\n },\n resolve: {\n plans: ['Plan', function (Plan) { return Plan.query().$promise; }],\n groups: ['Group', function (Group) { return Group.query().$promise; }],\n trainingsPricingsPromise: ['TrainingsPricing', function (TrainingsPricing) { return TrainingsPricing.query().$promise; }],\n trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }],\n machineCreditsPromise: ['Credit', function (Credit) { return Credit.query({ creditable_type: 'Machine' }).$promise; }],\n machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],\n trainingCreditsPromise: ['Credit', function (Credit) { return Credit.query({ creditable_type: 'Training' }).$promise; }],\n couponsPromise: ['Coupon', function (Coupon) { return Coupon.query({ page: 1, filter: 'all' }).$promise; }],\n spacesPromise: ['Space', function (Space) { return Space.query().$promise; }],\n spacesPricesPromise: ['Price', function (Price) { return Price.query({ priceable_type: 'Space', plan_id: 'null' }).$promise; }],\n spacesCreditsPromise: ['Credit', function (Credit) { return Credit.query({ creditable_type: 'Space' }).$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display', 'slot_duration', 'user_validation_required', 'user_validation_required_list']\" }).$promise; }],\n planCategories: ['PlanCategory', function (PlanCategory) { return PlanCategory.query().$promise; }]\n }\n })\n\n // plans\n .state('app.admin.plans', {\n abstract: true,\n resolve: {\n prices: ['Pricing', function (Pricing) { return Pricing.query().$promise; }],\n groups: ['Group', function (Group) { return Group.query().$promise; }],\n partners: ['User', function (User) { return User.query({ role: 'partner' }).$promise; }]\n }\n })\n .state('app.admin.plans.new', {\n url: '/admin/plans/new',\n views: {\n 'main@': {\n templateUrl: '/admin/plans/new.html',\n controller: 'NewPlanController'\n }\n },\n resolve: {\n planCategories: ['PlanCategory', function (PlanCategory) { return PlanCategory.query().$promise; }]\n }\n })\n .state('app.admin.plans.edit', {\n url: '/admin/plans/:id/edit',\n views: {\n 'main@': {\n templateUrl: '/admin/plans/edit.html',\n controller: 'EditPlanController'\n }\n },\n resolve: {\n spaces: ['Space', function (Space) { return Space.query().$promise; }],\n machines: ['Machine', function (Machine) { return Machine.query().$promise; }],\n plans: ['Plan', function (Plan) { return Plan.query().$promise; }],\n planPromise: ['Plan', '$transition$', function (Plan, $transition$) { return Plan.get({ id: $transition$.params().id }).$promise; }],\n planCategories: ['PlanCategory', function (PlanCategory) { return PlanCategory.query().$promise; }]\n }\n })\n // plan categories\n .state('app.admin.plan_categories', {\n url: '/admin/plan_categories',\n views: {\n 'main@': {\n templateUrl: '/admin/plans/categories.html',\n controller: 'PlanCategoriesController'\n }\n }\n })\n\n // coupons\n .state('app.admin.coupons_new', {\n url: '/admin/coupons/new',\n views: {\n 'main@': {\n templateUrl: '/admin/coupons/new.html',\n controller: 'NewCouponController'\n }\n }\n })\n .state('app.admin.coupons_edit', {\n url: '/admin/coupons/:id/edit',\n views: {\n 'main@': {\n templateUrl: '/admin/coupons/edit.html',\n controller: 'EditCouponController'\n }\n },\n resolve: {\n couponPromise: ['Coupon', '$transition$', function (Coupon, $transition$) { return Coupon.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n\n // show order\n .state('app.admin.order_show', {\n url: '/admin/store/orders/:id',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/admin/orders/show.html',\n controller: 'AdminShowOrdersController'\n }\n }\n })\n\n // invoices\n .state('app.admin.invoices', {\n url: '/admin/invoices',\n views: {\n 'main@': {\n templateUrl: '/admin/invoices/index.html',\n controller: 'InvoicesController'\n }\n },\n resolve: {\n settings: ['Setting', function (Setting) {\n return Setting.query({\n names: \"['invoice_legals', 'invoice_text', 'invoice_VAT-rate', 'invoice_VAT-rate_Machine', \" +\n \"'invoice_VAT-active', 'invoice_order-nb', 'invoice_code-value', \" +\n \"'invoice_code-active', 'invoice_reference', 'invoice_logo', 'payment_gateway', 'payment_schedule_prefix', 'invoicing_module', \" +\n \"'feature_tour_display', 'online_payment_module', 'stripe_public_key', 'stripe_currency', 'invoice_prefix', 'invoice_VAT-name']\"\n }).$promise;\n }],\n stripeSecretKey: ['Setting', function (Setting) { return Setting.isPresent({ name: 'stripe_secret_key' }).$promise; }],\n onlinePaymentStatus: ['Payment', function (Payment) { return Payment.onlinePaymentStatus().$promise; }],\n invoices: ['Invoice', function (Invoice) {\n return Invoice.list({\n query: { number: '', customer: '', date: null, order_by: '-date', page: 1, size: 20 }\n }).$promise;\n }],\n closedPeriods: ['AccountingPeriod', function (AccountingPeriod) { return AccountingPeriod.query().$promise; }]\n }\n })\n\n // members\n .state('app.admin.members', {\n url: '/admin/members',\n views: {\n 'main@': {\n templateUrl: '/admin/members/index.html',\n controller: 'AdminMembersController'\n },\n 'groups@app.admin.members': {\n templateUrl: '/admin/groups/index.html',\n controller: 'GroupsController'\n },\n 'tags@app.admin.members': {\n templateUrl: '/admin/tags/index.html',\n controller: 'TagsController'\n },\n 'authentification@app.admin.members': {\n templateUrl: '/admin/authentications/index.html',\n controller: 'AuthentificationController'\n }\n },\n resolve: {\n membersPromise: ['Member', function (Member) { return Member.list({ query: { search: '', order_by: 'id', page: 1, size: 20 } }).$promise; }],\n adminsPromise: ['Admin', function (Admin) { return Admin.query().$promise; }],\n partnersPromise: ['User', function (User) { return User.query({ role: 'partner' }).$promise; }],\n managersPromise: ['User', function (User) { return User.query({ role: 'manager' }).$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }],\n authProvidersPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display', 'user_validation_required', 'show_username_in_admin_list']\" }).$promise; }]\n }\n })\n .state('app.admin.members_new', {\n url: '/admin/members/new',\n views: {\n 'main@': {\n templateUrl: '/admin/members/new.html',\n controller: 'NewMemberController'\n }\n },\n resolve: {\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['phone_required', 'address_required']\" }).$promise; }]\n }\n })\n .state('app.admin.members_import', {\n url: '/admin/members/import',\n views: {\n 'main@': {\n templateUrl: '/admin/members/import.html',\n controller: 'ImportMembersController'\n }\n },\n resolve: {\n tags: ['Tag', function (Tag) { return Tag.query().$promise; }]\n }\n })\n .state('app.admin.members_import_result', {\n url: '/admin/members/import/:id/results',\n views: {\n 'main@': {\n templateUrl: '/admin/members/import_result.html',\n controller: 'ImportMembersResultController'\n }\n },\n resolve: {\n importItem: ['Import', '$transition$', function (Import, $transition$) { return Import.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n .state('app.admin.members_edit', {\n url: '/admin/members/:id/edit',\n views: {\n 'main@': {\n templateUrl: '/admin/members/edit.html',\n controller: 'EditMemberController'\n }\n },\n resolve: {\n memberPromise: ['Member', '$transition$', function (Member, $transition$) { return Member.get({ id: $transition$.params().id }).$promise; }],\n activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }],\n walletPromise: ['Wallet', '$transition$', function (Wallet, $transition$) { return Wallet.getWalletByUser({ user_id: $transition$.params().id }).$promise; }],\n transactionsPromise: ['Wallet', 'walletPromise', function (Wallet, walletPromise) { return Wallet.transactions({ id: walletPromise.id }).$promise; }],\n tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['phone_required', 'address_required', 'user_validation_required']\" }).$promise; }]\n }\n })\n .state('app.admin.admins_new', {\n url: '/admin/admins/new',\n views: {\n 'main@': {\n templateUrl: '/admin/admins/new.html',\n controller: 'NewAdminController'\n }\n },\n resolve: {\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['phone_required', 'address_required']\" }).$promise; }],\n groupsPromise: ['Group', function (Group) { return Group.query({ disabled: false }).$promise; }]\n }\n })\n .state('app.admin.managers_new', {\n url: '/admin/managers/new',\n views: {\n 'main@': {\n templateUrl: '/admin/managers/new.html',\n controller: 'NewManagerController'\n }\n },\n resolve: {\n groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],\n tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['phone_required', 'address_required']\" }).$promise; }]\n }\n })\n\n // authentication providers\n .state('app.admin.authentication_new', {\n url: '/admin/authentications/new',\n views: {\n 'main@': {\n templateUrl: '/admin/authentications/new.html',\n controller: 'NewAuthenticationController'\n }\n }\n })\n .state('app.admin.authentication_edit', {\n url: '/admin/authentications/:id/edit',\n views: {\n 'main@': {\n templateUrl: '/admin/authentications/edit.html',\n controller: 'EditAuthenticationController'\n }\n },\n resolve: {\n providerPromise: ['AuthProvider', '$transition$', function (AuthProvider, $transition$) { return AuthProvider.get({ id: $transition$.params().id }).$promise; }]\n }\n })\n\n // statistics\n .state('app.admin.statistics', {\n url: '/admin/statistics',\n abstract: !Fablab.statisticsModule,\n views: {\n 'main@': {\n templateUrl: '/admin/statistics/index.html',\n controller: 'StatisticsController'\n }\n },\n resolve: {\n membersPromise: ['Member', function (Member) { return Member.mapping().$promise; }],\n statisticsPromise: ['Statistics', function (Statistics) { return Statistics.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display']\" }).$promise; }]\n }\n })\n .state('app.admin.stats_graphs', {\n url: '/admin/statistics/evolution',\n abstract: !Fablab.statisticsModule,\n views: {\n 'main@': {\n templateUrl: '/admin/statistics/graphs.html',\n controller: 'GraphsController'\n }\n }\n })\n\n // configurations\n .state('app.admin.settings', {\n url: '/admin/settings',\n views: {\n 'main@': {\n templateUrl: '/admin/settings/index.html',\n controller: 'SettingsController'\n }\n },\n resolve: {\n settingsPromise: ['Setting', function (Setting) {\n return Setting.query({\n names: \"['twitter_name', 'about_title', 'about_body', 'tracking_id', 'facebook_app_id', 'email_from', \" +\n \"'privacy_body', 'privacy_dpo', 'about_contacts', 'book_overlapping_slots', 'invoicing_module', \" +\n \"'home_blogpost', 'machine_explications_alert', 'training_explications_alert', 'slot_duration', \" +\n \"'training_information_message', 'subscription_explications_alert', 'event_explications_alert', \" +\n \"'space_explications_alert', 'booking_window_start', 'booking_window_end', 'events_in_calendar', \" +\n \"'booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', 'feature_tour_display', \" +\n \"'booking_cancel_delay', 'main_color', 'secondary_color', 'spaces_module', 'twitter_analytics', \" +\n \"'fablab_name', 'name_genre', 'reminder_enable', 'plans_module', 'confirmation_required', \" +\n \"'reminder_delay', 'visibility_yearly', 'visibility_others', 'wallet_module', 'trainings_module', \" +\n \"'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', 'address_required', \" +\n \"'link_name', 'home_content', 'home_css', 'phone_required', 'upcoming_events_shown', 'public_agenda_module',\" +\n \"'renew_pack_threshold', 'pack_only_for_subscription', 'overlapping_categories', 'public_registrations',\" +\n \"'extended_prices_in_same_day', 'recaptcha_site_key', 'recaptcha_secret_key', 'user_validation_required', \" +\n \"'user_validation_required_list', 'machines_module', 'user_change_group', 'show_username_in_admin_list', \" +\n \"'store_module', 'machine_reservation_deadline', 'training_reservation_deadline', 'event_reservation_deadline', \" +\n \"'space_reservation_deadline']\"\n }).$promise;\n }],\n privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }],\n cguFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgu-file' }).$promise; }],\n cgvFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgv-file' }).$promise; }],\n faviconFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'favicon-file' }).$promise; }],\n profileImageFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'profile-image-file' }).$promise; }]\n }\n })\n\n .state('app.admin.store', {\n abstract: true,\n url: '/admin/store'\n })\n\n .state('app.admin.store.settings', {\n url: '/settings',\n abstract: !Fablab.storeModule,\n data: {\n authorizedRoles: ['admin']\n },\n views: {\n 'main@': {\n templateUrl: '/admin/store/index.html',\n controller: 'AdminStoreController'\n }\n }\n })\n\n .state('app.admin.store.products', {\n url: '/products?{categories:string}{machines:string}{keywords:string}{stock_type:string}{stock_from:string}{stock_to:string}{is_active:string}{page:string}{sort:string}',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/admin/store/index.html',\n controller: 'AdminStoreController'\n }\n },\n params: {\n categories: { array: true, dynamic: true, type: 'query', raw: true },\n machines: { array: true, dynamic: true, type: 'query', raw: true },\n keywords: { dynamic: true, type: 'query' },\n stock_type: { dynamic: true, type: 'query', value: 'internal', squash: true },\n stock_from: { dynamic: true, type: 'query', value: '0', squash: true },\n stock_to: { dynamic: true, type: 'query', value: '0', squash: true },\n is_active: { dynamic: true, type: 'query', value: 'false', squash: true },\n page: { dynamic: true, type: 'query', value: '1', squash: true },\n sort: { dynamic: true, type: 'query' }\n }\n })\n\n .state('app.admin.store.products_new', {\n url: '/products/new',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/admin/store/product_new.html',\n controller: 'AdminStoreProductController'\n }\n }\n })\n\n .state('app.admin.store.products_edit', {\n url: '/products/:id/edit',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/admin/store/product_edit.html',\n controller: 'AdminStoreProductController'\n }\n }\n })\n\n .state('app.admin.store.categories', {\n url: '/categories',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/admin/store/index.html',\n controller: 'AdminStoreController'\n }\n }\n })\n\n .state('app.admin.store.orders', {\n url: '/orders',\n abstract: !Fablab.storeModule,\n views: {\n 'main@': {\n templateUrl: '/admin/store/index.html',\n controller: 'AdminStoreController'\n }\n }\n })\n\n // OpenAPI Clients\n .state('app.admin.open_api_clients', {\n url: '/open_api_clients',\n views: {\n 'main@': {\n templateUrl: '/admin/open_api_clients/index.html.erb',\n controller: 'OpenAPIClientsController'\n }\n },\n resolve: {\n clientsPromise: ['OpenAPIClient', function (OpenAPIClient) { return OpenAPIClient.query().$promise; }],\n settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: \"['feature_tour_display']\" }).$promise; }]\n }\n });\n }\n\n ]);\n","'use strict';\n\nApplication.Services.factory('_t', ['$translate', function ($translate) {\n return function (key, interpolations) {\n if (interpolations == null) { interpolations = undefined; }\n return $translate.instant(key, interpolations);\n };\n}]);\n","'use strict';\n\nApplication.Services.factory('Abuse', ['$resource', function ($resource) {\n return $resource('/api/abuses/:id',\n { id: '@id' }, {\n query: {\n isArray: false\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('AccountingPeriod', ['$resource', function ($resource) {\n return $resource('/api/accounting_periods/:id',\n { id: '@id' }, {\n lastClosingEnd: {\n method: 'GET',\n url: '/api/accounting_periods/last_closing_end'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Admin', ['$resource', function ($resource) {\n return $resource('/api/admins/:id',\n { id: '@id' }, {\n query: {\n isArray: false\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('AgeRange', ['$resource', function ($resource) {\n return $resource('/api/age_ranges/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('AuthService', ['Session', function (Session) {\n const service = {};\n\n service.isAuthenticated = function () {\n return (Session.currentUser != null) && (Session.currentUser.id != null);\n };\n\n service.isAuthorized = function (authorizedRoles) {\n if (!angular.isArray(authorizedRoles)) {\n authorizedRoles = [authorizedRoles];\n }\n return service.isAuthenticated() && (authorizedRoles.indexOf(Session.currentUser.role) !== -1);\n };\n\n return service;\n}]);\n","'use strict';\n\nApplication.Services.factory('AuthProvider', ['$resource', function ($resource) {\n return $resource('/api/auth_providers/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n },\n mapping_fields: {\n method: 'GET',\n url: '/api/auth_providers/mapping_fields'\n },\n active: {\n method: 'GET',\n url: '/api/auth_providers/active'\n },\n send_code: {\n method: 'POST',\n url: '/api/auth_providers/send_code'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Availability', ['$resource', function ($resource) {\n return $resource('/api/availabilities/:id',\n { id: '@id' }, {\n machine: {\n method: 'GET',\n url: '/api/availabilities/machines/:machineId',\n params: { machineId: '@machineId' },\n isArray: true\n },\n reservations: {\n method: 'GET',\n url: '/api/availabilities/:id/reservations',\n isArray: true\n },\n trainings: {\n method: 'GET',\n url: '/api/availabilities/trainings/:trainingId',\n params: { trainingId: '@trainingId' },\n isArray: true\n },\n spaces: {\n method: 'GET',\n url: '/api/availabilities/spaces/:spaceId',\n params: { spaceId: '@spaceId' },\n isArray: true\n },\n update: {\n method: 'PUT'\n },\n lock: {\n method: 'PUT',\n url: '/api/availabilities/:id/lock'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('BrazillianData', ['$resource', function ($resource) {\n return $resource('/api/brazillian_data',\n {}, {\n all_states: {\n method: 'GET',\n url: '/api/brazillian_data/all_states',\n isArray: true\n },\n cities: {\n method: 'GET',\n url: '/api/brazillian_data/cities/:uf',\n params: { uf: '@uf' },\n isArray: true\n },\n zipcode: {\n method: 'GET',\n url: '/api/brazillian_data/zipcode/:zip',\n params: { zip: '@zip' },\n isArray: false\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('CalendarConfig', [() =>\n function (options) {\n // The calendar is divided in slots of 1 hour\n if (options == null) { options = {}; }\n const BASE_SLOT = '01:00:00';\n\n // The calendar will be initialized positioned under 9:00 AM\n const DEFAULT_CALENDAR_POSITION = '09:00:00';\n\n const defaultOptions = {\n timezone: Fablab.timezone,\n locale: Fablab.fullcalendar_locale,\n header: {\n left: 'month agendaWeek today prev,next',\n center: 'title',\n right: ''\n },\n firstDay: Fablab.weekStartingDay,\n scrollTime: DEFAULT_CALENDAR_POSITION,\n slotDuration: BASE_SLOT,\n allDayDefault: false,\n minTime: '00:00:00',\n maxTime: '24:00:00',\n height: 'auto',\n buttonIcons: {\n prev: 'left-single-arrow',\n next: 'right-single-arrow'\n },\n slotLabelFormat: 'H:mm',\n views: {\n agendaWeek: {\n timeFormat: 'H:mm'\n },\n month: {\n timeFormat: 'H(:mm)'\n }\n },\n\n allDaySlot: false,\n defaultView: 'agendaWeek',\n editable: false\n };\n\n return Object.assign({}, defaultOptions, options);\n }\n\n]);\n","'use strict';\n\nApplication.Services.factory('Category', ['$resource', function ($resource) {\n return $resource('/api/categories/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Component', ['$resource', function ($resource) {\n return $resource('/api/components/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Coupon', ['$resource', function ($resource) {\n return $resource('/api/coupons/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n },\n validate: {\n method: 'POST',\n url: '/api/coupons/validate'\n },\n send: {\n method: 'POST',\n url: '/api/coupons/send'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Credit', ['$resource', function ($resource) {\n return $resource('/api/credits/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.service('CSRF', ['$cookies',\n function ($cookies) {\n return ({\n setMetaTags () {\n if (angular.element('meta[name=\"csrf-param\"]').length === 0) {\n angular.element('head').append('');\n angular.element('head').append(``);\n } else {\n angular.element('meta[name=\"csrf-token\"]').replaceWith(``);\n }\n }\n });\n }\n]);\n","'use strict';\n\nApplication.Services.factory('CustomAsset', ['$resource', function ($resource) {\n return $resource('/api/custom_assets/:name',\n { name: '@name' });\n}]);\n","/**\n * Created by sylvain on 20/08/14.\n *\n * Based on http://jsperf.com/diacritics/12\n */\nApplication.Services.service('Diacritics', [\n function () {\n return {\n\n /**\n * Fast diacritics removing function, works on the provided string.\n * Eg. \"éêè çä bönjoür\" will become \"eee ca bonjour\"\n * @param str {string} to ascii-fy\n * @returns {string} without diacritics\n */\n remove: function (str) {\n const defaultDiacriticsRemovalap = [\n { base: 'A', letters: '\\u0041\\u24B6\\uFF21\\u00C0\\u00C1\\u00C2\\u1EA6\\u1EA4\\u1EAA\\u1EA8\\u00C3\\u0100\\u0102\\u1EB0\\u1EAE\\u1EB4\\u1EB2\\u0226\\u01E0\\u00C4\\u01DE\\u1EA2\\u00C5\\u01FA\\u01CD\\u0200\\u0202\\u1EA0\\u1EAC\\u1EB6\\u1E00\\u0104\\u023A\\u2C6F' },\n { base: 'AA', letters: '\\uA732' },\n { base: 'AE', letters: '\\u00C6\\u01FC\\u01E2' },\n { base: 'AO', letters: '\\uA734' },\n { base: 'AU', letters: '\\uA736' },\n { base: 'AV', letters: '\\uA738\\uA73A' },\n { base: 'AY', letters: '\\uA73C' },\n { base: 'B', letters: '\\u0042\\u24B7\\uFF22\\u1E02\\u1E04\\u1E06\\u0243\\u0182\\u0181' },\n { base: 'C', letters: '\\u0043\\u24B8\\uFF23\\u0106\\u0108\\u010A\\u010C\\u00C7\\u1E08\\u0187\\u023B\\uA73E' },\n { base: 'D', letters: '\\u0044\\u24B9\\uFF24\\u1E0A\\u010E\\u1E0C\\u1E10\\u1E12\\u1E0E\\u0110\\u018B\\u018A\\u0189\\uA779' },\n { base: 'DZ', letters: '\\u01F1\\u01C4' },\n { base: 'Dz', letters: '\\u01F2\\u01C5' },\n { base: 'E', letters: '\\u0045\\u24BA\\uFF25\\u00C8\\u00C9\\u00CA\\u1EC0\\u1EBE\\u1EC4\\u1EC2\\u1EBC\\u0112\\u1E14\\u1E16\\u0114\\u0116\\u00CB\\u1EBA\\u011A\\u0204\\u0206\\u1EB8\\u1EC6\\u0228\\u1E1C\\u0118\\u1E18\\u1E1A\\u0190\\u018E' },\n { base: 'F', letters: '\\u0046\\u24BB\\uFF26\\u1E1E\\u0191\\uA77B' },\n { base: 'G', letters: '\\u0047\\u24BC\\uFF27\\u01F4\\u011C\\u1E20\\u011E\\u0120\\u01E6\\u0122\\u01E4\\u0193\\uA7A0\\uA77D\\uA77E' },\n { base: 'H', letters: '\\u0048\\u24BD\\uFF28\\u0124\\u1E22\\u1E26\\u021E\\u1E24\\u1E28\\u1E2A\\u0126\\u2C67\\u2C75\\uA78D' },\n { base: 'I', letters: '\\u0049\\u24BE\\uFF29\\u00CC\\u00CD\\u00CE\\u0128\\u012A\\u012C\\u0130\\u00CF\\u1E2E\\u1EC8\\u01CF\\u0208\\u020A\\u1ECA\\u012E\\u1E2C\\u0197' },\n { base: 'J', letters: '\\u004A\\u24BF\\uFF2A\\u0134\\u0248' },\n { base: 'K', letters: '\\u004B\\u24C0\\uFF2B\\u1E30\\u01E8\\u1E32\\u0136\\u1E34\\u0198\\u2C69\\uA740\\uA742\\uA744\\uA7A2' },\n { base: 'L', letters: '\\u004C\\u24C1\\uFF2C\\u013F\\u0139\\u013D\\u1E36\\u1E38\\u013B\\u1E3C\\u1E3A\\u0141\\u023D\\u2C62\\u2C60\\uA748\\uA746\\uA780' },\n { base: 'LJ', letters: '\\u01C7' },\n { base: 'Lj', letters: '\\u01C8' },\n { base: 'M', letters: '\\u004D\\u24C2\\uFF2D\\u1E3E\\u1E40\\u1E42\\u2C6E\\u019C' },\n { base: 'N', letters: '\\u004E\\u24C3\\uFF2E\\u01F8\\u0143\\u00D1\\u1E44\\u0147\\u1E46\\u0145\\u1E4A\\u1E48\\u0220\\u019D\\uA790\\uA7A4' },\n { base: 'NJ', letters: '\\u01CA' },\n { base: 'Nj', letters: '\\u01CB' },\n { base: 'O', letters: '\\u004F\\u24C4\\uFF2F\\u00D2\\u00D3\\u00D4\\u1ED2\\u1ED0\\u1ED6\\u1ED4\\u00D5\\u1E4C\\u022C\\u1E4E\\u014C\\u1E50\\u1E52\\u014E\\u022E\\u0230\\u00D6\\u022A\\u1ECE\\u0150\\u01D1\\u020C\\u020E\\u01A0\\u1EDC\\u1EDA\\u1EE0\\u1EDE\\u1EE2\\u1ECC\\u1ED8\\u01EA\\u01EC\\u00D8\\u01FE\\u0186\\u019F\\uA74A\\uA74C' },\n { base: 'OI', letters: '\\u01A2' },\n { base: 'OO', letters: '\\uA74E' },\n { base: 'OU', letters: '\\u0222' },\n { base: 'OE', letters: '\\u008C\\u0152' },\n { base: 'oe', letters: '\\u009C\\u0153' },\n { base: 'P', letters: '\\u0050\\u24C5\\uFF30\\u1E54\\u1E56\\u01A4\\u2C63\\uA750\\uA752\\uA754' },\n { base: 'Q', letters: '\\u0051\\u24C6\\uFF31\\uA756\\uA758\\u024A' },\n { base: 'R', letters: '\\u0052\\u24C7\\uFF32\\u0154\\u1E58\\u0158\\u0210\\u0212\\u1E5A\\u1E5C\\u0156\\u1E5E\\u024C\\u2C64\\uA75A\\uA7A6\\uA782' },\n { base: 'S', letters: '\\u0053\\u24C8\\uFF33\\u1E9E\\u015A\\u1E64\\u015C\\u1E60\\u0160\\u1E66\\u1E62\\u1E68\\u0218\\u015E\\u2C7E\\uA7A8\\uA784' },\n { base: 'T', letters: '\\u0054\\u24C9\\uFF34\\u1E6A\\u0164\\u1E6C\\u021A\\u0162\\u1E70\\u1E6E\\u0166\\u01AC\\u01AE\\u023E\\uA786' },\n { base: 'TZ', letters: '\\uA728' },\n { base: 'U', letters: '\\u0055\\u24CA\\uFF35\\u00D9\\u00DA\\u00DB\\u0168\\u1E78\\u016A\\u1E7A\\u016C\\u00DC\\u01DB\\u01D7\\u01D5\\u01D9\\u1EE6\\u016E\\u0170\\u01D3\\u0214\\u0216\\u01AF\\u1EEA\\u1EE8\\u1EEE\\u1EEC\\u1EF0\\u1EE4\\u1E72\\u0172\\u1E76\\u1E74\\u0244' },\n { base: 'V', letters: '\\u0056\\u24CB\\uFF36\\u1E7C\\u1E7E\\u01B2\\uA75E\\u0245' },\n { base: 'VY', letters: '\\uA760' },\n { base: 'W', letters: '\\u0057\\u24CC\\uFF37\\u1E80\\u1E82\\u0174\\u1E86\\u1E84\\u1E88\\u2C72' },\n { base: 'X', letters: '\\u0058\\u24CD\\uFF38\\u1E8A\\u1E8C' },\n { base: 'Y', letters: '\\u0059\\u24CE\\uFF39\\u1EF2\\u00DD\\u0176\\u1EF8\\u0232\\u1E8E\\u0178\\u1EF6\\u1EF4\\u01B3\\u024E\\u1EFE' },\n { base: 'Z', letters: '\\u005A\\u24CF\\uFF3A\\u0179\\u1E90\\u017B\\u017D\\u1E92\\u1E94\\u01B5\\u0224\\u2C7F\\u2C6B\\uA762' },\n { base: 'a', letters: '\\u0061\\u24D0\\uFF41\\u1E9A\\u00E0\\u00E1\\u00E2\\u1EA7\\u1EA5\\u1EAB\\u1EA9\\u00E3\\u0101\\u0103\\u1EB1\\u1EAF\\u1EB5\\u1EB3\\u0227\\u01E1\\u00E4\\u01DF\\u1EA3\\u00E5\\u01FB\\u01CE\\u0201\\u0203\\u1EA1\\u1EAD\\u1EB7\\u1E01\\u0105\\u2C65\\u0250' },\n { base: 'aa', letters: '\\uA733' },\n { base: 'ae', letters: '\\u00E6\\u01FD\\u01E3' },\n { base: 'ao', letters: '\\uA735' },\n { base: 'au', letters: '\\uA737' },\n { base: 'av', letters: '\\uA739\\uA73B' },\n { base: 'ay', letters: '\\uA73D' },\n { base: 'b', letters: '\\u0062\\u24D1\\uFF42\\u1E03\\u1E05\\u1E07\\u0180\\u0183\\u0253' },\n { base: 'c', letters: '\\u0063\\u24D2\\uFF43\\u0107\\u0109\\u010B\\u010D\\u00E7\\u1E09\\u0188\\u023C\\uA73F\\u2184' },\n { base: 'd', letters: '\\u0064\\u24D3\\uFF44\\u1E0B\\u010F\\u1E0D\\u1E11\\u1E13\\u1E0F\\u0111\\u018C\\u0256\\u0257\\uA77A' },\n { base: 'dz', letters: '\\u01F3\\u01C6' },\n { base: 'e', letters: '\\u0065\\u24D4\\uFF45\\u00E8\\u00E9\\u00EA\\u1EC1\\u1EBF\\u1EC5\\u1EC3\\u1EBD\\u0113\\u1E15\\u1E17\\u0115\\u0117\\u00EB\\u1EBB\\u011B\\u0205\\u0207\\u1EB9\\u1EC7\\u0229\\u1E1D\\u0119\\u1E19\\u1E1B\\u0247\\u025B\\u01DD' },\n { base: 'f', letters: '\\u0066\\u24D5\\uFF46\\u1E1F\\u0192\\uA77C' },\n { base: 'g', letters: '\\u0067\\u24D6\\uFF47\\u01F5\\u011D\\u1E21\\u011F\\u0121\\u01E7\\u0123\\u01E5\\u0260\\uA7A1\\u1D79\\uA77F' },\n { base: 'h', letters: '\\u0068\\u24D7\\uFF48\\u0125\\u1E23\\u1E27\\u021F\\u1E25\\u1E29\\u1E2B\\u1E96\\u0127\\u2C68\\u2C76\\u0265' },\n { base: 'hv', letters: '\\u0195' },\n { base: 'i', letters: '\\u0069\\u24D8\\uFF49\\u00EC\\u00ED\\u00EE\\u0129\\u012B\\u012D\\u00EF\\u1E2F\\u1EC9\\u01D0\\u0209\\u020B\\u1ECB\\u012F\\u1E2D\\u0268\\u0131' },\n { base: 'j', letters: '\\u006A\\u24D9\\uFF4A\\u0135\\u01F0\\u0249' },\n { base: 'k', letters: '\\u006B\\u24DA\\uFF4B\\u1E31\\u01E9\\u1E33\\u0137\\u1E35\\u0199\\u2C6A\\uA741\\uA743\\uA745\\uA7A3' },\n { base: 'l', letters: '\\u006C\\u24DB\\uFF4C\\u0140\\u013A\\u013E\\u1E37\\u1E39\\u013C\\u1E3D\\u1E3B\\u017F\\u0142\\u019A\\u026B\\u2C61\\uA749\\uA781\\uA747' },\n { base: 'lj', letters: '\\u01C9' },\n { base: 'm', letters: '\\u006D\\u24DC\\uFF4D\\u1E3F\\u1E41\\u1E43\\u0271\\u026F' },\n { base: 'n', letters: '\\u006E\\u24DD\\uFF4E\\u01F9\\u0144\\u00F1\\u1E45\\u0148\\u1E47\\u0146\\u1E4B\\u1E49\\u019E\\u0272\\u0149\\uA791\\uA7A5' },\n { base: 'nj', letters: '\\u01CC' },\n { base: 'o', letters: '\\u006F\\u24DE\\uFF4F\\u00F2\\u00F3\\u00F4\\u1ED3\\u1ED1\\u1ED7\\u1ED5\\u00F5\\u1E4D\\u022D\\u1E4F\\u014D\\u1E51\\u1E53\\u014F\\u022F\\u0231\\u00F6\\u022B\\u1ECF\\u0151\\u01D2\\u020D\\u020F\\u01A1\\u1EDD\\u1EDB\\u1EE1\\u1EDF\\u1EE3\\u1ECD\\u1ED9\\u01EB\\u01ED\\u00F8\\u01FF\\u0254\\uA74B\\uA74D\\u0275' },\n { base: 'oi', letters: '\\u01A3' },\n { base: 'ou', letters: '\\u0223' },\n { base: 'oo', letters: '\\uA74F' },\n { base: 'p', letters: '\\u0070\\u24DF\\uFF50\\u1E55\\u1E57\\u01A5\\u1D7D\\uA751\\uA753\\uA755' },\n { base: 'q', letters: '\\u0071\\u24E0\\uFF51\\u024B\\uA757\\uA759' },\n { base: 'r', letters: '\\u0072\\u24E1\\uFF52\\u0155\\u1E59\\u0159\\u0211\\u0213\\u1E5B\\u1E5D\\u0157\\u1E5F\\u024D\\u027D\\uA75B\\uA7A7\\uA783' },\n { base: 's', letters: '\\u0073\\u24E2\\uFF53\\u00DF\\u015B\\u1E65\\u015D\\u1E61\\u0161\\u1E67\\u1E63\\u1E69\\u0219\\u015F\\u023F\\uA7A9\\uA785\\u1E9B' },\n { base: 't', letters: '\\u0074\\u24E3\\uFF54\\u1E6B\\u1E97\\u0165\\u1E6D\\u021B\\u0163\\u1E71\\u1E6F\\u0167\\u01AD\\u0288\\u2C66\\uA787' },\n { base: 'tz', letters: '\\uA729' },\n { base: 'u', letters: '\\u0075\\u24E4\\uFF55\\u00F9\\u00FA\\u00FB\\u0169\\u1E79\\u016B\\u1E7B\\u016D\\u00FC\\u01DC\\u01D8\\u01D6\\u01DA\\u1EE7\\u016F\\u0171\\u01D4\\u0215\\u0217\\u01B0\\u1EEB\\u1EE9\\u1EEF\\u1EED\\u1EF1\\u1EE5\\u1E73\\u0173\\u1E77\\u1E75\\u0289' },\n { base: 'v', letters: '\\u0076\\u24E5\\uFF56\\u1E7D\\u1E7F\\u028B\\uA75F\\u028C' },\n { base: 'vy', letters: '\\uA761' },\n { base: 'w', letters: '\\u0077\\u24E6\\uFF57\\u1E81\\u1E83\\u0175\\u1E87\\u1E85\\u1E98\\u1E89\\u2C73' },\n { base: 'x', letters: '\\u0078\\u24E7\\uFF58\\u1E8B\\u1E8D' },\n { base: 'y', letters: '\\u0079\\u24E8\\uFF59\\u1EF3\\u00FD\\u0177\\u1EF9\\u0233\\u1E8F\\u00FF\\u1EF7\\u1E99\\u1EF5\\u01B4\\u024F\\u1EFF' },\n { base: 'z', letters: '\\u007A\\u24E9\\uFF5A\\u017A\\u1E91\\u017C\\u017E\\u1E93\\u1E95\\u01B6\\u0225\\u0240\\u2C6C\\uA763' }\n ];\n\n const diacriticsMap = {};\n for (let i = 0; i < defaultDiacriticsRemovalap.length; i++) {\n const letters = defaultDiacriticsRemovalap[i].letters.split('');\n for (let j = 0; j < letters.length; j++) {\n diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base;\n }\n }\n\n // eslint-disable-next-line no-control-regex\n return str.replace(/[^\\u0000-\\u007E]/g, function (a) {\n return diacriticsMap[a] || a;\n });\n }\n\n };\n }\n]);\n","'use strict';\n\nApplication.Services.factory('dialogs', ['$uibModal', function ($uibModal) {\n return ({\n confirm (options, success, error) {\n const defaultOpts = {\n templateUrl: '/shared/confirm_modal.html',\n size: 'sm',\n resolve: {\n object () {\n return {\n title: 'Titre de confirmation',\n msg: 'Message de confirmation'\n };\n }\n },\n controller: ['$scope', '$uibModalInstance', '$state', 'object', function ($scope, $uibModalInstance, $state, object) {\n $scope.object = object;\n $scope.ok = function (info) { $uibModalInstance.close(info); };\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }]\n };\n if (angular.isObject(options)) { angular.extend(defaultOpts, options); }\n return $uibModal.open(defaultOpts)\n .result.finally(null).then(function (info) {\n if (angular.isFunction(success)) {\n return success(info);\n }\n }\n , function (reason) {\n if (angular.isFunction(error)) {\n return error(reason);\n }\n });\n }\n });\n}]);\n","Application.Services.service('es', ['esFactory', function (esFactory) {\n return esFactory({ host: window.location.origin });\n}]);\n","'use strict';\n\nApplication.Services.factory('Event', ['$resource', function ($resource) {\n return $resource('/api/events/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n },\n upcoming: {\n method: 'GET',\n url: '/api/events/upcoming/:limit',\n params: { limit: '@limit' },\n isArray: true\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('EventTheme', ['$resource', function ($resource) {\n return $resource('/api/event_themes/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Export', ['$http', function ($http) {\n return ({\n status (query) {\n return $http.post('/api/exports/status', query);\n }\n });\n}]);\n","Application.Services.factory('FabAnalytics', ['$resource', function ($resource) {\n return $resource('/api/analytics',\n {}, {\n data: {\n method: 'GET',\n url: '/api/analytics/data'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Group', ['$resource', function ($resource) {\n return $resource('/api/groups/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Help', ['$rootScope', '$uibModal', '$state', 'AuthService',\n function ($rootScope, $uibModal, $state, AuthService) {\n const TOURS = {\n 'app.public.home': 'welcome',\n 'app.public.machines_list': 'machines',\n 'app.public.spaces_list': 'spaces',\n 'app.admin.trainings': 'trainings',\n 'app.admin.calendar': 'calendar',\n 'app.admin.members': 'members',\n 'app.admin.invoices': 'invoices',\n 'app.admin.pricing': 'pricing',\n 'app.admin.events': 'events',\n 'app.admin.projects': 'projects',\n 'app.admin.statistics': 'statistics',\n 'app.admin.settings': 'settings',\n 'app.admin.open_api_clients': 'open-api'\n };\n\n return function (e) {\n if (!AuthService.isAuthorized(['admin', 'manager'])) return;\n\n if (e.key === 'F1') {\n e.preventDefault();\n // retrieve the tour name, based on the current location\n const tourName = TOURS[$state.current.name];\n\n // if no tour, just open the guide\n if (tourName === undefined) {\n return window.open('http://guide-fr.fab.mn', '_blank');\n }\n\n $uibModal.open({\n animation: true,\n templateUrl: '/shared/help_modal.html',\n resolve: {\n tourName: function () { return tourName; }\n },\n controller: ['$scope', '$uibModalInstance', 'uiTourService', 'tourName', function ($scope, $uibModalInstance, uiTourService, tourName) {\n // start the tour and hide the modal\n $scope.onTour = function () {\n const tour = uiTourService.getTourByName(tourName);\n if (tour) { tour.start(); }\n\n $uibModalInstance.close('tour');\n };\n\n // open the user's guide and hide the modal\n $scope.onGuide = function () {\n $uibModalInstance.close('guide');\n };\n }]\n });\n }\n };\n }]);\n","'use strict';\n\nApplication.Services.factory('helpers', ['AuthService', function (AuthService) {\n return ({\n getAmountToPay (price, walletAmount) {\n if (walletAmount > price) { return 0; } else { return price - walletAmount; }\n },\n\n isUserValidationRequired (settings, type) {\n return settings.user_validation_required === 'true' &&\n settings.user_validation_required_list &&\n settings.user_validation_required_list.split(',').includes(type);\n },\n\n isUserValidated (user) {\n return !!(user?.validated_at);\n },\n\n isUserValidatedByType (user, settings, type) {\n return AuthService.isAuthorized(['admin', 'manager']) || (!this.isUserValidationRequired(settings, type) || (\n this.isUserValidationRequired(settings, type) && this.isUserValidated(user)));\n }\n });\n}]);\n","'use strict';\n\nApplication.Services.factory('Ical', ['$resource', function ($resource) {\n return $resource('/api/ical/externals');\n}]);\n","'use strict';\n\nApplication.Services.factory('ICalendar', ['$resource', function ($resource) {\n return $resource('/api/i_calendar/:id',\n { id: '@id' }, {\n events: {\n method: 'GET',\n url: '/api/i_calendar/:id/events'\n },\n sync: {\n method: 'POST',\n url: '/api/i_calendar/:id/sync',\n params: { id: '@id' }\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Import', ['$resource', function ($resource) {\n return $resource('/api/imports/:id',\n { id: '@id' }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Invoice', ['$resource', function ($resource) {\n return $resource('/api/invoices/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n },\n list: {\n url: '/api/invoices/list',\n method: 'POST',\n isArray: true\n },\n first: {\n url: '/api/invoices/first',\n method: 'GET'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Licence', ['$resource', function ($resource) {\n return $resource('/api/licences/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('LocalPayment', ['$resource', function ($resource) {\n return $resource('/api/local_payment',\n {}, {\n confirm: {\n method: 'POST',\n url: '/api/local_payment/confirm_payment',\n isArray: false\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Machine', ['$resource', function ($resource) {\n return $resource('/api/machines/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('MachineCategory', ['$resource', function ($resource) {\n return $resource('/api/machine_categories/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Member', ['$resource', 'Setting', function ($resource, Setting) {\n return $resource('/api/members/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n },\n lastSubscribed: {\n method: 'GET',\n url: '/api/last_subscribed/:limit',\n params: { limit: '@limit' },\n isArray: true\n },\n merge: {\n method: 'PUT',\n url: '/api/members/:id/merge'\n },\n list: {\n url: '/api/members/list',\n method: 'POST',\n isArray: true\n },\n search: {\n method: 'GET',\n url: '/api/members/search/:query',\n params: { query: '@query' },\n isArray: true\n },\n mapping: {\n method: 'GET',\n url: '/api/members/mapping'\n },\n completeTour: {\n method: 'PATCH',\n url: '/api/members/:id/complete_tour',\n params: { id: '@id' },\n interceptor: {\n response: function (response) {\n return Setting.query({ names: \"['feature_tour_display']\" }).$promise.then((settings) => {\n if (settings.feature_tour_display === 'session') {\n Fablab.sessionTours.push(response.data.tours[0]);\n return { tours: Fablab.sessionTours };\n }\n return response.data;\n });\n }\n }\n },\n updateRole: {\n method: 'PATCH',\n url: '/api/members/:id/update_role'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Notification', ['$resource', function ($resource) {\n return $resource('/api/notifications/:id',\n { id: '@id' }, {\n query: {\n isArray: false\n },\n update: {\n method: 'PUT'\n },\n polling: {\n url: '/api/notifications/polling',\n method: 'GET'\n },\n last_unread: {\n url: '/api/notifications/last_unread',\n method: 'GET'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('OpenAPIClient', ['$resource', function ($resource) {\n return $resource('/api/open_api_clients/:id',\n { id: '@id' }, {\n resetToken: {\n method: 'PATCH',\n url: '/api/open_api_clients/:id/reset_token'\n },\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('OpenlabProject', ['$resource', function ($resource) {\n return $resource('/api/openlab_projects/:id',\n { id: '@id' }, {\n query: {\n method: 'GET',\n isArray: false\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('paginationService', [function () {\n const helpers = {};\n\n helpers.pageCount = (totalCount, perPage) => Math.ceil(totalCount / perPage);\n\n helpers.hasNextPage = function (currentPage, totalCount, perPage) {\n const _pageCount = helpers.pageCount(totalCount, perPage);\n return (_pageCount !== currentPage) && (_pageCount !== 0);\n };\n\n const Instance = function (resourceService, currentPage, perPage, totalCount, defaultQueryParams, callback, functionName) {\n this.resourceService = resourceService;\n this.currentPage = currentPage;\n this.perPage = perPage;\n this.totalCount = totalCount;\n this.defaultQueryParams = defaultQueryParams;\n this.callback = callback;\n this.functionName = functionName || 'query';\n this.loading = false;\n\n this.pageCount = function () {\n return helpers.pageCount(this.totalCount, this.perPage);\n };\n\n this.hasNextPage = function () {\n return helpers.hasNextPage(this.currentPage, this.totalCount, this.perPage);\n };\n\n this.loadMore = function (queryParams) {\n let k, v;\n this.currentPage += 1;\n this.loading = true;\n\n const _queryParams = { page: this.currentPage, per_page: this.perPage };\n\n if (queryParams) {\n for (k in queryParams) {\n v = queryParams[k];\n _queryParams[k] = v;\n }\n }\n\n for (k in this.defaultQueryParams) {\n v = this.defaultQueryParams[k];\n _queryParams[k] = v;\n }\n\n this.resourceService[this.functionName](_queryParams, dataPromise => {\n this.callback(dataPromise);\n this.loading = false;\n });\n };\n };\n\n return { Instance };\n}\n]);\n","'use strict';\n\nApplication.Services.factory('Payment', ['$resource', function ($resource) {\n return $resource('/api/payments',\n {}, {\n confirm: {\n method: 'POST',\n url: '/api/stripe/confirm_payment',\n isArray: false\n },\n onlinePaymentStatus: {\n method: 'GET',\n url: '/api/stripe/online_payment_status'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Plan', ['$resource', function ($resource) {\n return $resource('/api/plans/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('PlanCategory', ['$resource', function ($resource) {\n return $resource('/api/plan_categories');\n}]);\n","'use strict';\n\nApplication.Services.factory('Price', ['$resource', function ($resource) {\n return $resource('/api/prices/:id',\n {}, {\n query: {\n isArray: true\n },\n update: {\n method: 'PUT'\n },\n compute: {\n method: 'POST',\n url: '/api/prices/compute',\n isArray: false\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('PriceCategory', ['$resource', function ($resource) {\n return $resource('/api/price_categories/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Pricing', ['$resource', function ($resource) {\n return $resource('/api/pricing',\n {}, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('ProfileCustomField', ['$resource', function ($resource) {\n return $resource('/api/profile_custom_fields/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Project', ['$resource', function ($resource) {\n return $resource('/api/projects/:id',\n { id: '@id' }, {\n lastPublished: {\n method: 'GET',\n url: '/api/projects/last_published',\n isArray: true\n },\n search: {\n method: 'GET',\n url: '/api/projects/search',\n isArray: false\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Reservation', ['$resource', function ($resource) {\n return $resource('/api/reservations/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.service('Session', [function () {\n this.create = function (user) {\n this.currentUser = user;\n };\n\n this.destroy = function () {\n this.currentUser = null;\n };\n\n return this;\n}]);\n","'use strict';\n\nApplication.Services.factory('Setting', ['$resource', function ($resource) {\n return $resource('/api/settings/:name',\n { name: '@name' }, {\n update: {\n method: 'PUT',\n transformRequest: (data) => {\n return angular.toJson({ setting: data });\n }\n },\n bulkUpdate: {\n url: '/api/settings/bulk_update',\n method: 'PATCH'\n },\n query: {\n isArray: false\n },\n reset: {\n url: '/api/settings/reset/:name',\n params: { name: '@name' },\n method: 'PUT'\n },\n isPresent: {\n url: '/api/settings/is_present/:name',\n params: { name: '@name' },\n method: 'GET'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('SlotsReservation', ['$resource', function ($resource) {\n return $resource('/api/slots_reservations/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n },\n cancel: {\n method: 'PUT',\n url: '/api/slots_reservations/:id/cancel'\n }\n }\n );\n}]);\n","'use strict';\n\n// list the social networks supported in the user's profiles\nApplication.Services.factory('SocialNetworks', [function () {\n return ['facebook', 'twitter', 'viadeo', 'linkedin', 'instagram', 'youtube', 'vimeo', 'dailymotion', 'github', 'echosciences', 'website', 'pinterest', 'lastfm', 'flickr'];\n}]);\n","'use strict';\n\nApplication.Services.factory('Space', ['$resource', function ($resource) {\n return $resource('/api/spaces/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Statistics', ['$resource', function ($resource) {\n return $resource('/api/statistics');\n}]);\n","'use strict';\n\nApplication.Services.factory('Status', ['$resource', function ($resource) {\n return $resource('/api/statuses/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Subscription', ['$resource', function ($resource) {\n return $resource('/api/subscriptions/:id',\n { id: '@id' }, {\n payment_details: {\n url: '/api/subscriptions/:id/payment_details',\n method: 'GET'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('SupportingDocumentType', ['$resource', function ($resource) {\n return $resource('/api/supporting_document_types/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Tag', ['$resource', function ($resource) {\n return $resource('/api/tags/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Theme', ['$resource', function ($resource) {\n return $resource('/api/themes/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Training', ['$resource', function ($resource) {\n return $resource('/api/trainings/:id',\n { id: '@id' }, {\n update: {\n method: 'PUT'\n },\n availabilities: {\n method: 'GET',\n url: '/api/trainings/:id/availabilities'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('TrainingsPricing', ['$resource', function ($resource) {\n return $resource('/api/trainings_pricings/:id',\n {}, {\n update: {\n method: 'PUT'\n }\n }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Translations', ['$translatePartialLoader', '$translate', function ($translatePartialLoader, $translate) {\n return ({\n query (stateName) {\n if (angular.isArray((stateName))) {\n angular.forEach(stateName, state => $translatePartialLoader.addPart(state));\n } else {\n $translatePartialLoader.addPart(stateName);\n }\n return $translate.refresh();\n }\n });\n}]);\n","'use strict';\n\nApplication.Services.factory('User', ['$resource', function ($resource) {\n return $resource('/api/users/:id',\n { id: '@id' }\n );\n}]);\n","'use strict';\n\nApplication.Services.factory('Version', ['$resource', function ($resource) {\n return $resource('/api/version/:origin',\n {}, {\n get: {\n method: 'POST'\n }\n });\n}]);\n","'use strict';\n\nApplication.Services.factory('Wallet', ['$resource', function ($resource) {\n return $resource('/api/wallet',\n {}, {\n getWalletByUser: {\n method: 'GET',\n url: '/api/wallet/by_user/:user_id',\n isArray: false\n },\n transactions: {\n method: 'GET',\n url: '/api/wallet/:id/transactions',\n isArray: true\n },\n credit: {\n method: 'PUT',\n url: '/api/wallet/:id/credit',\n isArray: false\n }\n }\n );\n}]);\n","import 'core-js/stable';\nimport 'regenerator-runtime/runtime';\n\nimport 'jquery';\nimport {} from 'jquery-ujs';\nimport 'bootstrap-sass';\nimport 'src/javascript/lib/polyfill';\nimport 'angular';\n\nimport 'angular-i18n/angular-locale_pt-br.js';\n\nimport 'angular-cookies';\nimport 'angular-resource';\nimport 'angular-sanitize';\nimport 'angular-touch';\nimport '@uirouter/angularjs';\nimport 'angular-ui-bootstrap';\nimport 'ui-select';\nimport 'moment';\n\nimport 'moment/locale/pt-br.js';\n\nimport 'moment-timezone';\nimport 'angular-ui-calendar';\nimport 'fullcalendar';\n\nimport 'fullcalendar/dist/locale/pt-br.js';\n\nimport 'angular-moment';\nimport 'ngUpload';\nimport 'jasny-bootstrap/js/fileinput';\nimport 'holderjs';\nimport 'AngularDevise';\nimport 'src/javascript/lib/devise-modal';\nimport 'angular-growl-v2';\nimport 'angular-xeditable';\nimport 'checklist-model/checklist-model';\nimport 'angular-unsavedchanges/lib/unsavedChanges';\nimport 'angular-loading-bar/src/loading-bar';\nimport 'angular-scroll/angular-scroll';\nimport 'src/javascript/lib/dirDisqus';\nimport 'src/javascript/lib/humanize';\nimport 'underscore/underscore';\nimport 'elasticsearch-browser/elasticsearch.angular';\nimport 'd3/d3';\nimport 'nvd3/build/nv.d3.js';\nimport 'twitter-fetcher';\nimport 'medium-editor/dist/js/medium-editor';\nimport 'angular-medium-editor/dist/angular-medium-editor';\nimport 'bootstrap-switch/dist/js/bootstrap-switch';\nimport 'angular-bootstrap-switch/dist/angular-bootstrap-switch';\nimport 'angular-base64-upload/dist/angular-base64-upload.min';\nimport 'summernote';\n\nimport 'summernote/lang/summernote-pt-BR.js';\n\nimport 'angular-summernote/dist/angular-summernote';\nimport 'src/javascript/lib/summernote-ext-nugget';\nimport '@claviska/jquery-minicolors/jquery.minicolors.js';\nimport 'angular-minicolors/angular-minicolors.js';\nimport 'angular-translate/dist/angular-translate';\nimport 'angular-translate-loader-partial/angular-translate-loader-partial';\nimport 'messageformat/messageformat';\nimport 'angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat';\nimport 'ng-fittext/dist/ng-FitText.min';\nimport 'angular-aside/dist/js/angular-aside';\nimport 'ng-caps-lock/ng-caps-lock';\nimport 'angular-recaptcha';\nimport 'codemirror/lib/codemirror';\nimport 'codemirror/addon/edit/matchbrackets';\nimport 'codemirror/mode/css/css';\nimport 'codemirror/mode/sass/sass';\nimport 'angular-ui-codemirror/src/ui-codemirror';\nimport 'angular-hotkeys/build/hotkeys';\nimport 'hone/dist/hone';\nimport 'tether/dist/js/tether';\nimport 'angular-bind-html-compile/angular-bind-html-compile';\nimport 'angular-ui-tour/app/angular-ui-tour';\nimport '@fortawesome/fontawesome-free';\nimport '@fortawesome/fontawesome-free/js/v4-shims';\nimport 'inputmask';\n\nrequire('src/javascript/app.js');\nrequire('src/javascript/router.js');\nrequire('src/javascript/plugins.js.erb');\n\nfunction importAll (r) { r.keys().forEach(r); }\n\n// we do not include markdown files (*.md)\nimportAll(require.context('src/javascript/components/', true, /^.+\\.(?!md).+/));\nimportAll(require.context('src/javascript/controllers/', true, /.*/));\nimportAll(require.context('src/javascript/services/', true, /.*/));\nimportAll(require.context('src/javascript/directives/', true, /.*/));\nimportAll(require.context('src/javascript/filters/', true, /.*/));\nimportAll(require.context('src/javascript/typings/', true, /.*/));\n\nimportAll(require.context('images', true));\nimportAll(require.context('templates', true));\n","/* eslint-disable\n camelcase,\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n\nApplication.Controllers.controller('EventsController', ['$scope', '$state', 'Event', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'growl',\n function ($scope, $state, Event, categoriesPromise, themesPromise, ageRangesPromise, growl) {\n /* PUBLIC SCOPE */\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n growl.error(message);\n };\n\n // The events displayed on the page\n $scope.events = [];\n\n // The currently displayed page number\n $scope.page = 1;\n\n // List of categories for the events\n $scope.categories = categoriesPromise;\n\n // List of events themes\n $scope.themes = themesPromise;\n\n // List of age ranges\n $scope.ageRanges = ageRangesPromise;\n\n // Hide or show the 'load more' button\n $scope.noMoreResults = false;\n\n // Active filters for the events list\n $scope.filters = {\n category_id: null,\n theme_id: null,\n age_range_id: null\n };\n\n $scope.monthNames = [\"Janeiro\", \"Fevereiro\", \"Março\", \"Abril\", \"Maio\", \"Junho\", \"Julho\", \"Agosto\", \"Setembro\", \"Outubro\", \"Novembro\", \"Dezembro\"];\n\n /**\n * Adds a resultset of events to the bottom of the page, grouped by month\n */\n $scope.loadMoreEvents = function () {\n $scope.page += 1;\n return Event.query(Object.assign({ page: $scope.page }, $scope.filters), function (data) {\n $scope.events = $scope.events.concat(data);\n groupEvents($scope.events);\n\n if (!data[0] || (data[0].nb_total_events <= $scope.events.length)) {\n return $scope.noMoreResults = true;\n }\n });\n };\n\n /**\n * Callback to redirect the user to the specified event page\n * @param event {{id:number}}\n */\n $scope.showEvent = function (event) { $state.go('app.public.events_show', { id: event.id }); };\n\n /**\n * Callback to refresh the events list according to the filters set\n */\n $scope.filterEvents = function () {\n // reinitialize results datasets\n $scope.page = 1;\n $scope.eventsGroupByMonth = {};\n $scope.featuredEevent = null;\n $scope.events = [];\n $scope.monthOrder = [];\n $scope.noMoreResults = false;\n\n // run a search query\n return Event.query(Object.assign({ page: $scope.page }, $scope.filters), function (data) {\n $scope.events = data;\n groupEvents(data);\n\n if (!data[0] || (data[0].nb_total_events <= $scope.events.length)) {\n return $scope.noMoreResults = true;\n }\n });\n };\n\n /**\n * Test if the provided event occurs on a single day or on many days\n * @param event {{start_date:Date, end_date:Date}} Event object as retreived from the API\n * @return {boolean} false if the event occurs on many days\n */\n $scope.onSingleDay = function (event) { moment(event.start_date).isSame(event.end_date, 'day'); };\n\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n $scope.filterEvents();\n };\n\n /**\n * Group the provided events by month/year and concat them with existing results\n * Then compute the ordered list of months for the complete resultset.\n * Affect the resulting events groups in $scope.eventsGroupByMonth and the ordered month keys in $scope.monthOrder.\n * @param events {Array} Events retrieved from the API\n */\n const groupEvents = function (events) {\n if (events.length > 0) {\n const eventsGroupedByMonth = _.groupBy(events, function (obj) {\n return _.map(['month_id', 'year'], function (key) {\n return obj[key];\n });\n });\n $scope.eventsGroupByMonth = Object.assign($scope.eventsGroupByMonth, eventsGroupedByMonth);\n $scope.monthOrder = Object.keys($scope.eventsGroupByMonth);\n $scope.featuredEevent = _.minBy(events.filter(e => moment(e.start_date).isAfter()), e => e.start_date);\n }\n };\n\n // # !!! MUST BE CALLED AT THE END of the controller\n initialize();\n }\n]);\n\nApplication.Controllers.controller('ShowEventController', ['$scope', '$state', '$rootScope', 'Event', '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'SlotsReservation', 'eventPromise', 'growl', '_t', 'Wallet', 'AuthService', 'helpers', 'dialogs', 'priceCategoriesPromise', 'settingsPromise', 'LocalPayment',\n function ($scope, $state,$rootScope, Event, $uibModal, Member, Reservation, Price, CustomAsset, SlotsReservation, eventPromise, growl, _t, Wallet, AuthService, helpers, dialogs, priceCategoriesPromise, settingsPromise, LocalPayment) {\n /* PUBLIC SCOPE */\n\n // reservations for the currently shown event\n $scope.reservations = [];\n\n // current date & time\n $scope.now = moment();\n\n // user to deal with\n $scope.ctrl =\n { member: {} };\n\n // parameters for a new reservation\n $scope.reserve = {\n nbPlaces: {\n normal: []\n },\n nbReservePlaces: 0,\n tickets: {},\n toReserve: false,\n amountTotal: 0,\n totalNoCoupon: 0,\n totalSeats: 0\n };\n\n // Discount coupon to apply to the basket, if any\n $scope.coupon =\n { applied: null };\n\n // Get the details for the current event (event's id is recovered from the current URL)\n $scope.event = eventPromise;\n $scope.eventEndDateTime = moment(`${eventPromise.end_date}T${eventPromise.end_time}:00`);\n\n // the application global settings\n $scope.settings = settingsPromise;\n\n // List of price categories for the events\n $scope.priceCategories = priceCategoriesPromise;\n\n // Global config: is the user authorized to change his bookings slots?\n $scope.enableBookingMove = (settingsPromise.booking_move_enable === 'true');\n\n // Global config: delay in hours before a booking while changing the booking slot is forbidden\n $scope.moveBookingDelay = parseInt(settingsPromise.booking_move_delay);\n\n // Global config: is the user authorized to cancel his booking slots?\n $scope.enableBookingCancel = settingsPromise.booking_cancel_enable === 'true';\n\n // Global config: delay in hours from now when restrictions occurs about cancelling reservations\n $scope.cancelBookingDelay = parseInt(settingsPromise.booking_cancel_delay);\n\n // Message displayed to the end user about rules that applies to events reservations\n $scope.eventExplicationsAlert = settingsPromise.event_explications_alert;\n\n // Global config: is the user validation required ?\n $scope.enableUserValidationRequired = settingsPromise.user_validation_required === 'true';\n\n // online payments (by card)\n $scope.onlinePayment = {\n showModal: false,\n cartItems: undefined\n };\n\n /**\n * Callback to delete the provided event (admins only)\n */\n $scope.deleteEvent = function () {\n // open a confirmation dialog\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/events/deleteRecurrent.html',\n size: 'md',\n controller: 'DeleteRecurrentEventController',\n resolve: {\n eventPromise: ['Event', function (Event) { return Event.get({ id: $scope.event.id }).$promise; }]\n }\n });\n // once the dialog was closed, do things depending on the result\n modalInstance.result.then(function (res) {\n if (res.status === 'success') {\n $state.go('app.public.events_list');\n }\n });\n };\n\n /**\n * Callback to call when the number of tickets to book changes in the current booking\n */\n $scope.changeNbPlaces = function () {\n // compute the total remaining places\n let remain = $scope.event.nb_free_places - $scope.reserve.nbReservePlaces;\n for (let ticket in $scope.reserve.tickets) {\n remain -= $scope.reserve.tickets[ticket];\n }\n // we store the total number of seats booked, this is used to know if the 'pay' button must be shown\n $scope.reserve.totalSeats = $scope.event.nb_free_places - remain;\n\n // update the available seats for full price tickets\n const fullPriceRemains = $scope.reserve.nbReservePlaces + remain;\n $scope.reserve.nbPlaces.normal = __range__(0, fullPriceRemains, true);\n\n // update the available seats for other prices tickets\n for (let key in $scope.reserve.nbPlaces) {\n if (key !== 'normal') {\n const priceRemain = $scope.reserve.tickets[key] + remain;\n $scope.reserve.nbPlaces[key] = __range__(0, priceRemain, true);\n }\n }\n\n // recompute the total price\n return $scope.computeEventAmount();\n };\n\n /**\n * Callback to reset the current reservation parameters\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.cancelReserve = function (e) {\n e.preventDefault();\n return resetEventReserve();\n };\n\n $scope.isUserValidatedByType = () => {\n return helpers.isUserValidatedByType($scope.ctrl.member, $scope.settings, 'event');\n };\n\n $scope.isShowReserveEventButton = () => {\n return $scope.event.nb_free_places > 0 &&\n !$scope.reserve.toReserve &&\n $scope.now.isBefore($scope.eventEndDateTime) &&\n helpers.isUserValidatedByType($scope.ctrl.member, $scope.settings, 'event');\n };\n\n /**\n * Callback to allow the user to set the details for his reservation\n */\n $scope.reserveEvent = function () {\n if ($scope.event.nb_total_places > 0) {\n $scope.reserveSuccess = false;\n if (!$scope.isAuthenticated()) {\n $scope.login(null, function (user) {\n if (user.role !== 'admin' || user.role !== 'manager') {\n $scope.ctrl.member = user;\n }\n const sameTimeReservations = findReservationsAtSameTime();\n if (sameTimeReservations.length > 0) {\n showReserveSlotSameTimeModal(sameTimeReservations, function(res) {\n $scope.reserve.toReserve = !$scope.reserve.toReserve;\n });\n } else {\n $scope.reserve.toReserve = !$scope.reserve.toReserve;\n }\n $scope.reserve.nbReservePlaces = 1;\n $scope.changeNbPlaces();\n });\n } else {\n if (AuthService.isAuthorized(['admin', 'manager'])) {\n $scope.reserve.toReserve = !$scope.reserve.toReserve;\n } else {\n Member.get({ id: $scope.currentUser.id }, function (member) {\n $scope.ctrl.member = member;\n const sameTimeReservations = findReservationsAtSameTime();\n if (sameTimeReservations.length > 0) {\n showReserveSlotSameTimeModal(sameTimeReservations, function(res) {\n $scope.reserve.toReserve = !$scope.reserve.toReserve;\n });\n } else {\n $scope.reserve.toReserve = !$scope.reserve.toReserve;\n }\n });\n }\n $scope.reserve.nbReservePlaces = 1;\n $scope.changeNbPlaces();\n }\n }\n };\n\n /**\n * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's\n * reservations. (admins only)\n */\n $scope.updateMember = function () {\n resetEventReserve();\n $scope.reserveSuccess = false;\n if ($scope.ctrl.member) {\n Member.get({ id: $scope.ctrl.member.id }, function (member) {\n $scope.ctrl.member = member;\n getReservations($scope.event.id, 'Event', $scope.ctrl.member.id);\n });\n }\n };\n\n /**\n * Callback to trigger the payment process of the current reservation\n */\n $scope.payEvent = function () {\n // first, we check that a user was selected\n if (Object.keys($scope.ctrl.member).length > 0) {\n const reservation = mkReservation($scope.reserve, $scope.event);\n\n return Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }, function (wallet) {\n const amountToPay = helpers.getAmountToPay($scope.reserve.amountTotal, wallet.amount);\n if ((AuthService.isAuthorized('member') && amountToPay > 0)\n || (AuthService.isAuthorized(['manager', 'admin']) && $scope.ctrl.member.id === $rootScope.currentUser.id && amountToPay > 0)) {\n if (settingsPromise.online_payment_module !== 'true') {\n growl.error(_t('app.public.events_show.online_payment_disabled'));\n } else {\n return payOnline(reservation);\n }\n } else {\n if (AuthService.isAuthorized(['manager', 'admin']) && $scope.ctrl.member.id !== $rootScope.currentUser.id\n || amountToPay === 0) {\n return payOnSite(reservation);\n }\n }\n });\n } else {\n // otherwise we alert, this error musn't occur when the current user is not admin\n return growl.error(_t('app.public.events_show.please_select_a_member_first'));\n }\n };\n\n /**\n * Callback to validate the booking of a free event\n */\n $scope.validReserveEvent = function () {\n const reservation = mkReservation($scope.reserve, $scope.event)\n const cartItems = mkCartItems(reservation, $scope.coupon.applied);\n // set the attempting marker\n $scope.attempting = true;\n // save the reservation to the API\n return LocalPayment.confirm(cartItems, function (reservation) {\n // reservation successful\n afterPayment(reservation);\n return $scope.attempting = false;\n }\n , function (response) {\n // reservation failed\n growl.error(response && response.data && response.data.card && response.data.card[0] || 'server error');\n // unset the attempting marker\n $scope.attempting = false;\n })\n };\n\n /**\n * Callback to cancel a reservation\n * @param reservation {Reservation}\n */\n $scope.cancelReservation = function(reservation) {\n dialogs.confirm({\n resolve: {\n object: function() {\n return {\n title: _t('app.public.events_show.cancel_the_reservation'),\n msg: _t('app.public.events_show.do_you_really_want_to_cancel_this_reservation_this_apply_to_all_booked_tickets')\n };\n }\n }\n }, function() { // cancel confirmed\n SlotsReservation.cancel({\n id: reservation.slots_reservations_attributes[0].id\n }, function() { // successfully canceled\n let index;\n growl.success(_t('app.public.events_show.reservation_was_successfully_cancelled'));\n index = $scope.reservations.indexOf(reservation);\n $scope.event.nb_free_places = $scope.event.nb_free_places + reservation.total_booked_seats;\n $scope.reservations[index].slots_reservations_attributes[0].canceled_at = new Date();\n }, function(error) {\n growl.warning(_t('app.public.events_show.cancellation_failed'));\n });\n });\n };\n\n /**\n * Test if the provided reservation has been cancelled\n * @param reservation {Reservation}\n * @returns {boolean}\n */\n $scope.isCancelled = function(reservation) {\n return !!(reservation.slots_reservations_attributes[0].canceled_at);\n }\n\n /**\n * Callback to alter an already booked reservation date. A modal window will be opened to allow the user to choose\n * a new date for his reservation (if any available)\n * @param reservation {Reservation}\n */\n $scope.modifyReservation = function (reservation) {\n const index = $scope.reservations.indexOf(reservation);\n return $uibModal.open({\n templateUrl: '/events/modify_event_reservation_modal.html',\n resolve: {\n event () { return $scope.event; },\n reservation () { return reservation; }\n },\n controller: ['$scope', '$uibModalInstance', 'event', 'reservation', 'Reservation', function ($scope, $uibModalInstance, event, reservation, Reservation) {\n // we copy the controller's resolved parameters into the scope\n $scope.event = event;\n $scope.reservation = angular.copy(reservation);\n\n // set the reservable_id to the first available event\n for (evt of Array.from(event.recurrence_events)) {\n if (evt.nb_free_places > reservation.total_booked_seats) {\n $scope.reservation.reservable_id = evt.id;\n break;\n }\n }\n\n // Callback to validate the new reservation's date\n $scope.ok = function () {\n let eventToPlace = null;\n angular.forEach(event.recurrence_events, function (e) {\n if (e.id === parseInt($scope.reservation.reservable_id, 10)) {\n return eventToPlace = e;\n }\n });\n $scope.reservation.slots_reservations_attributes[0].slot_id = eventToPlace.slot_id;\n $scope.attempting = true;\n Reservation.update({ id: reservation.id }, { reservation: $scope.reservation }, function (reservation) {\n $uibModalInstance.close(reservation);\n $scope.attempting = true;\n }\n , function (response) {\n $scope.alerts = [];\n angular.forEach(response, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({ msg: k + ': ' + err, type: 'danger' });\n });\n });\n $scope.attempting = false;\n });\n };\n\n // Callback to cancel the modification\n $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }\n ] })\n .result['finally'](null).then(function (reservation) {\n // remove the reservation from the user's reservations list for this event (occurrence)\n $scope.reservations.splice(index, 1);\n // add the number of places transfered (to the new date) to the total of free places for this event\n $scope.event.nb_free_places = $scope.event.nb_free_places + reservation.total_booked_seats;\n // remove the number of places transfered from the total of free places of the receiving occurrance\n angular.forEach($scope.event.recurrence_events, function (e) {\n if (e.id === parseInt(reservation.reservable.id, 10)) {\n return e.nb_free_places = e.nb_free_places - reservation.total_booked_seats;\n }\n });\n });\n };\n\n /**\n * Checks if the provided reservation is able to be moved (date change)\n * @param reservation {Reservation}\n */\n $scope.reservationCanModify = function (reservation) {\n if (AuthService.isAuthorized(['admin', 'manager'])) return true;\n\n const slotStart = moment(reservation.slots_reservations_attributes[0].slot_attributes.start_at);\n const now = moment();\n\n let isAble = false;\n angular.forEach($scope.event.recurrence_events, function (e) {\n if (e.nb_free_places >= reservation.total_booked_seats) { return isAble = true; }\n });\n return (isAble && $scope.enableBookingMove && (slotStart.diff(now, 'hours') >= $scope.moveBookingDelay));\n };\n\n /**\n * Checks if the provided reservation is able to be cancelled\n * @param reservation {Reservation}\n */\n $scope.reservationCanCancel = function(reservation) {\n if (AuthService.isAuthorized(['admin', 'manager'])) return true;\n\n const slotStart = moment(reservation.slots_reservations_attributes[0].slot_attributes.start_at);\n const now = moment();\n return $scope.enableBookingCancel && slotStart.diff(now, \"hours\") >= $scope.cancelBookingDelay;\n };\n\n /**\n * Compute the total amount for the current reservation according to the previously set parameters\n * and assign the result in $scope.reserve.amountTotal\n */\n $scope.computeEventAmount = function () {\n // first we check that a user was selected\n if (Object.keys($scope.ctrl.member).length > 0) {\n const r = mkReservation($scope.reserve, $scope.event);\n return Price.compute(mkCartItems(r, $scope.coupon.applied), function (res) {\n $scope.reserve.amountTotal = res.price;\n return $scope.reserve.totalNoCoupon = res.price_without_coupon;\n });\n } else {\n return $scope.reserve.amountTotal = null;\n }\n };\n\n /**\n * Return the URL allowing to share the current project on the Facebook social network\n */\n $scope.shareOnFacebook = function () { return `https://www.facebook.com/share.php?u=${$state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }).replace('#', '%23')}`; };\n\n /**\n * Return the URL allowing to share the current project on the Twitter social network\n */\n $scope.shareOnTwitter = function () { return `https://twitter.com/intent/tweet?url=${encodeURIComponent($state.href('app.public.events_show', { id: $scope.event.id }, { absolute: true }))}&text=${encodeURIComponent($scope.event.title)}`; };\n\n /**\n * Return the textual description of the conditions applyable to the given price's category\n * @param category_id {number} ID of the price's category\n */\n $scope.getPriceCategoryConditions = function (category_id) {\n for (let cat of Array.from($scope.priceCategories)) {\n if (cat.id === category_id) {\n return cat.conditions;\n }\n }\n };\n\n /**\n * This will open/close the online payment modal\n */\n $scope.toggleOnlinePaymentModal = (beforeApply) => {\n setTimeout(() => {\n $scope.onlinePayment.showModal = !$scope.onlinePayment.showModal;\n if (typeof beforeApply === 'function') {\n beforeApply();\n }\n $scope.$apply();\n }, 50);\n };\n\n /**\n * Invoked atfer a successful card payment\n * @param invoice {*} the invoice\n */\n $scope.afterOnlinePaymentSuccess = (invoice) => {\n $scope.toggleOnlinePaymentModal();\n afterPayment(invoice);\n };\n\n /**\n * Invoked when something wrong occurred during the payment dialog initialization\n * @param message {string}\n */\n $scope.onOnlinePaymentError = (message) => {\n growl.error(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n // set the controlled user as the current user if the current user is not an admin\n if ($scope.currentUser) {\n if ($scope.currentUser.role !== 'admin') {\n $scope.ctrl.member = $scope.currentUser;\n }\n }\n\n // initialize the \"reserve\" object with the event's data\n resetEventReserve();\n\n // get the current user's reservations into $scope.reservations\n if ($scope.currentUser) {\n getReservations($scope.event.id, 'Event', $scope.currentUser.id);\n }\n\n // watch when a coupon is applied to re-compute the total price\n $scope.$watch('coupon.applied', function (newValue, oldValue) {\n if ((newValue !== null) || (oldValue !== null)) {\n return $scope.computeEventAmount();\n }\n });\n };\n\n /**\n * Retrieve the reservations for the couple event / user\n * @param reservable_id {number} the current event id\n * @param reservable_type {string} 'Event'\n * @param user_id {number} the user's id (current or managed)\n */\n const getReservations = function (reservable_id, reservable_type, user_id) {\n Reservation.query({\n reservable_id,\n reservable_type,\n user_id\n }).$promise.then(function (reservations) { $scope.reservations = reservations; });\n };\n\n /**\n * Create a hash map implementing the Reservation specs\n * @param reserve {Object} Reservation parameters (places...)\n * @param event {Object} Current event\n * @return {{reservation: Reservation}}\n */\n const mkReservation = function (reserve, event) {\n const reservation = {\n reservable_id: event.id,\n reservable_type: 'Event',\n slots_reservations_attributes: [],\n nb_reserve_places: reserve.nbReservePlaces,\n tickets_attributes: []\n };\n\n reservation.slots_reservations_attributes.push({\n offered: event.offered || false,\n slot_id: event.availability.slot_id\n });\n\n for (let evt_px_cat of Array.from(event.event_price_categories_attributes)) {\n const booked = reserve.tickets[evt_px_cat.id];\n if (booked > 0) {\n reservation.tickets_attributes.push({\n event_price_category_id: evt_px_cat.id,\n booked\n });\n }\n }\n\n return { reservation };\n };\n\n /**\n * Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object\n * @param reservation {Object} as returned by mkReservation()\n * @param coupon {Object} Coupon as returned from the API\n * @param paymentMethod {string} 'card' | ''\n * @return {ShoppingCart}\n */\n const mkCartItems = function (reservation, coupon, paymentMethod = '') {\n return {\n customer_id: $scope.ctrl.member.id,\n items: [reservation],\n coupon_code: ((coupon ? coupon.code : undefined)),\n payment_method: paymentMethod,\n };\n };\n\n /**\n * Set the current reservation to the default values. This implies the reservation form to be hidden.\n */\n const resetEventReserve = function () {\n if ($scope.event) {\n $scope.reserve = {\n nbPlaces: {\n normal: __range__(0, $scope.event.nb_free_places > 1 ? 1 : $scope.event.nb_free_places, true)\n },\n nbReservePlaces: 0,\n tickets: {},\n toReserve: false,\n amountTotal: 0,\n totalSeats: 0\n };\n\n for (let evt_px_cat of Array.from($scope.event.event_price_categories_attributes)) {\n $scope.reserve.nbPlaces[evt_px_cat.id] = __range__(0, $scope.event.nb_free_places, true);\n $scope.reserve.tickets[evt_px_cat.id] = 0;\n }\n\n return $scope.event.offered = false;\n }\n };\n\n /**\n * Open a modal window which trigger the stripe payment process\n * @param reservation {Object} to book\n */\n const payOnline = function (reservation) {\n // check that the online payment is enabled\n if (settingsPromise.online_payment_module !== 'true') {\n growl.error(_t('app.shared.cart.online_payment_disabled'));\n } else {\n $scope.toggleOnlinePaymentModal(() => {\n $scope.onlinePayment.cartItems = mkCartItems(reservation, $scope.coupon.applied, 'card');\n });\n }\n };\n\n /**\n * Open a modal window which trigger the local payment process\n * @param reservation {Object} to book\n */\n const payOnSite = function (reservation) {\n $uibModal.open({\n templateUrl: '/shared/valid_reservation_modal.html',\n size: 'sm',\n resolve: {\n reservation () {\n return reservation;\n },\n price () {\n return Price.compute(mkCartItems(reservation, $scope.coupon.applied)).$promise;\n },\n wallet () {\n return Wallet.getWalletByUser({ user_id: $scope.ctrl.member.id }).$promise;\n },\n coupon () {\n return $scope.coupon.applied;\n },\n cartItems () {\n return mkCartItems(reservation, $scope.coupon.applied);\n },\n event () {\n return $scope.event;\n }\n },\n controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'LocalPayment', 'wallet', 'helpers', '$filter', 'coupon', 'cartItems', 'event',\n function ($scope, $uibModalInstance, $state, reservation, price, Auth, LocalPayment, wallet, helpers, $filter, coupon, cartItems, event) {\n // User's wallet amount\n $scope.wallet = wallet;\n\n // Price\n $scope.price = price.price;\n\n // Cart items\n $scope.cartItems = cartItems;\n\n // price to pay\n $scope.amount = helpers.getAmountToPay(price.price, wallet.amount);\n\n // Reservation\n $scope.reservation = reservation;\n\n // the event\n $scope.bookedEvent = event;\n\n // Used in wallet info template to interpolate some translations\n $scope.numberFilter = $filter('number');\n\n // Button label\n if ($scope.amount > 0) {\n $scope.validButtonName = _t('app.public.events_show.confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')($scope.amount) });\n } else {\n if ((price.price > 0) && ($scope.walletAmount === 0)) {\n $scope.validButtonName = _t('app.public.events_show.confirm_payment_of_html', { ROLE: $scope.currentUser.role, AMOUNT: $filter('currency')(price.price) });\n } else {\n $scope.validButtonName = _t('app.shared.buttons.confirm');\n }\n }\n\n // Callback to validate the payment\n $scope.ok = function () {\n $scope.attempting = true;\n return LocalPayment.confirm(cartItems, function (reservation) {\n $uibModalInstance.close(reservation);\n return $scope.attempting = true;\n }\n , function (response) {\n $scope.alerts = [];\n angular.forEach(response, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n return $scope.attempting = false;\n });\n };\n\n // Callback to cancel the payment\n return $scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };\n }\n ] })\n .result['finally'](null).then(function (reservation) { afterPayment(reservation); });\n };\n\n /**\n * What to do after the payment was successful\n * @param invoice {Object} the invoice for the booked reservation\n */\n const afterPayment = function (invoice) {\n Reservation.get({ id: invoice.main_object.id }, function (reservation) {\n $scope.event.nb_free_places = $scope.event.nb_free_places - reservation.total_booked_seats;\n $scope.reservations.push(reservation);\n });\n resetEventReserve();\n $scope.reserveSuccess = true;\n $scope.coupon.applied = null;\n if ($scope.currentUser.role === 'admin') {\n return $scope.ctrl.member = null;\n }\n };\n\n /**\n * Find user's reservations, the same date at the same time, with event\n */\n const findReservationsAtSameTime = function () {\n let sameTimeReservations = [\n 'training_reservations',\n 'machine_reservations',\n 'space_reservations',\n 'events_reservations'\n ].map(function(k) {\n return _.filter($scope.ctrl.member[k], function(r) {\n if (r.reservable_type === 'Event' && r.reservable.id === $scope.event.id) {\n return false;\n }\n return moment($scope.event.start_time).isSame(r.start_at) ||\n (moment($scope.event.end_time).isAfter(r.start_at) && moment($scope.event.end_time).isBefore(r.end_at)) ||\n (moment($scope.event.start_time).isAfter(r.start_at) && moment($scope.event.start_time).isBefore(r.end_at)) ||\n (moment($scope.event.start_time).isBefore(r.start_at) && moment($scope.event.end_time).isAfter(r.end_at));\n });\n });\n return _.union.apply(null, sameTimeReservations);\n };\n\n /**\n * A modal for show reservations the same date at the same time\n *\n * @param sameTimeReservations {Array} reservations the same date at the same time\n * @param callback {function} callback will invoke when user confirm\n */\n const showReserveSlotSameTimeModal = function(sameTimeReservations, callback) {\n const modalInstance = $uibModal.open({\n animation: true,\n templateUrl: '/shared/_reserve_slot_same_time.html',\n size: 'md',\n controller: 'ReserveSlotSameTimeController',\n resolve: {\n sameTimeReservations: function() { return sameTimeReservations; },\n bookOverlappingSlotsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'book_overlapping_slots' }).$promise; }]\n }\n });\n modalInstance.result.then(callback);\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\nfunction __range__ (left, right, inclusive) {\n let range = [];\n let ascending = left < right;\n let end = !inclusive ? right : ascending ? right + 1 : right - 1;\n for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) {\n range.push(i);\n }\n return range;\n}\n\n\n/**\n * Controller used in the event deletion modal window\n */\nApplication.Controllers.controller('DeleteRecurrentEventController', ['$scope', '$uibModalInstance', 'Event', 'eventPromise', 'growl', '_t',\n function ($scope, $uibModalInstance, Event, eventPromise, growl, _t) {\n\n // is the current event (to be deleted) recurrent?\n $scope.isRecurrent = eventPromise.recurrence_events.length > 0;\n\n // with recurrent slots: how many slots should we delete?\n $scope.deleteMode = 'single';\n\n /**\n * Confirmation callback\n */\n $scope.ok = function () {\n const { id, start_at, end_at } = eventPromise;\n // the admin has confirmed, delete the slot\n Event.delete(\n { id, mode: $scope.deleteMode },\n function (res) {\n // delete success\n if (res.deleted > 1) {\n growl.success(_t(\n 'app.public.events_show.events_deleted',\n {COUNT: res.deleted - 1}\n ));\n } else {\n growl.success(_t(\n 'app.public.events_show.event_successfully_deleted'\n ));\n }\n $uibModalInstance.close({\n status: 'success',\n events: res.details.map(function (d) { return d.event.id })\n });\n },\n function (res) {\n // not everything was deleted\n const { data } = res;\n if (data.total > 1) {\n growl.warning(_t(\n 'app.public.events_show.events_not_deleted',\n {TOTAL: data.total, COUNT: data.total - data.deleted}\n ));\n } else {\n growl.error(_t(\n 'app.public.events_show.unable_to_delete_the_event'\n ));\n }\n $uibModalInstance.close({\n status: 'failed',\n availabilities: data.details.filter(function (d) { return d.status }).map(function (d) { return d.event.id })\n });\n });\n }\n\n /**\n * Cancellation callback\n */\n $scope.cancel = function () {\n $uibModalInstance.dismiss('cancel');\n }\n }\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/* COMMON CODE */\n\n/**\n * Provides a set of common callback methods to the $scope parameter. These methods are used\n * in the various machines' admin controllers.\n *\n * Provides :\n * - $scope.submited(content)\n * - $scope.cancel()\n * - $scope.fileinputClass(v)\n * - $scope.addFile()\n * - $scope.deleteFile(file)\n *\n * Requires :\n * - $scope.machine.machine_files_attributes = []\n * - $state (Ui-Router) [ 'app.public.machines_list' ]\n */\nclass MachinesController {\n constructor ($scope, $state) {\n /**\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when the upload is done: any raised error will be stacked in the\n * $scope.alerts array. If everything goes fine, the user is redirected to the machines list.\n * @param content {Object} JSON - The upload's result\n */\n $scope.submited = function (content) {\n if ((content.id == null)) {\n $scope.alerts = [];\n angular.forEach(content, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n } else {\n return $state.go('app.public.machines_list');\n }\n };\n\n /**\n * Changes the current user's view, redirecting him to the machines list\n */\n $scope.cancel = function () { $state.go('app.public.machines_list'); };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n\n /**\n * This will create a single new empty entry into the machine attachements list.\n */\n $scope.addFile = function () { $scope.machine.machine_files_attributes.push({}); };\n\n /**\n * This will remove the given file from the machine attachements list. If the file was previously uploaded\n * to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from\n * the attachements array.\n * @param file {Object} the file to delete\n */\n $scope.deleteFile = function (file) {\n const index = $scope.machine.machine_files_attributes.indexOf(file);\n if (file.id != null) {\n return file._destroy = true;\n } else {\n return $scope.machine.machine_files_attributes.splice(index, 1);\n }\n };\n }\n}\n\n/**\n * Controller used in the public listing page, allowing everyone to see the list of machines\n */\nApplication.Controllers.controller('MachinesController', ['$scope', '$state', '_t', 'AuthService', 'Machine', '$uibModal', 'settingsPromise', 'Member', 'uiTourService', 'machinesPromise', 'growl', 'helpers',\n function ($scope, $state, _t, AuthService, Machine, $uibModal, settingsPromise, Member, uiTourService, machinesPromise, growl, helpers) {\n /* PUBLIC SCOPE */\n\n // the application global settings\n $scope.settings = settingsPromise;\n\n /**\n * Redirect the user to the machine details page\n */\n $scope.showMachine = function (machine) { $state.go('app.public.machines_show', { id: machine.slug }); };\n\n /**\n * Shows an error message forwarded from a child component\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n }\n\n /**\n * Shows a success message forwarded from a child react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message)\n }\n\n /**\n * Open the modal dialog to log the user and resolves the returned promise when the logging process\n * was successfully completed.\n */\n $scope.onLoginRequest = function (e) {\n return new Promise((resolve, _reject) => {\n $scope.login(e, resolve);\n });\n }\n\n /**\n * Redirect the user to the training reservation page\n */\n $scope.onEnrollRequest = function (trainingId) {\n $state.go('app.logged.trainings_reserve', { id: trainingId });\n }\n\n /**\n * Callback to book a reservation for the current machine\n */\n $scope.reserveMachine = function (machine) {\n $state.go('app.logged.machines_reserve', { id: machine.slug });\n }\n\n $scope.canProposePacks = function () {\n return AuthService.isAuthorized(['admin', 'manager']) || !helpers.isUserValidationRequired($scope.settings, 'pack') || (helpers.isUserValidationRequired($scope.settings, 'pack') && helpers.isUserValidated($scope.currentUser));\n };\n\n /**\n * Setup the feature-tour for the machines page. (admins only)\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupMachinesTour = function () {\n // setup the tour for admins only\n if (AuthService.isAuthorized(['admin', 'manager'])) {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('machines');\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.public.tour.machines.welcome.title'),\n content: _t('app.public.tour.machines.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n if (machinesPromise.length > 0) {\n uitour.createStep({\n selector: '.machines-list .show-button',\n stepId: 'view',\n order: 1,\n title: _t('app.public.tour.machines.view.title'),\n content: _t('app.public.tour.machines.view.content'),\n placement: 'top'\n });\n }\n } else {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome_manager',\n order: 0,\n title: _t('app.public.tour.machines.welcome_manager.title'),\n content: _t('app.public.tour.machines.welcome_manager.content'),\n placement: 'bottom',\n orphan: true\n });\n }\n if (machinesPromise.length > 0) {\n uitour.createStep({\n selector: '.machines-list .reserve-button',\n stepId: 'reserve',\n order: 2,\n title: _t('app.public.tour.machines.reserve.title'),\n content: _t('app.public.tour.machines.reserve.content'),\n placement: 'top'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 3,\n title: _t('app.public.tour.conclusion.title'),\n content: _t('app.public.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('machines') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'machines' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('machines') < 0) {\n uitour.start();\n }\n }\n }\n }\n]);\n\n/**\n * Controller used in the machine creation page (admin)\n */\nApplication.Controllers.controller('NewMachineController', ['$scope', '$state', 'CSRF', 'growl', function ($scope, $state, CSRF, growl) {\n CSRF.setMetaTags();\n\n /**\n * Shows an error message forwarded from a child component\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n }\n\n /**\n * Shows a success message forwarded from a child react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message)\n }\n\n // Using the MachinesController\n return new MachinesController($scope, $state);\n}\n]);\n\n/**\n * Controller used in the machine edition page (admin)\n */\nApplication.Controllers.controller('EditMachineController', ['$scope', '$state', '$transition$', 'machinePromise', 'machineCategoriesPromise', 'CSRF', 'growl',\n function ($scope, $state, $transition$, machinePromise, machineCategoriesPromise, CSRF, growl) {\n /* PUBLIC SCOPE */\n\n // Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list\n $scope.machine = cleanMachine(machinePromise);\n\n // Retrieve all machine categories\n $scope.machineCategories = machineCategoriesPromise;\n\n /**\n * Shows an error message forwarded from a child component\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n /**\n * Shows a success message forwarded from a child react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n CSRF.setMetaTags();\n\n // Using the MachinesController\n return new MachinesController($scope, $state);\n };\n\n // prepare the machine for the react-hook-form\n function cleanMachine (machine) {\n delete machine.$promise;\n delete machine.$resolved;\n return machine;\n }\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the machine details page (public)\n */\nApplication.Controllers.controller('ShowMachineController', ['$scope', '$state', '$uibModal', '_t', 'Machine', 'growl', 'machinePromise', 'dialogs',\n function ($scope, $state, $uibModal, _t, Machine, growl, machinePromise, dialogs) {\n // Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list\n $scope.machine = machinePromise;\n\n /**\n * Callback to delete the current machine (admins only)\n */\n $scope.delete = function (machine) {\n // check the permissions\n if ($scope.currentUser.role !== 'admin') {\n console.error(_t('app.public.machines_show.unauthorized_operation'));\n } else {\n dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.public.machines_show.confirmation_required'),\n msg: _t('app.public.machines_show.do_you_really_want_to_delete_this_machine')\n };\n }\n }\n }\n , function () { // deletion confirmed\n // delete the machine then redirect to the machines listing\n machine.$delete(\n function () { $state.go('app.public.machines_list'); },\n function (error) { growl.warning(_t('app.public.machines_show.the_machine_cant_be_deleted_because_it_is_already_reserved_by_some_users')); console.error(error); }\n );\n });\n }\n };\n\n /**\n * Shows an error message forwarded from a child component\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n }\n\n /**\n * Shows a success message forwarded from a child react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message)\n }\n\n\n /**\n * Open the modal dialog to log the user and resolves the returned promise when the logging process\n * was successfully completed.\n */\n $scope.onLoginRequest = function (e) {\n return new Promise((resolve, _reject) => {\n $scope.login(e, resolve);\n });\n }\n\n /**\n * Redirect the user to the training reservation page\n */\n $scope.onEnrollRequest = function (trainingId) {\n $state.go('app.logged.trainings_reserve', { id: trainingId });\n }\n\n /**\n * Callback to book a reservation for the current machine\n */\n $scope.reserveMachine = function (machine) {\n $state.go('app.logged.machines_reserve', { id: machine.slug });\n }\n }\n]);\n\n/**\n * Controller used in the machine reservation page (for logged users who have completed the training and admins).\n * This controller workflow is pretty similar to the trainings reservation controller.\n */\n\nApplication.Controllers.controller('ReserveMachineController', ['$scope', '$transition$', '_t', 'moment', 'Auth', '$timeout', 'Member', 'Availability', 'plansPromise', 'groupsPromise', 'machinePromise', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig', 'Reservation', 'growl', 'helpers', 'AuthService',\n function ($scope, $transition$, _t, moment, Auth, $timeout, Member, Availability, plansPromise, groupsPromise, machinePromise, settingsPromise, uiCalendarConfig, CalendarConfig, Reservation, growl, helpers, AuthService) {\n /* PRIVATE STATIC CONSTANTS */\n\n // Slot free to be booked\n const FREE_SLOT_BORDER_COLOR = '#e4cd78';\n\n /* PUBLIC SCOPE */\n\n // bind the machine availabilities with full-Calendar events\n $scope.eventSources = [];\n\n // indicates the state of the current view : calendar or plans information\n $scope.plansAreShown = false;\n\n // will store the user's plan if he chose to buy one\n $scope.selectedPlan = null;\n\n // the moment when the plan selection changed for the last time, used to trigger changes in the cart\n $scope.planSelectionTime = null;\n\n // mapping of fullCalendar events.\n $scope.events = {\n reserved: [], // Slots that the user wants to book\n modifiable: null, // Slot that the user wants to change\n placable: null, // Destination slot for the change\n paid: [], // Slots that were just booked by the user (transaction ok)\n moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *}\n };\n\n // the moment when the slot selection changed for the last time, used to trigger changes in the cart\n $scope.selectionTime = null;\n\n // the last clicked event in the calendar\n $scope.selectedEvent = null;\n\n // the application global settings\n $scope.settings = settingsPromise;\n\n // all plans, used in \n $scope.plans = plansPromise;\n\n // all groups, used in \n $scope.groups = groupsPromise;\n\n // the user to deal with, ie. the current user for non-admins\n $scope.ctrl =\n { member: {} };\n\n // current machine to reserve\n $scope.machine = machinePromise;\n\n // will be set to a Promise and resolved after the payment is sone\n $scope.afterPaymentPromise = null;\n\n // fullCalendar (v2) configuration\n $scope.calendarConfig = CalendarConfig({\n minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')),\n maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')),\n eventClick (event, jsEvent, view) {\n return calendarEventClickCb(event, jsEvent, view);\n },\n eventRender (event, element, view) {\n return eventRenderCb(event, element);\n }\n });\n\n // Global config: message to the end user concerning the subscriptions rules\n $scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert;\n\n // Global config: message to the end user concerning the machine bookings\n $scope.machineExplicationsAlert = settingsPromise.machine_explications_alert;\n\n // Global config: is the user validation required ?\n $scope.enableUserValidationRequired = settingsPromise.user_validation_required === 'true';\n\n /**\n * Change the last selected slot's appearance to looks like 'added to cart'\n */\n $scope.markSlotAsAdded = function (slot) {\n let calSlot = { ...slot };\n calSlot.backgroundColor = FREE_SLOT_BORDER_COLOR;\n calSlot.oldTitle = $scope.selectedEvent.title;\n calSlot.title = _t('app.logged.machines_reserve.i_reserve');\n updateEvents(calSlot);\n };\n\n /**\n * Change the last selected slot's appearance to looks like 'never added to cart'\n */\n $scope.markSlotAsRemoved = function (slot) {\n let calSlot = { ...slot };\n calSlot.backgroundColor = 'white';\n calSlot.borderColor = FREE_SLOT_BORDER_COLOR;\n calSlot.title = calSlot.oldTitle;\n updateEvents(calSlot);\n };\n\n /**\n * Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'\n */\n $scope.slotCancelled = function () { refreshCalendar() };\n\n /**\n * Change the last selected slot's appearance to looks like 'currently looking for a new destination to exchange'\n */\n $scope.markSlotAsModifying = function () {\n $scope.selectedEvent.backgroundColor = '#eee';\n $scope.selectedEvent.oldTitle = $scope.selectedEvent.title;\n $scope.selectedEvent.title = _t('app.logged.machines_reserve.i_change');\n updateEvents($scope.selectedEvent);\n };\n\n /**\n * Change the last selected slot's appearance to looks like 'the slot being exchanged will take this place'\n */\n $scope.changeModifyMachineSlot = function () {\n if ($scope.events.placable) {\n $scope.events.placable.backgroundColor = 'white';\n $scope.events.placable.title = '';\n updateEvents($scope.events.placable);\n }\n if (!$scope.events.placable || ($scope.events.placable._id !== $scope.selectedEvent._id)) {\n $scope.selectedEvent.backgroundColor = '#bbb';\n $scope.selectedEvent.title = _t('app.logged.machines_reserve.i_shift');\n updateEvents($scope.selectedEvent);\n }\n return true;\n };\n\n /**\n * When modifying an already booked reservation, callback when the modification was successfully done.\n */\n $scope.modifyMachineSlot = function () {\n refreshCalendar();\n };\n\n /**\n * Cancel the current booking modification, resetting the whole process\n */\n $scope.cancelModifyMachineSlot = function () {\n if ($scope.events.placable) {\n $scope.events.placable.backgroundColor = 'white';\n $scope.events.placable.title = '';\n }\n $scope.events.modifiable.title = $scope.events.modifiable.oldTitle;\n $scope.events.modifiable.backgroundColor = 'white';\n\n updateEvents($scope.events.placable, $scope.events.modifiable);\n };\n\n /**\n * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's\n * reservations. (admins only)\n */\n $scope.updateMember = function () {\n $scope.plansAreShown = false;\n $scope.selectedPlan = null;\n Member.get({ id: $scope.ctrl.member.id }, function (member) {\n $scope.ctrl.member = member;\n refreshCalendar();\n });\n };\n\n /**\n * Changes the user current view from the plan subscription screen to the machine reservation agenda\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.doNotSubscribePlan = function (e) {\n e.preventDefault();\n $scope.plansAreShown = false;\n $scope.selectPlan($scope.selectedPlan);\n return $scope.planSelectionTime = new Date();\n };\n\n /**\n * Switch the user's view from the reservation agenda to the plan subscription\n */\n $scope.showPlans = function () { $scope.plansAreShown = true; };\n\n /**\n * Add the provided plan to the current shopping cart\n * @param plan {Object} the plan to subscribe\n */\n $scope.selectPlan = function (plan) {\n setTimeout(() => {\n // toggle selected plan\n if ($scope.selectedPlan !== plan) {\n $scope.selectedPlan = plan;\n } else {\n $scope.selectedPlan = null;\n }\n $scope.planSelectionTime = new Date();\n $scope.$apply();\n }, 50);\n };\n\n $scope.canSelectPlan = function () {\n return helpers.isUserValidatedByType($scope.ctrl.member, $scope.settings, 'subscription');\n };\n\n /**\n * Check if the provided plan is currently selected\n * @param plan {Object} Resource plan\n */\n $scope.isSelected = function (plan) {\n return $scope.selectedPlan === plan;\n };\n\n /**\n * Once the reservation is booked (payment process successfully completed), change the event style\n * in fullCalendar, update the user's subscription and free-credits if needed\n * @param paymentDocument {Invoice|PaymentSchedule}\n */\n $scope.afterPayment = function (paymentDocument) {\n Reservation.get({ id: paymentDocument.main_object.id }, function (reservation) {\n if ($scope.selectedPlan) {\n $scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);\n if ($scope.ctrl.member.id === Auth._currentUser.id) {\n Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);\n }\n $scope.plansAreShown = false;\n $scope.selectedPlan = null;\n }\n $scope.ctrl.member.training_credits = angular.copy(reservation.user.training_credits);\n $scope.ctrl.member.machine_credits = angular.copy(reservation.user.machine_credits);\n if ($scope.ctrl.member.id === Auth._currentUser.id) {\n Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits);\n Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);\n }\n\n refreshCalendar();\n\n // trigger the refresh of react components\n setTimeout(() => {\n $scope.afterPaymentPromise = new Promise(resolve => {\n resolve();\n });\n $scope.$apply();\n }, 50);\n });\n };\n\n /**\n * To use as callback in Array.prototype.filter to get only enabled plans\n */\n $scope.filterDisabledPlans = function (plan) { return !plan.disabled; };\n\n /**\n * Callback triggered after a successful prepaid-pack purchase\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n $scope.isShowPacks = function () {\n return !helpers.isUserValidationRequired($scope.settings, 'pack') || (helpers.isUserValidationRequired($scope.settings, 'pack') && helpers.isUserValidated($scope.ctrl.member));\n };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n $scope.eventSources.push({\n url: `/api/availabilities/machines/${$transition$.params().id}`,\n textColor: 'black'\n });\n\n if ($scope.currentUser.role !== 'admin') {\n $scope.ctrl.member = $scope.currentUser;\n return Member.get({ id: $scope.currentUser.id }, function (member) { $scope.ctrl.member = member; });\n }\n };\n\n /**\n * Triggered when the user click on a reservation slot in the agenda.\n * Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...),\n * the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation\n * if it's too late).\n */\n const calendarEventClickCb = function (event, jsEvent, view) {\n if (!AuthService.isAuthorized(['admin', 'manager']) && (helpers.isUserValidationRequired($scope.settings, 'machine') && !helpers.isUserValidated($scope.ctrl.member))) {\n return;\n }\n $scope.selectedEvent = event;\n $scope.selectionTime = new Date();\n };\n\n /**\n * Refetch all events from the API and re-populate the calendar with the resulting slots\n */\n const refreshCalendar = function () {\n const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');\n return Availability.machine({\n machineId: $scope.machine.id,\n member_id: $scope.ctrl.member.id,\n start: view.start,\n end: view.end,\n timezone: Fablab.timezone\n }, function (slots) {\n uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');\n return $scope.eventSources.splice(0, 1, {\n events: slots,\n textColor: 'black'\n }\n );\n });\n }\n\n /**\n * Triggered when fullCalendar tries to graphically render an event block.\n * Append the event tag into the block, just after the event title.\n * @see http://fullcalendar.io/docs/event_rendering/eventRender/\n */\n const eventRenderCb = function (event, element) {\n if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {\n let html = '';\n for (let tag of Array.from(event.tags)) {\n html += `${tag.name}`;\n }\n element.find('.fc-time').append(html);\n }\n };\n\n /**\n * Update the calendar's display to render the new attributes of the events\n * @param events Object[] events to update in full-calendar\n */\n const updateEvents = function (...events) {\n const realEvents = events.filter(e => !_.isNil(e));\n uiCalendarConfig.calendars.calendar.fullCalendar('updateEvents', realEvents);\n };\n\n /**\n * Asynchronously fetch the events from the API and refresh the calendar's view with these new events\n */\n const refetchCalendar = function () {\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n setTimeout(() => {\n uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents');\n }, 200);\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-self-compare,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * DS207: Consider shorter variations of null checks\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n\n/* COMMON CODE */\n\n/**\n * Provides a set of common callback methods to the $scope parameter. These methods are used\n * in the various spaces' admin controllers.\n *\n * Provides :\n * - $scope.submited(content)\n * - $scope.cancel()\n * - $scope.fileinputClass(v)\n * - $scope.addFile()\n * - $scope.deleteFile(file)\n *\n * Requires :\n * - $scope.space.space_files_attributes = []\n * - $state (Ui-Router) [ 'app.public.spaces_list' ]\n*/\nclass SpacesController {\n constructor ($scope, $state) {\n /*\n * For use with ngUpload (https://github.com/twilson63/ngUpload).\n * Intended to be the callback when the upload is done: any raised error will be stacked in the\n * $scope.alerts array. If everything goes fine, the user is redirected to the spaces list.\n * @param content {Object} JSON - The upload's result\n */\n $scope.submited = function (content) {\n if ((content.id == null)) {\n $scope.alerts = [];\n angular.forEach(content, function (v, k) {\n angular.forEach(v, function (err) {\n $scope.alerts.push({\n msg: k + ': ' + err,\n type: 'danger'\n });\n });\n });\n } else {\n $state.go('app.public.spaces_list');\n }\n };\n\n /**\n * Changes the current user's view, redirecting him to the spaces list\n */\n $scope.cancel = function () { $state.go('app.public.spaces_list'); };\n\n /**\n * For use with 'ng-class', returns the CSS class name for the uploads previews.\n * The preview may show a placeholder or the content of the file depending on the upload state.\n * @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)\n */\n $scope.fileinputClass = function (v) {\n if (v) {\n return 'fileinput-exists';\n } else {\n return 'fileinput-new';\n }\n };\n\n /**\n * This will create a single new empty entry into the space attachments list.\n */\n $scope.addFile = function () { $scope.space.space_files_attributes.push({}); };\n\n /**\n * This will remove the given file from the space attachments list. If the file was previously uploaded\n * to the server, it will be marked for deletion on the server. Otherwise, it will be simply truncated from\n * the attachments array.\n * @param file {Object} the file to delete\n */\n $scope.deleteFile = function (file) {\n const index = $scope.space.space_files_attributes.indexOf(file);\n if (file.id != null) {\n return file._destroy = true;\n } else {\n return $scope.space.space_files_attributes.splice(index, 1);\n }\n };\n }\n}\n\n/**\n * Controller used in the public listing page, allowing everyone to see the list of spaces\n */\nApplication.Controllers.controller('SpacesController', ['$scope', '$state', 'spacesPromise', 'AuthService', '_t', 'Member', 'uiTourService', 'settingsPromise',\n function ($scope, $state, spacesPromise, AuthService, _t, Member, uiTourService, settingsPromise) {\n /* PUBLIC SCOPE */\n\n // Retrieve the list of spaces\n $scope.spaces = spacesPromise;\n\n /**\n * Redirect the user to the space details page\n */\n $scope.showSpace = function (space) { $state.go('app.public.space_show', { id: space.slug }); };\n\n /**\n * Callback to book a reservation for the current space\n */\n $scope.reserveSpace = function (space) { $state.go('app.logged.space_reserve', { id: space.slug }); };\n\n // Default: we show only enabled spaces\n $scope.spaceFiltering = 'enabled';\n\n // Available options for filtering spaces by status\n $scope.filterDisabled = [\n 'enabled',\n 'disabled',\n 'all'\n ];\n\n /**\n * Setup the feature-tour for the spaces page. (admins only)\n * This is intended as a contextual help (when pressing F1)\n */\n $scope.setupSpacesTour = function () {\n // setup the tour for admins only\n if (AuthService.isAuthorized(['admin', 'manager'])) {\n // get the tour defined by the ui-tour directive\n const uitour = uiTourService.getTourByName('spaces');\n if (AuthService.isAuthorized('admin')) {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome',\n order: 0,\n title: _t('app.public.tour.spaces.welcome.title'),\n content: _t('app.public.tour.spaces.welcome.content'),\n placement: 'bottom',\n orphan: true\n });\n if ($scope.spaces.length > 0) {\n uitour.createStep({\n selector: '.spaces-list .show-button',\n stepId: 'view',\n order: 1,\n title: _t('app.public.tour.spaces.view.title'),\n content: _t('app.public.tour.spaces.view.content'),\n placement: 'top'\n });\n }\n } else {\n uitour.createStep({\n selector: 'body',\n stepId: 'welcome_manager',\n order: 0,\n title: _t('app.public.tour.spaces.welcome_manager.title'),\n content: _t('app.public.tour.spaces.welcome_manager.content'),\n placement: 'bottom',\n orphan: true\n });\n }\n if ($scope.spaces.length > 0) {\n uitour.createStep({\n selector: '.spaces-list .reserve-button',\n stepId: 'reserve',\n order: 2,\n title: _t('app.public.tour.spaces.reserve.title'),\n content: _t('app.public.tour.spaces.reserve.content'),\n placement: 'top'\n });\n }\n uitour.createStep({\n selector: 'body',\n stepId: 'conclusion',\n order: 3,\n title: _t('app.public.tour.conclusion.title'),\n content: _t('app.public.tour.conclusion.content'),\n placement: 'bottom',\n orphan: true\n });\n // on tour end, save the status in database\n uitour.on('ended', function () {\n if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('spaces') < 0) {\n Member.completeTour({ id: $scope.currentUser.id }, { tour: 'spaces' }, function (res) {\n $scope.currentUser.profile_attributes.tours = res.tours;\n });\n }\n });\n // if the user has never seen the tour, show him now\n if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('spaces') < 0) {\n uitour.start();\n }\n }\n }\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {}\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n]);\n\n/**\n * Controller used in the space creation page (admin)\n */\nApplication.Controllers.controller('NewSpaceController', ['$scope', '$state', 'CSRF', 'growl', function ($scope, $state, CSRF, growl) {\n CSRF.setMetaTags();\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n // Using the SpacesController\n return new SpacesController($scope, $state);\n}]);\n\n/**\n * Controller used in the space edition page (admin)\n */\nApplication.Controllers.controller('EditSpaceController', ['$scope', '$state', '$transition$', 'spacePromise', 'CSRF', 'growl',\n function ($scope, $state, $transition$, spacePromise, CSRF, growl) {\n CSRF.setMetaTags();\n\n // space to modify\n $scope.space = cleanSpace(spacePromise);\n\n /**\n * Callback triggered by react components\n */\n $scope.onSuccess = function (message) {\n growl.success(message);\n };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n console.error(message);\n growl.error(message);\n };\n\n // prepare the space for the react-hook-form\n function cleanSpace (space) {\n delete space.$promise;\n delete space.$resolved;\n return space;\n }\n\n // Using the SpacesController\n return new SpacesController($scope, $state);\n }]);\n\nApplication.Controllers.controller('ShowSpaceController', ['$scope', '$state', 'spacePromise', '_t', 'dialogs', 'growl',\n function ($scope, $state, spacePromise, _t, dialogs, growl) {\n // Details of the space witch id/slug is provided in the URL\n $scope.space = spacePromise;\n\n /**\n * Callback to book a reservation for the current space\n * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.reserveSpace = function (event) {\n event.preventDefault();\n return $state.go('app.logged.space_reserve', { id: $scope.space.slug });\n };\n\n /**\n * Callback to book a reservation for the current space\n * @param event {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.deleteSpace = function (event) {\n event.preventDefault();\n // check the permissions\n if ($scope.currentUser.role !== 'admin') {\n return console.error(_t('app.public.space_show.unauthorized_operation'));\n } else {\n return dialogs.confirm({\n resolve: {\n object () {\n return {\n title: _t('app.public.space_show.confirmation_required'),\n msg: _t('app.public.space_show.do_you_really_want_to_delete_this_space')\n };\n }\n }\n }\n , function () { // deletion confirmed\n // delete the machine then redirect to the machines listing\n $scope.space.$delete(\n function () {\n $state.go('app.public.spaces_list');\n },\n function (error) {\n growl.warning(_t('app.public.space_show.the_space_cant_be_deleted_because_it_is_already_reserved_by_some_users'));\n console.error(error);\n }\n );\n });\n }\n };\n }]);\n\n/**\n * Controller used in the spaces reservation agenda page.\n * This controller is very similar to the machine reservation controller with one major difference: here, there is many places\n * per slots.\n */\n\nApplication.Controllers.controller('ReserveSpaceController', ['$scope', '$transition$', 'Auth', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation', 'helpers', 'AuthService',\n function ($scope, $transition$, Auth, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig, Reservation, helpers, AuthService) {\n /* PRIVATE STATIC CONSTANTS */\n\n // Color of the selected event backgound\n const SELECTED_EVENT_BG_COLOR = '#ffdd00';\n\n // Slot free to be booked\n const FREE_SLOT_BORDER_COLOR = '#3fc7ff';\n\n // Slot with reservation from current user\n const RESERVED_SLOT_BORDER_COLOR = '#b2e774';\n\n /* PUBLIC SCOPE */\n\n // bind the spaces availabilities with full-Calendar events\n $scope.eventSources = [];\n\n // the user to deal with, ie. the current user for non-admins\n $scope.ctrl =\n { member: {} };\n\n // all plans, used in \n $scope.plans = plansPromise;\n\n // all groups, used in \n $scope.groups = groupsPromise;\n\n // mapping of fullCalendar events.\n $scope.events = {\n reserved: [], // Slots that the user wants to book\n modifiable: null, // Slot that the user wants to change\n placable: null, // Destination slot for the change\n paid: [], // Slots that were just booked by the user (transaction ok)\n moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *}\n };\n\n // the moment when the slot selection changed for the last time, used to trigger changes in the cart\n $scope.selectionTime = null;\n\n // the last clicked event in the calendar\n $scope.selectedEvent = null;\n\n // indicates the state of the current view : calendar or plans information\n $scope.plansAreShown = false;\n\n // will store the user's plan if he chose to buy one\n $scope.selectedPlan = null;\n\n // the moment when the plan selection changed for the last time, used to trigger changes in the cart\n $scope.planSelectionTime = null;\n\n // Selected space\n $scope.space = spacePromise;\n\n // fullCalendar (v2) configuration\n $scope.calendarConfig = CalendarConfig({\n minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')),\n maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')),\n eventClick (event, jsEvent, view) {\n return calendarEventClickCb(event, jsEvent, view);\n },\n eventRender (event, element, view) {\n return eventRenderCb(event, element, view);\n }\n });\n\n // Application global settings\n $scope.settings = settingsPromise;\n\n // Global config: message to the end user concerning the subscriptions rules\n $scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert;\n\n // Global config: message to the end user concerning the space reservation\n $scope.spaceExplicationsAlert = settingsPromise.space_explications_alert;\n\n // Global config: is the user validation required ?\n $scope.enableUserValidationRequired = settingsPromise.user_validation_required === 'true';\n\n /**\n * Change the last selected slot's appearance to looks like 'added to cart'\n */\n $scope.markSlotAsAdded = function () {\n $scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR;\n $scope.selectedEvent.oldTitle = $scope.selectedEvent.title;\n updateEvents($scope.selectedEvent);\n };\n\n /**\n * Change the last selected slot's appearance to looks like 'never added to cart'\n */\n $scope.markSlotAsRemoved = function (slot) {\n slot.backgroundColor = 'white';\n slot.title = slot.oldTitle;\n slot.borderColor = FREE_SLOT_BORDER_COLOR;\n updateEvents(slot);\n };\n\n /**\n * Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'\n */\n $scope.slotCancelled = function () { refreshCalendar(); };\n\n /**\n * Change the last selected slot's appearance to looks like 'currently looking for a new destination to exchange'\n */\n $scope.markSlotAsModifying = function () {\n $scope.selectedEvent.backgroundColor = '#eee';\n $scope.selectedEvent.oldTitle = $scope.selectedEvent.title;\n $scope.selectedEvent.title = _t('app.logged.space_reserve.i_change');\n updateEvents($scope.selectedEvent);\n };\n\n /**\n * Change the last selected slot's appearance to looks like 'the slot being exchanged will take this place'\n */\n $scope.changeModifySpaceSlot = function () {\n if ($scope.events.placable) {\n $scope.events.placable.backgroundColor = 'white';\n $scope.events.placable.title = '';\n updateEvents($scope.events.placable);\n }\n if (!$scope.events.placable || ($scope.events.placable._id !== $scope.selectedEvent._id)) {\n $scope.selectedEvent.backgroundColor = '#bbb';\n $scope.selectedEvent.title = _t('app.logged.space_reserve.i_shift');\n updateEvents($scope.selectedEvent);\n }\n return true;\n };\n\n /**\n * When modifying an already booked reservation, callback when the modification was successfully done.\n */\n $scope.modifySpaceSlot = function () {\n refreshCalendar();\n };\n\n /**\n * Cancel the current booking modification, reseting the whole process\n */\n $scope.cancelModifySpaceSlot = function () {\n if ($scope.events.placable) {\n $scope.events.placable.backgroundColor = 'white';\n $scope.events.placable.title = '';\n }\n $scope.events.modifiable.title = _t('app.logged.space_reserve.i_ve_reserved');\n $scope.events.modifiable.backgroundColor = 'white';\n\n updateEvents($scope.events.placable, $scope.events.modifiable);\n };\n\n /**\n * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's\n * reservations. (admins only)\n */\n $scope.updateMember = function () {\n if ($scope.ctrl.member) {\n Member.get({ id: $scope.ctrl.member.id }, function (member) {\n $scope.ctrl.member = member;\n refreshCalendar();\n });\n }\n // as the events are re-fetched for the new user, we must re-init the cart\n $scope.events.reserved = [];\n $scope.selectedPlan = null;\n return $scope.plansAreShown = false;\n };\n\n /**\n * Add the provided plan to the current shopping cart\n * @param plan {Object} the plan to subscribe\n */\n $scope.selectPlan = function (plan) {\n setTimeout(() => {\n // toggle selected plan\n if ($scope.selectedPlan !== plan) {\n $scope.selectedPlan = plan;\n } else {\n $scope.selectedPlan = null;\n }\n $scope.planSelectionTime = new Date();\n $scope.$apply();\n }, 50);\n };\n\n $scope.canSelectPlan = function () {\n return helpers.isUserValidatedByType($scope.ctrl.member, $scope.settings, 'subscription');\n };\n\n /**\n * Check if the provided plan is currently selected\n * @param plan {Object} Resource plan\n */\n $scope.isSelected = function (plan) {\n return $scope.selectedPlan === plan;\n };\n\n /**\n * Changes the user current view from the plan subscription screen to the machine reservation agenda\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.doNotSubscribePlan = function (e) {\n e.preventDefault();\n $scope.plansAreShown = false;\n $scope.selectedPlan = null;\n return $scope.planSelectionTime = new Date();\n };\n\n /**\n * Switch the user's view from the reservation agenda to the plan subscription\n */\n $scope.showPlans = function () { $scope.plansAreShown = true; };\n\n /**\n * Once the reservation is booked (payment process successfully completed), change the event style\n * in fullCalendar, update the user's subscription and free-credits if needed\n * @param paymentDocument {Invoice|PaymentSchedule}\n */\n $scope.afterPayment = function (paymentDocument) {\n Reservation.get({ id: paymentDocument.main_object.id }, function (reservation) {\n if ($scope.selectedPlan) {\n $scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);\n if ($scope.ctrl.member.id === Auth._currentUser.id) {\n Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);\n }\n $scope.plansAreShown = false;\n $scope.selectedPlan = null;\n }\n $scope.ctrl.member.training_credits = angular.copy(reservation.user.training_credits);\n $scope.ctrl.member.machine_credits = angular.copy(reservation.user.machine_credits);\n if ($scope.ctrl.member.id === Auth._currentUser.id) {\n Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits);\n Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);\n }\n\n refreshCalendar();\n });\n };\n\n /**\n * To use as callback in Array.prototype.filter to get only enabled plans\n */\n $scope.filterDisabledPlans = function (plan) { return !plan.disabled; };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if ($scope.currentUser.role !== 'admin') {\n $scope.ctrl.member = $scope.currentUser;\n Member.get({ id: $scope.currentUser.id }, function (member) { $scope.ctrl.member = member; });\n }\n // we load the availabilities from a callback function of the $scope.eventSources, instead of resolving a promise\n // in the router because this allows to refetchEvents from fullCalendar API.\n $scope.eventSources.push({\n url: `/api/availabilities/spaces/${$transition$.params().id}`,\n textColor: 'black'\n });\n };\n\n /**\n * Triggered when the user clicks on a reservation slot in the agenda.\n * Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...),\n * the user's subscription (current or about to be took), and the time (the user cannot modify a booked reservation\n * if it's too late).\n * @see http://fullcalendar.io/docs/mouse/eventClick/\n */\n const calendarEventClickCb = function (event, jsEvent, view) {\n if (!AuthService.isAuthorized(['admin', 'manager']) && (helpers.isUserValidationRequired($scope.settings, 'space') && !helpers.isUserValidated($scope.ctrl.member))) {\n return;\n }\n $scope.selectedEvent = event;\n $scope.selectionTime = new Date();\n };\n\n /**\n * Refetch all events from the API and re-populate the calendar with the resulting slots\n */\n const refreshCalendar = function () {\n const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');\n return Availability.spaces({\n spaceId: $scope.space.id,\n member_id: $scope.ctrl.member.id,\n start: view.start,\n end: view.end,\n timezone: Fablab.timezone\n }, function (spaces) {\n uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');\n return $scope.eventSources.splice(0, 1, {\n events: spaces,\n textColor: 'black'\n }\n );\n });\n };\n\n /**\n * Triggered when fullCalendar tries to graphically render an event block.\n * Append the event tag into the block, just after the event title.\n * @see http://fullcalendar.io/docs/event_rendering/eventRender/\n */\n const eventRenderCb = function (event, element, view) {\n if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {\n let html = '';\n for (let tag of Array.from(event.tags)) {\n html += `${tag.name}`;\n }\n element.find('.fc-time').append(html);\n }\n };\n\n /**\n * Update the calendar's display to render the new attributes of the events\n * @param events Object[] events to update in full-calendar\n */\n const updateEvents = function (...events) {\n const realEvents = events.filter(e => !_.isNil(e));\n uiCalendarConfig.calendars.calendar.fullCalendar('updateEvents', realEvents);\n };\n\n\n /**\n * Asynchronously fetch the events from the API and refresh the calendar's view with these new events\n */\n const refetchCalendar = function () {\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n setTimeout(() => {\n uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents');\n }, 200);\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n\n]);\n","/* eslint-disable\n handle-callback-err,\n no-return-assign,\n no-self-compare,\n no-undef,\n*/\n// TODO: This file was created by bulk-decaffeinate.\n// Fix any style issues and re-enable lint.\n/*\n * decaffeinate suggestions:\n * DS101: Remove unnecessary use of Array.from\n * DS102: Remove unnecessary code created because of implicit returns\n * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md\n */\n'use strict';\n\n/**\n * Public listing of the trainings\n */\nApplication.Controllers.controller('TrainingsController', ['$scope', '$state', 'trainingsPromise', 'growl',\n function ($scope, $state, trainingsPromise, growl) {\n // List of trainings\n $scope.trainings = trainingsPromise;\n\n /**\n * Callback for the 'reserve' button\n */\n $scope.reserveTraining = function (training, event) { $state.go('app.logged.trainings_reserve', { id: training.slug }); };\n\n /**\n * Callback for the 'show' button\n */\n $scope.showTraining = function (training) { $state.go('app.public.training_show', { id: training.slug }); };\n\n /**\n * Callback triggered by react components\n */\n $scope.onError = function (message) {\n growl.error(message);\n };\n }]);\n\n/**\n * Public view of a specific training\n */\nApplication.Controllers.controller('ShowTrainingController', ['$scope', '$state', 'trainingPromise', 'growl', '_t', 'dialogs',\n function ($scope, $state, trainingPromise, growl, _t, dialogs) {\n // Current training\n $scope.training = trainingPromise;\n\n /**\n * Callback to delete the current training (admins only)\n */\n $scope.delete = function (training) {\n // check the permissions\n if ($scope.currentUser.role !== 'admin') {\n growl.error(_t('app.public.training_show.unauthorized_operation'));\n } else {\n dialogs.confirm(\n {\n resolve: {\n object () {\n return {\n title: _t('app.public.training_show.confirmation_required'),\n msg: _t('app.public.training_show.do_you_really_want_to_delete_this_training')\n };\n }\n }\n },\n function () { // deletion confirmed\n // delete the training then redirect to the trainings listing\n training.$delete(\n function () { $state.go('app.public.trainings_list'); },\n function (error) {\n growl.warning(_t('app.public.training_show.the_training_cant_be_deleted_because_it_is_already_reserved_by_some_users'));\n console.error(error);\n }\n );\n }\n );\n }\n };\n\n /**\n * Callback for the 'reserve' button\n */\n $scope.reserveTraining = function (training, event) { $state.go('app.logged.trainings_reserve', { id: training.id }); };\n\n /**\n * Revert view to the full list of trainings (\"<-\" button)\n */\n $scope.cancel = function (event) { $scope.currentUser && $scope.currentUser.role === 'admin' ? $state.go('app.admin.trainings') : $state.go('app.public.trainings_list'); };\n }]);\n\n/**\n * Controller used in the training reservation agenda page.\n * This controller is very similar to the machine reservation controller with one major difference: here, ONLY ONE\n * training can be reserved during the reservation process (the shopping cart may contain only one training and a subscription).\n */\n\nApplication.Controllers.controller('ReserveTrainingController', ['$scope', '$transition$', 'Auth', 'AuthService', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation', 'helpers',\n function ($scope, $transition$, Auth, AuthService, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig, Reservation, helpers) {\n /* PRIVATE STATIC CONSTANTS */\n\n // Color of the selected event backgound\n const SELECTED_EVENT_BG_COLOR = '#ffdd00';\n\n // Slot free to be booked\n const FREE_SLOT_BORDER_COLOR = '#bd7ae9';\n\n /* PUBLIC SCOPE */\n\n // bind the trainings availabilities with full-Calendar events\n $scope.eventSources = [];\n\n // the user to deal with, ie. the current user for non-admins\n $scope.ctrl =\n { member: {} };\n\n // all plans, used in \n $scope.plans = plansPromise;\n\n // all groups, used in \n $scope.groups = groupsPromise;\n\n // mapping of fullCalendar events.\n $scope.events = {\n reserved: [], // Slots that the user wants to book\n modifiable: null, // Slot that the user wants to change\n placable: null, // Destination slot for the change\n paid: [], // Slots that were just booked by the user (transaction ok)\n moved: null // Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *}\n };\n\n // the moment when the slot selection changed for the last time, used to trigger changes in the cart\n $scope.selectionTime = null;\n\n // the last clicked event in the calendar\n $scope.selectedEvent = null;\n\n // indicates the state of the current view : calendar or plans information\n $scope.plansAreShown = false;\n\n // will store the user's plan if he chose to buy one\n $scope.selectedPlan = null;\n\n // the moment when the plan selection changed for the last time, used to trigger changes in the cart\n $scope.planSelectionTime = null;\n\n // Selected training\n $scope.training = trainingPromise;\n\n // 'all' OR training's slug\n $scope.mode = $transition$.params().id;\n\n // fullCalendar (v2) configuration\n $scope.calendarConfig = CalendarConfig({\n minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss')),\n maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss')),\n eventClick (event, jsEvent, view) {\n return calendarEventClickCb(event, jsEvent, view);\n },\n eventRender (event, element, view) {\n return eventRenderCb(event, element, view);\n }\n });\n\n // Application global settings\n $scope.settings = settingsPromise;\n\n // Global config: message to the end user concerning the subscriptions rules\n $scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert;\n\n // Global config: message to the end user concerning the training reservation\n $scope.trainingExplicationsAlert = settingsPromise.training_explications_alert;\n\n // Global config: message to the end user giving advice about the training reservation\n $scope.trainingInformationMessage = settingsPromise.training_information_message;\n\n // Global config: is the user validation required ?\n $scope.enableUserValidationRequired = settingsPromise.user_validation_required === 'true';\n\n /**\n * Change the last selected slot's appearance to looks like 'added to cart'\n */\n $scope.markSlotAsAdded = function () {\n $scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR;\n updateEvents($scope.selectedEvent);\n };\n\n /**\n * Change the last selected slot's appearance to looks like 'never added to cart'\n */\n $scope.markSlotAsRemoved = function (slot) {\n slot.backgroundColor = 'white';\n slot.title = slot.training.name;\n slot.borderColor = FREE_SLOT_BORDER_COLOR;\n updateEvents(slot);\n };\n\n /**\n * Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'\n */\n $scope.slotCancelled = function () { refreshCalendar() };\n\n /**\n * Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange'\n */\n $scope.markSlotAsModifying = function () {\n $scope.selectedEvent.backgroundColor = '#eee';\n $scope.selectedEvent.title = $scope.selectedEvent.training.name + ' - ' + _t('app.logged.trainings_reserve.i_change');\n updateEvents($scope.selectedEvent);\n };\n\n /**\n * Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place'\n */\n $scope.changeModifyTrainingSlot = function () {\n if ($scope.selectedEvent.training.id !== $scope.events.modifiable.training.id) return false;\n\n if ($scope.events.placable) {\n $scope.events.placable.backgroundColor = 'white';\n $scope.events.placable.title = $scope.events.placable.training.name;\n updateEvents($scope.events.placable);\n }\n if (!$scope.events.placable || ($scope.events.placable._id !== $scope.selectedEvent._id)) {\n $scope.selectedEvent.backgroundColor = '#bbb';\n $scope.selectedEvent.title = $scope.selectedEvent.training.name + ' - ' + _t('app.logged.trainings_reserve.i_shift');\n updateEvents($scope.selectedEvent);\n }\n return true;\n };\n\n /**\n * When modifying an already booked reservation, callback when the modification was successfully done.\n */\n $scope.modifyTrainingSlot = function () {\n refreshCalendar();\n };\n\n /**\n * Cancel the current booking modification, reseting the whole process\n */\n $scope.cancelModifyTrainingSlot = function () {\n if ($scope.events.placable) {\n $scope.events.placable.backgroundColor = 'white';\n $scope.events.placable.title = $scope.events.placable.training.name;\n }\n $scope.events.modifiable.title = $scope.currentUser.role !== 'admin' ? $scope.events.modifiable.training.name + ' - ' + _t('app.logged.trainings_reserve.i_ve_reserved') : $scope.events.modifiable.training.name;\n $scope.events.modifiable.backgroundColor = 'white';\n\n updateEvents($scope.events.placable, $scope.events.modifiable);\n };\n\n /**\n * Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's\n * reservations. (admins only)\n */\n $scope.updateMember = function () {\n if ($scope.ctrl.member) {\n Member.get({ id: $scope.ctrl.member.id }, function (member) {\n $scope.ctrl.member = member;\n refreshCalendar();\n });\n }\n // as the events are re-fetched for the new user, we must re-init the cart\n $scope.events.reserved = [];\n $scope.selectedPlan = null;\n $scope.plansAreShown = false;\n };\n\n /**\n * Add the provided plan to the current shopping cart\n * @param plan {Object} the plan to subscribe\n */\n $scope.selectPlan = function (plan) {\n setTimeout(() => {\n // toggle selected plan\n if ($scope.selectedPlan !== plan) {\n $scope.selectedPlan = plan;\n } else {\n $scope.selectedPlan = null;\n }\n $scope.planSelectionTime = new Date();\n $scope.$apply();\n }, 50);\n };\n\n $scope.canSelectPlan = function () {\n return helpers.isUserValidatedByType($scope.ctrl.member, $scope.settings, 'subscription');\n };\n\n /**\n * Check if the provided plan is currently selected\n * @param plan {Object} Resource plan\n */\n $scope.isSelected = function (plan) {\n return $scope.selectedPlan === plan;\n };\n\n /**\n * Changes the user current view from the plan subsription screen to the machine reservation agenda\n * @param e {Object} see https://docs.angularjs.org/guide/expression#-event-\n */\n $scope.doNotSubscribePlan = function (e) {\n e.preventDefault();\n $scope.plansAreShown = false;\n $scope.selectedPlan = null;\n return $scope.planSelectionTime = new Date();\n };\n\n /**\n * Switch the user's view from the reservation agenda to the plan subscription\n */\n $scope.showPlans = function () { $scope.plansAreShown = true; };\n\n /**\n * Once the reservation is booked (payment process successfully completed), change the event style\n * in fullCalendar, update the user's subscription and free-credits if needed\n * @param paymentDocument {Invoice|PaymentSchedule}\n */\n $scope.afterPayment = function (paymentDocument) {\n Reservation.get({ id: paymentDocument.main_object.id }, function (reservation) {\n if ($scope.selectedPlan) {\n $scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan);\n if ($scope.ctrl.member.id === Auth._currentUser.id) {\n Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan);\n }\n $scope.plansAreShown = false;\n $scope.selectedPlan = null;\n }\n $scope.ctrl.member.training_credits = angular.copy(reservation.user.training_credits);\n $scope.ctrl.member.machine_credits = angular.copy(reservation.user.machine_credits);\n if ($scope.ctrl.member.id === Auth._currentUser.id) {\n Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits);\n Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits);\n }\n\n refreshCalendar();\n });\n };\n\n /**\n * To use as callback in Array.prototype.filter to get only enabled plans\n */\n $scope.filterDisabledPlans = function (plan) { return !plan.disabled; };\n\n /* PRIVATE SCOPE */\n\n /**\n * Kind of constructor: these actions will be realized first when the controller is loaded\n */\n const initialize = function () {\n if ($scope.currentUser.role !== 'admin') {\n $scope.ctrl.member = $scope.currentUser;\n Member.get({ id: $scope.currentUser.id }, function (member) { $scope.ctrl.member = member; });\n }\n // we load the availabilities from a callback function of the $scope.eventSources, instead of resolving a promise\n // in the router because this allows to refetchEvents from fullCalendar API.\n $scope.eventSources.push({\n url: `/api/availabilities/trainings/${$transition$.params().id}`,\n textColor: 'black'\n });\n };\n\n /**\n * Triggered when the user clicks on a reservation slot in the agenda.\n * Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...),\n * the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation\n * if it's too late).\n * @see http://fullcalendar.io/docs/mouse/eventClick/\n */\n const calendarEventClickCb = function (event, jsEvent, view) {\n if (!AuthService.isAuthorized(['admin', 'manager']) && (helpers.isUserValidationRequired($scope.settings, 'training') && !helpers.isUserValidated($scope.ctrl.member))) {\n return;\n }\n $scope.selectedEvent = event;\n if ($transition$.params().id === 'all') {\n $scope.training = event.training;\n }\n return $scope.selectionTime = new Date();\n };\n\n /**\n * Refetch all events from the API and re-populate the calendar with the resulting slots\n */\n const refreshCalendar = function () {\n const view = uiCalendarConfig.calendars.calendar.fullCalendar('getView');\n const id = $transition$.params().id === 'all' ? $transition$.params().id : $scope.training.id;\n Availability.trainings({\n trainingId: id,\n member_id: $scope.ctrl.member.id,\n start: view.start,\n end: view.end,\n timezone: Fablab.timezone\n }, function (trainings) {\n uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');\n $scope.eventSources.splice(0, 1, {\n events: trainings,\n textColor: 'black'\n });\n });\n }\n\n /**\n * Triggered when fullCalendar tries to graphicaly render an event block.\n * Append the event tag into the block, just after the event title.\n * @see http://fullcalendar.io/docs/event_rendering/eventRender/\n */\n const eventRenderCb = function (event, element, view) {\n if (($scope.currentUser.role === 'admin') && (event.tags.length > 0)) {\n let html = '';\n for (let tag of Array.from(event.tags)) {\n html += `${tag.name}`;\n }\n element.find('.fc-time').append(html);\n }\n };\n\n /**\n * After payment, update the id of the newly reserved slot with the id returned by the server.\n * This will allow the user to modify the reservation he just booked.\n * @param slot {Object}\n * @param reservation {Object}\n */\n const updateTrainingSlotId = function (slot, reservation) {\n angular.forEach(reservation.slots, function (s) {\n if (slot.start.isSame(s.start_at)) {\n return slot.slot_id = s.id;\n }\n });\n };\n\n /**\n * Update the calendar's display to render the new attributes of the events\n * @param events Object[] events to update in full-calendar\n */\n const updateEvents = function (...events) {\n const realEvents = events.filter(e => !_.isNil(e));\n uiCalendarConfig.calendars.calendar.fullCalendar('updateEvents', realEvents);\n };\n\n\n /**\n * Asynchronously fetch the events from the API and refresh the calendar's view with these new events\n */\n const refetchCalendar = function () {\n uiCalendarConfig.calendars.calendar.fullCalendar('refetchEvents');\n setTimeout(() => {\n uiCalendarConfig.calendars.calendar.fullCalendar('rerenderEvents');\n }, 200);\n };\n\n // !!! MUST BE CALLED AT THE END of the controller\n return initialize();\n }\n\n]);\n","// extracted by mini-css-extract-plugin\nexport {};","var map = {\n\t\"./af\": \"./node_modules/moment/locale/af.js\",\n\t\"./af.js\": \"./node_modules/moment/locale/af.js\",\n\t\"./ar\": \"./node_modules/moment/locale/ar.js\",\n\t\"./ar-dz\": \"./node_modules/moment/locale/ar-dz.js\",\n\t\"./ar-dz.js\": \"./node_modules/moment/locale/ar-dz.js\",\n\t\"./ar-kw\": \"./node_modules/moment/locale/ar-kw.js\",\n\t\"./ar-kw.js\": \"./node_modules/moment/locale/ar-kw.js\",\n\t\"./ar-ly\": \"./node_modules/moment/locale/ar-ly.js\",\n\t\"./ar-ly.js\": \"./node_modules/moment/locale/ar-ly.js\",\n\t\"./ar-ma\": \"./node_modules/moment/locale/ar-ma.js\",\n\t\"./ar-ma.js\": \"./node_modules/moment/locale/ar-ma.js\",\n\t\"./ar-sa\": \"./node_modules/moment/locale/ar-sa.js\",\n\t\"./ar-sa.js\": \"./node_modules/moment/locale/ar-sa.js\",\n\t\"./ar-tn\": \"./node_modules/moment/locale/ar-tn.js\",\n\t\"./ar-tn.js\": \"./node_modules/moment/locale/ar-tn.js\",\n\t\"./ar.js\": \"./node_modules/moment/locale/ar.js\",\n\t\"./az\": \"./node_modules/moment/locale/az.js\",\n\t\"./az.js\": \"./node_modules/moment/locale/az.js\",\n\t\"./be\": \"./node_modules/moment/locale/be.js\",\n\t\"./be.js\": \"./node_modules/moment/locale/be.js\",\n\t\"./bg\": \"./node_modules/moment/locale/bg.js\",\n\t\"./bg.js\": \"./node_modules/moment/locale/bg.js\",\n\t\"./bm\": \"./node_modules/moment/locale/bm.js\",\n\t\"./bm.js\": \"./node_modules/moment/locale/bm.js\",\n\t\"./bn\": \"./node_modules/moment/locale/bn.js\",\n\t\"./bn-bd\": \"./node_modules/moment/locale/bn-bd.js\",\n\t\"./bn-bd.js\": \"./node_modules/moment/locale/bn-bd.js\",\n\t\"./bn.js\": \"./node_modules/moment/locale/bn.js\",\n\t\"./bo\": \"./node_modules/moment/locale/bo.js\",\n\t\"./bo.js\": \"./node_modules/moment/locale/bo.js\",\n\t\"./br\": \"./node_modules/moment/locale/br.js\",\n\t\"./br.js\": \"./node_modules/moment/locale/br.js\",\n\t\"./bs\": \"./node_modules/moment/locale/bs.js\",\n\t\"./bs.js\": \"./node_modules/moment/locale/bs.js\",\n\t\"./ca\": \"./node_modules/moment/locale/ca.js\",\n\t\"./ca.js\": \"./node_modules/moment/locale/ca.js\",\n\t\"./cs\": \"./node_modules/moment/locale/cs.js\",\n\t\"./cs.js\": \"./node_modules/moment/locale/cs.js\",\n\t\"./cv\": \"./node_modules/moment/locale/cv.js\",\n\t\"./cv.js\": \"./node_modules/moment/locale/cv.js\",\n\t\"./cy\": \"./node_modules/moment/locale/cy.js\",\n\t\"./cy.js\": \"./node_modules/moment/locale/cy.js\",\n\t\"./da\": \"./node_modules/moment/locale/da.js\",\n\t\"./da.js\": \"./node_modules/moment/locale/da.js\",\n\t\"./de\": \"./node_modules/moment/locale/de.js\",\n\t\"./de-at\": \"./node_modules/moment/locale/de-at.js\",\n\t\"./de-at.js\": \"./node_modules/moment/locale/de-at.js\",\n\t\"./de-ch\": \"./node_modules/moment/locale/de-ch.js\",\n\t\"./de-ch.js\": \"./node_modules/moment/locale/de-ch.js\",\n\t\"./de.js\": \"./node_modules/moment/locale/de.js\",\n\t\"./dv\": \"./node_modules/moment/locale/dv.js\",\n\t\"./dv.js\": \"./node_modules/moment/locale/dv.js\",\n\t\"./el\": \"./node_modules/moment/locale/el.js\",\n\t\"./el.js\": \"./node_modules/moment/locale/el.js\",\n\t\"./en-au\": \"./node_modules/moment/locale/en-au.js\",\n\t\"./en-au.js\": \"./node_modules/moment/locale/en-au.js\",\n\t\"./en-ca\": \"./node_modules/moment/locale/en-ca.js\",\n\t\"./en-ca.js\": \"./node_modules/moment/locale/en-ca.js\",\n\t\"./en-gb\": \"./node_modules/moment/locale/en-gb.js\",\n\t\"./en-gb.js\": \"./node_modules/moment/locale/en-gb.js\",\n\t\"./en-ie\": \"./node_modules/moment/locale/en-ie.js\",\n\t\"./en-ie.js\": \"./node_modules/moment/locale/en-ie.js\",\n\t\"./en-il\": \"./node_modules/moment/locale/en-il.js\",\n\t\"./en-il.js\": \"./node_modules/moment/locale/en-il.js\",\n\t\"./en-in\": \"./node_modules/moment/locale/en-in.js\",\n\t\"./en-in.js\": \"./node_modules/moment/locale/en-in.js\",\n\t\"./en-nz\": \"./node_modules/moment/locale/en-nz.js\",\n\t\"./en-nz.js\": \"./node_modules/moment/locale/en-nz.js\",\n\t\"./en-sg\": \"./node_modules/moment/locale/en-sg.js\",\n\t\"./en-sg.js\": \"./node_modules/moment/locale/en-sg.js\",\n\t\"./eo\": \"./node_modules/moment/locale/eo.js\",\n\t\"./eo.js\": \"./node_modules/moment/locale/eo.js\",\n\t\"./es\": \"./node_modules/moment/locale/es.js\",\n\t\"./es-do\": \"./node_modules/moment/locale/es-do.js\",\n\t\"./es-do.js\": \"./node_modules/moment/locale/es-do.js\",\n\t\"./es-mx\": \"./node_modules/moment/locale/es-mx.js\",\n\t\"./es-mx.js\": \"./node_modules/moment/locale/es-mx.js\",\n\t\"./es-us\": \"./node_modules/moment/locale/es-us.js\",\n\t\"./es-us.js\": \"./node_modules/moment/locale/es-us.js\",\n\t\"./es.js\": \"./node_modules/moment/locale/es.js\",\n\t\"./et\": \"./node_modules/moment/locale/et.js\",\n\t\"./et.js\": \"./node_modules/moment/locale/et.js\",\n\t\"./eu\": \"./node_modules/moment/locale/eu.js\",\n\t\"./eu.js\": \"./node_modules/moment/locale/eu.js\",\n\t\"./fa\": \"./node_modules/moment/locale/fa.js\",\n\t\"./fa.js\": \"./node_modules/moment/locale/fa.js\",\n\t\"./fi\": \"./node_modules/moment/locale/fi.js\",\n\t\"./fi.js\": \"./node_modules/moment/locale/fi.js\",\n\t\"./fil\": \"./node_modules/moment/locale/fil.js\",\n\t\"./fil.js\": \"./node_modules/moment/locale/fil.js\",\n\t\"./fo\": \"./node_modules/moment/locale/fo.js\",\n\t\"./fo.js\": \"./node_modules/moment/locale/fo.js\",\n\t\"./fr\": \"./node_modules/moment/locale/fr.js\",\n\t\"./fr-ca\": \"./node_modules/moment/locale/fr-ca.js\",\n\t\"./fr-ca.js\": \"./node_modules/moment/locale/fr-ca.js\",\n\t\"./fr-ch\": \"./node_modules/moment/locale/fr-ch.js\",\n\t\"./fr-ch.js\": \"./node_modules/moment/locale/fr-ch.js\",\n\t\"./fr.js\": \"./node_modules/moment/locale/fr.js\",\n\t\"./fy\": \"./node_modules/moment/locale/fy.js\",\n\t\"./fy.js\": \"./node_modules/moment/locale/fy.js\",\n\t\"./ga\": \"./node_modules/moment/locale/ga.js\",\n\t\"./ga.js\": \"./node_modules/moment/locale/ga.js\",\n\t\"./gd\": \"./node_modules/moment/locale/gd.js\",\n\t\"./gd.js\": \"./node_modules/moment/locale/gd.js\",\n\t\"./gl\": \"./node_modules/moment/locale/gl.js\",\n\t\"./gl.js\": \"./node_modules/moment/locale/gl.js\",\n\t\"./gom-deva\": \"./node_modules/moment/locale/gom-deva.js\",\n\t\"./gom-deva.js\": \"./node_modules/moment/locale/gom-deva.js\",\n\t\"./gom-latn\": \"./node_modules/moment/locale/gom-latn.js\",\n\t\"./gom-latn.js\": \"./node_modules/moment/locale/gom-latn.js\",\n\t\"./gu\": \"./node_modules/moment/locale/gu.js\",\n\t\"./gu.js\": \"./node_modules/moment/locale/gu.js\",\n\t\"./he\": \"./node_modules/moment/locale/he.js\",\n\t\"./he.js\": \"./node_modules/moment/locale/he.js\",\n\t\"./hi\": \"./node_modules/moment/locale/hi.js\",\n\t\"./hi.js\": \"./node_modules/moment/locale/hi.js\",\n\t\"./hr\": \"./node_modules/moment/locale/hr.js\",\n\t\"./hr.js\": \"./node_modules/moment/locale/hr.js\",\n\t\"./hu\": \"./node_modules/moment/locale/hu.js\",\n\t\"./hu.js\": \"./node_modules/moment/locale/hu.js\",\n\t\"./hy-am\": \"./node_modules/moment/locale/hy-am.js\",\n\t\"./hy-am.js\": \"./node_modules/moment/locale/hy-am.js\",\n\t\"./id\": \"./node_modules/moment/locale/id.js\",\n\t\"./id.js\": \"./node_modules/moment/locale/id.js\",\n\t\"./is\": \"./node_modules/moment/locale/is.js\",\n\t\"./is.js\": \"./node_modules/moment/locale/is.js\",\n\t\"./it\": \"./node_modules/moment/locale/it.js\",\n\t\"./it-ch\": \"./node_modules/moment/locale/it-ch.js\",\n\t\"./it-ch.js\": \"./node_modules/moment/locale/it-ch.js\",\n\t\"./it.js\": \"./node_modules/moment/locale/it.js\",\n\t\"./ja\": \"./node_modules/moment/locale/ja.js\",\n\t\"./ja.js\": \"./node_modules/moment/locale/ja.js\",\n\t\"./jv\": \"./node_modules/moment/locale/jv.js\",\n\t\"./jv.js\": \"./node_modules/moment/locale/jv.js\",\n\t\"./ka\": \"./node_modules/moment/locale/ka.js\",\n\t\"./ka.js\": \"./node_modules/moment/locale/ka.js\",\n\t\"./kk\": \"./node_modules/moment/locale/kk.js\",\n\t\"./kk.js\": \"./node_modules/moment/locale/kk.js\",\n\t\"./km\": \"./node_modules/moment/locale/km.js\",\n\t\"./km.js\": \"./node_modules/moment/locale/km.js\",\n\t\"./kn\": \"./node_modules/moment/locale/kn.js\",\n\t\"./kn.js\": \"./node_modules/moment/locale/kn.js\",\n\t\"./ko\": \"./node_modules/moment/locale/ko.js\",\n\t\"./ko.js\": \"./node_modules/moment/locale/ko.js\",\n\t\"./ku\": \"./node_modules/moment/locale/ku.js\",\n\t\"./ku.js\": \"./node_modules/moment/locale/ku.js\",\n\t\"./ky\": \"./node_modules/moment/locale/ky.js\",\n\t\"./ky.js\": \"./node_modules/moment/locale/ky.js\",\n\t\"./lb\": \"./node_modules/moment/locale/lb.js\",\n\t\"./lb.js\": \"./node_modules/moment/locale/lb.js\",\n\t\"./lo\": \"./node_modules/moment/locale/lo.js\",\n\t\"./lo.js\": \"./node_modules/moment/locale/lo.js\",\n\t\"./lt\": \"./node_modules/moment/locale/lt.js\",\n\t\"./lt.js\": \"./node_modules/moment/locale/lt.js\",\n\t\"./lv\": \"./node_modules/moment/locale/lv.js\",\n\t\"./lv.js\": \"./node_modules/moment/locale/lv.js\",\n\t\"./me\": \"./node_modules/moment/locale/me.js\",\n\t\"./me.js\": \"./node_modules/moment/locale/me.js\",\n\t\"./mi\": \"./node_modules/moment/locale/mi.js\",\n\t\"./mi.js\": \"./node_modules/moment/locale/mi.js\",\n\t\"./mk\": \"./node_modules/moment/locale/mk.js\",\n\t\"./mk.js\": \"./node_modules/moment/locale/mk.js\",\n\t\"./ml\": \"./node_modules/moment/locale/ml.js\",\n\t\"./ml.js\": \"./node_modules/moment/locale/ml.js\",\n\t\"./mn\": \"./node_modules/moment/locale/mn.js\",\n\t\"./mn.js\": \"./node_modules/moment/locale/mn.js\",\n\t\"./mr\": \"./node_modules/moment/locale/mr.js\",\n\t\"./mr.js\": \"./node_modules/moment/locale/mr.js\",\n\t\"./ms\": \"./node_modules/moment/locale/ms.js\",\n\t\"./ms-my\": \"./node_modules/moment/locale/ms-my.js\",\n\t\"./ms-my.js\": \"./node_modules/moment/locale/ms-my.js\",\n\t\"./ms.js\": \"./node_modules/moment/locale/ms.js\",\n\t\"./mt\": \"./node_modules/moment/locale/mt.js\",\n\t\"./mt.js\": \"./node_modules/moment/locale/mt.js\",\n\t\"./my\": \"./node_modules/moment/locale/my.js\",\n\t\"./my.js\": \"./node_modules/moment/locale/my.js\",\n\t\"./nb\": \"./node_modules/moment/locale/nb.js\",\n\t\"./nb.js\": \"./node_modules/moment/locale/nb.js\",\n\t\"./ne\": \"./node_modules/moment/locale/ne.js\",\n\t\"./ne.js\": \"./node_modules/moment/locale/ne.js\",\n\t\"./nl\": \"./node_modules/moment/locale/nl.js\",\n\t\"./nl-be\": \"./node_modules/moment/locale/nl-be.js\",\n\t\"./nl-be.js\": \"./node_modules/moment/locale/nl-be.js\",\n\t\"./nl.js\": \"./node_modules/moment/locale/nl.js\",\n\t\"./nn\": \"./node_modules/moment/locale/nn.js\",\n\t\"./nn.js\": \"./node_modules/moment/locale/nn.js\",\n\t\"./oc-lnc\": \"./node_modules/moment/locale/oc-lnc.js\",\n\t\"./oc-lnc.js\": \"./node_modules/moment/locale/oc-lnc.js\",\n\t\"./pa-in\": \"./node_modules/moment/locale/pa-in.js\",\n\t\"./pa-in.js\": \"./node_modules/moment/locale/pa-in.js\",\n\t\"./pl\": \"./node_modules/moment/locale/pl.js\",\n\t\"./pl.js\": \"./node_modules/moment/locale/pl.js\",\n\t\"./pt\": \"./node_modules/moment/locale/pt.js\",\n\t\"./pt-br\": \"./node_modules/moment/locale/pt-br.js\",\n\t\"./pt-br.js\": \"./node_modules/moment/locale/pt-br.js\",\n\t\"./pt.js\": \"./node_modules/moment/locale/pt.js\",\n\t\"./ro\": \"./node_modules/moment/locale/ro.js\",\n\t\"./ro.js\": \"./node_modules/moment/locale/ro.js\",\n\t\"./ru\": \"./node_modules/moment/locale/ru.js\",\n\t\"./ru.js\": \"./node_modules/moment/locale/ru.js\",\n\t\"./sd\": \"./node_modules/moment/locale/sd.js\",\n\t\"./sd.js\": \"./node_modules/moment/locale/sd.js\",\n\t\"./se\": \"./node_modules/moment/locale/se.js\",\n\t\"./se.js\": \"./node_modules/moment/locale/se.js\",\n\t\"./si\": \"./node_modules/moment/locale/si.js\",\n\t\"./si.js\": \"./node_modules/moment/locale/si.js\",\n\t\"./sk\": \"./node_modules/moment/locale/sk.js\",\n\t\"./sk.js\": \"./node_modules/moment/locale/sk.js\",\n\t\"./sl\": \"./node_modules/moment/locale/sl.js\",\n\t\"./sl.js\": \"./node_modules/moment/locale/sl.js\",\n\t\"./sq\": \"./node_modules/moment/locale/sq.js\",\n\t\"./sq.js\": \"./node_modules/moment/locale/sq.js\",\n\t\"./sr\": \"./node_modules/moment/locale/sr.js\",\n\t\"./sr-cyrl\": \"./node_modules/moment/locale/sr-cyrl.js\",\n\t\"./sr-cyrl.js\": \"./node_modules/moment/locale/sr-cyrl.js\",\n\t\"./sr.js\": \"./node_modules/moment/locale/sr.js\",\n\t\"./ss\": \"./node_modules/moment/locale/ss.js\",\n\t\"./ss.js\": \"./node_modules/moment/locale/ss.js\",\n\t\"./sv\": \"./node_modules/moment/locale/sv.js\",\n\t\"./sv.js\": \"./node_modules/moment/locale/sv.js\",\n\t\"./sw\": \"./node_modules/moment/locale/sw.js\",\n\t\"./sw.js\": \"./node_modules/moment/locale/sw.js\",\n\t\"./ta\": \"./node_modules/moment/locale/ta.js\",\n\t\"./ta.js\": \"./node_modules/moment/locale/ta.js\",\n\t\"./te\": \"./node_modules/moment/locale/te.js\",\n\t\"./te.js\": \"./node_modules/moment/locale/te.js\",\n\t\"./tet\": \"./node_modules/moment/locale/tet.js\",\n\t\"./tet.js\": \"./node_modules/moment/locale/tet.js\",\n\t\"./tg\": \"./node_modules/moment/locale/tg.js\",\n\t\"./tg.js\": \"./node_modules/moment/locale/tg.js\",\n\t\"./th\": \"./node_modules/moment/locale/th.js\",\n\t\"./th.js\": \"./node_modules/moment/locale/th.js\",\n\t\"./tk\": \"./node_modules/moment/locale/tk.js\",\n\t\"./tk.js\": \"./node_modules/moment/locale/tk.js\",\n\t\"./tl-ph\": \"./node_modules/moment/locale/tl-ph.js\",\n\t\"./tl-ph.js\": \"./node_modules/moment/locale/tl-ph.js\",\n\t\"./tlh\": \"./node_modules/moment/locale/tlh.js\",\n\t\"./tlh.js\": \"./node_modules/moment/locale/tlh.js\",\n\t\"./tr\": \"./node_modules/moment/locale/tr.js\",\n\t\"./tr.js\": \"./node_modules/moment/locale/tr.js\",\n\t\"./tzl\": \"./node_modules/moment/locale/tzl.js\",\n\t\"./tzl.js\": \"./node_modules/moment/locale/tzl.js\",\n\t\"./tzm\": \"./node_modules/moment/locale/tzm.js\",\n\t\"./tzm-latn\": \"./node_modules/moment/locale/tzm-latn.js\",\n\t\"./tzm-latn.js\": \"./node_modules/moment/locale/tzm-latn.js\",\n\t\"./tzm.js\": \"./node_modules/moment/locale/tzm.js\",\n\t\"./ug-cn\": \"./node_modules/moment/locale/ug-cn.js\",\n\t\"./ug-cn.js\": \"./node_modules/moment/locale/ug-cn.js\",\n\t\"./uk\": \"./node_modules/moment/locale/uk.js\",\n\t\"./uk.js\": \"./node_modules/moment/locale/uk.js\",\n\t\"./ur\": \"./node_modules/moment/locale/ur.js\",\n\t\"./ur.js\": \"./node_modules/moment/locale/ur.js\",\n\t\"./uz\": \"./node_modules/moment/locale/uz.js\",\n\t\"./uz-latn\": \"./node_modules/moment/locale/uz-latn.js\",\n\t\"./uz-latn.js\": \"./node_modules/moment/locale/uz-latn.js\",\n\t\"./uz.js\": \"./node_modules/moment/locale/uz.js\",\n\t\"./vi\": \"./node_modules/moment/locale/vi.js\",\n\t\"./vi.js\": \"./node_modules/moment/locale/vi.js\",\n\t\"./x-pseudo\": \"./node_modules/moment/locale/x-pseudo.js\",\n\t\"./x-pseudo.js\": \"./node_modules/moment/locale/x-pseudo.js\",\n\t\"./yo\": \"./node_modules/moment/locale/yo.js\",\n\t\"./yo.js\": \"./node_modules/moment/locale/yo.js\",\n\t\"./zh-cn\": \"./node_modules/moment/locale/zh-cn.js\",\n\t\"./zh-cn.js\": \"./node_modules/moment/locale/zh-cn.js\",\n\t\"./zh-hk\": \"./node_modules/moment/locale/zh-hk.js\",\n\t\"./zh-hk.js\": \"./node_modules/moment/locale/zh-hk.js\",\n\t\"./zh-mo\": \"./node_modules/moment/locale/zh-mo.js\",\n\t\"./zh-mo.js\": \"./node_modules/moment/locale/zh-mo.js\",\n\t\"./zh-tw\": \"./node_modules/moment/locale/zh-tw.js\",\n\t\"./zh-tw.js\": \"./node_modules/moment/locale/zh-tw.js\"\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 = \"./node_modules/moment/locale sync recursive ^\\\\.\\\\/.*$\";","// Module\nvar code = \"\\n\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.open_api_clients.open_api_clients' }}

\\n
\\n
\\n\\n \\n
\\n
\\n\\n
\\n
\\n
\\n
\\n\\n \\n\\n
\\n
\\n \\n
\\n\\n \\n \\n
\\n\\n \\n \\n \\n \\n\\n \\n\\n \\n\\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.open_api_clients.name' | translate }} {{ 'app.admin.open_api_clients.calls_count' | translate }} {{ 'app.admin.open_api_clients.token' | translate }}{{ 'app.admin.open_api_clients.created_at' | translate }}
{{ client.name }}{{ client.calls_count }}{{ client.token }}{{ client.created_at | amDateFormat: 'LL' }}\\n
\\n \\n\\n \\n\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/open_api_clients/index.html.erb';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n \\n\\n \\n\\n \\n \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/header.html.erb';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n \\n
4\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
\\n
\\n
\\n
{{user.username}}
\\n {{user.name}}\\n {{ 'app.shared.public_profile.private_profile' | translate }}\\n
\\n
\\n {{ 'app.shared.public_profile.last_activity_html' }}\\n
\\n {{ 'app.shared.public_profile.email_address' }}\\n
{{user.email}}
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n\\n
\\n\\n\\n\\n
\\n
\\n
\\n
\\n
\\n
\\n {{ 'app.shared.public_profile.interests' }}\\n
\\n
\\n
\\n {{ 'app.shared.public_profile.CAD_softwares_mastered' }}\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n\\n
\\n\\n
\\n
\\n
\\n

{{ 'app.shared.public_profile.trainings' }}

\\n \\n
    0 || user.trainings.length > 0\\\">\\n
  • \\n {{r.reservable.name}} - {{ 'app.shared.public_profile.to_come' }}\\n
  • \\n
  • \\n {{t.name}} - {{ 'app.shared.public_profile.approved' }}\\n
  • \\n
\\n
{{ 'app.shared.public_profile.no_trainings' }}
\\n
\\n
\\n\\n \\n\\n
\\n\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/publicProfile.html.erb';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.manage_abuses.abuses_list' }}

\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.manage_abuses.no_reports' }}\\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/abuses/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.admins_new.add_an_administrator' }}

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n
\\n \\n
\\n\\n\\n \\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/admins/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.authentication_edit.provider' | translate }} {{provider.name}}

\\n
\\n\\n
\\n\\n
\\n
\\n
\\n {{ 'app.shared.buttons.cancel' }}\\n
\\n
\\n\\n
\\n\\n
\\n\\n
\\n\\n\\n
\\n
\\n\\n
\\n\\n
\\n
\\n\\n \\n
\\n\\n
\\n
\\n\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/authentications/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n\\n \\n \\n \\n \\n\\n \\n\\n \\n\\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members.authentication_form.name' }}{{ 'app.admin.members.authentication_form.strategy_name' }}{{ 'app.admin.members.authentication_form.type' }}{{ 'app.admin.members.authentication_form.state' }}
{{ provider.name }}{{ provider.strategy_name }}{{ getType(provider.providable_type) }}{{ getState(provider.status) }}\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/authentications/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.authentication_new.add_a_new_authentication_provider' }}

\\n
\\n\\n
\\n\\n
\\n
\\n
\\n {{ 'app.shared.buttons.cancel' }}\\n
\\n
\\n\\n
\\n\\n
\\n\\n
\\n\\n\\n
\\n
\\n\\n\\n
\\n
\\n\\n \\n\\n
\\n
\\n\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/authentications/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.calendar.calendar_management' }}

\\n
\\n
\\n\\n \\n\\n
\\n
\\n\\n\\n
\\n\\n
\\n
\\n

{{ 'app.admin.calendar.legend' }}

\\n
\\n {{ 'app.admin.calendar.trainings' }}
\\n {{ 'app.admin.calendar.machines' }}
\\n {{ 'app.admin.calendar.spaces' }}\\n {{ 'app.admin.calendar.events' }}\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n
\\n\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/calendar/calendar.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

{{ 'app.admin.calendar.confirmation_required' }}

\\n
\\n
\\n

{{ 'app.admin.calendar.do_you_really_want_to_delete_this_slot' }}

\\n

{{ 'app.admin.calendar.delete_recurring_slot' }}

\\n
\\n \\n \\n \\n
\\n
\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/calendar/deleteRecurrent.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

\\n {{ 'app.admin.calendar.DATE_slot' | translate:{DATE:(start | amDateFormat: 'LL')} }} {{start | amDateFormat:'LT'}} - {{end | amDateFormat:'LT'}}\\n

\\n
\\n
\\n \\n
\\n
\\n \\n
\\n
\\n \\n
\\n
\\n \\n
\\n
\\n {{ 'app.admin.calendar.no_modules_available' }}\\n
\\n
\\n
\\n
\\n\\n
\\n

{{ 'app.admin.calendar.select_some_machines' | translate }}

\\n\\n
\\n \\n \\n
\\n \\n
\\n\\n
\\n \\n
\\n
\\n \\n
\\n \\n
\\n
\\n
\\n \\n
\\n\\n
\\n \\n
\\n
\\n \\n
\\n \\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.calendar.divide_this_availability' }}

\\n
\\n
\\n
\\n \\n {{ 'app.admin.calendar.slots' }}\\n
\\n
\\n

\\n {{ 'app.admin.calendar.slots_of' }}\\n

\\n
\\n
\\n \\n {{ 'app.admin.calendar.minutes' }}\\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.calendar.adjust_the_opening_hours' }}

\\n
\\n
\\n \\n
\\n {{ 'app.admin.calendar.to_time' }}\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.calendar.restrict_options' }}

\\n
\\n
\\n

{{ 'app.admin.calendar.restrict_with_labels' }}

\\n
\\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.calendar.restrict_for_subscriptions' }}

\\n
\\n
\\n \\n \\n
\\n
\\n

{{ 'app.admin.calendar.select_some_plans' | translate }}

\\n\\n
\\n \\n
\\n
{{::group.name}}
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.calendar.recurrence' }}

\\n
\\n
\\n \\n \\n \\n
\\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.calendar.summary' }}

\\n
\\n {{ 'app.admin.calendar.about_to_create' | translate:{NUMBER:occurrences.length,TYPE:availability.available_type} }}\\n
    \\n
  • {{slot.start_at | amDateFormat:'L LT'}} - {{slot.end_at | amDateFormat:'LT'}}
  • \\n
\\n
\\n \\n {{ 'app.admin.calendar.divided_in_slots' }}\\n
\\n
\\n {{ 'app.admin.calendar.reservable' }}\\n \\n
\\n
\\n {{ 'app.admin.calendar.labels' }}\\n \\n
\\n
\\n {{ 'app.admin.calendar.plans' }}\\n \\n
\\n
\\n
\\n
\\n
\\n \\n \\n \\n
\\n
\\n \\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/calendar/eventModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.icalendar.icalendar_import' }}

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n\\n
\\n
\\n {{ 'app.admin.icalendar.intro' }}\\n
\\n
\\n 0\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.icalendar.name' }}{{ 'app.admin.icalendar.url' }}{{ 'app.admin.icalendar.display' }}
{{calendar.name}}{{calendar.url}} {{ calendar.text_hidden ? '' : 'app.admin.icalendar.example' }}\\n \\n \\n \\n
\\n
\\n

{{ 'app.admin.icalendar.new_import' }}

\\n
\\n
\\n \\n
\\n \\n
\\n
\\n
\\n \\n
\\n \\n
\\n
\\n
\\n \\n
\\n \\n
\\n
\\n
\\n \\n
\\n \\n
\\n
\\n \\n \\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/calendar/icalendar.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n \\n {{ 'app.shared.coupon.name_is_required' }}\\n
\\n\\n
\\n \\n \\n {{ 'app.shared.coupon.code_is_required' }}\\n {{ 'app.shared.coupon.code_must_be_composed_of_capital_letters_digits_and_or_dashes' }}\\n
\\n\\n
\\n \\n \\n
\\n\\n
\\n \\n
\\n \\n \\n
\\n {{ 'app.shared.coupon.percent_off_is_required' }}\\n {{ 'app.shared.coupon.percentage_must_be_between_0_and_100' }}\\n
\\n\\n\\n
\\n
\\n {{currencySymbol}}\\n \\n
\\n {{ 'app.shared.coupon.percent_off_is_required' }}\\n {{ 'app.shared.coupon.percentage_must_be_between_0_and_100' }}\\n
\\n\\n
\\n \\n \\n {{ 'app.shared.coupon.validity_per_user_is_required' }}\\n
\\n

{{ 'app.shared.coupon.warn_validity_once' }}

\\n

{{ 'app.shared.coupon.warn_validity_forever' }}

\\n\\n
\\n \\n
\\n \\n \\n \\n \\n
\\n {{ errors['valid_until'].join(' ; ') }}\\n\\n \\n {{ 'app.shared.coupon.leave_empty_for_no_limit' | translate }}\\n \\n
\\n\\n
\\n \\n \\n {{ 'app.shared.coupon.max_usages_must_be_equal_or_greater_than_0' }}\\n\\n \\n {{ 'app.shared.coupon.leave_empty_for_no_limit' | translate }}\\n \\n
\\n\\n
\\n \\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/coupons/_form.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.coupons_edit.coupon' | translate }} {{ coupon.name }}

\\n
\\n
\\n\\n \\n\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n \\n\\n \\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/coupons/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.coupons_new.add_a_coupon' }}

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n \\n\\n \\n\\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/coupons/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.events.categories' }}

\\n

{{ 'app.admin.events.at_least_one_category_is_required' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.events.name' }}
\\n \\n {{ category.name }}\\n \\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n\\n

{{ 'app.admin.events.themes' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.events.name' }}
\\n \\n {{ theme.name }}\\n \\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n\\n

{{ 'app.admin.events.age_ranges' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.events.name' }}
\\n \\n {{ range.name }}\\n \\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/events/filters.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.events.fablab_events' }}

\\n
\\n
\\n\\n \\n
\\n\\n
\\n
\\n
\\n \\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n \\n
\\n
\\n \\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/events/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n
\\n\\n\\n \\n \\n \\n \\n\\t \\n \\n \\n \\n \\n \\n\\n \\n\\n \\n\\n\\t\\n\\n \\n \\n \\n
{{ 'app.admin.events.title' }}{{ 'app.admin.events.dates' }}{{ 'app.admin.events.booking' }}
\\n {{ event.title }} \\n \\n\\n \\n\\t \\n\\t\\t{{ 'app.admin.events.on_DATE' | translate:{DATE:(event.start_date | amDateFormat:'LL')} }}\\n \\n {{ 'app.admin.events.from_TIME' | translate:{TIME:event.start_time} }}\\n {{ 'app.admin.events.to_time' }}\\n {{event.end_time}}\\n \\n\\t \\n\\n \\n\\t \\n\\t {{'app.admin.events.from_DATE' | translate:{DATE:(event.start_date | amDateFormat:'LL')} }}\\n\\t {{'app.admin.events.to_date' | translate}} {{event.end_date | amDateFormat:'LL'}}\\n
\\n \\n {{ 'app.admin.events.from_TIME' | translate:{TIME:event.start_time} }}\\n {{ 'app.admin.events.to_time' }}\\n {{event.end_time}}\\n \\n
\\n
\\n\\t 0\\\">{{ event.nb_total_places - event.nb_free_places }} / {{ event.nb_total_places }}\\n\\t {{ 'app.admin.events.cancelled' }}\\n {{ 'app.admin.events.without_reservation' }}\\n\\t\\n \\n
\\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/events/monitoring.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

{{ 'app.admin.events.price_category' }}

\\n
\\n
\\n
\\n
\\n
\\n
\\n \\n \\n
\\n {{ 'app.admin.events.category_name_is_required' }}\\n
\\n
\\n\\n
\\n
\\n \\n {{ 'app.admin.events.conditions_are_required' }}\\n
\\n
\\n
\\n
\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/events/price_form.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.events.prices_categories' }}

\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.events.name' }}{{ 'app.admin.events.usages_count' }}
{{ category.name }}{{ category.events }}\\n
\\n \\n \\n
\\n
\\n\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/events/prices.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.event_reservations.the_reservations' | translate }} {{event.title}}

\\n
\\n
\\n
\\n\\n
\\n
\\n
\\n\\n\\n 0\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.event_reservations.user' }}{{ 'app.admin.event_reservations.payment_date' }}{{ 'app.admin.event_reservations.reserved_tickets' }}
\\n {{ reservation.user_full_name }} \\n {{ reservation.created_at | amDateFormat:'LL LTS' }}\\n 0\\\">{{ 'app.admin.event_reservations.full_price_' | translate }} {{reservation.nb_reserve_places}}
\\n {{ticket.event_price_category.price_category.name}} : {{ticket.booked}}\\n
{{ 'app.admin.event_reservations.canceled' }}
\\n
\\n
\\n \\n
\\n
\\n

{{ 'app.admin.event_reservations.no_reservations_for_now' }}

\\n\\n \\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/events/reservations.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members.group_form.group_name' }}
\\n \\n {{group.name}}\\n \\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/groups/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
  • {{ 'app.admin.invoices.closed_at' }} : {{period.closed_at | amDateFormat:'L'}}
  • \\n
  • {{ 'app.admin.invoices.closed_by' }} : {{period.user_name}}
  • \\n
  • {{ 'app.admin.invoices.period_total' }} : {{period.period_total | currency}}
  • \\n
  • {{ 'app.admin.invoices.perpetual_total' }} : {{period.perpetual_total | currency}}
  • \\n
  • \\n {{ 'app.admin.invoices.integrity' }} :\\n \\n \\n
  • \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/_period.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.invoices.export_accounting_data' }}

\\n
\\n
\\n
\\n
\\n
\\n \\n
\\n \\n \\n
\\n
\\n
\\n \\n
\\n \\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.invoices.export_what' }}

\\n
\\n \\n \\n
\\n
\\n
\\n
{{ 'app.admin.invoices.format' }}
\\n
{{ exportTarget.settings.format }}
\\n
{{ 'app.admin.invoices.encoding' }}
\\n
{{ exportTarget.settings.encoding }}
\\n
{{ 'app.admin.invoices.separator' }}
\\n
{{ exportTarget.settings.separator }}
\\n
{{ 'app.admin.invoices.dateFormat' }}
\\n \\n
{{ 'app.admin.invoices.labelMaxLength' }}
\\n
{{ exportTarget.settings.labelMaxLength }}
\\n
{{ 'app.admin.invoices.decimalSeparator' }}
\\n
{{ exportTarget.settings.decimalSeparator }}
\\n
{{ 'app.admin.invoices.exportInvoicesAtZero' }}
\\n
{{ exportTarget.settings.exportInvoicesAtZero ? 'app.shared.buttons.yes' : 'app.shared.buttons.no' }}
\\n
{{ 'app.admin.invoices.columns' }}
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.invoices.exportColumns.' + column }}
\\n
\\n
\\n
\\n
\\n
\\n \\n \\n \\n \\n \\n \\n \\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/accountingExportModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.invoices.create_a_refund_on_this_invoice' }}

\\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
1\\\" class=\\\"form-group\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.invoices.description' }}{{ 'app.admin.invoices.price' }}
{{item.amount | currency}}
\\n
\\n
\\n \\n

{{ 'app.admin.invoices.will_appear_on_the_refund_invoice' }}

\\n \\n
\\n
\\n
\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/avoirModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.invoices.close_accounting_period' }}

\\n
\\n
\\n
\\n
\\n \\n
\\n \\n \\n
\\n {{ 'app.admin.invoices.start_date_is_required' }}\\n {{ errors.start_at[0] }}\\n
\\n
\\n \\n
\\n \\n \\n
\\n {{ 'app.admin.invoices.end_date_is_required' }}\\n {{ errors.end_at[0] }}\\n
\\n
\\n
\\n {{ $parent.invoiceErrorRE.exec(key)[1] }} : {{ value[0] }}\\n
\\n
\\n

{{ 'app.admin.invoices.previous_closings' }}

\\n 0\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.invoices.start_date' }}{{ 'app.admin.invoices.end_date' }}
{{period.start_at | amDateFormat:'L'}}{{period.end_at | amDateFormat:'L'}}\\n \\n \\n \\n
\\n
{{ 'app.admin.invoices.no_periods'}}
\\n
\\n
\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/closePeriodModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/codes.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.invoices.invoices' }}

\\n
\\n
\\n \\n
\\n
\\n\\n
\\n
\\n
\\n \\n \\n \\n\\t \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\t \\n\\t
\\n\\n
\\n \\n \\n \\n \\n\\n \\n \\n \\n \\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"

{{ 'app.admin.invoices.filter_invoices' | translate }}

\\n\\n
\\n
\\n
\\n
\\n {{ 'app.admin.invoices.invoice_num_' }}\\n \\n
\\n
\\n
\\n\\n
\\n
\\n
\\n {{ 'app.admin.invoices.customer_' }}\\n \\n
\\n
\\n
\\n\\n
\\n
\\n
\\n {{ \\\"app.admin.invoices.date_\\\" | translate }}\\n \\n
\\n
\\n
\\n\\n
\\n\\n
\\n
\\n\\n 0\\\">\\n \\n \\n \\n \\n\\n \\n\\n \\n\\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.invoices.invoice_num' | translate }} {{ 'app.admin.invoices.date' | translate }} {{ 'app.admin.invoices.price' | translate }} {{ 'app.admin.invoices.customer' | translate }}
\\n \\n \\n \\n \\n \\n \\n \\n {{ invoice.reference }}{{ invoice.date | amDateFormat:'L LTS' }}{{ invoice.date | amDateFormat:'L' }}{{ invoice.total | currency}}\\n {{ invoice.name }}\\n {{ invoice.name }}\\n \\n \\n
\\n
\\n \\n
\\n

{{ 'app.admin.invoices.no_invoices_for_now' }}

\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/list.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n {{ 'app.admin.invoices.payment.payment_settings' }}\\n
\\n
\\n
\\n

{{ 'app.admin.invoices.payment.online_payment' }}

\\n

\\n \\n \\n \\n
\\n
\\n

{{ 'app.admin.invoices.payment.stripe_keys' }}

\\n
\\n \\n
\\n \\n \\n
\\n
\\n
\\n \\n
\\n \\n \\n
\\n
\\n
\\n \\n
\\n
\\n
\\n

{{ 'app.admin.invoices.payment.currency' }}

\\n

\\n

\\n
\\n \\n \\n
\\n
\\n
\\n \\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/payment.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n {{ 'app.admin.invoices.warning_invoices_disabled' }}\\n
\\n
\\n \\n
\\n
\\n \\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n {{ 'app.admin.invoices.change_logo' | translate }}\\n \\n
\\n
\\n
\\n
\\n
\\n {{ 'app.admin.invoices.john_smith' }}\\n
{{ 'app.admin.invoices.john_smith_at_example_com' }}
\\n
\\n
{{ 'app.admin.invoices.invoice_reference_' | translate }} {{mkReference()}}
\\n
{{ 'app.admin.invoices.code_' | translate }} {{invoice.code.model}}
\\n
{{ 'app.admin.invoices.code_disabled' }}
\\n
{{ 'app.admin.invoices.order_num' | translate }} {{mkNumber()}}
\\n
{{ 'app.admin.invoices.invoice_issued_on_DATE_at_TIME' | translate:{DATE:(today | amDateFormat:'L'), TIME:(today | amDateFormat:'LT')} }}
\\n
\\n {{ 'app.admin.invoices.object_reservation_of_john_smith_on_DATE_at_TIME' | translate:{DATE:(inOneWeek | amDateFormat:'L'), TIME:(inOneWeek | amDateFormat:'LT')} }}\\n
\\n
\\n {{ 'app.admin.invoices.order_summary' | translate }}\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n\\n \\n
{{ 'app.admin.invoices.details' }}{{ 'app.admin.invoices.amount' }}
{{ 'app.admin.invoices.machine_booking-3D_printer' | translate }} {{inOneWeek | amDateFormat:'LLL'}} - {{inOneWeekAndOneHour | amDateFormat:'LT'}}{{30.0 | currency}}
{{ 'app.admin.invoices.total_amount' }}{{ 'app.admin.invoices.total_including_all_taxes' }}{{30.0 | currency}}
{{ 'app.admin.invoices.VAT_disabled' }}
{{ 'app.admin.invoices.including_VAT' }}{{30-(30/(getMachineExampleRate()/100+1)) | currency}}
{{ 'app.admin.invoices.including_total_excluding_taxes' }}{{30/(getMachineExampleRate()/100+1) | currency}}
{{ 'app.admin.invoices.including_amount_payed_on_ordering' }}{{30.0 | currency}}
\\n

\\n {{ 'app.admin.invoices.settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT' }}\\n

\\n
\\n
\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/settings.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n

{{ 'app.admin.invoices.code' }}

\\n
\\n
\\n
\\n \\n \\n
\\n\\n
\\n \\n \\n
\\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/settings/editCode.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n

{{ 'app.admin.invoices.order_number' }}

\\n
\\n
\\n
\\n

{{ 'app.admin.invoices.elements' }}

\\n
    \\n
  • {{ 'app.admin.invoices.year' | translate }}
  • \\n
  • {{ 'app.admin.invoices.month' | translate }}
  • \\n
  • {{ 'app.admin.invoices.day' | translate }}
  • \\n
  • {{ 'app.admin.invoices.order_num' | translate }}
  • \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.invoices.model' }}

\\n \\n
\\n
\\n

{{ 'app.admin.invoices.documentation' }}

\\n \\n \\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/settings/editNumber.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n

{{ 'app.admin.invoices.invoice_reference' }}

\\n
\\n
\\n
\\n

Éléments

\\n
    \\n
  • {{ 'app.admin.invoices.year' | translate }}
  • \\n
  • {{ 'app.admin.invoices.month' | translate }}
  • \\n
  • {{ 'app.admin.invoices.day' | translate }}
  • \\n
  • {{ 'app.admin.invoices.num_of_invoice' | translate }}
  • \\n
  • {{ 'app.admin.invoices.online_sales' | translate }}
  • \\n
  • {{ 'app.admin.invoices.refund' | translate }}
  • \\n
  • {{ 'app.admin.invoices.payment_schedule' | translate }}
  • \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.invoices.model' }}

\\n \\n {{ 'app.admin.invoices.invoice_reference_is_required' }}\\n
\\n
\\n

{{ 'app.admin.invoices.documentation' }}

\\n \\n \\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/settings/editReference.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n

{{ 'app.admin.invoices.payment.stripe_keys' }}

\\n
\\n
\\n
\\n
\\n
\\n \\n
\\n \\n \\n \\n \\n \\n \\n
\\n
\\n
\\n \\n
\\n \\n \\n \\n \\n \\n \\n
\\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/invoices/settings/stripeKeys.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/machines/categories.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n
\\n\\n
\\n

{{ 'app.admin.machines.the_fablab_s_machines' }}

\\n
\\n
\\n\\n
\\n \\n\\n \\n \\n \\n\\n \\n
\\n
\\n

{{ 'app.admin.machines.all_machines' }}

\\n \\n
\\n \\n
\\n
\\n\\n \\n \\n \\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/machines/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n \\n \\n\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/machines/machines.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.manager_new.add_a_manager' }}

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n
\\n \\n
\\n\\n\\n \\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/managers/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n
\\n \\n \\n {{ 'app.shared.user_admin.group_is_required' }}\\n
\\n
\\n\\n
\\n \\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
\\n
\\n\\n
\\n \\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/_form.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n\\n \\n \\n \\n \\n\\n \\n\\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members.surname' | translate }} {{ 'app.admin.members.first_name' | translate }} {{ 'app.admin.members.email' | translate }} {{ 'app.admin.members.phone' | translate }}
{{ admin.profile_attributes.last_name }}{{ admin.profile_attributes.first_name }}{{ admin.email }}{{ admin.profile_attributes.phone }}\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/administrators.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

{{ 'app.admin.members_edit.change_role' }}

\\n
\\n
\\n

{{ 'app.admin.members_edit.warning_role_change' }}

\\n \\n
\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/change_role_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.shared.user_admin.user' | translate }} {{ user.name }}

\\n {{ 'app.shared.user_admin.incomplete_profile' }}\\n
\\n \\n
\\n
\\n
\\n\\n
\\n
\\n
\\n \\\"role{{ 'app.admin.members_edit.change_role' }}\\n
\\n \\n
\\n\\n
\\n\\n
\\n\\n
\\n\\n\\n
\\n
\\n\\n \\n\\n \\n\\n
\\n
\\n {{ 'app.shared.user_admin.warning_incomplete_user_profile_probably_imported_from_sso' }}\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n\\n
\\n\\n \\n \\n \\n\\n \\n\\n\\n
\\n
\\n
\\n

{{ subscription.plan | humanReadablePlanName }}

\\n

\\n {{ 'app.admin.members_edit.duration' | translate }} {{ subscription.plan.interval | planIntervalFilter: subscription.plan.interval_count }}\\n

\\n

\\n {{ 'app.admin.members_edit.expires_at' | translate }} {{ subscription.expired_at | amDateFormat: 'L' }}\\n

\\n

\\n {{ 'app.admin.members_edit.price_' | translate }} {{ subscription.plan.amount | currency}}\\n

\\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
\\n

\\n {{ 'app.admin.members_edit.cannot_extend_own_subscription' }}\\n

\\n
\\n\\n\\n
\\n

\\n {{ 'app.admin.members_edit.user_has_no_current_subscription' }}\\n

\\n \\n \\n \\n
\\n\\n
\\n\\n
\\n
\\n\\n \\n
\\n
\\n
\\n

{{ 'app.admin.members_edit.next_trainings' | translate }}

\\n
\\n
\\n
    0\\\">\\n
  • \\n {{r.reservable.name}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n
  • \\n
\\n
{{ 'app.admin.members_edit.no_trainings' }}
\\n
\\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.members_edit.passed_trainings' | translate }}

\\n
\\n
\\n
    0\\\">\\n
  • \\n {{r.reservable.name}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n \\n\\n
  • \\n
\\n
{{ 'app.admin.members_edit.no_trainings' }}
\\n
\\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.members_edit.validated_trainings' | translate }}

\\n
\\n
\\n
    0\\\">\\n
  • \\n {{t.name}}\\n
  • \\n
\\n
{{ 'app.admin.members_edit.no_trainings' }}
\\n
\\n
\\n
\\n
\\n\\n \\n
\\n
\\n
\\n

{{ 'app.admin.members_edit.next_events' | translate }}

\\n
\\n
\\n
    0\\\">\\n
  • \\n {{r.reservable.title}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n 0\\\">\\n
    \\n {{ 'app.admin.members_edit.NUMBER_full_price_tickets_reserved' }}\\n
    \\n \\n
    \\n {{ 'app.admin.members_edit.NUMBER_NAME_tickets_reserved' }}\\n
    \\n
  • \\n
\\n
{{ 'app.admin.members_edit.no_upcoming_events' }}
\\n
\\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.members_edit.passed_events' | translate }}

\\n
\\n
\\n
    0\\\">\\n
  • \\n {{r.reservable.title}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n
  • \\n
\\n
{{ 'app.admin.members_edit.no_passed_events' }}
\\n
\\n
\\n
\\n
\\n\\n \\n
\\n\\n\\n 0\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members_edit.invoice_num' }}{{ 'app.admin.members_edit.date' }}{{ 'app.admin.members_edit.price' }}
{{ invoice.reference }}{{ invoice.date | amDateFormat:'L LTS' }}{{ invoice.date | amDateFormat:'L' }}{{ invoice.total | currency }}\\n \\n
\\n

{{ 'app.admin.members_edit.no_invoices_for_now' }}

\\n\\n
\\n
\\n\\n \\n
\\n \\n\\n
\\n
\\n \\n
\\n

\\n {{ 'app.admin.members_edit.cannot_credit_own_wallet' }}\\n

\\n\\n
\\n\\n
\\n \\n
\\n
\\n
\\n\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n\\n
\\n
\\n

{{ 'app.admin.members_import.import_members' }}

\\n
\\n
\\n\\n \\n\\n
\\n
\\n\\n
\\n
\\n

\\n {{ 'app.admin.members_import.info' }}\\n

\\n
\\n
\\n\\n
\\n\\n
\\n

{{ 'app.admin.members_import.groups' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members_import.group_name' }}{{ 'app.admin.members_import.group_identifier' }}
\\n {{ group.name }}\\n \\n {{ group.slug }}\\n
\\n
\\n\\n
\\n

{{ 'app.admin.members_import.trainings' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members_import.training_name' }}{{ 'app.admin.members_import.training_identifier' }}
\\n {{ training.name }}\\n \\n {{ training.id }}\\n
\\n
\\n\\n
\\n\\n\\n
\\n\\n
\\n

{{ 'app.admin.members_import.tags' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members_import.tag_name' }}{{ 'app.admin.members_import.tag_identifier' }}
\\n {{ tag.name }}\\n \\n {{ tag.id }}\\n
\\n
\\n\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n\\n
\\n

\\n {{ 'app.admin.members_import.required_fields' }}\\n

\\n

\\n
\\n\\n
\\n
\\n {{file.attachment}}\\n
\\n {{ 'app.admin.members_import.select_file' }}\\n {{ 'app.shared.buttons.change' }}\\n \\n \\n
\\n\\n
\\n {{ 'app.admin.members_import.update_field' }}\\n
\\n \\n
\\n
\\n \\n
\\n
\\n \\n
\\n
\\n\\n
\\n\\n\\n \\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/import.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n\\n
\\n
\\n

{{ 'app.admin.members_import_result.import_results' }}

\\n
\\n
\\n\\n
\\n
\\n\\n\\n
\\n
\\n\\n

{{ 'app.admin.members_import_result.import_details' | translate:{DATE:(import.created_at | amDateFormat:'L'), USER:import.user.full_name, ID:import.id} }}

\\n\\n

{{ 'app.admin.members_import_result.pending' }}

\\n
\\n

{{ 'app.admin.members_import_result.results' }}

\\n\\n
\\n
\\n \\n \\n \\n \\n \\n \\n \\n
{{key}}
{{value}}
\\n
\\n
\\n \\n {{ 'app.admin.members_import_result.status_' + resultRow.status | translate:{ID:resultRow.user} }}\\n \\n \\n {{ 'app.admin.members_import_result.success' }}\\n \\n \\n \\n \\n \\n \\n {{ 'app.admin.members_import_result.failed' }}\\n \\n
\\n
\\n {{ 'app.admin.members_import_result.error_details' }}{{resultRow}}\\n
\\n
\\n
\\n\\n
\\n
\\n\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/import_result.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.members.users_management' }}

\\n
\\n
\\n
\\n
\\n \\n \\n \\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n
\\n \\n\\n \\n \\n \\n\\n \\n
\\n
\\n\\n \\n
\\n
\\n\\n \\n
\\n
\\n
\\n\\n
\\n \\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"

\\n {{ 'app.admin.members.managers_info' }}\\n

\\n\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n\\n \\n \\n \\n \\n\\n \\n\\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members.surname' | translate }} {{ 'app.admin.members.first_name' | translate }} {{ 'app.admin.members.email' | translate }} {{ 'app.admin.members.phone' | translate }}
{{ manager.profile_attributes.last_name }}{{ manager.profile_attributes.first_name }}{{ manager.email }}{{ manager.profile_attributes.phone }}\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/managers.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n \\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members.username' | translate }} {{ 'app.admin.members.surname' | translate }} {{ 'app.admin.members.first_name' | translate }} {{ 'app.admin.members.email' | translate }} {{ 'app.admin.members.phone' | translate }} {{ 'app.admin.members.user_type' | translate }} {{ 'app.admin.members.subscription' | translate }}
\\n \\n {{ m.username }}{{ m.profile.last_name }}{{ m.profile.first_name }}{{ m.email }}{{ m.profile.phone }}{{ m.group.name }}{{ m.subscribed_plan | humanReadablePlanName }}\\n
\\n \\n \\n {{ 'app.shared.user_admin.incomplete_profile' }}\\n
\\n
\\n
\\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/members.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.members_new.add_a_member' }}

\\n
\\n\\n
\\n\\n
\\n
\\n
\\n {{ 'app.shared.buttons.cancel' }}\\n
\\n
\\n\\n
\\n\\n
\\n\\n
\\n\\n\\n
\\n
\\n\\n
\\n
\\n\\n \\n
\\n
\\n\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"

\\n {{ 'app.admin.members.partners_info' }}\\n

\\n\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n\\n \\n \\n \\n \\n\\n \\n\\n \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members.surname' | translate }} {{ 'app.admin.members.first_name' | translate }} {{ 'app.admin.members.email' | translate }} {{ 'app.admin.members.associated_plan' | translate }}
{{ partner.profile_attributes.last_name }}{{ partner.profile_attributes.first_name }}{{ partner.email }}{{ partner.resource ? partner.resource.base_name : '' }}\\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/partners.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/members/users.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n
\\n\\n
\\n

{{ 'app.admin.store.manage_the_store' }}

\\n
\\n
\\n\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/orders/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.plans_categories.manage_plans_categories' }}

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/plans/categories.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.plans.edit.subscription_plan' | translate }} {{ suscriptionPlan.base_name }}

\\n
\\n
\\n
\\n
\\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/plans/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.plans.new.add_a_subscription_plan' }}

\\n
\\n
\\n\\n
\\n
\\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/plans/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"

{{ 'app.admin.pricing.list_of_the_coupons' }}

\\n\\n
\\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.pricing.name' }}{{ 'app.admin.pricing.discount' }}{{ 'app.admin.pricing.nb_of_usages' }}{{ 'app.admin.pricing.status' }}
{{coupon.name}}\\n {{coupon.percent_off}} %\\n {{coupon.amount_off}} {{currencySymbol}}\\n {{coupon.usages}}{{'app.admin.pricing.'+coupon.status}}\\n \\n \\n \\n
\\n\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/coupons.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.pricing.trainings' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n\\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.pricing.subscription' }}{{ 'app.admin.pricing.credits' }}{{ 'app.admin.pricing.related_trainings' }}
\\n {{ plan | humanReadablePlanName: groups }}\\n \\n \\n {{ plan.training_credit_nb }}\\n \\n \\n \\n {{ showTrainings(trainingIds) }}\\n \\n \\n
\\n \\n \\n
\\n
\\n \\n
\\n
\\n
\\n\\n
\\n

{{ 'app.admin.pricing.machines' }}

\\n
\\n \\n
\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.pricing.machine' }}{{ 'app.admin.pricing.hours' | translate:{DURATION:slotDuration} }}{{ 'app.admin.pricing.related_subscriptions' }}
\\n \\n {{ showCreditableName(mc) }}\\n \\n \\n \\n {{ mc.hours }}\\n \\n \\n \\n {{ getPlanFromId(mc.plan_id) | humanReadablePlanName: groups: 'short' }}\\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n\\n
\\n

{{ 'app.admin.pricing.spaces' }}

\\n
\\n \\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.pricing.space' }}{{ 'app.admin.pricing.hours' | translate:{DURATION:slotDuration} }}{{ 'app.admin.pricing.related_subscriptions' }}
\\n \\n {{ showCreditableName(sc) }}\\n \\n \\n \\n {{ sc.hours }}\\n \\n \\n \\n {{ getPlanFromId(sc.plan_id) | humanReadablePlanName: groups: 'short' }}\\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/credits.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.pricing.pricing_management' }}

\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n\\n
\\n
\\n\\n\\n
\\n
\\n\\n
\\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n \\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/machine_hours.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.pricing.send_a_coupon' }}

\\n
\\n
\\n \\n
\\n
\\n

{{ 'app.admin.pricing.coupon' }}

\\n
\\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{'app.admin.pricing.code'}} {{coupon.code}}
{{'app.admin.pricing.discount'}} {{coupon.percent_off}} %{{coupon.amount_off}} {{currencySymbol}}
{{'app.admin.pricing.validity_per_user'}} {{'app.admin.pricing.'+coupon.validity_per_user}}
{{'app.admin.pricing.valid_until'}} {{coupon.valid_until | amDateFormat:'L'}}
{{'app.admin.pricing.usages'}} {{coupon.usages}} / {{coupon.max_usages | maxCount}}
{{'app.admin.pricing.enabled'}} {{coupon.active | booleanFormat}}
\\n
\\n
\\n
\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/sendCoupon.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/spaces.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"

{{ 'app.admin.pricing.list_of_the_subscription_plans' }}

\\n\\n
\\n
\\n\\n
\\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.pricing.name' | translate }} {{ 'app.admin.pricing.duration' | translate }} {{ 'app.admin.pricing.group' | translate }} {{ 'app.admin.pricing.category' | translate }} {{ 'app.admin.pricing.prominence' | translate }} {{ 'app.admin.pricing.price' | translate }}
{{plan.base_name}}{{ plan.interval | planIntervalFilter:plan.interval_count }}{{group.name}}{{getPlanCategory(plan.plan_category_id)}}{{plan.ui_weight}}{{plan.amount | currency}}
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/subscriptions.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.pricing.trainings' }}\\n {{group.name}}\\n
\\n {{ training.name }}\\n \\n \\n {{ findTrainingsPricing(trainingsPricings, training.id, group.id).amount | currency}}\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/pricing/trainings.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.projects.projects_settings' }}

\\n
\\n
\\n \\n
\\n
\\n\\n\\n
\\n
\\n\\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/projects/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.projects.name' }}{{ 'app.admin.projects.description' }}
\\n \\n {{ licence.name }}\\n \\n \\n \\n
{{ licence.description }}
\\n
\\n
\\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/projects/licences.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.projects.name' }}
\\n \\n {{ component.name }}\\n \\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/projects/materials.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n {{ 'app.admin.projects.settings.comments' }}\\n
\\n
\\n
\\n

{{ 'app.admin.projects.settings.disqus' }}

\\n

{{ 'app.admin.projects.settings.disqus_info' }}

\\n
\\n \\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.projects.settings.cad_files' }}\\n
\\n
\\n
\\n

{{ 'app.admin.projects.settings.validation' }}

\\n

{{ 'app.admin.projects.settings.validation_info' }}

\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n \\n
\\n
\\n {{file.attachment}}\\n
\\n \\n {{ 'app.admin.projects.settings.set_a_file' }}\\n {{ 'app.shared.buttons.change' }}\\n \\n \\n
\\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.projects.settings.projects_sharing' }}\\n
\\n
\\n
\\n

{{ 'app.admin.projects.settings.open_lab_projects' }}

\\n

\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n

\\n \\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/projects/settings.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.projects.name' }}
\\n \\n {{ theme.name }}\\n \\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/projects/themes.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n {{ 'app.admin.settings.link' }}\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.content' }}\\n
\\n
\\n\\n
\\n
\\n

\\n {{ 'app.admin.settings.shift_enter_to_force_carriage_return' | translate }}\\n \\n
\\n\\n
\\n\\n
\\n
\\n
\\n\\n
\\n {{ 'app.admin.settings.drag_and_drop_to_insert_images' | translate }} (max. 1200px)\\n \\n
\\n
\\n
\\n\\n
\\n {{ 'app.admin.settings.shift_enter_to_force_carriage_return' | translate }}\\n \\n
\\n
\\n

{{ 'app.admin.settings.about_follow_us' }}

\\n \\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/about.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.settings.fab_analytics' }}

\\n
\\n
\\n

{{ 'app.admin.settings.privacy.analytics.intro_analytics_html' }}

\\n
\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.settings.privacy.analytics.version' }}{{ data.version }}
{{ 'app.admin.settings.privacy.analytics.members' }}{{ data.members }}
{{ 'app.admin.settings.privacy.analytics.admins' }}{{ data.admins }}
{{ 'app.admin.settings.privacy.analytics.managers' }}{{ data.managers }}
{{ 'app.admin.settings.privacy.analytics.availabilities' }}{{ data.availabilities }}
{{ 'app.admin.settings.privacy.analytics.reservations' }}{{ data.reservations }}
{{ 'app.admin.settings.privacy.analytics.orders' }}{{ data.orders }}
{{ 'app.admin.settings.privacy.analytics.plans' }}{{ data.plans }}
{{ 'app.admin.settings.privacy.analytics.spaces' }}{{ data.spaces }}
{{ 'app.admin.settings.privacy.analytics.online_payment' }}{{ data.online_payment }}
{{ 'app.admin.settings.privacy.analytics.gateway' }}{{ data.gateway }}
{{ 'app.admin.settings.privacy.analytics.wallet' }}{{ data.wallet }}
{{ 'app.admin.settings.privacy.analytics.statistics' }}{{ data.statistics }}
{{ 'app.admin.settings.privacy.analytics.trainings' }}{{ data.trainings }}
{{ 'app.admin.settings.privacy.analytics.public_agenda' }}{{ data.public_agenda }}
{{ 'app.admin.settings.privacy.analytics.machines' }}{{ data.machines }}
{{ 'app.admin.settings.privacy.analytics.store' }}{{ data.store }}
{{ 'app.admin.settings.privacy.analytics.invoices' }}{{ data.invoices }}
{{ 'app.admin.settings.privacy.analytics.openlab' }}{{ data.openlab }}
\\n
\\n
\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/analyticsModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n {{ 'app.admin.settings.account_creation' }}\\n
\\n
\\n
\\n

{{ 'app.admin.settings.general.public_registrations' }}

\\n

\\n {{ 'app.admin.settings.general.public_registrations_info' }}\\n

\\n
\\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.account_confirmation' }}

\\n

\\n {{ 'app.admin.settings.confirmation_required_info' }}\\n

\\n
\\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.change_group' }}

\\n

\\n {{ 'app.admin.settings.change_group_info' }}\\n

\\n
\\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.account.user_validation_required_title' }}

\\n

\\n {{ 'app.admin.settings.account.user_validation_required_info' }}\\n

\\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.captcha' }}

\\n

\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n
\\n
\\n {{ 'app.admin.settings.accounts_management' }}\\n
\\n
\\n
\\n

{{ 'app.admin.settings.members_list' }}

\\n

\\n {{ 'app.admin.settings.members_list_info' }}\\n

\\n
\\n \\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.account.customize_account_settings' }}\\n
\\n
\\n
\\n

{{ 'app.admin.settings.phone' }}

\\n

\\n {{ 'app.admin.settings.phone_required_info' }}\\n

\\n
\\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.address' }}

\\n

\\n {{ 'app.admin.settings.address_required_info_html' }}\\n

\\n
\\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.external_id' }}

\\n

\\n {{ 'app.admin.settings.external_id_info_html' }}\\n

\\n
\\n \\n \\n
\\n
\\n\\n
\\n

{{ 'app.admin.settings.account.organization' }}

\\n

\\n {{ 'app.admin.settings.account.organization_profile_custom_fields_info' }}\\n

\\n

\\n {{ 'app.admin.settings.account.organization_profile_custom_fields_alert' }}\\n

\\n
\\n \\n
\\n
\\n
\\n
\\n\\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/compte.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n {{ 'app.admin.settings.general.title' }}\\n
\\n
\\n
\\n
\\n \\n \\n
\\n\\n
\\n
\\n

{{ 'app.admin.settings.general.title_concordance' }}

\\n
\\n \\n
\\n \\n
\\n \\n
\\n \\n
\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.customize_information_messages' }}\\n
\\n
\\n\\n\\n
\\n
\\n

{{ 'app.admin.settings.message_of_the_machine_booking_page' }}

\\n
\\n\\n
\\n \\n
\\n
\\n

{{ 'app.admin.settings.warning_message_of_the_training_booking_page'}}

\\n
\\n\\n
\\n \\n
\\n
\\n

{{ 'app.admin.settings.information_message_of_the_training_reservation_page'}}

\\n
\\n\\n
\\n \\n
\\n
\\n

{{ 'app.admin.settings.message_of_the_subscriptions_page' }}

\\n
\\n
\\n \\n
\\n
\\n

{{ 'app.admin.settings.message_of_the_events_page' }}

\\n
\\n
\\n \\n
\\n
\\n

{{ 'app.admin.settings.message_of_the_spaces_page' }}

\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.legal_documents'}}\\n
\\n
\\n
\\n {{ 'app.admin.settings.if_these_documents_are_not_filled_no_consent_about_them_will_be_asked_to_the_user' }}\\n
\\n
\\n
\\n \\n \\n \\n
\\n
\\n
\\n {{cgvFile.custom_asset_file_attributes.attachment}}\\n
\\n \\n {{ 'app.shared.buttons.browse' }}\\n {{ 'app.shared.buttons.change' }}\\n \\n \\n
\\n
\\n \\n
\\n
\\n
\\n
\\n \\n \\n \\n
\\n
\\n
\\n {{cguFile.custom_asset_file_attributes.attachment}}\\n
\\n \\n {{ 'app.shared.buttons.browse' }}\\n {{ 'app.shared.buttons.change' }}\\n \\n \\n
\\n
\\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.customize_the_graphics' }}\\n
\\n
\\n
\\n {{ 'app.admin.settings.for_an_optimal_rendering_the_logo_image_must_be_at_the_PNG_format_with_a_transparent_background_and_with_an_aspect_ratio_3.5_times_wider_than_the_height' }}
\\n {{ 'app.admin.settings.concerning_the_favicon_it_must_be_at_ICO_format_with_a_size_of_16x16_pixels' }}
\\n
\\n {{ 'app.admin.settings.remember_to_refresh_the_page_for_the_changes_to_take_effect' }}\\n
\\n
\\n
\\n
\\n \\n \\n

{{ 'app.admin.settings.logo_white_background' }}

\\n
\\n \\n \\n \\\"{{customLogo.custom_asset_file_attributes.attachment}}\\\"\\n
\\n
\\n
\\n {{ 'app.admin.settings.change_the_logo' | translate }}\\n \\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n \\n \\n

{{ 'app.admin.settings.logo_black_background' }}

\\n \\n \\n
\\n
\\n
\\n
\\n \\n \\n

{{ 'app.admin.settings.favicon' }}

\\n
\\n \\n \\n \\\"{{customFavicon.custom_asset_file_attributes.attachment}}\\\"\\n
\\n
\\n
\\n {{ 'app.admin.settings.change_the_favicon' | translate }}\\n \\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.main_colour' }}

\\n
\\n
\\n
\\n
\\n \\n
\\n \\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.secondary_colour' }}

\\n
\\n
\\n
\\n
\\n \\n
\\n \\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n
\\n \\n \\n

{{ 'app.admin.settings.background_picture_of_the_profile_banner' }}

\\n
\\n \\n \\n \\\"{{profileImage.custom_asset_file_attributes.attachment}}\\\"\\n
\\n
\\n
\\n {{ 'app.admin.settings.change_the_profile_banner' | translate }}\\n \\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.general.elements_ordering' }}\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.general.machines_order' }}

\\n \\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.general.help' }}\\n
\\n
\\n
\\n

{{ 'app.admin.settings.general.feature_tour' }}

\\n

\\n
\\n \\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.general.notifications' }}\\n
\\n
\\n
\\n

{{ 'app.admin.settings.general.email' }}

\\n

{{ 'app.admin.settings.general.email_info' }}

\\n
\\n \\n \\n
\\n
\\n
\\n
\\n\\n\\n\\n
\\n
\\n {{ 'app.admin.settings.modules' }}\\n
\\n
\\n

{{ 'app.admin.settings.remember_to_refresh_the_page_for_the_changes_to_take_effect' }}

\\n
\\n

{{ 'app.admin.settings.machines' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.spaces' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.plans' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.trainings' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.store' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.invoicing' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.general.wallet' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.general.public_agenda' }}

\\n

\\n \\n
\\n
\\n

{{ 'app.admin.settings.general.statistics' }}

\\n

\\n \\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/general.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.customize_home_page' }}

\\n \\n \\n \\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.news_of_the_home_page' }}

\\n
\\n
\\n {{ 'app.admin.settings.leave_it_empty_to_not_bring_up_any_news_on_the_home_page' | translate }}\\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n \\n \\n \\n {{ 'app.admin.settings.advanced' }} \\n \\n
\\n

{{ 'app.admin.settings.customize_home_page_css' }}

\\n
\\n
\\n \\n

\\n \\n {{ 'app.admin.settings.home_css_notice_html' }}\\n

\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/home_page.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.customize_the_application' }}

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n\\n
\\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n\\n \\n \\n \\n \\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n

{{ titleNew }}

\\n
\\n
\\n

\\n
\\n \\n
\\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/newSelectOption.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n
\\n
\\n
\\n \\n
\\n \\n
\\n \\n {{ helperText | translate }}\\n \\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/number.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n {{ 'app.admin.settings.privacy.privacy_policy' }}\\n
\\n
\\n\\n
\\n
\\n \\n
\\n\\n
\\n {{ 'app.admin.settings.drag_and_drop_to_insert_images' | translate }}\\n \\n
\\n
\\n
\\n\\n
\\n {{ 'app.admin.settings.shift_enter_to_force_carriage_return' | translate }}\\n \\n
\\n\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.privacy.analytics.title' }}\\n
\\n
\\n
\\n
\\n \\n \\n

\\n {{ 'app.admin.settings.privacy.about_analytics' }}\\n {{ 'app.admin.settings.privacy.read_more' }}\\n

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.privacy.statistics' }}\\n
\\n
\\n

{{ 'app.admin.settings.remember_to_refresh_the_page_for_the_changes_to_take_effect' }}

\\n
\\n

{{ 'app.admin.settings.privacy.google_analytics' }}

\\n

\\n
\\n \\n \\n
\\n
\\n\\n
\\n

{{ 'app.admin.settings.privacy.facebook' }}

\\n

\\n
\\n \\n \\n
\\n
\\n\\n
\\n

{{ 'app.admin.settings.privacy.twitter' }}

\\n

\\n
\\n \\n \\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/privacy.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n {{ 'app.admin.settings.reservations_parameters' }}\\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.confine_the_booking_agenda' }}

\\n
\\n

{{ 'app.admin.settings.opening_time' }}

\\n \\n
\\n
\\n \\n
\\n
\\n

{{ 'app.admin.settings.closing_time' }}

\\n \\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.max_visibility' }}

\\n \\n \\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.ability_for_the_users_to_move_their_reservations' }}

\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.ability_for_the_users_to_cancel_their_reservations' }}

\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.book_overlapping_slots_info' }}

\\n
\\n \\n \\n
\\n {{ 'app.admin.settings.overlapping_categories_info' }}\\n
\\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.settings.reservation_deadline' }}

\\n

{{ 'app.admin.settings.reservation_deadline_help' }}

\\n \\n \\n \\n \\n \\n \\n \\n \\n
\\n
\\n
\\n

{{ 'app.admin.settings.default_slot_duration' }}

\\n

{{ 'app.admin.settings.default_slot_duration_info' }}

\\n \\n \\n
\\n\\n
\\n
\\n

{{ 'app.admin.settings.pack_only_for_subscription_info' }}

\\n

\\n \\n \\n
\\n\\n
\\n
\\n

{{ 'app.admin.settings.extended_prices' }}

\\n

\\n \\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n {{ 'app.admin.settings.reservations_reminders' }}\\n
\\n
\\n
\\n

{{ 'app.admin.settings.notification_sending_before_the_reservation_occurs' }}

\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n\\n\\n
\\n
\\n {{ 'app.admin.settings.display' }}\\n
\\n
\\n
\\n

{{ 'app.admin.settings.display_reservation_user_name' }}

\\n

\\n \\n \\n
\\n
\\n

{{ 'app.admin.settings.events_in_the_calendar' }}

\\n

{{ 'app.admin.settings.events_in_calendar_info' }}

\\n \\n
\\n\\n
\\n
\\n

{{ 'app.admin.settings.display_invite_to_renew_pack' }}

\\n

\\n \\n \\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/reservations.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.settings.privacy.save_or_publish' }}

\\n
\\n
\\n

{{ 'app.admin.settings.privacy.save_or_publish_body' }}

\\n

{{ 'app.admin.settings.privacy.publish_will_notify' }}

\\n
\\n
\\n \\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/save_policy.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/select-multiple.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n \\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/select.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n
\\n
\\n
\\n \\n
\\n \\n
\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/settings/text.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

{{ 'app.admin.statistics.export_statistics_to_excel' }}

\\n
\\n
\\n
\\n
\\n \\n
\\n
\\n
    \\n
  • \\n {{ 'app.admin.statistics.start' }}\\n
    \\n \\n \\n \\n \\n
    \\n
  • \\n
  • \\n {{ 'app.admin.statistics.end' }}\\n
    \\n \\n \\n \\n \\n
    \\n
  • \\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n
\\n \\n \\n \\n \\n \\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/statistics/export.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.stats_graphs.statistics' }}

\\n
\\n
\\n \\n
\\n
\\n\\n\\n
\\n
\\n\\n
\\n
\\n\\n \\n\\n
\\n \\n
\\n
    \\n
  • \\n {{ 'app.admin.stats_graphs.start' }}\\n
    \\n \\n \\n \\n \\n
    \\n
  • \\n
  • \\n {{ 'app.admin.stats_graphs.end' }}\\n
    \\n \\n \\n \\n \\n
    \\n
  • \\n
  • \\n \\n
  • \\n
\\n
\\n
\\n
\\n\\n \\n \\n\\n
\\n
\\n
\\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.stats_graphs.top_list_of' | translate}} {{stat.label}}

\\n
\\n \\n
\\n
\\n
\\n\\n\\n
\\n

{{type.label}}

\\n
\\n \\n
\\n
\\n\\n
\\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/statistics/graphs.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.statistics.statistics' }}

\\n
\\n
\\n \\n
\\n
\\n\\n\\n
\\n
\\n\\n
\\n \\n \\n
\\n
\\n \\n
\\n
    \\n
  • {{ 'app.admin.statistics.start' }}\\n
    \\n \\n \\n
    \\n
  • \\n
  • {{ 'app.admin.statistics.end' }}\\n
    \\n \\n \\n
    \\n
  • \\n
\\n
\\n
\\n\\n
\\n \\n \\n
\\n\\n
\\n \\n
\\n
    \\n
  • {{ 'app.admin.statistics.criterion' }}\\n
    \\n \\n \\n
    \\n
  • \\n
  • {{ 'app.admin.statistics.value' }}\\n
    \\n \\n \\n\\n \\n\\n
    \\n \\n \\n \\n \\n
    \\n\\n \\n\\n \\n
    \\n
    \\n
  • \\n
  • \\n
    \\n \\n
    \\n
  • \\n
\\n
\\n
\\n\\n
\\n \\n
\\n\\n
\\n \\n
\\n
    \\n
  • \\n {{ 'app.admin.statistics.start' }}\\n
    \\n \\n \\n \\n \\n
    \\n
  • \\n
  • \\n {{ 'app.admin.statistics.end' }}\\n
    \\n \\n \\n \\n \\n
    \\n
  • \\n
  • \\n \\n
  • \\n
\\n
\\n
\\n
\\n\\n
\\n
    \\n
  • {{ 'app.admin.statistics.entries' | translate }} {{totalHits}}
  • \\n
  • {{ 'app.admin.statistics.revenue_' | translate }} {{sumCA | currency}}
  • \\n
  • {{ 'app.admin.statistics.average_age' | translate }} {{averageAge}} {{ 'app.admin.statistics.years_old' | translate }}
  • \\n
  • {{ 'app.admin.statistics.total' | translate }} {{type.active.label}} : {{sumStat}}
  • \\n
  • {{ customFieldName(custom.field) }} {{customAggs[custom.field]}}
  • \\n
\\n
\\n\\n
\\n \\n {{ 'app.admin.statistics.create_plans_to_start' }}\\n {{ 'app.admin.statistics.click_here' }}\\n
\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.statistics.reservation_date' }}{{ 'app.admin.statistics.date' }}{{ 'app.admin.statistics.user' }}{{ 'app.admin.statistics.gender' }}{{ 'app.admin.statistics.age' }}{{ 'app.admin.statistics.type' }}{{type.active.label}}{{field.label}}{{ 'app.admin.statistics.revenue' | translate }}\\n \\n \\n \\n \\n \\n \\n \\n
{{formatDate(datum._source.date)}}\\n {{getUserNameFromId(datum._source.userId)}}\\n {{ 'app.admin.statistics.deleted_user' }}\\n {{formatSex(datum._source.gender)}}\\n {{datum._source.age}} {{ 'app.admin.statistics.years_old' | translate }}\\n {{ 'app.admin.statistics.unknown' }}\\n {{formatSubtype(datum._source.subType)}}{{datum._source.stat}}\\n \\n {{formatDate(datum._source[field.key])}}\\n
    \\n
  • {{elem.name}}
  • \\n
\\n {{datum._source[field.key]}}\\n
\\n
{{datum._source.ca | currency}}{{ 'app.admin.statistics.unknown' }}
\\n
\\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/statistics/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/store/categories.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n
\\n\\n
\\n

{{ 'app.admin.store.manage_the_store' }}

\\n
\\n
\\n\\n
\\n
\\n\\n
\\n \\n\\n \\n
\\n \\n
\\n
\\n\\n \\n
\\n \\n
\\n
\\n\\n \\n
\\n \\n
\\n
\\n\\n \\n
\\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/store/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/store/orders.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n
\\n\\n
\\n

{{ 'app.admin.store.manage_the_store' }}

\\n
\\n
\\n\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/store/product_edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n
\\n\\n
\\n

{{ 'app.admin.store.manage_the_store' }}

\\n
\\n
\\n\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/store/product_new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/store/products.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/store/settings.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.members.tag_form.tag_name' }}
\\n \\n {{tag.name}}\\n \\n \\n \\n
\\n \\n \\n
\\n
\\n \\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/tags/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ training.name }}

\\n
\\n
\\n
\\n
\\n\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/trainings/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.trainings.trainings_monitoring' }}

\\n
\\n
\\n
\\n
\\n\\n\\n
\\n
\\n\\n
\\n \\n \\n \\n \\n \\n \\n \\n\\n \\n
\\n \\n \\n
\\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.admin.trainings.training' }}{{ 'app.admin.trainings.date' }}
{{training_name}}\\n \\n \\n\\n \\n \\n\\n \\n \\n \\n \\n \\n\\n \\n \\n\\n \\n \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/trainings/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.trainings.edition_of_the_description_tooltip' }}

\\n
\\n
\\n
\\n
\\n \\n {{ 'app.admin.trainings.description_is_limited_to_255_characters' }}\\n
\\n
\\n
\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/trainings/modal_edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.admin.trainings_new.add_a_new_training' }}

\\n
\\n
\\n
\\n
\\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/trainings/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.admin.trainings.training_validation' }}

\\n
\\n
\\n

\\n {{ 'app.admin.trainings.training_of_the_DATE_TIME_html' }}\\n
\\n {{ 'app.admin.trainings.you_can_validate_the_training_of_the_following_members' }}

\\n
    0\\\">\\n
  • \\n \\n {{ 'app.admin.trainings.deleted_user' }}\\n \\n
  • \\n
\\n

{{ 'app.admin.trainings.no_reservation' }}

\\n
\\n
\\n \\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/trainings/validTrainingModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.public.common.upgrade_fabmanager' }}

\\n
\\n
\\n

{{ 'app.public.common.security_version_html' }}

\\n

{{ 'app.public.common.current_version' }}

\\n

{{ 'app.public.common.upgrade_to' }}

\\n

\\n {{ 'app.public.common.read_more' }}\\n

\\n

\\n \\n {{ 'app.public.common.how_to' }}\\n \\n

\\n
\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/admin/versions/upgradeModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n
\\n \\n
\\n
\\n
\\n
\\n

{{ 'app.public.calendar.calendar' }}

\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n\\n
\\n
\\n\\n\\n
\\n
\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/calendar/calendar.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

\\n {{ 'app.public.calendar.choose_a_machine' }}\\n

\\n
\\n
\\n \\n
\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/calendar/chooseMachine.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n

{{ 'app.shared.calendar.show_reserved_uniq' }}

\\n
\\n \\n
\\n
\\n
\\n

{{ 'app.shared.calendar.show_unavailables' }}

\\n
\\n \\n
\\n
\\n
\\n
\\n

\\n \\n {{ 'app.shared.calendar.trainings' }}\\n

\\n \\n
\\n
\\n {{::t.name}}\\n \\n
\\n
\\n
\\n
\\n

\\n \\n {{ 'app.shared.calendar.machines' }}\\n

\\n \\n
\\n
\\n {{::m.name}}\\n \\n
\\n
\\n \\n \\n {{::category.name}}\\n \\n \\n
\\n
\\n {{::m.name}}\\n \\n
\\n
\\n
\\n
\\n
\\n
\\n

\\n \\n {{ 'app.shared.calendar.spaces' }}\\n

\\n \\n
\\n
\\n {{::s.name}}\\n \\n
\\n
\\n
\\n

{{ 'app.shared.calendar.events' }}

\\n \\n
\\n
\\n
\\n

{{ 'app.shared.calendar.externals' }}

\\n \\n
\\n\\n
\\n {{::e.name}}\\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/calendar/filter.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n

{{ 'app.shared.calendar.filter_calendar' }}

\\n
\\n
\\n \\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/calendar/filterAside.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n \\n
\\n\\n
\\n

{{ 'app.public.cart.my_cart' }}

\\n
\\n
\\n\\n
\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/cart/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n \\n
\\n\\n
\\n\\n\\n
\\n\\n
\\n
\\n
\\n

{{ 'app.logged.dashboard.events.your_next_events' | translate }}

\\n
\\n
\\n
    0\\\">\\n
  • \\n {{r.reservable.title}}\\n -\\n {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n
    \\n \\n {{ 'app.logged.dashboard.events.NUMBER_normal_places_reserved' }}\\n \\n \\n
    \\n \\n {{ 'app.logged.dashboard.events.NUMBER_of_NAME_places_reserved' }}\\n \\n
    \\n
  • \\n
\\n
{{ 'app.logged.dashboard.events.no_events_to_come' }}
\\n
\\n
\\n
\\n
\\n
\\n
\\n

{{ 'app.logged.dashboard.events.your_previous_events' | translate }}

\\n
\\n
\\n
    0\\\">\\n
  • \\n {{r.reservable.title}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n
  • \\n
\\n
{{ 'app.logged.dashboard.events.no_passed_events' }}
\\n
\\n
\\n
\\n\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/events.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n \\n
\\n\\n
\\n\\n\\n
\\n
\\n\\n\\n 0\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
{{ 'app.logged.dashboard.invoices.reference_number' }}{{ 'app.logged.dashboard.invoices.date' }}{{ 'app.logged.dashboard.invoices.price' }}
{{ invoice.reference }}{{ invoice.date | amDateFormat:'L LTS' }}{{ invoice.date | amDateFormat:'L' }}{{ invoice.total | currency}}\\n \\n
\\n

{{ 'app.logged.dashboard.invoices.no_invoices_for_now' }}

\\n\\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/invoices.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n \\n\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/nav.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n
\\n
\\n \\n
\\n
\\n\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/orders.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n \\n
\\n\\n
\\n\\n \\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/payment_schedules.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n \\n
\\n\\n
\\n\\n\\n
\\n
\\n \\n
\\n
\\n
\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/profile.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
\\n\\n
\\n
\\n \\n
\\n
\\n\\n\\n
\\n\\n \\n\\n
{{ 'app.logged.dashboard.projects.you_dont_have_any_projects' }}
\\n
\\n
\\n

{{project.name}}

\\n {{project.author_id == currentUser.id ? 'app.logged.dashboard.projects.author' : 'app.logged.dashboard.projects.collaborator' | translate}}\\n {{ 'app.logged.dashboard.projects.rough_draft' }}\\n \\n
\\n
\\n\\n
\\n
\\n
\\n

{{ 'app.logged.dashboard.projects.description' }}

\\n
\\n
\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n
\\n

{{ 'app.logged.dashboard.projects.machines_and_materials' }}

\\n
\\n
\\n

{{ 'app.logged.dashboard.projects.machines' | translate }} :

\\n
    \\n
  • {{m.name}}
  • \\n
\\n

{{ 'app.logged.dashboard.projects.materials' | translate }} :

\\n
    \\n
  • {{c.name}}
  • \\n
\\n
\\n
\\n
\\n\\n
\\n
\\n
\\n

{{ 'app.logged.dashboard.projects.collaborators' }}

\\n
\\n
\\n
  • \\n \\n \\n\\n \\n \\n \\n {{collaborator.full_name}}\\n {{collaborator.username}}\\n \\n\\n
  • \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/projects.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n \\n
    \\n\\n
    \\n\\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/reservations.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n \\n\\n\\n\\n
    \\n
    \\n
    \\n
    \\n \\n test\\n \\n
    {{user.name}}
    \\n
    {{user.email}}
    \\n
    {{ 'app.logged.dashboard.settings.last_activity_on_' | translate:{DATE:(user.last_sign_in_at | amDateFormat: 'LL')} }}
    \\n
    \\n
    \\n \\n \\n
    \\n

    {{ 'app.logged.dashboard.settings.subscription' }}

    \\n
    \\n \\n {{ user.subscribed_plan | humanReadablePlanName }}\\n
    {{ 'app.logged.dashboard.settings.your_subscription_expires_on_' | translate }} {{user.subscription.expired_at | amDateFormat: 'LL'}}
    \\n
    \\n\\n
    \\n
    {{ 'app.logged.dashboard.settings.no_subscriptions' | translate }}
    {{ 'app.logged.dashboard.settings.i_want_to_subscribe' }}
    \\n
    \\n\\n
    \\n

    {{ 'app.logged.dashboard.settings.trainings' }}

    \\n
      0 || user.trainings.length > 0\\\">\\n
    • \\n {{r.reservable.name}} - {{ 'app.logged.dashboard.settings.to_come' | translate }}\\n
    • \\n
    • \\n {{t.name}} - {{ 'app.logged.dashboard.settings.approved' | translate }}\\n
    • \\n
    \\n
    {{ 'app.logged.dashboard.settings.no_trainings' }}
    \\n
    \\n\\n
    \\n

    {{ 'app.logged.dashboard.settings.projects' }}

    \\n
      0\\\">\\n
    • \\n {{p.name}}\\n
    • \\n
    \\n
    {{ 'app.logged.dashboard.settings.no_projects' }}
    \\n
    \\n\\n
    \\n

    {{ 'app.logged.dashboard.settings.labels' }}

    \\n 0\\\" ng-repeat=\\\"t in user.tags\\\">\\n {{t.name}}\\n \\n
    {{ 'app.logged.dashboard.settings.no_labels' }}
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.dashboard.settings.cookies' }}

    \\n
    {{ 'app.logged.dashboard.settings.cookies_accepted' }}
    \\n
    {{ 'app.logged.dashboard.settings.cookies_declined' }}
    \\n
    {{ 'app.logged.dashboard.settings.cookies_unset' }}
    \\n \\n
    \\n
    \\n \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n
    \\n

    {{ 'app.logged.dashboard.settings.edit_my_profile' }}

    \\n
    \\n
    \\n
    \\n
    \\n
    \\n

    \\n {{activeProvider.name}}\\n

    \\n
    \\n
    \\n
    \\n \\n {{ 'app.logged.dashboard.settings.change_my_data' | translate }}\\n \\n

    {{ 'app.logged.dashboard.settings.once_your_data_are_up_to_date_' | translate }} {{ 'app.logged.dashboard.settings._click_on_the_synchronization_button_opposite_' }} {{ 'app.logged.dashboard.settings.or' | translate}} {{ 'app.logged.dashboard.settings._disconnect_then_reconnect_' }} {{ 'app.logged.dashboard.settings._for_your_changes_to_take_effect' | translate }}

    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/settings.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n \\n
    \\n
    \\n\\n\\n
    \\n \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/supporting_document_files.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n \\n
    \\n\\n
    \\n\\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.dashboard.trainings.your_training_credits' | translate }}

    \\n
    \\n
    \\n {{ 'app.logged.dashboard.trainings.subscribe_for_credits' }}\\n {{ 'app.logged.dashboard.trainings.register_for_free' }}\\n
      \\n
    • \\n {{getTrainingName(c.training_id)}}\\n \\n
    • \\n
    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n
    \\n\\n
    \\n
    \\n
    \\n

    {{ 'app.logged.dashboard.trainings.your_next_trainings' | translate }}

    \\n
    \\n
    \\n
      0\\\">\\n
    • \\n {{r.reservable.name}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n
    • \\n
    \\n
    {{ 'app.logged.dashboard.trainings.no_trainings' }}
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.dashboard.trainings.your_previous_trainings' | translate }}

    \\n
    \\n
    \\n
      0\\\">\\n
    • \\n {{r.reservable.name}} - {{ r.start_at | amDateFormat:'LLL' }} - {{ r.end_at | amDateFormat:'LT' }}\\n
    • \\n
    \\n
    {{ 'app.logged.dashboard.trainings.no_trainings' }}
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.dashboard.trainings.your_approved_trainings' | translate }}

    \\n
    \\n
    \\n
      0\\\">\\n
    • \\n {{t.name}}\\n
    • \\n
    \\n
    {{ 'app.logged.dashboard.trainings.no_trainings' }}
    \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/trainings.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\n
    \\n\\n
    \\n \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/dashboard/wallet.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.public.events_show.confirmation_required' }}

    \\n
    \\n
    \\n

    {{ 'app.public.events_show.do_you_really_want_to_delete_this_event' }}

    \\n

    {{ 'app.public.events_show.delete_recurring_event' }}

    \\n
    \\n \\n \\n \\n
    \\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/events/deleteRecurrent.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.admin.events_edit.edit_the_event' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/events/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.events_list.the_fablab_s_events' }}

    \\n
    \\n
    \\n\\n \\n
    \\n\\n\\n
    \\n \\n\\n
    \\n
    0\\\">\\n \\n
    \\n\\n
    0\\\">\\n \\n
    \\n\\n
    0\\\">\\n \\n
    \\n
    \\n\\n
    \\n \\n \\n
    \\n\\n
    \\n

    {{monthNames[month.split(',')[0] - 1]}}, {{month.split(',')[1]}}

    \\n\\n
    \\n \\n \\n
    \\n\\n
    \\n\\n \\n\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/events/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.public.events_show.change_the_reservation' }}

    \\n
    \\n
    \\n

    {{ 'app.public.events_show.you_can_shift_this_reservation_on_the_following_slots' }}

    \\n \\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/events/modify_event_reservation_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.admin.events_new.add_an_event' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/events/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ event.title }} {{event.category.name}}

    \\n
    \\n
    \\n\\n \\n
    \\n
    \\n\\n\\n
    \\n
    \\n\\n
    \\n\\n
    \\n \\\"{{event.title}}\\\"\\n
    \\n\\n

    {{ 'app.public.events_show.event_description' }}

    \\n

    \\n
    \\n\\n\\n \\n\\n
    \\n\\n
    \\n\\n
    \\n
    \\n {{event.event_files_attributes.length}}\\n

    {{ 'app.public.events_show.downloadable_documents' }}

    \\n
    \\n\\n \\n
    \\n\\n
    \\n \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.public.events_show.information_and_booking' }}

    \\n
    \\n\\n
    \\n\\n
    {{event.category.name}}
    \\n
    \\n
    \\n {{theme.name}}\\n
    \\n
    {{event.age_range.name}}
    \\n
    \\n
    \\n
    {{ 'app.public.events_show.dates' | translate }}
    \\n
    {{ 'app.public.events_show.beginning' | translate }} {{event.start_date | amDateFormat:'L'}}
    {{ 'app.public.events_show.ending' | translate }} {{event.end_date | amDateFormat:'L'}}
    \\n
    {{ 'app.public.events_show.opening_hours' | translate }}
    \\n
    {{ 'app.public.events_show.all_day' }}
    \\n
    {{ 'app.public.events_show.from_time' | translate }} {{event.start_time}} {{ 'app.public.events_show.to_time' | translate }} {{event.end_time}}
    \\n
    \\n\\n
    \\n
    {{ 'app.public.events_show.full_price_' | translate }} {{ event.amount | currency}}
    \\n
    \\n \\n {{price.category.name}} :\\n \\n {{price.amount | currency}}\\n
    \\n
    \\n\\n
    \\n
    0\\\">{{ 'app.public.events_show.tickets_still_availables' | translate }} {{event.nb_free_places}}
    \\n
    0 && event.nb_free_places <= 0\\\">{{ 'app.public.events_show.sold_out' }}
    \\n
    {{ 'app.public.events_show.cancelled' }}
    \\n
    \\n
    \\n
    {{ 'app.public.events_show.without_reservation' }}
    \\n
    \\n\\n\\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n \\n
    \\n
    \\n \\n \\n
    \\n\\n
    \\n \\n \\n
    \\n
    \\n
    \\n\\n
    \\n\\n \\n\\n
    {{ 'app.public.events_show.thank_you_your_payment_has_been_successfully_registered' | translate }}
    \\n {{ 'app.public.events_show.you_can_find_your_reservation_s_details_on_your_' | translate }} {{ 'app.public.events_show.dashboard' }}\\n
    \\n
    \\n
    \\n
    {{ 'app.public.events_show.you_booked_DATE' | translate:{DATE:(reservation.created_at | amDateFormat:'L LT')} }}
    \\n
    0\\\">{{ 'app.public.events_show.full_price_' | translate }} {{reservation.nb_reserve_places}} {{ 'app.public.events_show.ticket' | translate:{NUMBER:reservation.nb_reserve_places} }}
    \\n
    \\n {{ticket.event_price_category.price_category.name}} : {{ticket.booked}} {{ 'app.public.events_show.ticket' | translate:{NUMBER:ticket.booked} }}\\n
    \\n
    0 && reservationCanModify(reservation)\\\">\\n {{ 'app.shared.buttons.change' }}\\n
    \\n \\n
    \\n
    \\n
    {{ 'app.public.events_show.canceled_reservation_SEATS' | translate:{SEATS:reservation.total_booked_seats} }}
    \\n
    \\n
    \\n\\n\\n
    \\n {{ 'app.public.events_show.event_is_over' }}\\n 0\\\" translate>{{ 'app.public.events_show.thanks_for_coming' }}\\n {{ 'app.public.events_show.view_event_list' }}\\n
    \\n \\n \\n

    \\n \\n {{ 'app.shared.cart.user_validation_required_alert' }}\\n

    \\n
    \\n\\n 0 && ctrl.member\\\" coupon=\\\"coupon.applied\\\" total=\\\"reserve.totalNoCoupon\\\" user-id=\\\"{{ctrl.member.id}}\\\">\\n
    \\n
    \\n\\n \\n\\n \\n\\n
    \\n\\n 0\\\">\\n

    \\n \\n

    \\n

    \\n
    \\n\\n
    \\n\\n
    \\n\\n
    \\n \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/events/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/home.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n

    \\n {{ 'app.public.home.fablab_s_next_events' | translate }}\\n \\n {{ 'app.public.home.every_events' | translate }}\\n \\n

    \\n\\n
    \\n \\n \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/home/events.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n

    {{ 'app.public.home.latest_registered_members' }}

    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n \\n \\n \\n {{member.name}}\\n \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\n
    \\n\\n
    \\n \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/home/members.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/home/news.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n

    {{ 'app.public.home.latest_documented_projects' }}

    \\n\\n \\n \\n
    \\n

    {{p.name}}

    \\n
    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/home/projects.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n \\n

    {{ 'app.public.home.latest_tweets' }}

    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/home/twitter.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ machine.name }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/machines/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.machines_list.the_fablab_s_machines' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n \\n\\n \\n \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/machines/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.admin.machines_new.declare_a_new_machine' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/machines/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.machines_reserve.machine_planning' | translate }} : {{machine.name}}

    \\n
    \\n
    \\n\\n
    \\n
    \\n\\n\\n
    \\n
    \\n
    \\n \\n
    \\n\\n\\n
    \\n \\n \\n \\n\\n
    \\n \\n
    \\n\\n \\n\\n \\n

    \\n \\n \\n

    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/machines/reserve.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ machine.name }}

    \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n\\n {{ 'app.shared.buttons.edit' | translate }}\\n \\n\\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n\\n
    \\n \\\"{{machine.name}}\\\"\\n
    \\n\\n

    \\n\\n
    \\n\\n
    \\n\\n
    \\n\\n
    \\n
    \\n

    {{ 'app.public.machines_show.technical_specifications' }}

    \\n
    \\n
    \\n

    \\n

    \\n
    \\n
    \\n\\n
    \\n
    \\n {{machine.machine_files_attributes.length}}\\n

    {{ 'app.public.machines_show.files_to_download' }}

    \\n
    \\n\\n \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.public.machines_show.projects_using_the_machine' }}

    \\n
    \\n\\n \\n
    \\n\\n
    \\n\\n\\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/machines/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.members.the_fablab_members' }}

    \\n
    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    {{ 'app.logged.members.avatar' }}{{ 'app.logged.members.user' }}{{ 'app.logged.members.pseudonym' }}{{ 'app.logged.members.email_address' }}
    \\n \\n \\n \\n {{ member.name }}{{ member.username }}{{ member.email }}\\n
    \\n \\n
    \\n
    \\n
    \\n \\n
    \\n

    {{ 'app.logged.members.no_members_for_now' }}

    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/members/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{user.name}}

    \\n
    \\n
    \\n\\n \\n\\n
    \\n
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/members/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.notifications.notifications_center' }}

    \\n
    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/notifications/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n \\n
    \\n
    \\n\\n
    \\n \\n \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/orders/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n \\n \\n\\n {{ 'app.shared.plan_subscribe.do_not_subscribe' | translate }} \\n\\n
    \\n
    \\n \\n \\n \\n \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/plans/_plan.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.plans.subscriptions' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n
    \\n
    \\n\\n
    \\n \\n {{ 'app.public.plans.your_subscription_expires_on_the_DATE' | translate:{DATE:(ctrl.member.subscription.expired_at | amDateFormat:'L' )} }}\\n \\n
    \\n\\n \\n \\n\\n
    \\n\\n
    \\n\\n
    \\n \\n
    \\n\\n \\n \\n\\n
    \\n
    \\n

    {{ 'app.public.plans.summary' }}

    \\n
    \\n\\n
    \\n {{ 'app.public.plans.your_subscription_has_expired_on_the_DATE' | translate:{DATE:(ctrl.member.subscription.expired_at | amDateFormat:'LL')} }}\\n\\n
    \\n {{ctrl.member.subscription.plan | humanReadablePlanName }}\\n
    {{ 'app.public.plans.subscription_price' | translate }} {{ctrl.member.subscription.plan.amount | currency}}
    \\n
    \\n
    \\n
    \\n\\n \\n\\n\\n
    \\n
    \\n

    {{ 'app.public.plans.summary' }}

    \\n
    \\n\\n
    \\n {{ 'app.public.plans.you_ve_just_payed_the_subscription_html' }}\\n\\n
    \\n {{ paid.plan | humanReadablePlanName }}\\n
    {{ 'app.public.plans.subscription_price' | translate }} {{paid.plan.amount | currency}}
    \\n
    \\n\\n
    {{ 'app.public.plans.thank_you_your_subscription_is_successful' | translate }}
    \\n {{ 'app.public.plans.your_invoice_will_be_available_soon_from_your_dashboard' }}
    \\n\\n
    \\n
    \\n\\n\\n \\n

    \\n \\n

    \\n
    \\n\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/plans/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n \\n
    \\n\\n
    \\n

    {{ 'app.public.store.fablab_store' }}

    \\n
    \\n\\n
    \\n \\n
    \\n
    \\n\\n
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/products/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n

    {{ 'app.logged.profile_completion.do_you_already_have_an_account' }}

    \\n

    {{ 'app.logged.profile_completion.do_not_fill_the_form_beside_but_specify_here_the_code_you_ve_received_by_email_to_recover_your_access' }}

    \\n

    {{ 'app.logged.profile_completion.just_specify_code_here_to_recover_access' }}

    \\n

    {{ 'app.logged.profile_completion.i_did_not_receive_the_code' }}

    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/profile/_token.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Imports\nvar ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\"../../../../node_modules/html-loader/dist/runtime/getUrl.js\");\nvar ___HTML_LOADER_IMPORT_0___ = require(\"../../images/arrow-left.png\");\n// Module\nvar ___HTML_LOADER_REPLACEMENT_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___);\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.profile_completion.confirm_your_new_account' }}

    \\n
    \\n\\n
    \\n\\n
    \\n\\n
    \\n\\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n

    \\n \\n {{ 'app.logged.profile_completion.or' }}\\n \\n

    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n

    \\n {{ 'app.logged.profile_completion.or' }}\\n

    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/profile/complete.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.logged.profile_completion.send_code_again' }}

    \\n
    \\n
    \\n\\n
    \\n \\n
    \\n \\n \\n
    \\n {{'app.logged.profile_completion.email_is_required'}}\\n {{'app.logged.profile_completion.email_format_is_incorrect'}}\\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/profile/resend_code_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n\\n
    \\n
    \\n\\n {{alert.msg}}\\n\\n \\n\\n
    \\n \\n
    \\n \\n {{ 'app.shared.project.name_is_required' }}\\n
    \\n
    \\n\\n\\n
    \\n \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n \\\"\\\"\\n
    \\n
    \\n {{ 'app.shared.project.add_an_illustration' | translate }} {{ 'app.shared.buttons.change' }}\\n \\n {{ 'app.shared.buttons.delete' }}\\n
    \\n
    \\n
    \\n
    \\n\\n\\n
    \\n \\n
    \\n
    \\n
    \\n \\n \\n\\n
    \\n
    \\n {{file.attachment}}\\n
    \\n {{ 'app.shared.buttons.browse' }}\\n {{ 'app.shared.buttons.change' }}\\n \\n \\n \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n {{ 'app.shared.project.add_a_new_file' | translate }} \\n
    \\n
    \\n\\n
    \\n \\n
    \\n \\n \\n {{ 'app.shared.project.description_is_required' }}\\n
    \\n
    \\n\\n\\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n \\n \\n \\n \\n \\n\\n \\n \\n\\n
    \\n
    \\n
    \\n \\n \\n\\n
    \\n
    \\n \\n
    \\n
    \\n \\\"{{image.attachment}}\\\"\\n
    \\n
    \\n {{ 'app.shared.buttons.browse' | translate }} {{ 'app.shared.buttons.change' }}\\n \\n \\n {{ 'app.shared.buttons.delete' }}\\n
    \\n
    \\n
    \\n
    \\n \\n\\n \\n
    \\n
    \\n \\n \\n {{ 'app.shared.project.add_a_new_step' }}\\n
    \\n
    \\n\\n\\n\\n
    \\n \\n
    \\n\\n
    \\n\\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.status' }}

    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.employed_materials' }}

    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.employed_machines' }}

    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.collaborators' }}

    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.creative_commons_licences' }}

    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.themes' }}

    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.tags' }}

    \\n
    \\n
    \\n \\n
    \\n
    \\n\\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/projects/_form.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n\\n
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.projects_edit.edit_the_project' | translate }} {{ 'app.logged.projects_edit.rough_draft' }}

    \\n
    \\n
    \\n\\n
    \\n
    \\n \\n
    {{ 'app.logged.projects_edit.publish' }}
    \\n\\n
    \\n
    \\n
    \\n
    \\n\\n\\n\\n \\n
    \\n\\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/projects/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.projects_list.the_fablab_projects' }}

    \\n
    \\n
    \\n\\n \\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n

    Filter

    \\n {{ 'app.public.projects_list.reset_all_filters' | translate }}\\n
    \\n \\n \\n \\n \\n\\n
    \\n
    \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n \\n\\n \\n\\n \\n\\n \\n\\n \\n
    \\n
    \\n\\n
    \\n {{ 'app.public.projects_list.project_search_result_is_empty' | translate }} \\n
    \\n
    \\n \\n
    \\n\\n
    \\n {{ 'app.public.projects_list.rough_draft' }}\\n

    {{project.name}}

    \\n {{ project.app_name }}\\n
    \\n\\n
    \\n {{ 'app.public.projects_list.load_next_projects' }}\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/projects/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.projects_new.add_a_new_project' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n
    \\n\\n \\n\\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/projects/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ project.name }} {{ 'app.public.projects_show.rough_draft' }}

    \\n
    \\n
    \\n\\n \\n
    \\n
    \\n\\n\\n
    \\n
    \\n\\n
    \\n\\n
    \\n \\\"{{project.name}}\\\"\\n
    \\n\\n

    {{ 'app.public.projects_show.project_description' }}

    \\n

    \\n\\n
    \\n
    \\n
    \\n

    {{ 'app.public.projects_show.step_N' | translate:{INDEX:step.step_nb} }} : {{step.title}}

    \\n
    \\n
    \\n
    \\n \\\"{{image.attachment}}\\\"\\n
    \\n
    1 || step.project_step_images_attributes.length == 0}\\\">\\n\\n

    \\n
    \\n\\n\\n
    \\n
    \\n\\n
    \\n\\n \\n\\n
    \\n \\n \\n
    \\n\\n
    \\n\\n
    \\n\\n\\n
    \\n
    \\n \\n
    \\n \\n {{ 'app.public.projects_show.posted_on_' | translate }} {{project.created_at | amDateFormat: 'LL'}}\\n\\n
    \\n \\n {{theme.name}}\\n \\n
    \\n\\n
    \\n\\n\\n
    \\n
    \\n {{project.project_caos_attributes.length}}\\n

    {{ 'app.public.projects_show.CAD_file_to_download' }}

    \\n
    \\n\\n \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.public.projects_show.status' }}

    \\n
    \\n
    \\n {{ project.status.name }}\\n
    \\n
    \\n\\n
    \\n
    \\n {{project.machines.length}}\\n

    {{ 'app.public.projects_show.machines_and_materials' }}

    \\n
    \\n\\n \\n\\n
      \\n
    • \\n {{component.name}}\\n
    • \\n
    \\n
    \\n\\n
    0\\\">\\n
    \\n {{project.project_users.length}}\\n

    {{ 'app.public.projects_show.collaborators' }}

    \\n
    \\n\\n
      \\n
    • \\n \\n \\n\\n \\n \\n \\n {{collaborator.full_name}}\\n {{collaborator.username}}\\n \\n\\n
    • \\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.public.projects_show.licence' }}

    \\n
    \\n
    \\n {{ project.licence.name }}\\n
    \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.shared.project.tags' }}

    \\n
    \\n
    \\n
    {{ project.tags }}
    \\n
    \\n
    \\n\\n
    \\n\\n \\n
    \\n
    \\n
    \\n\\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/projects/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.public.common.confirm_my_account' }}

    \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.common.you_will_receive_confirmation_instructions_by_email' }}

    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/ConfirmationNewModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n \\n \\n \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.admins_new.pseudonym_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.admins_new.surname_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.admins_new.first_name_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.admins_new.email_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n
    \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_admin_form.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Imports\nvar ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\"../../../../node_modules/html-loader/dist/runtime/getUrl.js\");\nvar ___HTML_LOADER_IMPORT_0___ = require(\"../../images/arrow-left.png\");\n// Module\nvar ___HTML_LOADER_REPLACEMENT_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___);\nvar code = \"\\n

    \\n \\n {{ 'app.shared.cart.user_validation_required_alert' }}\\n

    \\n
    \\n
    \\n
    \\n

    {{ 'app.shared.cart.summary' }}

    \\n
    \\n\\n
    \\n

    \\n \\n {{ 'app.shared.cart.select_one_or_more_slots_in_the_calendar' | translate:{SINGLE:limitToOneSlot} }}\\n {{ 'app.shared.cart.select_a_plan' }}\\n

    \\n
    \\n\\n
    0\\\">\\n\\n
    {{ 'app.shared.cart.you_ve_just_selected_the_slot' }}
    \\n\\n
    \\n
    \\n
    {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(slot.start | amDateFormat:'LLLL'), END_TIME:(slot.end | amDateFormat:'LT') } }}
    \\n
    {{ 'app.shared.cart.cost_of_TYPE' | translate:{TYPE:reservableType} }} {{slot.price | currency}}
    \\n
    \\n \\n \\n
    \\n
    0\\\">\\n
    0\\\">\\n
    {{ 'app.shared.cart.slot_restrict_plans' }}
    \\n
    \\n
    {{::group.name}}
    \\n
      \\n
    • {{::plan.base_name}}
    • \\n
    \\n
    \\n
    \\n
    \\n
    {{ 'app.shared.cart.slot_restrict_plans_of_others_groups' }}
    \\n
    \\n
    \\n
    \\n
    0 && slot.plansGrouped.length === 0\\\">\\n \\n
    \\n\\n \\n
    \\n\\n \\n\\n
    \\n
    \\n

    {{ 'app.shared.cart.to_benefit_from_attractive_prices' }}

    \\n
    \\n

    {{ 'app.shared.cart.or' }}

    \\n
    \\n\\n
    \\n
    {{ 'app.shared.cart.you_ve_just_selected_a_subscription_html' }}
    \\n
    \\n
    \\n
    {{selectedPlan | humanReadablePlanName }}
    \\n
    {{ 'app.shared.cart.cost_of_the_subscription' | translate }} {{selectedPlan.amount | currency}}
    \\n
    \\n
    \\n \\n
    \\n
    \\n\\n
    \\n\\n
    \\n {{ 'app.shared.cart.you_ve_just_selected_a_subscription_html' }}\\n\\n
    \\n {{ selectedPlan | humanReadablePlanName }}\\n
    {{ 'app.shared.cart.subscription_price' | translate }} {{selectedPlan.amount | currency}}
    \\n
    \\n\\n \\n \\n
    \\n\\n
    \\n \\n
    \\n\\n \\n\\n
    0\\\">\\n {{ 'app.shared.cart.you_have_settled_the_following_TYPE' | translate:{TYPE:reservableType} }} {{reservableName}}:\\n\\n
    \\n {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(paidSlot.start | amDateFormat:'LLLL'), END_TIME:(paidSlot.end | amDateFormat:'LT') } }}\\n
    {{ 'app.shared.cart.cost_of_TYPE' | translate:{TYPE:reservableType} }} {{paidSlot.price | currency}}
    \\n
    \\n\\n
    \\n
    {{ 'app.shared.cart.you_have_settled_a_' | translate }}
    {{ 'app.shared.cart._subscription' }} :
    \\n
    \\n {{selectedPlan | humanReadablePlanName }}\\n
    {{ 'app.shared.cart.cost_of_the_subscription' | translate }} {{selectedPlan.amount | currency}}
    \\n
    \\n
    \\n\\n
    {{ 'app.shared.cart.total_' | translate }} {{amountPaid | currency}}
    \\n\\n
    {{ 'app.shared.cart.thank_you_your_payment_has_been_successfully_registered' | translate }}
    \\n {{ 'app.shared.cart.your_invoice_will_be_available_soon_from_your_' | translate }} {{ 'app.shared.cart.dashboard' }}\\n
    \\n\\n
    \\n
    \\n\\n\\n
    \\n
    \\n

    {{ 'app.shared.cart.summary' }}

    \\n
    \\n
    \\n
    {{ 'app.shared.cart.i_want_to_change_the_following_reservation' }}
    \\n\\n
    \\n
    \\n
    {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(events.modifiable.start | amDateFormat:'LLLL'), END_TIME:(events.modifiable.end | amDateFormat:'LT') } }}
    \\n
    \\n \\n
    \\n\\n
    \\n

    \\n {{ 'app.shared.cart.select_a_new_slot_in_the_calendar' | translate }}

    \\n
    \\n\\n
    \\n
    \\n
    {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(events.placable.start | amDateFormat:'LLLL'), END_TIME:(events.placable.end | amDateFormat:'LT') } }}
    \\n
    \\n \\n
    \\n\\n
    0 || events.placable.tags.length > 0)\\\" ng-class=\\\"{'panel panel-danger bg-red': tagMissmatch()}\\\">\\n
    \\n
    \\n {{ 'app.shared.cart.tags_of_the_original_slot' | translate }}
    \\n \\n {{tag.name}}\\n \\n \\n {{ 'app.shared.cart.none' }}\\n \\n

    \\n
    \\n {{ 'app.shared.cart.tags_of_the_destination_slot' | translate }}
    \\n \\n {{tag.name}}\\n \\n \\n {{ 'app.shared.cart.none' }}\\n \\n
    \\n
    \\n
    \\n
    \\n\\n\\n \\n\\n
    \\n
    {{ 'app.shared.cart.your_booking_slot_was_successfully_moved_from_' }}
    \\n\\n
    \\n
    \\n
    {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(events.moved.oldSlot.start | amDateFormat:'LLLL'), END_TIME:(events.moved.oldSlot.end | amDateFormat:'LT') } }}
    \\n
    \\n
    \\n\\n

    {{ 'app.shared.cart.to_date' }}

    \\n\\n
    \\n
    \\n
    {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(events.moved.newSlot.start | amDateFormat:'LLLL'), END_TIME:(events.moved.newSlot.end | amDateFormat:'LT') } }}
    \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n \\n
    \\n\\n
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_cart.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n {{ 'app.shared.coupon_input.i_have_a_coupon' }}\\n\\n
    \\n \\n
    \\n \\n \\n \\n \\n \\n \\n
    \\n\\n {{msg.message}}\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_coupon.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n \\n \\n \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.manager_new.pseudonym_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.manager_new.surname_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.manager_new.first_name_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.admin.manager_new.email_is_required' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n \\n \\n \\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n \\n
    \\n \\n \\n {{ 'app.shared.user_admin.group_is_required' }}\\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_manager_form.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n

    {{ 'app.shared.member_select.select_a_member' }}

    \\n
    \\n
    \\n \\n \\n \\n \\n \\n \\n \\n \\n {{member}}\\n
    \\n {{ 'app.shared.member_select.member_not_validated' }}\\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_member_select.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n

    {{ 'app.shared.plan.new_partner' }}

    \\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n \\n \\n
    \\n {{ 'app.shared.plan.first_name_is_required' }}\\n
    \\n
    \\n \\n
    \\n \\n \\n
    \\n {{ 'app.shared.plan.surname_is_required' }}\\n
    \\n
    \\n \\n
    \\n \\n \\n
    \\n {{ 'app.shared.plan.email_address_is_required' }}\\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_partner_new_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.shared.cart.slot_at_same_time' }}

    \\n
    \\n
    \\n

    {{ 'app.shared.cart.do_you_really_want_to_book_slot_at_same_time' }}

    \\n

    {{ 'app.shared.cart.unable_to_book_slot_because_really_have_reservation_at_same_time' }}

    \\n
      \\n
    • \\n {{::r.reservable.name}}{{::r.reservable.title}}\\n
      {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(r.start_at | amDateFormat:'LLLL'), END_TIME:(r.end_at | amDateFormat:'LT') } }}
      \\n
    • \\n
    \\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_reserve_slot_same_time.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.shared.cart.tags_mismatch' }}

    \\n
    \\n
    \\n

    {{ 'app.shared.cart.confirm_book_slot_tags_mismatch' }}

    \\n

    {{ 'app.shared.cart.unable_to_book_slot_tags_mismatch' }}

    \\n

    {{ 'app.shared.cart.slot_tags' }}

    \\n
      0\\\">\\n
    • \\n {{t.name}}\\n
    • \\n
    \\n 0\\\" translate>{{ 'app.shared.cart.no_tags' }}\\n

    {{ 'app.shared.cart.user_tags' }}

    \\n
      \\n
    • 0\\\">\\n {{t.name}}\\n
    • \\n
    \\n 0\\\" translate>{{ 'app.shared.cart.no_tags' }}\\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_reserve_slot_tags_mismatch.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.shared.cart.selected_plan_dont_match_slot' }}

    \\n

    {{ 'app.shared.cart.user_plan_dont_match_slot' }}

    \\n

    {{ 'app.shared.cart.no_plan_match_slot' }}

    \\n
    \\n
    \\n
    {{ 'app.shared.cart.datetime_to_time' | translate:{START_DATETIME:(slot.start | amDateFormat:'LLLL'), END_TIME:(slot.end | amDateFormat:'LT') } }}
    \\n
    0\\\">\\n
    {{ 'app.shared.cart.slot_restrict_plans' }}
    \\n
    \\n
    {{::group.name}}
    \\n
      \\n
    • {{::plan.base_name}}
    • \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_reserve_slot_without_plan.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n \\\"{{altText}}\\\"\\n \\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_social_link.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Imports\nvar ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___ = require(\"../../../../node_modules/html-loader/dist/runtime/getUrl.js\");\nvar ___HTML_LOADER_IMPORT_0___ = require(\"../../images/no_avatar.png\");\n// Module\nvar ___HTML_LOADER_REPLACEMENT_0___ = ___HTML_LOADER_GET_SOURCE_FROM_IMPORT___(___HTML_LOADER_IMPORT_0___);\nvar code = \"\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/_user_avatar.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n

    \\n
    \\n
    \\n
    \\n\\n
    \\n \\n\\n
    \\n

    {{ 'app.public.about.your_fablab_s_contacts' }}

    \\n \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/about.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{object.title}}

    \\n
    \\n
    \\n

    \\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/confirm_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.shared.confirm_modify_slot_modal.change_the_slot' }}

    \\n
    \\n
    \\n

    {{ 'app.shared.confirm_modify_slot_modal.do_you_want_to_change_your_booking_slot_initially_planned_at' }}

    \\n

    {{ 'app.shared.confirm_modify_slot_modal.do_you_want_to_change_NAME_s_booking_slot_initially_planned_at' }}

    \\n

    {{object.start | amDateFormat: 'LL'}} : {{object.start | amDateFormat:'LT'}} - {{object.end | amDateFormat:'LT'}}

    \\n
    \\n
    \\n \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/confirm_modify_slot_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n

    \\n {{ 'app.public.common.cookies.about_cookies' }}\\n {{ 'app.public.common.cookies.learn_more' }}\\n

    \\n
    \\n \\n \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/cookies.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n \\n

    \\n {{ 'app.public.common.connection' }}\\n

    \\n
    \\n
    \\n {{alert.msg}}\\n\\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n \\n \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.public.common.password_forgotten' }}\\n \\n
    {{ 'app.public.common.confirm_my_account' }}\\n
    \\n
    \\n \\n {{ 'app.public.common.caps_lock_is_on' | translate }}\\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n \\n
    \\n

    \\n {{ 'app.public.common.not_registered_to_the_fablab' }}\\n
    \\n {{ 'app.public.common.create_an_account' }}
    \\n

    \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/deviseModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    \\n \\n {{ 'app.shared.help.title' }}\\n

    \\n
    \\n
    \\n

    {{ 'app.shared.help.what_to_do' }}

    \\n
    \\n \\n
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/help_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"\\n
    \\n
    \\n \\n
    \\n\\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/leftnav.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.public.common.change_your_password' }}

    \\n
    \\n
    \\n {{alert.msg}}\\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.public.common.password_is_required' }}\\n {{ 'app.public.common.password_is_too_short' }}\\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.public.common.password_confirmation_is_required' }}\\n {{ 'app.public.common.password_does_not_match_with_confirmation' }}\\n
    \\n
    \\n
    \\n\\n
    \\n \\n
    \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/passwordEditModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.public.common.password_forgotten' }}

    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n \\n
    \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/passwordNewModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.privacy.title' }}

    \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n {{ 'app.public.privacy.last_update' }}\\n {{ privacyBody.last_update | amDateFormat:'LL' }}\\n
    \\n \\n
    \\n\\n
    \\n

    {{ 'app.public.privacy.dpo' }}

    \\n \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/privacy.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.public.projects_show.report_an_abuse' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n \\n {{ 'app.public.projects_show.your_first_name_is_required' }}\\n
    \\n
    \\n
    \\n \\n {{ 'app.public.projects_show.your_surname_is_required' }}\\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n \\n
    \\n {{ 'app.public.projects_show.your_email_address_is_required' }}\\n
    \\n
    \\n\\n
    \\n
    \\n \\n {{ 'app.public.projects_show.message_is_required' }}\\n
    \\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/signalAbuseModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n \\n

    {{ 'app.public.common.create_your_account' }}

    \\n
    \\n
    \\n {{alert.msg}}\\n\\n
    \\n
    \\n \\n
    \\n\\n
    \\n \\n \\n {{ 'app.public.common.first_name_is_required' }}\\n
    \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.surname_is_required' }}\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n
    \\n
    \\n
    \\n \\n \\n \\n {{ 'app.public.common.gender_is_required'}}\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.birth_date_is_required' }}\\n
    \\n
    \\n
    \\n \\n \\n Estado de origiem é obrigatório\\n
    \\n
    \\n
    \\n \\n \\n Cidade de nascimento é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.cpf_is_required' }}\\n O CPF é inválido\\n
    \\n
    \\n
    \\n \\n \\n RG é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n The RG date of emission is required\\n
    \\n
    \\n
    \\n \\n \\n O órgão emissor é obrigatório\\n
    \\n
    \\n
    \\n \\n \\n O estado de emissão é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n Nome da mãe é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n CPF do responsável financeiro é obrigatório\\n CPF inválido\\n
    \\n
    \\n
    \\n \\n \\n O responsável financeiro é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n A situação ocupacional é obrigatória\\n
    \\n
    \\n \\n \\n O nível educacional é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n O CEP é obrigatório\\n
    \\n
    \\n
    \\n \\n \\n Logradouro é obrigatório\\n
    \\n
    \\n
    \\n \\n \\n O bairro é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n Número é obrigatório\\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n \\n \\n Cidade é obrigatório\\n
    \\n
    \\n
    \\n \\n \\n Estado é obrigatório\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.email_is_required' }}\\n
    \\n
    \\n
    \\n \\n \\n \\n \\n {{ 'app.public.common.phone_number_is_required' }}\\n
    \\n
    \\n\\n \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.pseudonym_is_required' }}\\n
    \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.password_is_required' }}\\n {{ 'app.public.common.password_is_too_short' }}\\n
    \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.password_confirmation_is_required' }}\\n {{ 'app.public.common.password_does_not_match_with_confirmation' }}\\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n \\n
    \\n \\n {{ 'app.public.common.organization_name_is_required' }}\\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n \\n \\n
    \\n \\n {{ 'app.public.common.organization_address_is_required' }}\\n
    \\n
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n \\n {{ 'app.public.common.profile_custom_field_is_required' }}\\n
    \\n
    \\n
    \\n\\n
    \\n

    \\n \\n {{ 'app.public.common.user_supporting_documents_required' }}\\n

    \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
    \\n \\n \\n {{ 'app.public.common.field_required' }}\\n \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/signupModal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n \\n \\n
    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/tour-step-template.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.shared.valid_reservation_modal.booking_confirmation' }}

    \\n

    {{ 'app.shared.valid_reservation_modal.subscription_confirmation' }}

    \\n
    \\n
    \\n {{alert.msg}}\\n
    \\n
    \\n \\n
    \\n

    {{ 'app.shared.valid_reservation_modal.here_is_the_summary_of_the_slots_to_book_for_the_current_user' }}

    \\n
      \\n
    • {{bookedEvent.availability.start_at | amDateFormat: 'LL'}} : {{bookedEvent.availability.start_at | amDateFormat:'LT'}} - {{bookedEvent.availability.end_at | amDateFormat:'LT'}}
    • \\n
    \\n
    \\n
    \\n

    {{ 'app.shared.valid_reservation_modal.here_is_the_subscription_summary' }}

    \\n

    {{ plan | humanReadablePlanName }}

    \\n
    \\n
    \\n \\n \\n

    {{ 'app.shared.valid_reservation_modal.card_collection_info' }}

    \\n

    {{ 'app.shared.valid_reservation_modal.check_collection_info' }}

    \\n
    \\n
    \\n
    \\n
      \\n
    • \\n {{item.due_date | amDateFormat: 'L'}}\\n \\n {{item.amount | currency}}\\n
    • \\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/shared/valid_reservation_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.admin.space_edit.edit_the_space_NAME' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/spaces/edit.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.spaces_list.the_spaces' }}

    \\n
    \\n
    \\n\\n \\n
    \\n
    \\n\\n\\n
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n \\n
    \\n
    \\n \\n
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{space.name}}

    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/spaces/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.admin.space_new.add_a_new_space' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/spaces/new.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.space_reserve.planning_of_space_NAME' }}

    \\n
    \\n
    \\n
    \\n
    \\n\\n\\n
    \\n
    \\n
    \\n \\n
    \\n\\n\\n
    \\n\\n
    \\n \\n
    \\n\\n \\n\\n\\n \\n

    \\n \\n

    \\n

    \\n
    \\n\\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/spaces/reserve.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ space.name }}

    \\n
    \\n
    \\n\\n \\n
    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n\\n
    \\n \\\"{{space.name}}\\\"\\n
    \\n\\n

    \\n\\n
    \\n\\n
    \\n\\n
    \\n\\n
    \\n
    \\n

    {{ 'app.public.space_show.characteristics' }}

    \\n
    \\n
    \\n

    \\n

    \\n
    \\n
    \\n\\n
    \\n
    \\n {{space.space_files_attributes.length}}\\n

    {{ 'app.public.space_show.files_to_download' }}

    \\n
    \\n\\n \\n
    \\n\\n
    \\n
    \\n

    {{ 'app.public.space_show.projects_using_the_space' }}

    \\n
    \\n\\n \\n
    \\n\\n
    \\n\\n\\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/spaces/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n \\n
    \\n\\n
    \\n

    {{ 'app.public.store.fablab_store' }}

    \\n
    \\n\\n
    \\n \\n
    \\n
    \\n\\n
    \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/store/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.public.trainings_list.the_trainings' }}

    \\n
    \\n
    \\n\\n
    \\n
    \\n\\n\\n
    \\n
    \\n \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{training.name}}

    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/trainings/index.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ 'app.logged.trainings_reserve.trainings_planning' }}

    \\n

    {{ 'app.logged.trainings_reserve.planning_of' }} {{training.name}}

    \\n
    \\n
    \\n \\n
    \\n
    \\n\\n\\n
    \\n
    \\n
    \\n \\n
    \\n\\n\\n
    \\n\\n
    \\n \\n
    \\n\\n\\n\\n \\n\\n\\n \\n

    \\n \\n \\n

    \\n
    \\n\\n \\n

    \\n \\n \\n

    \\n
    \\n\\n
    \\n\\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/trainings/reserve.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n\\n
    \\n
    \\n
    \\n
    \\n \\n
    \\n
    \\n
    \\n
    \\n

    {{ training.name }}

    \\n
    \\n
    \\n\\n \\n
    \\n
    \\n\\n
    \\n
    \\n\\n
    \\n\\n
    \\n \\\"{{training.name}}\\\"\\n
    \\n\\n

    \\n\\n
    \\n\\n
    \\n\\n\\n
    \\n\\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/trainings/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n \\\"{{logo.custom_asset_file_attributes.attachment}}\\\"\\n

    {{ 'app.shared.wallet.credit_title' }}

    \\n
    \\n
    \\n\\n
    \\n \\n {{ 'app.shared.wallet.warning_uneditable_credit' }}\\n
    \\n\\n
    \\n
    \\n \\n \\n {{currencySymbol}}\\n {{'app.shared.wallet.amount_is_required'}}\\n {{ 'app.shared.wallet.amount_minimum_1' | translate }} {{currencySymbol}}.\\n
    \\n
    \\n \\n \\n {{currencySymbol}}\\n {{'app.shared.wallet.amount_confirm_is_required'}}\\n {{ 'app.shared.wallet.amount_confirm_does_not_match' | translate }}\\n
    \\n\\n
    \\n
    \\n \\n
    \\n \\n
    \\n
    \\n\\n
    \\n
    \\n \\n

    {{ 'app.shared.wallet.will_appear_on_the_refund_invoice' }}

    \\n \\n
    \\n
    \\n
    \\n\\n
    \\n
    \\n \\n \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/wallet/credit_modal.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n

    {{'app.shared.wallet.your_wallet_amount'}}

    \\n

    {{'app.shared.wallet.wallet_amount'}}

    \\n
    \\n
    {{wallet.amount | currency}}
    \\n
    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/wallet/show.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;","// Module\nvar code = \"
    \\n 0\\\">\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
    {{ 'app.shared.wallet.date' }}{{ 'app.shared.wallet.operation' }}{{ 'app.shared.wallet.operator' }}{{ 'app.shared.wallet.amount' }}
    {{ ::t.created_at | amDateFormat:'L' }}\\n {{ 'app.shared.wallet.credit' }}\\n {{ 'app.shared.wallet.debit' }}\\n \\n {{::t.invoice.reference}}\\n \\n \\n {{::t.payment_schedule.reference}}\\n \\n {{ ::t.user.full_name }}\\n +\\n -\\n {{ ::t.amount | currency }}\\n
    \\n

    {{ 'app.shared.wallet.no_transactions_for_now' }}

    \\n
    \\n\";\n// Exports\nvar _module_exports = code;;\nvar path = '/wallet/transactions.html';\nvar angular = require('angular');\nangular.module('ng').run(['$templateCache', function(c) { c.put(path, _module_exports) }]);\nmodule.exports = path;"],"names":[],"sourceRoot":""}