{"version":3,"file":"dwv.min.js","mappings":"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AAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAC35BD,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,GACllCD,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAK9lCO,IAAK,CACHP,IAAKN,GAtIT,SAAyBxE,GACvB,MAAMF,EAAU,EAAJE,EACZ,OAAIF,EAAMyE,IACDA,IAEFzE,CACT,IAiIIiF,MAAOP,GAvHX,SAA0BxE,GACxB,MAAMsF,EAAQf,EAAgB,EAC9B,IAAIzE,EAAM,EACV,OAAIE,GAAKsF,IACPxF,EAAoB,GAAbE,EAAIsF,GACPxF,EAAMyE,KACDA,IAGJzE,CACT,IA8GIkF,KAAMR,GArGV,SAAyBxE,GACvB,MAAMsF,EAAQf,EAAgB,EAC9B,IAAIzE,EAAM,EACV,OAAIE,GAAK,EAAIsF,IACXxF,EAAwB,GAAjBE,EAAI,EAAIsF,GACXxF,EAAMyE,KACDA,IAGJzE,CACT,KAgGEyF,SAAU,CACRT,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC1sCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC58BC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAM12BQ,IAAK,CACHV,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC1kCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC9lCC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAMrpCS,eAAgB,CACdX,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC7iCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC19BC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,MAMxmCU,WAAY,CACVZ,IAAK,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KACpnCC,MAAO,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAC3lCC,KAAM,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,GAAI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,I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","sources":["webpack://dwv/webpack/universalModuleDefinition","webpack://dwv/external umd {\"root\":\"JSZip\",\"commonjs\":\"jszip\",\"commonjs2\":\"jszip\",\"amd\":\"jszip\"}","webpack://dwv/external umd {\"root\":\"Konva\",\"commonjs\":\"konva\",\"commonjs2\":\"konva\",\"amd\":\"konva\"}","webpack://dwv/external umd {\"root\":\"MagicWand\",\"commonjs\":\"magic-wand-tool\",\"commonjs2\":\"magic-wand-tool\",\"amd\":\"konmagic-wand-tool\"}","webpack://dwv/webpack/bootstrap","webpack://dwv/webpack/runtime/compat get default export","webpack://dwv/webpack/runtime/define property getters","webpack://dwv/webpack/runtime/hasOwnProperty shorthand","webpack://dwv/webpack/runtime/make namespace object","webpack://dwv/./src/math/index.js","webpack://dwv/./src/image/rescaleLut.js","webpack://dwv/./src/image/windowCenterAndWidth.js","webpack://dwv/./src/image/windowLut.js","webpack://dwv/./src/image/luts.js","webpack://dwv/./src/utils/logger.js","webpack://dwv/./src/utils/colour.js","webpack://dwv/./src/math/vector.js","webpack://dwv/./src/math/matrix.js","webpack://dwv/./src/math/point.js","webpack://dwv/./src/dicom/dictionary.js","webpack://dwv/./src/dicom/dicomTag.js","webpack://dwv/./src/dicom/dataReader.js","webpack://dwv/./src/utils/string.js","webpack://dwv/./src/utils/array.js","webpack://dwv/./src/dicom/dataElement.js","webpack://dwv/./src/dicom/dicomParser.js","webpack://dwv/./src/utils/listen.js","webpack://dwv/./src/image/iterator.js","webpack://dwv/./src/image/rsi.js","webpack://dwv/./src/image/size.js","webpack://dwv/./src/image/spacing.js","webpack://dwv/./src/image/geometry.js","webpack://dwv/./src/dicom/dicomElementsWrapper.js","webpack://dwv/./src/image/imageFactory.js","webpack://dwv/./src/image/maskFactory.js","webpack://dwv/./src/image/image.js","webpack://dwv/./src/image/viewFactory.js","webpack://dwv/./src/image/view.js","webpack://dwv/./src/image/viewMonochrome.js","webpack://dwv/./src/image/viewPaletteColor.js","webpack://dwv/./src/image/viewRgb.js","webpack://dwv/./src/image/viewYbrFull.js","webpack://dwv/./src/image/planeHelper.js","webpack://dwv/./src/gui/layerGroup.js","webpack://dwv/./src/image/maskSegmentHelper.js","webpack://dwv/./src/app/viewController.js","webpack://dwv/./src/gui/generic.js","webpack://dwv/./src/gui/viewLayer.js","webpack://dwv/./src/gui/style.js","webpack://dwv/./src/tools/drawCommands.js","webpack://dwv/./src/app/drawController.js","webpack://dwv/./src/gui/drawLayer.js","webpack://dwv/./src/gui/stage.js","webpack://dwv/./src/io/state.js","webpack://dwv/./src/utils/uri.js","webpack://dwv/./src/tools/undo.js","webpack://dwv/./src/app/toolboxController.js","webpack://dwv/./src/utils/progress.js","webpack://dwv/./src/io/urlsLoader.js","webpack://dwv/./src/utils/thread.js","webpack://dwv/./src/image/decoder.js","webpack://dwv/./src/image/dicomBufferToView.js","webpack://dwv/./src/io/memoryLoader.js","webpack://dwv/./src/image/domReader.js","webpack://dwv/./src/io/loaderList.js","webpack://dwv/./src/io/dicomDataLoader.js","webpack://dwv/./src/io/jsonTextLoader.js","webpack://dwv/./src/io/multipartLoader.js","webpack://dwv/./src/io/rawImageLoader.js","webpack://dwv/./src/io/rawVideoLoader.js","webpack://dwv/./src/io/zipLoader.js","webpack://dwv/./src/io/filesLoader.js","webpack://dwv/./src/app/loadController.js","webpack://dwv/./src/app/dataController.js","webpack://dwv/./src/utils/operator.js","webpack://dwv/./src/tools/scrollWheel.js","webpack://dwv/./src/utils/i18n.js","webpack://dwv/./src/math/line.js","webpack://dwv/./src/math/stats.js","webpack://dwv/./src/tools/editor.js","webpack://dwv/./src/tools/draw.js","webpack://dwv/./src/math/roi.js","webpack://dwv/./src/tools/roi.js","webpack://dwv/./src/math/path.js","webpack://dwv/./src/math/bucketQueue.js","webpack://dwv/./src/math/scissors.js","webpack://dwv/./src/math/circle.js","webpack://dwv/./src/math/ellipse.js","webpack://dwv/./src/math/rectangle.js","webpack://dwv/./src/image/filter.js","webpack://dwv/./src/tools/filter.js","webpack://dwv/./src/tools/index.js","webpack://dwv/./src/tools/windowLevel.js","webpack://dwv/./src/tools/scroll.js","webpack://dwv/./src/tools/zoomPan.js","webpack://dwv/./src/tools/opacity.js","webpack://dwv/./src/tools/floodfill.js","webpack://dwv/./src/tools/livewire.js","webpack://dwv/./src/tools/arrow.js","webpack://dwv/./src/tools/circle.js","webpack://dwv/./src/tools/ellipse.js","webpack://dwv/./src/tools/freeHand.js","webpack://dwv/./src/tools/protractor.js","webpack://dwv/./src/tools/rectangle.js","webpack://dwv/./src/tools/ruler.js","webpack://dwv/./src/app/application.js","webpack://dwv/./src/dicom/dataWriter.js","webpack://dwv/./src/dicom/dicomWriter.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"konva\"), require(\"jszip\"), require(\"magic-wand-tool\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"konva\", \"jszip\", \"konmagic-wand-tool\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"dwv\"] = factory(require(\"konva\"), require(\"jszip\"), require(\"magic-wand-tool\"));\n\telse\n\t\troot[\"dwv\"] = factory(root[\"Konva\"], root[\"JSZip\"], root[\"MagicWand\"]);\n})(this, function(__WEBPACK_EXTERNAL_MODULE__436__, __WEBPACK_EXTERNAL_MODULE__626__, __WEBPACK_EXTERNAL_MODULE__812__) {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__626__;","module.exports = __WEBPACK_EXTERNAL_MODULE__436__;","module.exports = __WEBPACK_EXTERNAL_MODULE__812__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Immutable index.\n * Warning: the input array is NOT cloned, modifying it will\n *  modify the index values.\n */\nexport class Index {\n\n  /**\n   * Index values.\n   *\n   * @type {number[]}\n   */\n  #values;\n\n  /**\n   * @param {number[]} values The index values.\n   */\n  constructor(values) {\n    if (!values || typeof values === 'undefined') {\n      throw new Error('Cannot create index with no values.');\n    }\n    if (values.length === 0) {\n      throw new Error('Cannot create index with empty values.');\n    }\n    const valueCheck = function (val) {\n      return !isNaN(val);\n    };\n    if (!values.every(valueCheck)) {\n      throw new Error('Cannot create index with non number values.');\n    }\n    this.#values = values;\n  }\n\n  /**\n   * Get the index value at the given array index.\n   *\n   * @param {number} i The index to get.\n   * @returns {number|undefined} The value or undefined if not in range.\n   */\n  get(i) {\n    return this.#values[i];\n  }\n\n  /**\n   * Get the length of the index.\n   *\n   * @returns {number} The length.\n   */\n  length() {\n    return this.#values.length;\n  }\n\n  /**\n   * Get a string representation of the Index.\n   *\n   * @returns {string} The Index as a string.\n   */\n  toString() {\n    return '(' + this.#values.toString() + ')';\n  }\n\n  /**\n   * Get the values of this index.\n   *\n   * @returns {number[]} The array of values.\n   */\n  getValues() {\n    return this.#values.slice();\n  }\n\n  /**\n   * Check if the input index can be compared to this one.\n   *\n   * @param {Index} rhs The index to compare to.\n   * @returns {boolean} True if both indices are comparable.\n   */\n  canCompare(rhs) {\n    // check input\n    if (!rhs) {\n      return false;\n    }\n    // check length\n    if (this.length() !== rhs.length()) {\n      return false;\n    }\n    // seems ok!\n    return true;\n  }\n\n  /**\n   * Check for Index equality.\n   *\n   * @param {Index} rhs The index to compare to.\n   * @returns {boolean} True if both indices are equal.\n   */\n  equals(rhs) {\n    // check if can compare\n    if (!this.canCompare(rhs)) {\n      return false;\n    }\n    // check values\n    for (let i = 0, leni = this.length(); i < leni; ++i) {\n      if (this.get(i) !== rhs.get(i)) {\n        return false;\n      }\n    }\n    // seems ok!\n    return true;\n  }\n\n  /**\n   * Compare indices and return different dimensions.\n   *\n   * @param {Index} rhs The index to compare to.\n   * @returns {number[]} The list of different dimensions.\n   */\n  compare(rhs) {\n    // check if can compare\n    if (!this.canCompare(rhs)) {\n      return null;\n    }\n    // check values\n    const diffDims = [];\n    for (let i = 0, leni = this.length(); i < leni; ++i) {\n      if (this.get(i) !== rhs.get(i)) {\n        diffDims.push(i);\n      }\n    }\n    return diffDims;\n  }\n\n  /**\n   * Add another index to this one.\n   *\n   * @param {Index} rhs The index to add.\n   * @returns {Index} The index representing the sum of both indices.\n   */\n  add(rhs) {\n    // check if can compare\n    if (!this.canCompare(rhs)) {\n      return null;\n    }\n    // add values\n    const values = [];\n    for (let i = 0, leni = this.length(); i < leni; ++i) {\n      values.push(this.get(i) + rhs.get(i));\n    }\n    // seems ok!\n    return new Index(values);\n  }\n\n  /**\n   * Get the current index with a new 2D base.\n   *\n   * @param {number} i The new 0 index.\n   * @param {number} j The new 1 index.\n   * @returns {Index} The new index.\n   */\n  getWithNew2D(i, j) {\n    const values = [i, j];\n    for (let l = 2, lenl = this.length(); l < lenl; ++l) {\n      values.push(this.get(l));\n    }\n    return new Index(values);\n  }\n\n  /**\n   * Get a string id from the index values in the form of: '#0-1_#1-2'.\n   *\n   * @param {number[]} [dims] Optional list of dimensions to use.\n   * @returns {string} The string id.\n   */\n  toStringId(dims) {\n    if (typeof dims === 'undefined') {\n      dims = [];\n      for (let j = 0; j < this.length(); ++j) {\n        dims.push(j);\n      }\n    }\n    for (let ii = 0; ii < dims.length; ++ii) {\n      if (dims[ii] >= this.length()) {\n        throw new Error('Non valid dimension for toStringId.');\n      }\n    }\n    let res = '';\n    for (let i = 0; i < dims.length; ++i) {\n      if (i !== 0) {\n        res += '_';\n      }\n      res += '#' + dims[i] + '-' + this.get(dims[i]);\n    }\n    return res;\n  }\n\n} // Index class\n\n/**\n * Get an index with values set to 0 and the input size.\n *\n * @param {number} size The size of the index.\n * @returns {Index} The zero index.\n */\nexport function getZeroIndex(size) {\n  const values = new Array(size);\n  values.fill(0);\n  return new Index(values);\n}\n\n/**\n * Get an array sort callback.\n * f(a,b) > 0 -> b,a\n * f(a,b) < 0 -> a,b\n * f(a,b) = 0 -> original order\n *\n * @param {number} direction The direction to use to compare indices.\n * @returns {Function} A function that compares two Index.\n */\nexport function getIndexCompareFunction(direction) {\n  return function (a, b) {\n    return a.get(direction) - b.get(direction);\n  };\n}\n\n/**\n * Get an index from an id string in the form of: '#0-1_#1-2'\n * (result of index.toStringId).\n *\n * @param {string} inputStr The input string.\n * @returns {Index} The corresponding index.\n */\nexport function getIndexFromStringId(inputStr) {\n  // split ids\n  const strIds = inputStr.split('_');\n  // get the size of the index\n  let pointLength = 0;\n  let dim;\n  for (let i = 0; i < strIds.length; ++i) {\n    dim = parseInt(strIds[i].substring(1, 2), 10);\n    if (dim > pointLength) {\n      pointLength = dim;\n    }\n  }\n  if (pointLength === 0) {\n    throw new Error('No dimension found in point stringId');\n  }\n  // default values\n  const values = new Array(pointLength);\n  values.fill(0);\n  // get other values from the input string\n  for (let j = 0; j < strIds.length; ++j) {\n    dim = parseInt(strIds[j].substring(1, 3), 10);\n    const value = parseInt(strIds[j].substring(3), 10);\n    values[dim] = value;\n  }\n  return new Index(values);\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {RescaleSlopeAndIntercept} from './rsi';\n/* eslint-enable no-unused-vars */\n\n/**\n * Rescale LUT class.\n * Typically converts from integer to float.\n */\nexport class RescaleLut {\n\n  /**\n   * The rescale slope.\n   *\n   * @type {RescaleSlopeAndIntercept}\n   */\n  #rsi;\n\n  /**\n   * The internal array.\n   *\n   * @type {Float32Array}\n   */\n  #lut = null;\n\n  /**\n   * Flag to know if the lut is ready or not.\n   *\n   * @type {boolean}\n   */\n  #isReady = false;\n\n  /**\n   * The size of the LUT array.\n   *\n   * @type {number}\n   */\n  #length;\n\n  /**\n   * @param {RescaleSlopeAndIntercept} rsi The rescale slope and intercept.\n   * @param {number} bitsStored The number of bits used to store the data.\n   */\n  constructor(rsi, bitsStored) {\n    this.#rsi = rsi;\n    this.#length = Math.pow(2, bitsStored);\n  }\n\n  /**\n   * Get the Rescale Slope and Intercept (RSI).\n   *\n   * @returns {RescaleSlopeAndIntercept} The rescale slope and intercept object.\n   */\n  getRSI() {\n    return this.#rsi;\n  }\n\n  /**\n   * Is the lut ready to use or not? If not, the user must\n   * call 'initialise'.\n   *\n   * @returns {boolean} True if the lut is ready to use.\n   */\n  isReady() {\n    return this.#isReady;\n  }\n\n  /**\n   * Initialise the LUT.\n   */\n  initialise() {\n    // check if already initialised\n    if (this.#isReady) {\n      return;\n    }\n    // create lut and fill it\n    this.#lut = new Float32Array(this.#length);\n    for (let i = 0; i < this.#length; ++i) {\n      this.#lut[i] = this.#rsi.apply(i);\n    }\n    // update ready flag\n    this.#isReady = true;\n  }\n\n  /**\n   * Get the length of the LUT array.\n   *\n   * @returns {number} The length of the LUT array.\n   */\n  getLength() {\n    return this.#length;\n  }\n\n  /**\n   * Get the value of the LUT at the given offset.\n   *\n   * @param {number} offset The input offset in [0,2^bitsStored] range.\n   * @returns {number} The float32 value of the LUT at the given offset.\n   */\n  getValue(offset) {\n    return this.#lut[offset];\n  }\n\n} // class RescaleLut\n","/**\n * Minimum window width value.\n *\n * @see http://dicom.nema.org/dicom/2013/output/chtml/part03/sect_C.11.html#sect_C.11.2.1.2\n */\nconst minWindowWidth = 1;\n\n/**\n * List of default window level presets.\n *\n * @type {Object.<string, Object.<string, {center: number, width: number}>>}\n */\nexport const defaultPresets = {\n  CT: {\n    mediastinum: {center: 40, width: 400},\n    lung: {center: -500, width: 1500},\n    bone: {center: 500, width: 2000},\n    brain: {center: 40, width: 80},\n    head: {center: 90, width: 350}\n  }\n};\n\n/**\n * Validate an input window width.\n *\n * @param {number} value The value to test.\n * @returns {number} A valid window width.\n */\nexport function validateWindowWidth(value) {\n  return value < minWindowWidth ? minWindowWidth : value;\n}\n\n/**\n * WindowCenterAndWidth class.\n * <br>Pseudo-code:\n * <pre>\n *  if (x &lt;= c - 0.5 - (w-1)/2), then y = ymin\n *  else if (x > c - 0.5 + (w-1)/2), then y = ymax,\n *  else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin) + ymin\n * </pre>\n *\n * @see DICOM doc for [Window Center and Window Width]{@link http://dicom.nema.org/dicom/2013/output/chtml/part03/sect_C.11.html#sect_C.11.2.1.2}\n */\nexport class WindowCenterAndWidth {\n\n  /**\n   * The center.\n   *\n   * @type {number}\n   */\n  #center;\n\n  /**\n   * The width.\n   *\n   * @type {number}\n   */\n  #width;\n\n  /**\n   * @param {number} center The window center.\n   * @param {number} width The window width.\n   */\n  constructor(center, width) {\n    // check width\n    if (width < minWindowWidth) {\n      throw new Error('Window width shall always be greater than or equal to ' +\n        minWindowWidth);\n    }\n    this.#center = center;\n    this.#width = width;\n\n    this.#init();\n  }\n\n  /**\n   * Signed data offset. Defaults to 0.\n   *\n   * @type {number}\n   */\n  #signedOffset = 0;\n\n  /**\n   * Output value minimum. Defaults to 0.\n   *\n   * @type {number}\n   */\n  #ymin = 0;\n\n  /**\n   * Output value maximum. Defaults to 255.\n   *\n   * @type {number}\n   */\n  #ymax = 255;\n\n  /**\n   * Input value minimum (calculated).\n   *\n   * @type {number}\n   */\n  #xmin = null;\n\n  /**\n   * Input value maximum (calculated).\n   *\n   * @type {number}\n   */\n  #xmax = null;\n\n  /**\n   * Window level equation slope (calculated).\n   *\n   * @type {number}\n   */\n  #slope = null;\n\n  /**\n   * Window level equation intercept (calculated).\n   *\n   * @type {number}\n   */\n  #inter = null;\n\n  /**\n   * Initialise members. Called at construction.\n   *\n   */\n  #init() {\n    const c = this.#center + this.#signedOffset;\n    // from the standard\n    this.#xmin = c - 0.5 - ((this.#width - 1) / 2);\n    this.#xmax = c - 0.5 + ((this.#width - 1) / 2);\n    // develop the equation:\n    // y = ( ( x - (c - 0.5) ) / (w-1) + 0.5 ) * (ymax - ymin) + ymin\n    // y = ( x / (w-1) ) * (ymax - ymin) +\n    //     ( -(c - 0.5) / (w-1) + 0.5 ) * (ymax - ymin) + ymin\n    this.#slope = (this.#ymax - this.#ymin) / (this.#width - 1);\n    this.#inter = (-(c - 0.5) / (this.#width - 1) + 0.5) *\n      (this.#ymax - this.#ymin) + this.#ymin;\n  }\n\n  /**\n   * Get the window center.\n   *\n   * @returns {number} The window center.\n   */\n  getCenter() {\n    return this.#center;\n  }\n\n  /**\n   * Get the window width.\n   *\n   * @returns {number} The window width.\n   */\n  getWidth() {\n    return this.#width;\n  }\n\n  /**\n   * Set the output value range.\n   *\n   * @param {string} min The output value minimum.\n   * @param {string} max The output value maximum.\n   */\n  setRange(min, max) {\n    this.#ymin = parseInt(min, 10);\n    this.#ymax = parseInt(max, 10);\n    // re-initialise\n    this.#init();\n  }\n\n  /**\n   * Set the signed offset.\n   *\n   * @param {number} offset The signed data offset,\n   *   typically: slope * ( size / 2).\n   */\n  setSignedOffset(offset) {\n    this.#signedOffset = offset;\n    // re-initialise\n    this.#init();\n  }\n\n  /**\n   * Apply the window level on an input value.\n   *\n   * @param {number} value The value to rescale as an integer.\n   * @returns {number} The leveled value, in the\n   *  [ymin, ymax] range (default [0,255]).\n   */\n  apply(value) {\n    if (value <= this.#xmin) {\n      return this.#ymin;\n    } else if (value > this.#xmax) {\n      return this.#ymax;\n    } else {\n      return (value * this.#slope) + this.#inter;\n    }\n  }\n\n  /**\n   * Check for window level equality.\n   *\n   * @param {WindowCenterAndWidth} rhs The other window level to compare to.\n   * @returns {boolean} True if both window level are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getCenter() === rhs.getCenter() &&\n      this.getWidth() === rhs.getWidth();\n  }\n\n  /**\n   * Get a string representation of the window level.\n   *\n   * @returns {string} The window level as a string.\n   */\n  toString() {\n    return (this.getCenter() + ', ' + this.getWidth());\n  }\n\n} // class WindowLevel\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {RescaleLut} from './rescaleLut';\nimport {WindowCenterAndWidth} from './windowCenterAndWidth';\n/* eslint-enable no-unused-vars */\n\n/**\n * Window LUT class.\n * Typically converts from float to integer.\n */\nexport class WindowLut {\n\n  /**\n   * The rescale LUT.\n   *\n   * @type {RescaleLut}\n   */\n  #rescaleLut;\n\n  /**\n   * Signed data flag.\n   *\n   * @type {boolean}\n   */\n  #isSigned;\n\n  /**\n   * The internal array: Uint8ClampedArray clamps between 0 and 255.\n   *\n   * @type {Uint8ClampedArray}\n   */\n  #lut = null;\n\n  /**\n   * The window level.\n   *\n   * @type {WindowCenterAndWidth}\n   */\n  #windowLevel = null;\n\n  /**\n   * Flag to know if the lut is ready or not.\n   *\n   * @type {boolean}\n   */\n  #isReady = false;\n\n  /**\n   * Shift for signed data.\n   *\n   * @type {number}\n   */\n  #signedShift = 0;\n\n  /**\n   * @param {RescaleLut} rescaleLut The associated rescale LUT.\n   * @param {boolean} isSigned Flag to know if the data is signed or not.\n   */\n  constructor(rescaleLut, isSigned) {\n    this.#rescaleLut = rescaleLut;\n    this.#isSigned = isSigned;\n  }\n\n  /**\n   * Get the window / level.\n   *\n   * @returns {WindowCenterAndWidth} The window / level.\n   */\n  getWindowLevel() {\n    return this.#windowLevel;\n  }\n\n  /**\n   * Get the signed flag.\n   *\n   * @returns {boolean} The signed flag.\n   */\n  isSigned() {\n    return this.#isSigned;\n  }\n\n  /**\n   * Get the rescale lut.\n   *\n   * @returns {RescaleLut} The rescale lut.\n   */\n  getRescaleLut() {\n    return this.#rescaleLut;\n  }\n\n  /**\n   * Is the lut ready to use or not? If not, the user must\n   * call 'update'.\n   *\n   * @returns {boolean} True if the lut is ready to use.\n   */\n  isReady() {\n    return this.#isReady;\n  }\n\n  /**\n   * Set the window center and width.\n   *\n   * @param {WindowCenterAndWidth} wl The window level.\n   */\n  setWindowLevel(wl) {\n    // store the window values\n    this.#windowLevel = wl;\n    // possible signed shift\n    this.#signedShift = 0;\n    this.#windowLevel.setSignedOffset(0);\n    if (this.#isSigned) {\n      const size = this.#rescaleLut.getLength();\n      this.#signedShift = size / 2;\n      this.#windowLevel.setSignedOffset(\n        this.#rescaleLut.getRSI().getSlope() * this.#signedShift);\n    }\n    // update ready flag\n    this.#isReady = false;\n  }\n\n  /**\n   * Update the lut if needed..\n   */\n  update() {\n    // check if we need to update\n    if (this.#isReady) {\n      return;\n    }\n\n    // check rescale lut\n    if (!this.#rescaleLut.isReady()) {\n      this.#rescaleLut.initialise();\n    }\n    // create window lut\n    const size = this.#rescaleLut.getLength();\n    if (!this.#lut) {\n      // use clamped array (polyfilled in env.js)\n      this.#lut = new Uint8ClampedArray(size);\n    }\n    // by default WindowLevel returns a value in the [0,255] range\n    // this is ok with regular Arrays and ClampedArray.\n    for (let i = 0; i < size; ++i) {\n      this.#lut[i] = this.#windowLevel.apply(this.#rescaleLut.getValue(i));\n    }\n\n    // update ready flag\n    this.#isReady = true;\n  }\n\n  /**\n   * Get the length of the LUT array.\n   *\n   * @returns {number} The length of the LUT array.\n   */\n  getLength() {\n    return this.#lut.length;\n  }\n\n  /**\n   * Get the value of the LUT at the given offset.\n   *\n   * @param {number} offset The input offset in [0,2^bitsStored] range.\n   * @returns {number} The integer value (default [0,255]) of the LUT\n   *   at the given offset.\n   */\n  getValue(offset) {\n    return this.#lut[offset + this.#signedShift];\n  }\n\n} // class WindowLut\n","/**\n * Lookup tables for image colour display.\n */\n\nconst lut_range_max = 256;\n\n/**\n * Build a LUT of size lut_range_max.\n *\n * @param {Function} func The i to lut function.\n * @returns {Array} The LUT.\n */\nfunction buildLut(func) {\n  const lut = [];\n  for (let i = 0; i < lut_range_max; ++i) {\n    lut.push(func(i));\n  }\n  return lut;\n}\n\n/**\n * Ramp to lut_range_max minus one on the first third values.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxFirstThird(i) {\n  const val = i * 3;\n  if (val > lut_range_max - 1) {\n    return lut_range_max - 1;\n  }\n  return val;\n}\n\n/**\n * Ramp to lut_range_max minus one on the second third values.\n *  otherwise return 0 for the first third and\n *  lut_range_max minus one for the last third.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxSecondThird(i) {\n  const third = lut_range_max / 3;\n  let val = 0;\n  if (i >= third) {\n    val = (i - third) * 3;\n    if (val > lut_range_max - 1) {\n      return lut_range_max - 1;\n    }\n  }\n  return val;\n}\n\n/**\n * Ramp to lut_range_max minus one on the last third values.\n *  otherwise return 0.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction toMaxThirdThird(i) {\n  const third = lut_range_max / 3;\n  let val = 0;\n  if (i >= 2 * third) {\n    val = (i - 2 * third) * 3;\n    if (val > lut_range_max - 1) {\n      return lut_range_max - 1;\n    }\n  }\n  return val;\n}\n\n/**\n * Identity, returns i.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction id(i) {\n  return i;\n}\n\n/**\n * Returns lut_range_max minus one minus i.\n *\n * @param {number} i The input index.\n * @returns {number} The lut value.\n */\nfunction invId(i) {\n  return (lut_range_max - 1) - i;\n}\n\n/**\n * Colour map: red, green and blue components\n * to associate with intensity values.\n */\nexport class ColourMap {\n  /**\n   * Red component: 256 values in the [0, 255] range.\n   *\n   * @type {number[]}\n   */\n  red;\n  /**\n   * Green component: 256 values in the [0, 255] range.\n   *\n   * @type {number[]}\n   */\n  green;\n  /**\n   * Blue component: 256 values in the [0, 255] range.\n   *\n   * @type {number[]}\n   */\n  blue;\n\n  /**\n   * @param {number[]} red Red component.\n   * @param {number[]} green Green component.\n   * @param {number[]} blue Blue component.\n   */\n  constructor(red, green, blue) {\n    this.red = red;\n    this.green = green;\n    this.blue = blue;\n  }\n}\n\n/**\n * List of available lookup tables (lut).\n *\n * @type {Object<string, ColourMap>}\n */\nexport const luts = {\n  // plain\n  plain: {\n    red: buildLut(id),\n    green: buildLut(id),\n    blue: buildLut(id)\n  },\n\n  // inverse plain\n  invPlain: {\n    red: buildLut(invId),\n    green: buildLut(invId),\n    blue: buildLut(invId)\n  },\n\n  // rainbow\n  /* eslint-disable max-len */\n  rainbow: {\n    blue: [0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255, 247, 239, 231, 223, 215, 207, 199, 191, 183, 175, 167, 159, 151, 143, 135, 127, 119, 111, 103, 95, 87, 79, 71, 63, 55, 47, 39, 31, 23, 15, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n    green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232, 240, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 251, 249, 247, 245, 243, 241, 239, 237, 235, 233, 231, 229, 227, 225, 223, 221, 219, 217, 215, 213, 211, 209, 207, 205, 203, 201, 199, 197, 195, 193, 192, 189, 186, 183, 180, 177, 174, 171, 168, 165, 162, 159, 156, 153, 150, 147, 144, 141, 138, 135, 132, 129, 126, 123, 120, 117, 114, 111, 108, 105, 102, 99, 96, 93, 90, 87, 84, 81, 78, 75, 72, 69, 66, 63, 60, 57, 54, 51, 48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3],\n    red: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 62, 60, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]\n  },\n  /* eslint-enable max-len */\n\n  // hot\n  hot: {\n    red: buildLut(toMaxFirstThird),\n    green: buildLut(toMaxSecondThird),\n    blue: buildLut(toMaxThirdThird)\n  },\n\n  // hot iron\n  /* eslint-disable max-len */\n  hot_iron: {\n    red: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n    green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255],\n    blue: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 248, 252, 255]\n  },\n  /* eslint-enable max-len */\n\n  // pet\n  /* eslint-disable max-len */\n  pet: {\n    red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n    green: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 128, 126, 124, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 94, 92, 90, 88, 86, 84, 82, 80, 78, 76, 74, 72, 70, 68, 66, 64, 63, 61, 59, 57, 55, 53, 51, 49, 47, 45, 43, 41, 39, 37, 35, 33, 31, 29, 27, 25, 23, 21, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 255],\n    blue: [0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 252, 248, 244, 240, 236, 232, 228, 224, 220, 216, 212, 208, 204, 200, 196, 192, 188, 184, 180, 176, 172, 168, 164, 160, 156, 152, 148, 144, 140, 136, 132, 128, 124, 120, 116, 112, 108, 104, 100, 96, 92, 88, 84, 80, 76, 72, 68, 64, 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153, 157, 161, 165, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 214, 218, 222, 226, 230, 234, 238, 242, 246, 250, 255]\n  },\n  /* eslint-enable max-len */\n\n  // hot metal blue\n  /* eslint-disable max-len */\n  hot_metal_blue: {\n    red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 12, 15, 18, 21, 24, 26, 29, 32, 35, 38, 41, 44, 47, 50, 52, 55, 57, 59, 62, 64, 66, 69, 71, 74, 76, 78, 81, 83, 85, 88, 90, 93, 96, 99, 102, 105, 108, 111, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 161, 164, 166, 169, 172, 175, 178, 181, 184, 187, 190, 194, 198, 201, 205, 209, 213, 217, 221, 224, 228, 232, 236, 240, 244, 247, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n    green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 9, 11, 13, 15, 17, 19, 21, 23, 24, 26, 28, 30, 32, 34, 36, 38, 40, 41, 43, 45, 47, 49, 51, 53, 55, 56, 58, 60, 62, 64, 66, 68, 70, 72, 73, 75, 77, 79, 81, 83, 85, 87, 88, 90, 92, 94, 96, 98, 100, 102, 104, 105, 107, 109, 111, 113, 115, 117, 119, 120, 122, 124, 126, 128, 130, 132, 134, 136, 137, 139, 141, 143, 145, 147, 149, 151, 152, 154, 156, 158, 160, 162, 164, 166, 168, 169, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, 190, 192, 194, 196, 198, 200, 201, 203, 205, 207, 209, 211, 213, 215, 216, 218, 220, 222, 224, 226, 228, 229, 231, 233, 235, 237, 239, 240, 242, 244, 246, 248, 250, 251, 253, 255],\n    blue: [0, 2, 4, 6, 8, 10, 12, 14, 16, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 184, 186, 188, 190, 192, 194, 196, 198, 200, 197, 194, 191, 188, 185, 182, 179, 176, 174, 171, 168, 165, 162, 159, 156, 153, 150, 144, 138, 132, 126, 121, 115, 109, 103, 97, 91, 85, 79, 74, 68, 62, 56, 50, 47, 44, 41, 38, 35, 32, 29, 26, 24, 21, 18, 15, 12, 9, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 9, 12, 15, 18, 21, 24, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124, 126, 129, 132, 135, 138, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 174, 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, 206, 210, 213, 216, 219, 223, 226, 229, 232, 236, 239, 242, 245, 249, 252, 255]\n  },\n  /* eslint-enable max-len */\n\n  // pet 20 step\n  /* eslint-disable max-len */\n  pet_20step: {\n    red: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n    green: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],\n    blue: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]\n  }\n  /* eslint-enable max-len */\n};\n","export const logger = {\n  /**\n   * Available log levels.\n   * Note: need to activate verbose level in\n   *   Chrome console to see DEBUG messages.\n   */\n  levels: {\n    TRACE: 0,\n    DEBUG: 1,\n    INFO: 2,\n    WARN: 3,\n    ERROR: 4\n  },\n\n  /**\n   * Logger level: default to WARN.\n   */\n  level: 3,\n\n  /**\n   * Log a trace message.\n   *\n   * @param {string} msg The message to log.\n   */\n  trace: function (msg) {\n    if (this.level <= this.levels.TRACE) {\n      console.trace(msg);\n    }\n  },\n\n  /**\n   * Log a debug message.\n   * Careful: depends on console settings.\n   *\n   * @param {string} msg The message to log.\n   */\n  debug: function (msg) {\n    if (this.level <= this.levels.DEBUG) {\n      console.debug(msg);\n    }\n  },\n\n  /**\n   * Log an info message.\n   *\n   * @param {string} msg The message to log.\n   */\n  info: function (msg) {\n    if (this.level <= this.levels.INFO) {\n      console.info(msg);\n    }\n  },\n\n  /**\n   * Log a warn message.\n   *\n   * @param {string} msg The message to log.\n   */\n  warn: function (msg) {\n    if (this.level <= this.levels.WARN) {\n      console.warn(msg);\n    }\n  },\n\n  /**\n   * Log an error message.\n   *\n   * @param {string} msg The message to log.\n   */\n  error: function (msg) {\n    if (this.level <= this.levels.ERROR) {\n      console.error(msg);\n    }\n  }\n\n}; // logger\n","// example implementation: dcmtk/dcmiod/libsrc/cielabutil.cc\n// https://github.com/DCMTK/dcmtk/blob/DCMTK-3.6.6/dcmiod/libsrc/cielabutil.cc\n\n/**\n * Check if two rgb objects are equal.\n *\n * @param {object} c1 The first colour.\n * @param {object} c2 The second colour.\n * @returns {boolean} True if both colour are equal.\n */\nexport function isEqualRgb(c1, c2) {\n  return c1 !== null &&\n    c2 !== null &&\n    typeof c1 !== 'undefined' &&\n    typeof c2 !== 'undefined' &&\n    c1.r === c2.r &&\n    c1.g === c2.g &&\n    c1.b === c2.b;\n}\n\n/**\n * Convert YBR to RGB.\n *\n * @see http://dicom.nema.org/dicom/2013/output/chtml/part03/sect_C.7.html#sect_C.7.6.3.1.2\n * @see https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion\n * @param {number} y The Y component.\n * @param {number} cb The Cb component.\n * @param {number} cr The Cr component.\n * @returns {object} RGB equivalent as {r,g,b}.\n */\nexport function ybrToRgb(y, cb, cr) {\n  return {\n    r: y + 1.402 * (cr - 128),\n    g: y - 0.34414 * (cb - 128) - 0.71414 * (cr - 128),\n    b: y + 1.772 * (cb - 128)\n  };\n}\n\n/**\n * Convert a hex color into RGB.\n *\n * @param {string} hexStr The hex color as '#ab01ef'.\n * @returns {object} The RGB values as {r,g,b}.\n */\nexport function hexToRgb(hexStr) {\n  return {\n    r: parseInt(hexStr.substring(1, 3), 16),\n    g: parseInt(hexStr.substring(3, 5), 16),\n    b: parseInt(hexStr.substring(5, 7), 16)\n  };\n}\n\n/**\n * Convert RGB to its hex equivalent.\n *\n * @param {object} rgb The RGB object as {r,g,b}.\n * @returns {string} A string representing the hex color as '#ab01ef'.\n */\nexport function rgbToHex(rgb) {\n  return '#' +\n    ((1 << 24) + (rgb.r << 16) + (rgb.g << 8) + rgb.b).toString(16).slice(1);\n}\n\n/**\n * Get the brightness of a RGB colour: calculates\n * the luma (Y) of the YIQ colour space.\n *\n * @see https://en.wikipedia.org/wiki/YIQ#From_RGB_to_YIQ\n * @param {object} rgbTriplet RGB triplet.\n * @returns {number} The brightness ([0,1]).\n */\nexport function getBrightness(rgbTriplet) {\n  // 0.001172549 = 0.299 / 255\n  // 0.002301961 = 0.587 / 255\n  // 0.000447059 = 0.114 / 255\n  return rgbTriplet.r * 0.001172549 +\n    rgbTriplet.g * 0.002301961 +\n    rgbTriplet.b * 0.000447059;\n}\n\n/**\n * Check if a colour given in hexadecimal format is dark.\n *\n * @param {string} hexColour The colour (as '#ab01ef').\n * @returns {boolean} True if the colour is dark (brightness < 0.5).\n */\nexport function isDarkColour(hexColour) {\n  return getBrightness(hexToRgb(hexColour)) < 0.5;\n}\n\n/**\n * Get the shadow colour of an input colour.\n *\n * @param {string} hexColour The colour (as '#ab01ef').\n * @returns {string} The shadow colour (white or black).\n */\nexport function getShadowColour(hexColour) {\n  return isDarkColour(hexColour) ? '#fff' : '#000';\n}\n\n/**\n * Unsigned int CIE LAB value ([0, 65535]) to CIE LAB value\n *   (L: [0, 100], a: [-128, 127], b: [-128, 127]).\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b} with unsigned range.\n * @returns {object} CIE LAB triplet as {l,a,b} with CIE LAB range.\n */\nexport function uintLabToLab(triplet) {\n  // 0.001525902 = 100 / 65535\n  // 0.003891051 = 255 / 65535\n  return {\n    l: 0.001525902 * triplet.l,\n    a: 0.003891051 * triplet.a - 128,\n    b: 0.003891051 * triplet.b - 128,\n  };\n}\n\n/**\n * CIE LAB value (L: [0, 100], a: [-128, 127], b: [-128, 127]) to\n *   unsigned int CIE LAB ([0, 65535]).\n *\n * @param {object} triplet CIE XYZ triplet as {x,y,z} with CIE LAB range.\n * @returns {object} CIE LAB triplet as {l,a,b} with unsigned range.\n */\nexport function labToUintLab(triplet) {\n  // 655.35 = 65535 / 100\n  // aUint = (a + 128) * 65535 / 255\n  // 257 = 65535 / 255\n  // 32896 = 257 * 128\n  return {\n    l: 655.35 * triplet.l,\n    a: 257 * triplet.a + 32896,\n    b: 257 * triplet.b + 32896,\n  };\n}\n\n/**\n * CIE Standard Illuminant D65, standard 2° observer.\n *\n * @see https://en.wikipedia.org/wiki/Illuminant_D65\n */\nconst d65 = {\n  x: 95.0489,\n  y: 100,\n  z: 108.884\n};\n\n/**\n * Convert CIE LAB to CIE XYZ (standard illuminant D65, 2degree 1931).\n *\n * @see https://en.wikipedia.org/wiki/CIELAB_color_space#From_CIELAB_to_CIEXYZ\n * @param {object} triplet CIE LAB triplet as {l,a,b}.\n * @returns {object} CIE XYZ triplet as {x,y,z}.\n */\nexport function cielabToCiexyz(triplet) {\n  /**\n   * Apply the inverse lab function.\n   *\n   * @param {number} x The input value.\n   * @returns {number} The result\n   */\n  function invLabFunc(x) {\n    let res = null;\n    // delta = 6 / 29 = 0.206896552\n    if (x > 0.206896552) {\n      res = Math.pow(x, 3);\n    } else {\n      // 0.128418549 = 3 * delta^2\n      // 0.017712903 = 3 * delta^2 * (4 / 29)\n      res = 0.128418549 * x - 0.017712903;\n    }\n    return res;\n  }\n\n  const illuminant = d65;\n  const l0 = (triplet.l + 16) / 116;\n\n  return {\n    x: illuminant.x * invLabFunc(l0 + triplet.a / 500),\n    y: illuminant.y * invLabFunc(l0),\n    z: illuminant.z * invLabFunc(l0 - triplet.b / 200)\n  };\n}\n\n/**\n * Convert CIE XYZ to CIE LAB (standard illuminant D65, 2degree 1931).\n *\n * @see https://en.wikipedia.org/wiki/CIELAB_color_space#From_CIEXYZ_to_CIELAB\n * @param {object} triplet CIE XYZ triplet as {x,y,z}.\n * @returns {object} CIE LAB triplet as {l,a,b}.\n */\nexport function ciexyzToCielab(triplet) {\n  /**\n   * Apply the lab function.\n   *\n   * @param {number} x The input value.\n   * @returns {number} The result\n   */\n  function labFunc(x) {\n    let res = null;\n    // delta = 6 / 29 = 0.206896552\n    // delta^3 = 0.008856452\n    if (x > 0.008856452) {\n      res = Math.pow(x, 0.333333333);\n    } else {\n      // 7.787037037 = 1 / 3 * delta^2\n      // 0.137931034 = 4 / 29\n      res = 7.787037037 * x + 0.137931034;\n    }\n    return res;\n  }\n\n  const illuminant = d65;\n  const fy = labFunc(triplet.y / illuminant.y);\n\n  return {\n    l: 116 * fy - 16,\n    a: 500 * (labFunc(triplet.x / illuminant.x) - fy),\n    b: 200 * (fy - labFunc(triplet.z / illuminant.z))\n  };\n}\n\n/**\n * Convert CIE XYZ to sRGB.\n *\n * @see https://en.wikipedia.org/wiki/SRGB#From_CIE_XYZ_to_sRGB\n * @param {object} triplet CIE XYZ triplet as {x,y,z}.\n * @returns {object} sRGB triplet as {r,g,b}.\n */\nexport function ciexyzToSrgb(triplet) {\n  /**\n   * Apply the gamma function.\n   *\n   * @param {number} x The input value.\n   * @returns {number} The result\n   */\n  function gammaFunc(x) {\n    let res = null;\n    if (x <= 0.0031308) {\n      res = 12.92 * x;\n    } else {\n      // 0.416666667 = 1 / 2.4\n      res = 1.055 * Math.pow(x, 0.416666667) - 0.055;\n    }\n    // clip [0,1]\n    return Math.min(1, Math.max(0, res));\n  }\n\n  const x = triplet.x / 100;\n  const y = triplet.y / 100;\n  const z = triplet.z / 100;\n\n  return {\n    r: Math.round(255 * gammaFunc(3.2406 * x - 1.5372 * y - 0.4986 * z)),\n    g: Math.round(255 * gammaFunc(-0.9689 * x + 1.8758 * y + 0.0415 * z)),\n    b: Math.round(255 * gammaFunc(0.0557 * x - 0.2040 * y + 1.0570 * z))\n  };\n}\n\n/**\n * Convert sRGB to CIE XYZ.\n *\n * @see https://en.wikipedia.org/wiki/SRGB#From_sRGB_to_CIE_XYZ\n * @param {object} triplet sRGB triplet as {r,g,b}.\n * @returns {object} CIE XYZ triplet as {x,y,z}.\n */\nexport function srgbToCiexyz(triplet) {\n  /**\n   * Apply the inverse gamma function.\n   *\n   * @param {number} x The input value.\n   * @returns {number} The result\n   */\n  function invGammaFunc(x) {\n    let res = null;\n    if (x <= 0.04045) {\n      res = x / 12.92;\n    } else {\n      res = Math.pow((x + 0.055) / 1.055, 2.4);\n    }\n    return res;\n  }\n\n  const rl = invGammaFunc(triplet.r / 255);\n  const gl = invGammaFunc(triplet.g / 255);\n  const bl = invGammaFunc(triplet.b / 255);\n\n  return {\n    x: 100 * (0.4124 * rl + 0.3576 * gl + 0.1805 * bl),\n    y: 100 * (0.2126 * rl + 0.7152 * gl + 0.0722 * bl),\n    z: 100 * (0.0193 * rl + 0.1192 * gl + 0.9505 * bl)\n  };\n}\n\n/**\n * Convert CIE LAB to sRGB (standard illuminant D65).\n *\n * @param {object} triplet CIE LAB triplet as {l,a,b}.\n * @returns {object} sRGB triplet as {r,g,b}.\n */\nexport function cielabToSrgb(triplet) {\n  return ciexyzToSrgb(cielabToCiexyz(triplet));\n}\n\n/**\n * Convert sRGB to CIE LAB (standard illuminant D65).\n *\n * @param {object} triplet sRGB triplet as {r,g,b}.\n * @returns {object} CIE LAB triplet as {l,a,b}.\n */\nexport function srgbToCielab(triplet) {\n  return ciexyzToCielab(srgbToCiexyz(triplet));\n}\n\n/**\n * Get the hex code of a string colour for a colour used in pre dwv v0.17.\n *\n * @param {string} name The name of a colour.\n * @returns {string} The hex representing the colour.\n */\nexport function colourNameToHex(name) {\n  // default colours used in dwv version < 0.17\n  const dict = {\n    Yellow: '#ffff00',\n    Red: '#ff0000',\n    White: '#ffffff',\n    Green: '#008000',\n    Blue: '#0000ff',\n    Lime: '#00ff00',\n    Fuchsia: '#ff00ff',\n    Black: '#000000'\n  };\n  let res = '#ffff00';\n  if (typeof dict[name] !== 'undefined') {\n    res = dict[name];\n  }\n  return res;\n}\n","/**\n * Immutable 3D vector.\n */\nexport class Vector3D {\n\n  /**\n   * X coordinate.\n   *\n   * @type {number}\n   */\n  #x;\n\n  /**\n   * Y coordinate.\n   *\n   * @type {number}\n   */\n  #y;\n\n  /**\n   * Z coordinate.\n   *\n   * @type {number}\n   */\n  #z;\n\n  /**\n   * @param {number} x The X component of the vector.\n   * @param {number} y The Y component of the vector.\n   * @param {number} z The Z component of the vector.\n   */\n  constructor(x, y, z) {\n    this.#x = x;\n    this.#y = y;\n    this.#z = z;\n  }\n\n  /**\n   * Get the X component of the vector.\n   *\n   * @returns {number} The X component of the vector.\n   */\n  getX() {\n    return this.#x;\n  }\n\n  /**\n   * Get the Y component of the vector.\n   *\n   * @returns {number} The Y component of the vector.\n   */\n  getY() {\n    return this.#y;\n  }\n\n  /**\n   * Get the Z component of the vector.\n   *\n   * @returns {number} The Z component of the vector.\n   */\n  getZ() {\n    return this.#z;\n  }\n\n  /**\n   * Check for Vector3D equality.\n   *\n   * @param {Vector3D} rhs The other vector to compare to.\n   * @returns {boolean} True if both vectors are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getX() === rhs.getX() &&\n      this.getY() === rhs.getY() &&\n      this.getZ() === rhs.getZ();\n  }\n\n  /**\n   * Get a string representation of the Vector3D.\n   *\n   * @returns {string} The vector as a string.\n   */\n  toString() {\n    return '(' + this.getX() +\n      ', ' + this.getY() +\n      ', ' + this.getZ() + ')';\n  }\n\n  /**\n   * Get the norm of the vector.\n   *\n   * @returns {number} The norm.\n   */\n  norm() {\n    return Math.sqrt(\n      (this.getX() * this.getX()) +\n      (this.getY() * this.getY()) +\n      (this.getZ() * this.getZ())\n    );\n  }\n\n  /**\n   * Get the cross product with another Vector3D, ie the\n   * vector that is perpendicular to both a and b.\n   * If both vectors are parallel, the cross product is a zero vector.\n   *\n   * @see https://en.wikipedia.org/wiki/Cross_product\n   * @param {Vector3D} vector3D The input vector.\n   * @returns {Vector3D} The result vector.\n   */\n  crossProduct(vector3D) {\n    return new Vector3D(\n      (this.getY() * vector3D.getZ()) - (vector3D.getY() * this.getZ()),\n      (this.getZ() * vector3D.getX()) - (vector3D.getZ() * this.getX()),\n      (this.getX() * vector3D.getY()) - (vector3D.getX() * this.getY()));\n  }\n\n  /**\n   * Get the dot product with another Vector3D.\n   *\n   * @see https://en.wikipedia.org/wiki/Dot_product\n   * @param {Vector3D} vector3D The input vector.\n   * @returns {number} The dot product.\n   */\n  dotProduct(vector3D) {\n    return (this.getX() * vector3D.getX()) +\n      (this.getY() * vector3D.getY()) +\n      (this.getZ() * vector3D.getZ());\n  }\n\n} // Vector3D class","import {Vector3D} from './vector';\nimport {Point3D} from './point';\nimport {Index} from './index';\nimport {logger} from '../utils/logger';\n\n// Number.EPSILON is difference between 1 and the smallest\n// floating point number greater than 1\n// -> ~2e-16\n// BIG_EPSILON -> ~2e-12\nexport const BIG_EPSILON = Number.EPSILON * 1e4;\n// 'real world', for example when comparing positions\nexport const REAL_WORLD_EPSILON = 1e-4;\n\n/**\n * Check if two numbers are similar.\n *\n * @param {number} a The first number.\n * @param {number} b The second number.\n * @param {number} tol The comparison tolerance,\n *   default to Number.EPSILON.\n * @returns {boolean} True if similar.\n */\nexport function isSimilar(a, b, tol) {\n  if (typeof tol === 'undefined') {\n    tol = Number.EPSILON;\n  }\n  return Math.abs(a - b) < tol;\n}\n\n/**\n * Immutable 3x3 Matrix.\n */\nexport class Matrix33 {\n\n  /**\n   * Matrix values.\n   *\n   * @type {Array}\n   */\n  #values;\n\n  /**\n   * Matrix inverse, calculated at first ask\n   *\n   * @type {Matrix33}\n   */\n  #inverse;\n\n  /**\n   * @param {Array} values row-major ordered 9 values.\n   */\n  constructor(values) {\n    this.#values = values;\n  }\n\n  /**\n   * Get a value of the matrix.\n   *\n   * @param {number} row The row at wich to get the value.\n   * @param {number} col The column at wich to get the value.\n   * @returns {number} The value at the position.\n   */\n  get(row, col) {\n    return this.#values[row * 3 + col];\n  }\n\n  /**\n   * Get the inverse of this matrix.\n   *\n   * @returns {Matrix33|undefined} The inverse matrix or undefined\n   *   if the determinant is zero.\n   */\n  getInverse() {\n    if (typeof this.#inverse === 'undefined') {\n      this.#inverse = getMatrixInverse(this);\n    }\n    return this.#inverse;\n  }\n\n  /**\n   * Check for Matrix33 equality.\n   *\n   * @param {Matrix33} rhs The other matrix to compare to.\n   * @param {number} [p] A numeric expression for the precision to use in check\n   *   (ex: 0.001). Defaults to Number.EPSILON if not provided.\n   * @returns {boolean} True if both matrices are equal.\n   */\n  equals(rhs, p) {\n    // TODO: add type check\n    // check values\n    for (let i = 0; i < 3; ++i) {\n      for (let j = 0; j < 3; ++j) {\n        if (!isSimilar(this.get(i, j), rhs.get(i, j), p)) {\n          return false;\n        }\n      }\n    }\n    return true;\n  }\n\n  /**\n   * Get a string representation of the Matrix33.\n   *\n   * @returns {string} The matrix as a string.\n   */\n  toString() {\n    let str = '[';\n    for (let i = 0; i < 3; ++i) {\n      if (i !== 0) {\n        str += ', \\n ';\n      }\n      for (let j = 0; j < 3; ++j) {\n        if (j !== 0) {\n          str += ', ';\n        }\n        str += this.get(i, j);\n      }\n    }\n    str += ']';\n    return str;\n  }\n\n  /**\n   * Multiply this matrix by another.\n   *\n   * @param {Matrix33} rhs The matrix to multiply by.\n   * @returns {Matrix33} The product matrix.\n   */\n  multiply(rhs) {\n    const values = [];\n    for (let i = 0; i < 3; ++i) {\n      for (let j = 0; j < 3; ++j) {\n        let tmp = 0;\n        for (let k = 0; k < 3; ++k) {\n          tmp += this.get(i, k) * rhs.get(k, j);\n        }\n        values.push(tmp);\n      }\n    }\n    return new Matrix33(values);\n  }\n\n  /**\n   * Get the absolute value of this matrix.\n   *\n   * @returns {Matrix33} The result matrix.\n   */\n  getAbs() {\n    const values = [];\n    for (let i = 0; i < 3; ++i) {\n      for (let j = 0; j < 3; ++j) {\n        values.push(Math.abs(this.get(i, j)));\n      }\n    }\n    return new Matrix33(values);\n  }\n\n  /**\n   * Multiply this matrix by a 3D array.\n   *\n   * @param {Array} array3D The input 3D array.\n   * @returns {Array} The result 3D array.\n   */\n  multiplyArray3D(array3D) {\n    if (array3D.length !== 3) {\n      throw new Error('Cannot multiply 3x3 matrix with non 3D array: ' +\n        array3D.length);\n    }\n    const values = [];\n    for (let i = 0; i < 3; ++i) {\n      let tmp = 0;\n      for (let j = 0; j < 3; ++j) {\n        tmp += this.get(i, j) * array3D[j];\n      }\n      values.push(tmp);\n    }\n    return values;\n  }\n\n  /**\n   * Multiply this matrix by a 3D vector.\n   *\n   * @param {Vector3D} vector3D The input 3D vector.\n   * @returns {Vector3D} The result 3D vector.\n   */\n  multiplyVector3D(vector3D) {\n    const array3D = this.multiplyArray3D(\n      [vector3D.getX(), vector3D.getY(), vector3D.getZ()]\n    );\n    return new Vector3D(array3D[0], array3D[1], array3D[2]);\n  }\n\n  /**\n   * Multiply this matrix by a 3D point.\n   *\n   * @param {Point3D} point3D The input 3D point.\n   * @returns {Point3D} The result 3D point.\n   */\n  multiplyPoint3D(point3D) {\n    const array3D = this.multiplyArray3D(\n      [point3D.getX(), point3D.getY(), point3D.getZ()]\n    );\n    return new Point3D(array3D[0], array3D[1], array3D[2]);\n  }\n\n  /**\n   * Multiply this matrix by a 3D index.\n   *\n   * @param {Index} index3D The input 3D index.\n   * @returns {Index} The result 3D index.\n   */\n  multiplyIndex3D(index3D) {\n    const array3D = this.multiplyArray3D(index3D.getValues());\n    return new Index(array3D);\n  }\n\n  /**\n   * Get the index of the maximum in absolute value of a row.\n   *\n   * @param {number} row The row to get the maximum from.\n   * @returns {object} The {value,index} of the maximum.\n   */\n  getRowAbsMax(row) {\n    const values = [\n      Math.abs(this.get(row, 0)),\n      Math.abs(this.get(row, 1)),\n      Math.abs(this.get(row, 2))\n    ];\n    const absMax = Math.max.apply(null, values);\n    const index = values.indexOf(absMax);\n    return {\n      value: this.get(row, index),\n      index: index\n    };\n  }\n\n  /**\n   * Get the index of the maximum in absolute value of a column.\n   *\n   * @param {number} col The column to get the maximum from.\n   * @returns {object} The {value,index} of the maximum.\n   */\n  getColAbsMax(col) {\n    const values = [\n      Math.abs(this.get(0, col)),\n      Math.abs(this.get(1, col)),\n      Math.abs(this.get(2, col))\n    ];\n    const absMax = Math.max.apply(null, values);\n    const index = values.indexOf(absMax);\n    return {\n      value: this.get(index, col),\n      index: index\n    };\n  }\n\n  /**\n   * Get this matrix with only zero and +/- ones instead of the maximum,\n   *\n   * @returns {Matrix33} The simplified matrix.\n   */\n  asOneAndZeros() {\n    const res = [];\n    for (let j = 0; j < 3; ++j) {\n      const max = this.getRowAbsMax(j);\n      const sign = max.value > 0 ? 1 : -1;\n      for (let i = 0; i < 3; ++i) {\n        if (i === max.index) {\n          //res.push(1);\n          res.push(1 * sign);\n        } else {\n          res.push(0);\n        }\n      }\n    }\n    return new Matrix33(res);\n  }\n\n  /**\n   * Get the third column direction index of an orientation matrix.\n   *\n   * @returns {number} The index of the absolute maximum of the last column.\n   */\n  getThirdColMajorDirection() {\n    return this.getColAbsMax(2).index;\n  }\n\n} // Matrix33\n\n/**\n * Get the inverse of an input 3*3 matrix.\n *\n * @param {Matrix33} m The input matrix.\n * @returns {Matrix33|undefined} The inverse matrix or undefined\n *   if the determinant is zero.\n * @see https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3_%C3%97_3_matrices\n * @see https://github.com/willnode/N-Matrix-Programmer\n */\nfunction getMatrixInverse(m) {\n  const m00 = m.get(0, 0);\n  const m01 = m.get(0, 1);\n  const m02 = m.get(0, 2);\n  const m10 = m.get(1, 0);\n  const m11 = m.get(1, 1);\n  const m12 = m.get(1, 2);\n  const m20 = m.get(2, 0);\n  const m21 = m.get(2, 1);\n  const m22 = m.get(2, 2);\n\n  const a1212 = m11 * m22 - m12 * m21;\n  const a2012 = m12 * m20 - m10 * m22;\n  const a0112 = m10 * m21 - m11 * m20;\n\n  let det = m00 * a1212 + m01 * a2012 + m02 * a0112;\n  if (det === 0) {\n    logger.warn('Cannot invert 3*3 matrix with zero determinant.');\n    return undefined;\n  }\n  det = 1 / det;\n\n  const values = [\n    det * a1212,\n    det * (m02 * m21 - m01 * m22),\n    det * (m01 * m12 - m02 * m11),\n    det * a2012,\n    det * (m00 * m22 - m02 * m20),\n    det * (m02 * m10 - m00 * m12),\n    det * a0112,\n    det * (m01 * m20 - m00 * m21),\n    det * (m00 * m11 - m01 * m10)\n  ];\n\n  return new Matrix33(values);\n}\n\n/**\n * Create a 3x3 identity matrix.\n *\n * @returns {Matrix33} The identity matrix.\n */\nexport function getIdentityMat33() {\n  /* eslint-disable array-element-newline */\n  return new Matrix33([\n    1, 0, 0,\n    0, 1, 0,\n    0, 0, 1\n  ]);\n  /* eslint-enable array-element-newline */\n}\n\n/**\n * Check if a matrix is a 3x3 identity matrix.\n *\n * @param {Matrix33} mat33 The matrix to test.\n * @returns {boolean} True if identity.\n */\nexport function isIdentityMat33(mat33) {\n  return mat33.equals(getIdentityMat33());\n}\n\n/**\n * Create a 3x3 coronal (xzy) matrix.\n *\n * @returns {Matrix33} The coronal matrix.\n */\nexport function getCoronalMat33() {\n  /* eslint-disable array-element-newline */\n  return new Matrix33([\n    1, 0, 0,\n    0, 0, 1,\n    0, -1, 0\n  ]);\n  /* eslint-enable array-element-newline */\n}\n\n/**\n * Create a 3x3 sagittal (yzx) matrix.\n *\n * @returns {Matrix33} The sagittal matrix.\n */\nexport function getSagittalMat33() {\n  /* eslint-disable array-element-newline */\n  return new Matrix33([\n    0, 0, -1,\n    1, 0, 0,\n    0, -1, 0\n  ]);\n  /* eslint-enable array-element-newline */\n}\n\n/**\n * Get an orientation matrix from a name.\n *\n * @param {string} name The orientation name.\n * @returns {Matrix33} The orientation matrix.\n */\nexport function getMatrixFromName(name) {\n  let matrix = null;\n  if (name === 'axial') {\n    matrix = getIdentityMat33();\n  } else if (name === 'coronal') {\n    matrix = getCoronalMat33();\n  } else if (name === 'sagittal') {\n    matrix = getSagittalMat33();\n  }\n  return matrix;\n}\n","import {isSimilar} from './matrix';\nimport {Vector3D} from './vector';\n\n/**\n * Immutable 2D point.\n */\nexport class Point2D {\n\n  /**\n   * X position.\n   *\n   * @type {number}\n   */\n  #x;\n\n  /**\n   * Y position.\n   *\n   * @type {number}\n   */\n  #y;\n\n  /**\n   * @param {number} x The X coordinate for the point.\n   * @param {number} y The Y coordinate for the point.\n   */\n  constructor(x, y) {\n    this.#x = x;\n    this.#y = y;\n  }\n\n  /**\n   * Get the X position of the point.\n   *\n   * @returns {number} The X position of the point.\n   */\n  getX() {\n    return this.#x;\n  }\n\n  /**\n   * Get the Y position of the point.\n   *\n   * @returns {number} The Y position of the point.\n   */\n  getY() {\n    return this.#y;\n  }\n\n  /**\n   * Check for Point2D equality.\n   *\n   * @param {Point2D} rhs The other point to compare to.\n   * @returns {boolean} True if both points are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getX() === rhs.getX() &&\n      this.getY() === rhs.getY();\n  }\n\n  /**\n   * Get a string representation of the Point2D.\n   *\n   * @returns {string} The point as a string.\n   */\n  toString() {\n    return '(' + this.getX() + ', ' + this.getY() + ')';\n  }\n\n  /**\n   * Get the distance to another Point2D.\n   *\n   * @param {Point2D} point2D The input point.\n   * @returns {number} The distance to the input point.\n   */\n  getDistance(point2D) {\n    return Math.sqrt(\n      (this.getX() - point2D.getX()) * (this.getX() - point2D.getX()) +\n      (this.getY() - point2D.getY()) * (this.getY() - point2D.getY()));\n  }\n\n  /**\n   * Round a Point2D.\n   *\n   * @returns {Point2D} The rounded point.\n   */\n  getRound() {\n    return new Point2D(\n      Math.round(this.getX()),\n      Math.round(this.getY())\n    );\n  }\n\n} // Point2D class\n\n/**\n * Immutable 3D point.\n */\nexport class Point3D {\n\n  /**\n   * X position.\n   *\n   * @type {number}\n   */\n  #x;\n\n  /**\n   * Y position.\n   *\n   * @type {number}\n   */\n  #y;\n\n  /**\n   * Z position.\n   *\n   * @type {number}\n   */\n  #z;\n\n  /**\n   * @param {number} x The X coordinate for the point.\n   * @param {number} y The Y coordinate for the point.\n   * @param {number} z The Z coordinate for the point.\n   */\n  constructor(x, y, z) {\n    this.#x = x;\n    this.#y = y;\n    this.#z = z;\n  }\n\n  /**\n   * Get the X position of the point.\n   *\n   * @returns {number} The X position of the point.\n   */\n  getX() {\n    return this.#x;\n  }\n\n  /**\n   * Get the Y position of the point.\n   *\n   * @returns {number} The Y position of the point.\n   */\n  getY() {\n    return this.#y;\n  }\n\n  /**\n   * Get the Z position of the point.\n   *\n   * @returns {number} The Z position of the point.\n   */\n  getZ() {\n    return this.#z;\n  }\n\n\n  /**\n   * Check for Point3D equality.\n   *\n   * @param {Point3D} rhs The other point to compare to.\n   * @returns {boolean} True if both points are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getX() === rhs.getX() &&\n      this.getY() === rhs.getY() &&\n      this.getZ() === rhs.getZ();\n  }\n\n  /**\n   * Check for Point3D similarity.\n   *\n   * @param {Point3D} rhs The other point to compare to.\n   * @param {number} tol Optional comparison tolerance,\n   *   default to Number.EPSILON.\n   * @returns {boolean} True if both points are equal.\n   */\n  isSimilar(rhs, tol) {\n    return rhs !== null &&\n      isSimilar(this.getX(), rhs.getX(), tol) &&\n      isSimilar(this.getY(), rhs.getY(), tol) &&\n      isSimilar(this.getZ(), rhs.getZ(), tol);\n  }\n\n  /**\n   * Get a string representation of the Point3D.\n   *\n   * @returns {string} The point as a string.\n   */\n  toString() {\n    return '(' + this.getX() +\n      ', ' + this.getY() +\n      ', ' + this.getZ() + ')';\n  }\n\n  /**\n   * Get the distance to another Point3D.\n   *\n   * @param {Point3D} point3D The input point.\n   * @returns {number} Ths distance to the input point.\n   */\n  getDistance(point3D) {\n    return Math.sqrt(\n      (this.getX() - point3D.getX()) * (this.getX() - point3D.getX()) +\n      (this.getY() - point3D.getY()) * (this.getY() - point3D.getY()) +\n      (this.getZ() - point3D.getZ()) * (this.getZ() - point3D.getZ()));\n  }\n\n  /**\n   * Get the difference to another Point3D.\n   *\n   * @param {Point3D} point3D The input point.\n   * @returns {Vector3D} The 3D vector from the input point to this one.\n   */\n  minus(point3D) {\n    return new Vector3D(\n      (this.getX() - point3D.getX()),\n      (this.getY() - point3D.getY()),\n      (this.getZ() - point3D.getZ()));\n  }\n\n} // Point3D class\n\n/**\n * Get an array find callback for an equal input point.\n *\n * @param {Point3D} point The point to compare to.\n * @returns {Function} A function that compares, using `equals`,\n *   its input point to the one given as input to this function.\n */\nexport function getEqualPoint3DFunction(point) {\n  return function (element) {\n    return element.equals(point);\n  };\n}\n\n/**\n * Get an array find callback for a similar input point.\n *\n * @param {Point3D} point The point to compare to.\n * @param {number} tol The comparison tolerance\n *   default to Number.EPSILON.\n * @returns {Function} A function that compares, using `isSimilar`,\n *   its input point to the one given as input to this function.\n */\nexport function getSimilarPoint3DFunction(point, tol) {\n  return function (element) {\n    return element.isSimilar(point, tol);\n  };\n}\n\n/**\n * Immutable point.\n * Warning: the input array is NOT cloned, modifying it will\n *  modify the index values.\n */\nexport class Point {\n\n  /**\n   * Point values.\n   *\n   * @type {number[]}\n   */\n  #values;\n\n  /**\n   * @param {number[]} values The point values.\n   */\n  constructor(values) {\n    if (!values || typeof values === 'undefined') {\n      throw new Error('Cannot create point with no values.');\n    }\n    if (values.length === 0) {\n      throw new Error('Cannot create point with empty values.');\n    }\n    const valueCheck = function (val) {\n      return !isNaN(val);\n    };\n    if (!values.every(valueCheck)) {\n      throw new Error('Cannot create point with non number values.');\n    }\n    this.#values = values;\n  }\n\n  /**\n   * Get the index value at the given array index.\n   *\n   * @param {number} i The index to get.\n   * @returns {number} The value.\n   */\n  get(i) {\n    return this.#values[i];\n  }\n\n  /**\n   * Get the length of the index.\n   *\n   * @returns {number} The length.\n   */\n  length() {\n    return this.#values.length;\n  }\n\n  /**\n   * Get a string representation of the Index.\n   *\n   * @returns {string} The Index as a string.\n   */\n  toString() {\n    return '(' + this.#values.toString() + ')';\n  }\n\n  /**\n   * Get the values of this index.\n   *\n   * @returns {number[]} The array of values.\n   */\n  getValues() {\n    return this.#values.slice();\n  }\n\n  /**\n   * Check if the input point can be compared to this one.\n   *\n   * @param {Point} rhs The point to compare to.\n   * @returns {boolean} True if both points are comparable.\n   */\n  canCompare(rhs) {\n    // check input\n    if (!rhs) {\n      return false;\n    }\n    // check length\n    if (this.length() !== rhs.length()) {\n      return false;\n    }\n    // seems ok!\n    return true;\n  }\n\n  /**\n   * Check for Point equality.\n   *\n   * @param {Point} rhs The point to compare to.\n   * @returns {boolean} True if both points are equal.\n   */\n  equals(rhs) {\n    // check if can compare\n    if (!this.canCompare(rhs)) {\n      return false;\n    }\n    // check values\n    for (let i = 0, leni = this.length(); i < leni; ++i) {\n      if (this.get(i) !== rhs.get(i)) {\n        return false;\n      }\n    }\n    // seems ok!\n    return true;\n  }\n\n  /**\n   * Compare points and return different dimensions.\n   *\n   * @param {Point} rhs The point to compare to.\n   * @returns {number[]} The list of different dimensions.\n   */\n  compare(rhs) {\n    // check if can compare\n    if (!this.canCompare(rhs)) {\n      return null;\n    }\n    // check values\n    const diffDims = [];\n    for (let i = 0, leni = this.length(); i < leni; ++i) {\n      if (this.get(i) !== rhs.get(i)) {\n        diffDims.push(i);\n      }\n    }\n    return diffDims;\n  }\n\n  /**\n   * Get the 3D part of this point.\n   *\n   * @returns {Point3D} The Point3D.\n   */\n  get3D() {\n    return new Point3D(this.get(0), this.get(1), this.get(2));\n  }\n\n  /**\n   * Add another point to this one.\n   *\n   * @param {Point} rhs The point to add.\n   * @returns {Point} The point representing the sum of both points.\n   */\n  add(rhs) {\n    // check if can compare\n    if (!this.canCompare(rhs)) {\n      return null;\n    }\n    const values = [];\n    const values0 = this.getValues();\n    const values1 = rhs.getValues();\n    for (let i = 0; i < values0.length; ++i) {\n      values.push(values0[i] + values1[i]);\n    }\n    return new Point(values);\n  }\n\n  /**\n   * Merge this point with a Point3D to create a new point.\n   *\n   * @param {Point3D} rhs The Point3D to merge with.\n   * @returns {Point} The merge result.\n   */\n  mergeWith3D(rhs) {\n    const values = this.getValues();\n    values[0] = rhs.getX();\n    values[1] = rhs.getY();\n    values[2] = rhs.getZ();\n    return new Point(values);\n  }\n\n} // Point class\n","/* eslint-disable quote-props */\n/* eslint max-len:0 */\n\n/**\n * DICOM tag dictionary 2022a.\n * Generated using xml standard conversion from {@link https://github.com/ivmartel/dcmStdToJs} v0.1.0.\n * Conversion changes:\n * - (vr) 'See Note' -> 'NONE'\n * - (vr) 'OB or OW' -> 'ox'\n * - (vr) 'US or SS' -> 'xs'\n * - (vr) 'US or OW' -> 'xx'\n * - (vr) 'US or SS or OW' -> 'xs'\n * - added 'GenericGroupLength' element to each group\n * Local changes:\n * - tag numbers with 'xx' were replaced with '00', 'xxx' with '001' and\n *  'xxxx' with '0004'\n */\nexport const dictionary = {\n  '0000': {\n    '0000': ['UL', '1', 'CommandGroupLength'],\n    '0001': ['UL', '1', 'CommandLengthToEnd'],\n    '0002': ['UI', '1', 'AffectedSOPClassUID'],\n    '0003': ['UI', '1', 'RequestedSOPClassUID'],\n    '0010': ['SH', '1', 'CommandRecognitionCode'],\n    '0100': ['US', '1', 'CommandField'],\n    '0110': ['US', '1', 'MessageID'],\n    '0120': ['US', '1', 'MessageIDBeingRespondedTo'],\n    '0200': ['AE', '1', 'Initiator'],\n    '0300': ['AE', '1', 'Receiver'],\n    '0400': ['AE', '1', 'FindLocation'],\n    '0600': ['AE', '1', 'MoveDestination'],\n    '0700': ['US', '1', 'Priority'],\n    '0800': ['US', '1', 'CommandDataSetType'],\n    '0850': ['US', '1', 'NumberOfMatches'],\n    '0860': ['US', '1', 'ResponseSequenceNumber'],\n    '0900': ['US', '1', 'Status'],\n    '0901': ['AT', '1-n', 'OffendingElement'],\n    '0902': ['LO', '1', 'ErrorComment'],\n    '0903': ['US', '1', 'ErrorID'],\n    '1000': ['UI', '1', 'AffectedSOPInstanceUID'],\n    '1001': ['UI', '1', 'RequestedSOPInstanceUID'],\n    '1002': ['US', '1', 'EventTypeID'],\n    '1005': ['AT', '1-n', 'AttributeIdentifierList'],\n    '1008': ['US', '1', 'ActionTypeID'],\n    '1020': ['US', '1', 'NumberOfRemainingSuboperations'],\n    '1021': ['US', '1', 'NumberOfCompletedSuboperations'],\n    '1022': ['US', '1', 'NumberOfFailedSuboperations'],\n    '1023': ['US', '1', 'NumberOfWarningSuboperations'],\n    '1030': ['AE', '1', 'MoveOriginatorApplicationEntityTitle'],\n    '1031': ['US', '1', 'MoveOriginatorMessageID'],\n    '4000': ['LT', '1', 'DialogReceiver'],\n    '4010': ['LT', '1', 'TerminalType'],\n    '5010': ['SH', '1', 'MessageSetID'],\n    '5020': ['SH', '1', 'EndMessageID'],\n    '5110': ['LT', '1', 'DisplayFormat'],\n    '5120': ['LT', '1', 'PagePositionID'],\n    '5130': ['CS', '1', 'TextFormatID'],\n    '5140': ['CS', '1', 'NormalReverse'],\n    '5150': ['CS', '1', 'AddGrayScale'],\n    '5160': ['CS', '1', 'Borders'],\n    '5170': ['IS', '1', 'Copies'],\n    '5180': ['CS', '1', 'CommandMagnificationType'],\n    '5190': ['CS', '1', 'Erase'],\n    '51A0': ['CS', '1', 'Print'],\n    '51B0': ['US', '1-n', 'Overlays']\n  },\n  '0002': {\n    '0000': ['UL', '1', 'FileMetaInformationGroupLength'],\n    '0001': ['OB', '1', 'FileMetaInformationVersion'],\n    '0002': ['UI', '1', 'MediaStorageSOPClassUID'],\n    '0003': ['UI', '1', 'MediaStorageSOPInstanceUID'],\n    '0010': ['UI', '1', 'TransferSyntaxUID'],\n    '0012': ['UI', '1', 'ImplementationClassUID'],\n    '0013': ['SH', '1', 'ImplementationVersionName'],\n    '0016': ['AE', '1', 'SourceApplicationEntityTitle'],\n    '0017': ['AE', '1', 'SendingApplicationEntityTitle'],\n    '0018': ['AE', '1', 'ReceivingApplicationEntityTitle'],\n    '0026': ['UR', '1', 'SourcePresentationAddress'],\n    '0027': ['UR', '1', 'SendingPresentationAddress'],\n    '0028': ['UR', '1', 'ReceivingPresentationAddress'],\n    '0031': ['OB', '1', 'RTVMetaInformationVersion'],\n    '0032': ['UI', '1', 'RTVCommunicationSOPClassUID'],\n    '0033': ['UI', '1', 'RTVCommunicationSOPInstanceUID'],\n    '0035': ['OB', '1', 'RTVSourceIdentifier'],\n    '0036': ['OB', '1', 'RTVFlowIdentifier'],\n    '0037': ['UL', '1', 'RTVFlowRTPSamplingRate'],\n    '0038': ['FD', '1', 'RTVFlowActualFrameDuration'],\n    '0100': ['UI', '1', 'PrivateInformationCreatorUID'],\n    '0102': ['OB', '1', 'PrivateInformation']\n  },\n  '0004': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '1130': ['CS', '1', 'FileSetID'],\n    '1141': ['CS', '1-8', 'FileSetDescriptorFileID'],\n    '1142': ['CS', '1', 'SpecificCharacterSetOfFileSetDescriptorFile'],\n    '1200': ['UL', '1', 'OffsetOfTheFirstDirectoryRecordOfTheRootDirectoryEntity'],\n    '1202': ['UL', '1', 'OffsetOfTheLastDirectoryRecordOfTheRootDirectoryEntity'],\n    '1212': ['US', '1', 'FileSetConsistencyFlag'],\n    '1220': ['SQ', '1', 'DirectoryRecordSequence'],\n    '1400': ['UL', '1', 'OffsetOfTheNextDirectoryRecord'],\n    '1410': ['US', '1', 'RecordInUseFlag'],\n    '1420': ['UL', '1', 'OffsetOfReferencedLowerLevelDirectoryEntity'],\n    '1430': ['CS', '1', 'DirectoryRecordType'],\n    '1432': ['UI', '1', 'PrivateRecordUID'],\n    '1500': ['CS', '1-8', 'ReferencedFileID'],\n    '1504': ['UL', '1', 'MRDRDirectoryRecordOffset'],\n    '1510': ['UI', '1', 'ReferencedSOPClassUIDInFile'],\n    '1511': ['UI', '1', 'ReferencedSOPInstanceUIDInFile'],\n    '1512': ['UI', '1', 'ReferencedTransferSyntaxUIDInFile'],\n    '151A': ['UI', '1-n', 'ReferencedRelatedGeneralSOPClassUIDInFile'],\n    '1600': ['UL', '1', 'NumberOfReferences']\n  },\n  '0008': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['UL', '1', 'LengthToEnd'],\n    '0005': ['CS', '1-n', 'SpecificCharacterSet'],\n    '0006': ['SQ', '1', 'LanguageCodeSequence'],\n    '0008': ['CS', '2-n', 'ImageType'],\n    '0010': ['SH', '1', 'RecognitionCode'],\n    '0012': ['DA', '1', 'InstanceCreationDate'],\n    '0013': ['TM', '1', 'InstanceCreationTime'],\n    '0014': ['UI', '1', 'InstanceCreatorUID'],\n    '0015': ['DT', '1', 'InstanceCoercionDateTime'],\n    '0016': ['UI', '1', 'SOPClassUID'],\n    '0018': ['UI', '1', 'SOPInstanceUID'],\n    '001A': ['UI', '1-n', 'RelatedGeneralSOPClassUID'],\n    '001B': ['UI', '1', 'OriginalSpecializedSOPClassUID'],\n    '0020': ['DA', '1', 'StudyDate'],\n    '0021': ['DA', '1', 'SeriesDate'],\n    '0022': ['DA', '1', 'AcquisitionDate'],\n    '0023': ['DA', '1', 'ContentDate'],\n    '0024': ['DA', '1', 'OverlayDate'],\n    '0025': ['DA', '1', 'CurveDate'],\n    '002A': ['DT', '1', 'AcquisitionDateTime'],\n    '0030': ['TM', '1', 'StudyTime'],\n    '0031': ['TM', '1', 'SeriesTime'],\n    '0032': ['TM', '1', 'AcquisitionTime'],\n    '0033': ['TM', '1', 'ContentTime'],\n    '0034': ['TM', '1', 'OverlayTime'],\n    '0035': ['TM', '1', 'CurveTime'],\n    '0040': ['US', '1', 'DataSetType'],\n    '0041': ['LO', '1', 'DataSetSubtype'],\n    '0042': ['CS', '1', 'NuclearMedicineSeriesType'],\n    '0050': ['SH', '1', 'AccessionNumber'],\n    '0051': ['SQ', '1', 'IssuerOfAccessionNumberSequence'],\n    '0052': ['CS', '1', 'QueryRetrieveLevel'],\n    '0053': ['CS', '1', 'QueryRetrieveView'],\n    '0054': ['AE', '1-n', 'RetrieveAETitle'],\n    '0055': ['AE', '1', 'StationAETitle'],\n    '0056': ['CS', '1', 'InstanceAvailability'],\n    '0058': ['UI', '1-n', 'FailedSOPInstanceUIDList'],\n    '0060': ['CS', '1', 'Modality'],\n    '0061': ['CS', '1-n', 'ModalitiesInStudy'],\n    '0062': ['UI', '1-n', 'SOPClassesInStudy'],\n    '0063': ['SQ', '1', 'AnatomicRegionsInStudyCodeSequence'],\n    '0064': ['CS', '1', 'ConversionType'],\n    '0068': ['CS', '1', 'PresentationIntentType'],\n    '0070': ['LO', '1', 'Manufacturer'],\n    '0080': ['LO', '1', 'InstitutionName'],\n    '0081': ['ST', '1', 'InstitutionAddress'],\n    '0082': ['SQ', '1', 'InstitutionCodeSequence'],\n    '0090': ['PN', '1', 'ReferringPhysicianName'],\n    '0092': ['ST', '1', 'ReferringPhysicianAddress'],\n    '0094': ['SH', '1-n', 'ReferringPhysicianTelephoneNumbers'],\n    '0096': ['SQ', '1', 'ReferringPhysicianIdentificationSequence'],\n    '009C': ['PN', '1-n', 'ConsultingPhysicianName'],\n    '009D': ['SQ', '1', 'ConsultingPhysicianIdentificationSequence'],\n    '0100': ['SH', '1', 'CodeValue'],\n    '0101': ['LO', '1', 'ExtendedCodeValue'],\n    '0102': ['SH', '1', 'CodingSchemeDesignator'],\n    '0103': ['SH', '1', 'CodingSchemeVersion'],\n    '0104': ['LO', '1', 'CodeMeaning'],\n    '0105': ['CS', '1', 'MappingResource'],\n    '0106': ['DT', '1', 'ContextGroupVersion'],\n    '0107': ['DT', '1', 'ContextGroupLocalVersion'],\n    '0108': ['LT', '1', 'ExtendedCodeMeaning'],\n    '0109': ['SQ', '1', 'CodingSchemeResourcesSequence'],\n    '010A': ['CS', '1', 'CodingSchemeURLType'],\n    '010B': ['CS', '1', 'ContextGroupExtensionFlag'],\n    '010C': ['UI', '1', 'CodingSchemeUID'],\n    '010D': ['UI', '1', 'ContextGroupExtensionCreatorUID'],\n    '010E': ['UR', '1', 'CodingSchemeURL'],\n    '010F': ['CS', '1', 'ContextIdentifier'],\n    '0110': ['SQ', '1', 'CodingSchemeIdentificationSequence'],\n    '0112': ['LO', '1', 'CodingSchemeRegistry'],\n    '0114': ['ST', '1', 'CodingSchemeExternalID'],\n    '0115': ['ST', '1', 'CodingSchemeName'],\n    '0116': ['ST', '1', 'CodingSchemeResponsibleOrganization'],\n    '0117': ['UI', '1', 'ContextUID'],\n    '0118': ['UI', '1', 'MappingResourceUID'],\n    '0119': ['UC', '1', 'LongCodeValue'],\n    '0120': ['UR', '1', 'URNCodeValue'],\n    '0121': ['SQ', '1', 'EquivalentCodeSequence'],\n    '0122': ['LO', '1', 'MappingResourceName'],\n    '0123': ['SQ', '1', 'ContextGroupIdentificationSequence'],\n    '0124': ['SQ', '1', 'MappingResourceIdentificationSequence'],\n    '0201': ['SH', '1', 'TimezoneOffsetFromUTC'],\n    '0202': ['', '', ''],\n    '0220': ['SQ', '1', 'ResponsibleGroupCodeSequence'],\n    '0221': ['CS', '1', 'EquipmentModality'],\n    '0222': ['LO', '1', 'ManufacturerRelatedModelGroup'],\n    '0300': ['SQ', '1', 'PrivateDataElementCharacteristicsSequence'],\n    '0301': ['US', '1', 'PrivateGroupReference'],\n    '0302': ['LO', '1', 'PrivateCreatorReference'],\n    '0303': ['CS', '1', 'BlockIdentifyingInformationStatus'],\n    '0304': ['US', '1-n', 'NonidentifyingPrivateElements'],\n    '0305': ['SQ', '1', 'DeidentificationActionSequence'],\n    '0306': ['US', '1-n', 'IdentifyingPrivateElements'],\n    '0307': ['CS', '1', 'DeidentificationAction'],\n    '0308': ['US', '1', 'PrivateDataElement'],\n    '0309': ['UL', '1-3', 'PrivateDataElementValueMultiplicity'],\n    '030A': ['CS', '1', 'PrivateDataElementValueRepresentation'],\n    '030B': ['UL', '1-2', 'PrivateDataElementNumberOfItems'],\n    '030C': ['UC', '1', 'PrivateDataElementName'],\n    '030D': ['UC', '1', 'PrivateDataElementKeyword'],\n    '030E': ['UT', '1', 'PrivateDataElementDescription'],\n    '030F': ['UT', '1', 'PrivateDataElementEncoding'],\n    '0310': ['SQ', '1', 'PrivateDataElementDefinitionSequence'],\n    '1000': ['AE', '1', 'NetworkID'],\n    '1010': ['SH', '1', 'StationName'],\n    '1030': ['LO', '1', 'StudyDescription'],\n    '1032': ['SQ', '1', 'ProcedureCodeSequence'],\n    '103E': ['LO', '1', 'SeriesDescription'],\n    '103F': ['SQ', '1', 'SeriesDescriptionCodeSequence'],\n    '1040': ['LO', '1', 'InstitutionalDepartmentName'],\n    '1041': ['SQ', '1', 'InstitutionalDepartmentTypeCodeSequence'],\n    '1048': ['PN', '1-n', 'PhysiciansOfRecord'],\n    '1049': ['SQ', '1', 'PhysiciansOfRecordIdentificationSequence'],\n    '1050': ['PN', '1-n', 'PerformingPhysicianName'],\n    '1052': ['SQ', '1', 'PerformingPhysicianIdentificationSequence'],\n    '1060': ['PN', '1-n', 'NameOfPhysiciansReadingStudy'],\n    '1062': ['SQ', '1', 'PhysiciansReadingStudyIdentificationSequence'],\n    '1070': ['PN', '1-n', 'OperatorsName'],\n    '1072': ['SQ', '1', 'OperatorIdentificationSequence'],\n    '1080': ['LO', '1-n', 'AdmittingDiagnosesDescription'],\n    '1084': ['SQ', '1', 'AdmittingDiagnosesCodeSequence'],\n    '1090': ['LO', '1', 'ManufacturerModelName'],\n    '1100': ['SQ', '1', 'ReferencedResultsSequence'],\n    '1110': ['SQ', '1', 'ReferencedStudySequence'],\n    '1111': ['SQ', '1', 'ReferencedPerformedProcedureStepSequence'],\n    '1115': ['SQ', '1', 'ReferencedSeriesSequence'],\n    '1120': ['SQ', '1', 'ReferencedPatientSequence'],\n    '1125': ['SQ', '1', 'ReferencedVisitSequence'],\n    '1130': ['SQ', '1', 'ReferencedOverlaySequence'],\n    '1134': ['SQ', '1', 'ReferencedStereometricInstanceSequence'],\n    '113A': ['SQ', '1', 'ReferencedWaveformSequence'],\n    '1140': ['SQ', '1', 'ReferencedImageSequence'],\n    '1145': ['SQ', '1', 'ReferencedCurveSequence'],\n    '114A': ['SQ', '1', 'ReferencedInstanceSequence'],\n    '114B': ['SQ', '1', 'ReferencedRealWorldValueMappingInstanceSequence'],\n    '1150': ['UI', '1', 'ReferencedSOPClassUID'],\n    '1155': ['UI', '1', 'ReferencedSOPInstanceUID'],\n    '1156': ['SQ', '1', 'DefinitionSourceSequence'],\n    '115A': ['UI', '1-n', 'SOPClassesSupported'],\n    '1160': ['IS', '1-n', 'ReferencedFrameNumber'],\n    '1161': ['UL', '1-n', 'SimpleFrameList'],\n    '1162': ['UL', '3-3n', 'CalculatedFrameList'],\n    '1163': ['FD', '2', 'TimeRange'],\n    '1164': ['SQ', '1', 'FrameExtractionSequence'],\n    '1167': ['UI', '1', 'MultiFrameSourceSOPInstanceUID'],\n    '1190': ['UR', '1', 'RetrieveURL'],\n    '1195': ['UI', '1', 'TransactionUID'],\n    '1196': ['US', '1', 'WarningReason'],\n    '1197': ['US', '1', 'FailureReason'],\n    '1198': ['SQ', '1', 'FailedSOPSequence'],\n    '1199': ['SQ', '1', 'ReferencedSOPSequence'],\n    '119A': ['SQ', '1', 'OtherFailuresSequence'],\n    '1200': ['SQ', '1', 'StudiesContainingOtherReferencedInstancesSequence'],\n    '1250': ['SQ', '1', 'RelatedSeriesSequence'],\n    '2110': ['CS', '1', 'LossyImageCompressionRetired'],\n    '2111': ['ST', '1', 'DerivationDescription'],\n    '2112': ['SQ', '1', 'SourceImageSequence'],\n    '2120': ['SH', '1', 'StageName'],\n    '2122': ['IS', '1', 'StageNumber'],\n    '2124': ['IS', '1', 'NumberOfStages'],\n    '2127': ['SH', '1', 'ViewName'],\n    '2128': ['IS', '1', 'ViewNumber'],\n    '2129': ['IS', '1', 'NumberOfEventTimers'],\n    '212A': ['IS', '1', 'NumberOfViewsInStage'],\n    '2130': ['DS', '1-n', 'EventElapsedTimes'],\n    '2132': ['LO', '1-n', 'EventTimerNames'],\n    '2133': ['SQ', '1', 'EventTimerSequence'],\n    '2134': ['FD', '1', 'EventTimeOffset'],\n    '2135': ['SQ', '1', 'EventCodeSequence'],\n    '2142': ['IS', '1', 'StartTrim'],\n    '2143': ['IS', '1', 'StopTrim'],\n    '2144': ['IS', '1', 'RecommendedDisplayFrameRate'],\n    '2200': ['CS', '1', 'TransducerPosition'],\n    '2204': ['CS', '1', 'TransducerOrientation'],\n    '2208': ['CS', '1', 'AnatomicStructure'],\n    '2218': ['SQ', '1', 'AnatomicRegionSequence'],\n    '2220': ['SQ', '1', 'AnatomicRegionModifierSequence'],\n    '2228': ['SQ', '1', 'PrimaryAnatomicStructureSequence'],\n    '2229': ['SQ', '1', 'AnatomicStructureSpaceOrRegionSequence'],\n    '2230': ['SQ', '1', 'PrimaryAnatomicStructureModifierSequence'],\n    '2240': ['SQ', '1', 'TransducerPositionSequence'],\n    '2242': ['SQ', '1', 'TransducerPositionModifierSequence'],\n    '2244': ['SQ', '1', 'TransducerOrientationSequence'],\n    '2246': ['SQ', '1', 'TransducerOrientationModifierSequence'],\n    '2251': ['SQ', '1', 'AnatomicStructureSpaceOrRegionCodeSequenceTrial'],\n    '2253': ['SQ', '1', 'AnatomicPortalOfEntranceCodeSequenceTrial'],\n    '2255': ['SQ', '1', 'AnatomicApproachDirectionCodeSequenceTrial'],\n    '2256': ['ST', '1', 'AnatomicPerspectiveDescriptionTrial'],\n    '2257': ['SQ', '1', 'AnatomicPerspectiveCodeSequenceTrial'],\n    '2258': ['ST', '1', 'AnatomicLocationOfExaminingInstrumentDescriptionTrial'],\n    '2259': ['SQ', '1', 'AnatomicLocationOfExaminingInstrumentCodeSequenceTrial'],\n    '225A': ['SQ', '1', 'AnatomicStructureSpaceOrRegionModifierCodeSequenceTrial'],\n    '225C': ['SQ', '1', 'OnAxisBackgroundAnatomicStructureCodeSequenceTrial'],\n    '3001': ['SQ', '1', 'AlternateRepresentationSequence'],\n    '3002': ['UI', '1-n', 'AvailableTransferSyntaxUID'],\n    '3010': ['UI', '1-n', 'IrradiationEventUID'],\n    '3011': ['SQ', '1', 'SourceIrradiationEventSequence'],\n    '3012': ['UI', '1', 'RadiopharmaceuticalAdministrationEventUID'],\n    '4000': ['LT', '1', 'IdentifyingComments'],\n    '9007': ['CS', '4', 'FrameType'],\n    '9092': ['SQ', '1', 'ReferencedImageEvidenceSequence'],\n    '9121': ['SQ', '1', 'ReferencedRawDataSequence'],\n    '9123': ['UI', '1', 'CreatorVersionUID'],\n    '9124': ['SQ', '1', 'DerivationImageSequence'],\n    '9154': ['SQ', '1', 'SourceImageEvidenceSequence'],\n    '9205': ['CS', '1', 'PixelPresentation'],\n    '9206': ['CS', '1', 'VolumetricProperties'],\n    '9207': ['CS', '1', 'VolumeBasedCalculationTechnique'],\n    '9208': ['CS', '1', 'ComplexImageComponent'],\n    '9209': ['CS', '1', 'AcquisitionContrast'],\n    '9215': ['SQ', '1', 'DerivationCodeSequence'],\n    '9237': ['SQ', '1', 'ReferencedPresentationStateSequence'],\n    '9410': ['SQ', '1', 'ReferencedOtherPlaneSequence'],\n    '9458': ['SQ', '1', 'FrameDisplaySequence'],\n    '9459': ['FL', '1', 'RecommendedDisplayFrameRateInFloat'],\n    '9460': ['CS', '1', 'SkipFrameRangeFlag']\n  },\n  '0010': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['PN', '1', 'PatientName'],\n    '0020': ['LO', '1', 'PatientID'],\n    '0021': ['LO', '1', 'IssuerOfPatientID'],\n    '0022': ['CS', '1', 'TypeOfPatientID'],\n    '0024': ['SQ', '1', 'IssuerOfPatientIDQualifiersSequence'],\n    '0026': ['SQ', '1', 'SourcePatientGroupIdentificationSequence'],\n    '0027': ['SQ', '1', 'GroupOfPatientsIdentificationSequence'],\n    '0028': ['US', '3', 'SubjectRelativePositionInImage'],\n    '0030': ['DA', '1', 'PatientBirthDate'],\n    '0032': ['TM', '1', 'PatientBirthTime'],\n    '0033': ['LO', '1', 'PatientBirthDateInAlternativeCalendar'],\n    '0034': ['LO', '1', 'PatientDeathDateInAlternativeCalendar'],\n    '0035': ['CS', '1', 'PatientAlternativeCalendar'],\n    '0040': ['CS', '1', 'PatientSex'],\n    '0050': ['SQ', '1', 'PatientInsurancePlanCodeSequence'],\n    '0101': ['SQ', '1', 'PatientPrimaryLanguageCodeSequence'],\n    '0102': ['SQ', '1', 'PatientPrimaryLanguageModifierCodeSequence'],\n    '0200': ['CS', '1', 'QualityControlSubject'],\n    '0201': ['SQ', '1', 'QualityControlSubjectTypeCodeSequence'],\n    '0212': ['UC', '1', 'StrainDescription'],\n    '0213': ['LO', '1', 'StrainNomenclature'],\n    '0214': ['LO', '1', 'StrainStockNumber'],\n    '0215': ['SQ', '1', 'StrainSourceRegistryCodeSequence'],\n    '0216': ['SQ', '1', 'StrainStockSequence'],\n    '0217': ['LO', '1', 'StrainSource'],\n    '0218': ['UT', '1', 'StrainAdditionalInformation'],\n    '0219': ['SQ', '1', 'StrainCodeSequence'],\n    '0221': ['SQ', '1', 'GeneticModificationsSequence'],\n    '0222': ['UC', '1', 'GeneticModificationsDescription'],\n    '0223': ['LO', '1', 'GeneticModificationsNomenclature'],\n    '0229': ['SQ', '1', 'GeneticModificationsCodeSequence'],\n    '1000': ['LO', '1-n', 'OtherPatientIDs'],\n    '1001': ['PN', '1-n', 'OtherPatientNames'],\n    '1002': ['SQ', '1', 'OtherPatientIDsSequence'],\n    '1005': ['PN', '1', 'PatientBirthName'],\n    '1010': ['AS', '1', 'PatientAge'],\n    '1020': ['DS', '1', 'PatientSize'],\n    '1021': ['SQ', '1', 'PatientSizeCodeSequence'],\n    '1022': ['DS', '1', 'PatientBodyMassIndex'],\n    '1023': ['DS', '1', 'MeasuredAPDimension'],\n    '1024': ['DS', '1', 'MeasuredLateralDimension'],\n    '1030': ['DS', '1', 'PatientWeight'],\n    '1040': ['LO', '1', 'PatientAddress'],\n    '1050': ['LO', '1-n', 'InsurancePlanIdentification'],\n    '1060': ['PN', '1', 'PatientMotherBirthName'],\n    '1080': ['LO', '1', 'MilitaryRank'],\n    '1081': ['LO', '1', 'BranchOfService'],\n    '1090': ['LO', '1', 'MedicalRecordLocator'],\n    '1100': ['SQ', '1', 'ReferencedPatientPhotoSequence'],\n    '2000': ['LO', '1-n', 'MedicalAlerts'],\n    '2110': ['LO', '1-n', 'Allergies'],\n    '2150': ['LO', '1', 'CountryOfResidence'],\n    '2152': ['LO', '1', 'RegionOfResidence'],\n    '2154': ['SH', '1-n', 'PatientTelephoneNumbers'],\n    '2155': ['LT', '1', 'PatientTelecomInformation'],\n    '2160': ['SH', '1', 'EthnicGroup'],\n    '2180': ['SH', '1', 'Occupation'],\n    '21A0': ['CS', '1', 'SmokingStatus'],\n    '21B0': ['LT', '1', 'AdditionalPatientHistory'],\n    '21C0': ['US', '1', 'PregnancyStatus'],\n    '21D0': ['DA', '1', 'LastMenstrualDate'],\n    '21F0': ['LO', '1', 'PatientReligiousPreference'],\n    '2201': ['LO', '1', 'PatientSpeciesDescription'],\n    '2202': ['SQ', '1', 'PatientSpeciesCodeSequence'],\n    '2203': ['CS', '1', 'PatientSexNeutered'],\n    '2210': ['CS', '1', 'AnatomicalOrientationType'],\n    '2292': ['LO', '1', 'PatientBreedDescription'],\n    '2293': ['SQ', '1', 'PatientBreedCodeSequence'],\n    '2294': ['SQ', '1', 'BreedRegistrationSequence'],\n    '2295': ['LO', '1', 'BreedRegistrationNumber'],\n    '2296': ['SQ', '1', 'BreedRegistryCodeSequence'],\n    '2297': ['PN', '1', 'ResponsiblePerson'],\n    '2298': ['CS', '1', 'ResponsiblePersonRole'],\n    '2299': ['LO', '1', 'ResponsibleOrganization'],\n    '4000': ['LT', '1', 'PatientComments'],\n    '9431': ['FL', '1', 'ExaminedBodyThickness']\n  },\n  '0012': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['LO', '1', 'ClinicalTrialSponsorName'],\n    '0020': ['LO', '1', 'ClinicalTrialProtocolID'],\n    '0021': ['LO', '1', 'ClinicalTrialProtocolName'],\n    '0030': ['LO', '1', 'ClinicalTrialSiteID'],\n    '0031': ['LO', '1', 'ClinicalTrialSiteName'],\n    '0040': ['LO', '1', 'ClinicalTrialSubjectID'],\n    '0042': ['LO', '1', 'ClinicalTrialSubjectReadingID'],\n    '0050': ['LO', '1', 'ClinicalTrialTimePointID'],\n    '0051': ['ST', '1', 'ClinicalTrialTimePointDescription'],\n    '0052': ['FD', '1', 'LongitudinalTemporalOffsetFromEvent'],\n    '0053': ['CS', '1', 'LongitudinalTemporalEventType'],\n    '0060': ['LO', '1', 'ClinicalTrialCoordinatingCenterName'],\n    '0062': ['CS', '1', 'PatientIdentityRemoved'],\n    '0063': ['LO', '1-n', 'DeidentificationMethod'],\n    '0064': ['SQ', '1', 'DeidentificationMethodCodeSequence'],\n    '0071': ['LO', '1', 'ClinicalTrialSeriesID'],\n    '0072': ['LO', '1', 'ClinicalTrialSeriesDescription'],\n    '0081': ['LO', '1', 'ClinicalTrialProtocolEthicsCommitteeName'],\n    '0082': ['LO', '1', 'ClinicalTrialProtocolEthicsCommitteeApprovalNumber'],\n    '0083': ['SQ', '1', 'ConsentForClinicalTrialUseSequence'],\n    '0084': ['CS', '1', 'DistributionType'],\n    '0085': ['CS', '1', 'ConsentForDistributionFlag'],\n    '0086': ['DA', '1', 'EthicsCommitteeApprovalEffectivenessStartDate'],\n    '0087': ['DA', '1', 'EthicsCommitteeApprovalEffectivenessEndDate']\n  },\n  '0014': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0023': ['ST', '1', 'CADFileFormat'],\n    '0024': ['ST', '1', 'ComponentReferenceSystem'],\n    '0025': ['ST', '1', 'ComponentManufacturingProcedure'],\n    '0028': ['ST', '1', 'ComponentManufacturer'],\n    '0030': ['DS', '1-n', 'MaterialThickness'],\n    '0032': ['DS', '1-n', 'MaterialPipeDiameter'],\n    '0034': ['DS', '1-n', 'MaterialIsolationDiameter'],\n    '0042': ['ST', '1', 'MaterialGrade'],\n    '0044': ['ST', '1', 'MaterialPropertiesDescription'],\n    '0045': ['ST', '1', 'MaterialPropertiesFileFormatRetired'],\n    '0046': ['LT', '1', 'MaterialNotes'],\n    '0050': ['CS', '1', 'ComponentShape'],\n    '0052': ['CS', '1', 'CurvatureType'],\n    '0054': ['DS', '1', 'OuterDiameter'],\n    '0056': ['DS', '1', 'InnerDiameter'],\n    '0100': ['LO', '1-n', 'ComponentWelderIDs'],\n    '0101': ['CS', '1', 'SecondaryApprovalStatus'],\n    '0102': ['DA', '1', 'SecondaryReviewDate'],\n    '0103': ['TM', '1', 'SecondaryReviewTime'],\n    '0104': ['PN', '1', 'SecondaryReviewerName'],\n    '0105': ['ST', '1', 'RepairID'],\n    '0106': ['SQ', '1', 'MultipleComponentApprovalSequence'],\n    '0107': ['CS', '1-n', 'OtherApprovalStatus'],\n    '0108': ['CS', '1-n', 'OtherSecondaryApprovalStatus'],\n    '1010': ['ST', '1', 'ActualEnvironmentalConditions'],\n    '1020': ['DA', '1', 'ExpiryDate'],\n    '1040': ['ST', '1', 'EnvironmentalConditions'],\n    '2002': ['SQ', '1', 'EvaluatorSequence'],\n    '2004': ['IS', '1', 'EvaluatorNumber'],\n    '2006': ['PN', '1', 'EvaluatorName'],\n    '2008': ['IS', '1', 'EvaluationAttempt'],\n    '2012': ['SQ', '1', 'IndicationSequence'],\n    '2014': ['IS', '1', 'IndicationNumber'],\n    '2016': ['SH', '1', 'IndicationLabel'],\n    '2018': ['ST', '1', 'IndicationDescription'],\n    '201A': ['CS', '1-n', 'IndicationType'],\n    '201C': ['CS', '1', 'IndicationDisposition'],\n    '201E': ['SQ', '1', 'IndicationROISequence'],\n    '2030': ['SQ', '1', 'IndicationPhysicalPropertySequence'],\n    '2032': ['SH', '1', 'PropertyLabel'],\n    '2202': ['IS', '1', 'CoordinateSystemNumberOfAxes'],\n    '2204': ['SQ', '1', 'CoordinateSystemAxesSequence'],\n    '2206': ['ST', '1', 'CoordinateSystemAxisDescription'],\n    '2208': ['CS', '1', 'CoordinateSystemDataSetMapping'],\n    '220A': ['IS', '1', 'CoordinateSystemAxisNumber'],\n    '220C': ['CS', '1', 'CoordinateSystemAxisType'],\n    '220E': ['CS', '1', 'CoordinateSystemAxisUnits'],\n    '2210': ['OB', '1', 'CoordinateSystemAxisValues'],\n    '2220': ['SQ', '1', 'CoordinateSystemTransformSequence'],\n    '2222': ['ST', '1', 'TransformDescription'],\n    '2224': ['IS', '1', 'TransformNumberOfAxes'],\n    '2226': ['IS', '1-n', 'TransformOrderOfAxes'],\n    '2228': ['CS', '1', 'TransformedAxisUnits'],\n    '222A': ['DS', '1-n', 'CoordinateSystemTransformRotationAndScaleMatrix'],\n    '222C': ['DS', '1-n', 'CoordinateSystemTransformTranslationMatrix'],\n    '3011': ['DS', '1', 'InternalDetectorFrameTime'],\n    '3012': ['DS', '1', 'NumberOfFramesIntegrated'],\n    '3020': ['SQ', '1', 'DetectorTemperatureSequence'],\n    '3022': ['ST', '1', 'SensorName'],\n    '3024': ['DS', '1', 'HorizontalOffsetOfSensor'],\n    '3026': ['DS', '1', 'VerticalOffsetOfSensor'],\n    '3028': ['DS', '1', 'SensorTemperature'],\n    '3040': ['SQ', '1', 'DarkCurrentSequence'],\n    '3050': ['ox', '1', 'DarkCurrentCounts'],\n    '3060': ['SQ', '1', 'GainCorrectionReferenceSequence'],\n    '3070': ['ox', '1', 'AirCounts'],\n    '3071': ['DS', '1', 'KVUsedInGainCalibration'],\n    '3072': ['DS', '1', 'MAUsedInGainCalibration'],\n    '3073': ['DS', '1', 'NumberOfFramesUsedForIntegration'],\n    '3074': ['LO', '1', 'FilterMaterialUsedInGainCalibration'],\n    '3075': ['DS', '1', 'FilterThicknessUsedInGainCalibration'],\n    '3076': ['DA', '1', 'DateOfGainCalibration'],\n    '3077': ['TM', '1', 'TimeOfGainCalibration'],\n    '3080': ['OB', '1', 'BadPixelImage'],\n    '3099': ['LT', '1', 'CalibrationNotes'],\n    '3100': ['LT', '1', 'LinearityCorrectionTechnique'],\n    '3101': ['LT', '1', 'BeamHardeningCorrectionTechnique'],\n    '4002': ['SQ', '1', 'PulserEquipmentSequence'],\n    '4004': ['CS', '1', 'PulserType'],\n    '4006': ['LT', '1', 'PulserNotes'],\n    '4008': ['SQ', '1', 'ReceiverEquipmentSequence'],\n    '400A': ['CS', '1', 'AmplifierType'],\n    '400C': ['LT', '1', 'ReceiverNotes'],\n    '400E': ['SQ', '1', 'PreAmplifierEquipmentSequence'],\n    '400F': ['LT', '1', 'PreAmplifierNotes'],\n    '4010': ['SQ', '1', 'TransmitTransducerSequence'],\n    '4011': ['SQ', '1', 'ReceiveTransducerSequence'],\n    '4012': ['US', '1', 'NumberOfElements'],\n    '4013': ['CS', '1', 'ElementShape'],\n    '4014': ['DS', '1', 'ElementDimensionA'],\n    '4015': ['DS', '1', 'ElementDimensionB'],\n    '4016': ['DS', '1', 'ElementPitchA'],\n    '4017': ['DS', '1', 'MeasuredBeamDimensionA'],\n    '4018': ['DS', '1', 'MeasuredBeamDimensionB'],\n    '4019': ['DS', '1', 'LocationOfMeasuredBeamDiameter'],\n    '401A': ['DS', '1', 'NominalFrequency'],\n    '401B': ['DS', '1', 'MeasuredCenterFrequency'],\n    '401C': ['DS', '1', 'MeasuredBandwidth'],\n    '401D': ['DS', '1', 'ElementPitchB'],\n    '4020': ['SQ', '1', 'PulserSettingsSequence'],\n    '4022': ['DS', '1', 'PulseWidth'],\n    '4024': ['DS', '1', 'ExcitationFrequency'],\n    '4026': ['CS', '1', 'ModulationType'],\n    '4028': ['DS', '1', 'Damping'],\n    '4030': ['SQ', '1', 'ReceiverSettingsSequence'],\n    '4031': ['DS', '1', 'AcquiredSoundpathLength'],\n    '4032': ['CS', '1', 'AcquisitionCompressionType'],\n    '4033': ['IS', '1', 'AcquisitionSampleSize'],\n    '4034': ['DS', '1', 'RectifierSmoothing'],\n    '4035': ['SQ', '1', 'DACSequence'],\n    '4036': ['CS', '1', 'DACType'],\n    '4038': ['DS', '1-n', 'DACGainPoints'],\n    '403A': ['DS', '1-n', 'DACTimePoints'],\n    '403C': ['DS', '1-n', 'DACAmplitude'],\n    '4040': ['SQ', '1', 'PreAmplifierSettingsSequence'],\n    '4050': ['SQ', '1', 'TransmitTransducerSettingsSequence'],\n    '4051': ['SQ', '1', 'ReceiveTransducerSettingsSequence'],\n    '4052': ['DS', '1', 'IncidentAngle'],\n    '4054': ['ST', '1', 'CouplingTechnique'],\n    '4056': ['ST', '1', 'CouplingMedium'],\n    '4057': ['DS', '1', 'CouplingVelocity'],\n    '4058': ['DS', '1', 'ProbeCenterLocationX'],\n    '4059': ['DS', '1', 'ProbeCenterLocationZ'],\n    '405A': ['DS', '1', 'SoundPathLength'],\n    '405C': ['ST', '1', 'DelayLawIdentifier'],\n    '4060': ['SQ', '1', 'GateSettingsSequence'],\n    '4062': ['DS', '1', 'GateThreshold'],\n    '4064': ['DS', '1', 'VelocityOfSound'],\n    '4070': ['SQ', '1', 'CalibrationSettingsSequence'],\n    '4072': ['ST', '1', 'CalibrationProcedure'],\n    '4074': ['SH', '1', 'ProcedureVersion'],\n    '4076': ['DA', '1', 'ProcedureCreationDate'],\n    '4078': ['DA', '1', 'ProcedureExpirationDate'],\n    '407A': ['DA', '1', 'ProcedureLastModifiedDate'],\n    '407C': ['TM', '1-n', 'CalibrationTime'],\n    '407E': ['DA', '1-n', 'CalibrationDate'],\n    '4080': ['SQ', '1', 'ProbeDriveEquipmentSequence'],\n    '4081': ['CS', '1', 'DriveType'],\n    '4082': ['LT', '1', 'ProbeDriveNotes'],\n    '4083': ['SQ', '1', 'DriveProbeSequence'],\n    '4084': ['DS', '1', 'ProbeInductance'],\n    '4085': ['DS', '1', 'ProbeResistance'],\n    '4086': ['SQ', '1', 'ReceiveProbeSequence'],\n    '4087': ['SQ', '1', 'ProbeDriveSettingsSequence'],\n    '4088': ['DS', '1', 'BridgeResistors'],\n    '4089': ['DS', '1', 'ProbeOrientationAngle'],\n    '408B': ['DS', '1', 'UserSelectedGainY'],\n    '408C': ['DS', '1', 'UserSelectedPhase'],\n    '408D': ['DS', '1', 'UserSelectedOffsetX'],\n    '408E': ['DS', '1', 'UserSelectedOffsetY'],\n    '4091': ['SQ', '1', 'ChannelSettingsSequence'],\n    '4092': ['DS', '1', 'ChannelThreshold'],\n    '409A': ['SQ', '1', 'ScannerSettingsSequence'],\n    '409B': ['ST', '1', 'ScanProcedure'],\n    '409C': ['DS', '1', 'TranslationRateX'],\n    '409D': ['DS', '1', 'TranslationRateY'],\n    '409F': ['DS', '1', 'ChannelOverlap'],\n    '40A0': ['LO', '1-n', 'ImageQualityIndicatorType'],\n    '40A1': ['LO', '1-n', 'ImageQualityIndicatorMaterial'],\n    '40A2': ['LO', '1-n', 'ImageQualityIndicatorSize'],\n    '5002': ['IS', '1', 'LINACEnergy'],\n    '5004': ['IS', '1', 'LINACOutput'],\n    '5100': ['US', '1', 'ActiveAperture'],\n    '5101': ['DS', '1', 'TotalAperture'],\n    '5102': ['DS', '1', 'ApertureElevation'],\n    '5103': ['DS', '1', 'MainLobeAngle'],\n    '5104': ['DS', '1', 'MainRoofAngle'],\n    '5105': ['CS', '1', 'ConnectorType'],\n    '5106': ['SH', '1', 'WedgeModelNumber'],\n    '5107': ['DS', '1', 'WedgeAngleFloat'],\n    '5108': ['DS', '1', 'WedgeRoofAngle'],\n    '5109': ['CS', '1', 'WedgeElement1Position'],\n    '510A': ['DS', '1', 'WedgeMaterialVelocity'],\n    '510B': ['SH', '1', 'WedgeMaterial'],\n    '510C': ['DS', '1', 'WedgeOffsetZ'],\n    '510D': ['DS', '1', 'WedgeOriginOffsetX'],\n    '510E': ['DS', '1', 'WedgeTimeDelay'],\n    '510F': ['SH', '1', 'WedgeName'],\n    '5110': ['SH', '1', 'WedgeManufacturerName'],\n    '5111': ['LO', '1', 'WedgeDescription'],\n    '5112': ['DS', '1', 'NominalBeamAngle'],\n    '5113': ['DS', '1', 'WedgeOffsetX'],\n    '5114': ['DS', '1', 'WedgeOffsetY'],\n    '5115': ['DS', '1', 'WedgeTotalLength'],\n    '5116': ['DS', '1', 'WedgeInContactLength'],\n    '5117': ['DS', '1', 'WedgeFrontGap'],\n    '5118': ['DS', '1', 'WedgeTotalHeight'],\n    '5119': ['DS', '1', 'WedgeFrontHeight'],\n    '511A': ['DS', '1', 'WedgeRearHeight'],\n    '511B': ['DS', '1', 'WedgeTotalWidth'],\n    '511C': ['DS', '1', 'WedgeInContactWidth'],\n    '511D': ['DS', '1', 'WedgeChamferHeight'],\n    '511E': ['CS', '1', 'WedgeCurve'],\n    '511F': ['DS', '1', 'RadiusAlongWedge']\n  },\n  '0016': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['DS', '1', 'WhitePoint'],\n    '0002': ['DS', '3', 'PrimaryChromaticities'],\n    '0003': ['UT', '1', 'BatteryLevel'],\n    '0004': ['DS', '1', 'ExposureTimeInSeconds'],\n    '0005': ['DS', '1', 'FNumber'],\n    '0006': ['IS', '1', 'OECFRows'],\n    '0007': ['IS', '1', 'OECFColumns'],\n    '0008': ['UC', '1-n', 'OECFColumnNames'],\n    '0009': ['DS', '1-n', 'OECFValues'],\n    '000A': ['IS', '1', 'SpatialFrequencyResponseRows'],\n    '000B': ['IS', '1', 'SpatialFrequencyResponseColumns'],\n    '000C': ['UC', '1-n', 'SpatialFrequencyResponseColumnNames'],\n    '000D': ['DS', '1-n', 'SpatialFrequencyResponseValues'],\n    '000E': ['IS', '1', 'ColorFilterArrayPatternRows'],\n    '000F': ['IS', '1', 'ColorFilterArrayPatternColumns'],\n    '0010': ['DS', '1-n', 'ColorFilterArrayPatternValues'],\n    '0011': ['US', '1', 'FlashFiringStatus'],\n    '0012': ['US', '1', 'FlashReturnStatus'],\n    '0013': ['US', '1', 'FlashMode'],\n    '0014': ['US', '1', 'FlashFunctionPresent'],\n    '0015': ['US', '1', 'FlashRedEyeMode'],\n    '0016': ['US', '1', 'ExposureProgram'],\n    '0017': ['UT', '1', 'SpectralSensitivity'],\n    '0018': ['IS', '1', 'PhotographicSensitivity'],\n    '0019': ['IS', '1', 'SelfTimerMode'],\n    '001A': ['US', '1', 'SensitivityType'],\n    '001B': ['IS', '1', 'StandardOutputSensitivity'],\n    '001C': ['IS', '1', 'RecommendedExposureIndex'],\n    '001D': ['IS', '1', 'ISOSpeed'],\n    '001E': ['IS', '1', 'ISOSpeedLatitudeyyy'],\n    '001F': ['IS', '1', 'ISOSpeedLatitudezzz'],\n    '0020': ['UT', '1', 'EXIFVersion'],\n    '0021': ['DS', '1', 'ShutterSpeedValue'],\n    '0022': ['DS', '1', 'ApertureValue'],\n    '0023': ['DS', '1', 'BrightnessValue'],\n    '0024': ['DS', '1', 'ExposureBiasValue'],\n    '0025': ['DS', '1', 'MaxApertureValue'],\n    '0026': ['DS', '1', 'SubjectDistance'],\n    '0027': ['US', '1', 'MeteringMode'],\n    '0028': ['US', '1', 'LightSource'],\n    '0029': ['DS', '1', 'FocalLength'],\n    '002A': ['IS', '2-4', 'SubjectArea'],\n    '002B': ['OB', '1', 'MakerNote'],\n    '0030': ['DS', '1', 'Temperature'],\n    '0031': ['DS', '1', 'Humidity'],\n    '0032': ['DS', '1', 'Pressure'],\n    '0033': ['DS', '1', 'WaterDepth'],\n    '0034': ['DS', '1', 'Acceleration'],\n    '0035': ['DS', '1', 'CameraElevationAngle'],\n    '0036': ['DS', '1-2', 'FlashEnergy'],\n    '0037': ['IS', '2', 'SubjectLocation'],\n    '0038': ['DS', '1', 'PhotographicExposureIndex'],\n    '0039': ['US', '1', 'SensingMethod'],\n    '003A': ['US', '1', 'FileSource'],\n    '003B': ['US', '1', 'SceneType'],\n    '0041': ['US', '1', 'CustomRendered'],\n    '0042': ['US', '1', 'ExposureMode'],\n    '0043': ['US', '1', 'WhiteBalance'],\n    '0044': ['DS', '1', 'DigitalZoomRatio'],\n    '0045': ['IS', '1', 'FocalLengthIn35mmFilm'],\n    '0046': ['US', '1', 'SceneCaptureType'],\n    '0047': ['US', '1', 'GainControl'],\n    '0048': ['US', '1', 'Contrast'],\n    '0049': ['US', '1', 'Saturation'],\n    '004A': ['US', '1', 'Sharpness'],\n    '004B': ['OB', '1', 'DeviceSettingDescription'],\n    '004C': ['US', '1', 'SubjectDistanceRange'],\n    '004D': ['UT', '1', 'CameraOwnerName'],\n    '004E': ['DS', '4', 'LensSpecification'],\n    '004F': ['UT', '1', 'LensMake'],\n    '0050': ['UT', '1', 'LensModel'],\n    '0051': ['UT', '1', 'LensSerialNumber'],\n    '0061': ['CS', '1', 'InteroperabilityIndex'],\n    '0062': ['OB', '1', 'InteroperabilityVersion'],\n    '0070': ['OB', '1', 'GPSVersionID'],\n    '0071': ['CS', '1', 'GPSLatitudeRef'],\n    '0072': ['DS', '3', 'GPSLatitude'],\n    '0073': ['CS', '1', 'GPSLongitudeRef'],\n    '0074': ['DS', '3', 'GPSLongitude'],\n    '0075': ['US', '1', 'GPSAltitudeRef'],\n    '0076': ['DS', '1', 'GPSAltitude'],\n    '0077': ['DT', '1', 'GPSTimeStamp'],\n    '0078': ['UT', '1', 'GPSSatellites'],\n    '0079': ['CS', '1', 'GPSStatus'],\n    '007A': ['CS', '1', 'GPSMeasureMode'],\n    '007B': ['DS', '1', 'GPSDOP'],\n    '007C': ['CS', '1', 'GPSSpeedRef'],\n    '007D': ['DS', '1', 'GPSSpeed'],\n    '007E': ['CS', '1', 'GPSTrackRef'],\n    '007F': ['DS', '1', 'GPSTrack'],\n    '0080': ['CS', '1', 'GPSImgDirectionRef'],\n    '0081': ['DS', '1', 'GPSImgDirection'],\n    '0082': ['UT', '1', 'GPSMapDatum'],\n    '0083': ['CS', '1', 'GPSDestLatitudeRef'],\n    '0084': ['DS', '3', 'GPSDestLatitude'],\n    '0085': ['CS', '1', 'GPSDestLongitudeRef'],\n    '0086': ['DS', '3', 'GPSDestLongitude'],\n    '0087': ['CS', '1', 'GPSDestBearingRef'],\n    '0088': ['DS', '1', 'GPSDestBearing'],\n    '0089': ['CS', '1', 'GPSDestDistanceRef'],\n    '008A': ['DS', '1', 'GPSDestDistance'],\n    '008B': ['OB', '1', 'GPSProcessingMethod'],\n    '008C': ['OB', '1', 'GPSAreaInformation'],\n    '008D': ['DT', '1', 'GPSDateStamp'],\n    '008E': ['IS', '1', 'GPSDifferential'],\n    '1001': ['CS', '1', 'LightSourcePolarization'],\n    '1002': ['DS', '1', 'EmitterColorTemperature'],\n    '1003': ['CS', '1', 'ContactMethod'],\n    '1004': ['CS', '1-n', 'ImmersionMedia'],\n    '1005': ['DS', '1', 'OpticalMagnificationFactor']\n  },\n  '0018': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['LO', '1', 'ContrastBolusAgent'],\n    '0012': ['SQ', '1', 'ContrastBolusAgentSequence'],\n    '0013': ['FL', '1', 'ContrastBolusT1Relaxivity'],\n    '0014': ['SQ', '1', 'ContrastBolusAdministrationRouteSequence'],\n    '0015': ['CS', '1', 'BodyPartExamined'],\n    '0020': ['CS', '1-n', 'ScanningSequence'],\n    '0021': ['CS', '1-n', 'SequenceVariant'],\n    '0022': ['CS', '1-n', 'ScanOptions'],\n    '0023': ['CS', '1', 'MRAcquisitionType'],\n    '0024': ['SH', '1', 'SequenceName'],\n    '0025': ['CS', '1', 'AngioFlag'],\n    '0026': ['SQ', '1', 'InterventionDrugInformationSequence'],\n    '0027': ['TM', '1', 'InterventionDrugStopTime'],\n    '0028': ['DS', '1', 'InterventionDrugDose'],\n    '0029': ['SQ', '1', 'InterventionDrugCodeSequence'],\n    '002A': ['SQ', '1', 'AdditionalDrugSequence'],\n    '0030': ['LO', '1-n', 'Radionuclide'],\n    '0031': ['LO', '1', 'Radiopharmaceutical'],\n    '0032': ['DS', '1', 'EnergyWindowCenterline'],\n    '0033': ['DS', '1-n', 'EnergyWindowTotalWidth'],\n    '0034': ['LO', '1', 'InterventionDrugName'],\n    '0035': ['TM', '1', 'InterventionDrugStartTime'],\n    '0036': ['SQ', '1', 'InterventionSequence'],\n    '0037': ['CS', '1', 'TherapyType'],\n    '0038': ['CS', '1', 'InterventionStatus'],\n    '0039': ['CS', '1', 'TherapyDescription'],\n    '003A': ['ST', '1', 'InterventionDescription'],\n    '0040': ['IS', '1', 'CineRate'],\n    '0042': ['CS', '1', 'InitialCineRunState'],\n    '0050': ['DS', '1', 'SliceThickness'],\n    '0060': ['DS', '1', 'KVP'],\n    '0061': ['DS', '1', ''],\n    '0070': ['IS', '1', 'CountsAccumulated'],\n    '0071': ['CS', '1', 'AcquisitionTerminationCondition'],\n    '0072': ['DS', '1', 'EffectiveDuration'],\n    '0073': ['CS', '1', 'AcquisitionStartCondition'],\n    '0074': ['IS', '1', 'AcquisitionStartConditionData'],\n    '0075': ['IS', '1', 'AcquisitionTerminationConditionData'],\n    '0080': ['DS', '1', 'RepetitionTime'],\n    '0081': ['DS', '1', 'EchoTime'],\n    '0082': ['DS', '1', 'InversionTime'],\n    '0083': ['DS', '1', 'NumberOfAverages'],\n    '0084': ['DS', '1', 'ImagingFrequency'],\n    '0085': ['SH', '1', 'ImagedNucleus'],\n    '0086': ['IS', '1-n', 'EchoNumbers'],\n    '0087': ['DS', '1', 'MagneticFieldStrength'],\n    '0088': ['DS', '1', 'SpacingBetweenSlices'],\n    '0089': ['IS', '1', 'NumberOfPhaseEncodingSteps'],\n    '0090': ['DS', '1', 'DataCollectionDiameter'],\n    '0091': ['IS', '1', 'EchoTrainLength'],\n    '0093': ['DS', '1', 'PercentSampling'],\n    '0094': ['DS', '1', 'PercentPhaseFieldOfView'],\n    '0095': ['DS', '1', 'PixelBandwidth'],\n    '1000': ['LO', '1', 'DeviceSerialNumber'],\n    '1002': ['UI', '1', 'DeviceUID'],\n    '1003': ['LO', '1', 'DeviceID'],\n    '1004': ['LO', '1', 'PlateID'],\n    '1005': ['LO', '1', 'GeneratorID'],\n    '1006': ['LO', '1', 'GridID'],\n    '1007': ['LO', '1', 'CassetteID'],\n    '1008': ['LO', '1', 'GantryID'],\n    '1009': ['UT', '1', 'UniqueDeviceIdentifier'],\n    '100A': ['SQ', '1', 'UDISequence'],\n    '100B': ['UI', '1-n', 'ManufacturerDeviceClassUID'],\n    '1010': ['LO', '1', 'SecondaryCaptureDeviceID'],\n    '1011': ['LO', '1', 'HardcopyCreationDeviceID'],\n    '1012': ['DA', '1', 'DateOfSecondaryCapture'],\n    '1014': ['TM', '1', 'TimeOfSecondaryCapture'],\n    '1016': ['LO', '1', 'SecondaryCaptureDeviceManufacturer'],\n    '1017': ['LO', '1', 'HardcopyDeviceManufacturer'],\n    '1018': ['LO', '1', 'SecondaryCaptureDeviceManufacturerModelName'],\n    '1019': ['LO', '1-n', 'SecondaryCaptureDeviceSoftwareVersions'],\n    '101A': ['LO', '1-n', 'HardcopyDeviceSoftwareVersion'],\n    '101B': ['LO', '1', 'HardcopyDeviceManufacturerModelName'],\n    '1020': ['LO', '1-n', 'SoftwareVersions'],\n    '1022': ['SH', '1', 'VideoImageFormatAcquired'],\n    '1023': ['LO', '1', 'DigitalImageFormatAcquired'],\n    '1030': ['LO', '1', 'ProtocolName'],\n    '1040': ['LO', '1', 'ContrastBolusRoute'],\n    '1041': ['DS', '1', 'ContrastBolusVolume'],\n    '1042': ['TM', '1', 'ContrastBolusStartTime'],\n    '1043': ['TM', '1', 'ContrastBolusStopTime'],\n    '1044': ['DS', '1', 'ContrastBolusTotalDose'],\n    '1045': ['IS', '1', 'SyringeCounts'],\n    '1046': ['DS', '1-n', 'ContrastFlowRate'],\n    '1047': ['DS', '1-n', 'ContrastFlowDuration'],\n    '1048': ['CS', '1', 'ContrastBolusIngredient'],\n    '1049': ['DS', '1', 'ContrastBolusIngredientConcentration'],\n    '1050': ['DS', '1', 'SpatialResolution'],\n    '1060': ['DS', '1', 'TriggerTime'],\n    '1061': ['LO', '1', 'TriggerSourceOrType'],\n    '1062': ['IS', '1', 'NominalInterval'],\n    '1063': ['DS', '1', 'FrameTime'],\n    '1064': ['LO', '1', 'CardiacFramingType'],\n    '1065': ['DS', '1-n', 'FrameTimeVector'],\n    '1066': ['DS', '1', 'FrameDelay'],\n    '1067': ['DS', '1', 'ImageTriggerDelay'],\n    '1068': ['DS', '1', 'MultiplexGroupTimeOffset'],\n    '1069': ['DS', '1', 'TriggerTimeOffset'],\n    '106A': ['CS', '1', 'SynchronizationTrigger'],\n    '106C': ['US', '2', 'SynchronizationChannel'],\n    '106E': ['UL', '1', 'TriggerSamplePosition'],\n    '1070': ['LO', '1', 'RadiopharmaceuticalRoute'],\n    '1071': ['DS', '1', 'RadiopharmaceuticalVolume'],\n    '1072': ['TM', '1', 'RadiopharmaceuticalStartTime'],\n    '1073': ['TM', '1', 'RadiopharmaceuticalStopTime'],\n    '1074': ['DS', '1', 'RadionuclideTotalDose'],\n    '1075': ['DS', '1', 'RadionuclideHalfLife'],\n    '1076': ['DS', '1', 'RadionuclidePositronFraction'],\n    '1077': ['DS', '1', 'RadiopharmaceuticalSpecificActivity'],\n    '1078': ['DT', '1', 'RadiopharmaceuticalStartDateTime'],\n    '1079': ['DT', '1', 'RadiopharmaceuticalStopDateTime'],\n    '1080': ['CS', '1', 'BeatRejectionFlag'],\n    '1081': ['IS', '1', 'LowRRValue'],\n    '1082': ['IS', '1', 'HighRRValue'],\n    '1083': ['IS', '1', 'IntervalsAcquired'],\n    '1084': ['IS', '1', 'IntervalsRejected'],\n    '1085': ['LO', '1', 'PVCRejection'],\n    '1086': ['IS', '1', 'SkipBeats'],\n    '1088': ['IS', '1', 'HeartRate'],\n    '1090': ['IS', '1', 'CardiacNumberOfImages'],\n    '1094': ['IS', '1', 'TriggerWindow'],\n    '1100': ['DS', '1', 'ReconstructionDiameter'],\n    '1110': ['DS', '1', 'DistanceSourceToDetector'],\n    '1111': ['DS', '1', 'DistanceSourceToPatient'],\n    '1114': ['DS', '1', 'EstimatedRadiographicMagnificationFactor'],\n    '1120': ['DS', '1', 'GantryDetectorTilt'],\n    '1121': ['DS', '1', 'GantryDetectorSlew'],\n    '1130': ['DS', '1', 'TableHeight'],\n    '1131': ['DS', '1', 'TableTraverse'],\n    '1134': ['CS', '1', 'TableMotion'],\n    '1135': ['DS', '1-n', 'TableVerticalIncrement'],\n    '1136': ['DS', '1-n', 'TableLateralIncrement'],\n    '1137': ['DS', '1-n', 'TableLongitudinalIncrement'],\n    '1138': ['DS', '1', 'TableAngle'],\n    '113A': ['CS', '1', 'TableType'],\n    '1140': ['CS', '1', 'RotationDirection'],\n    '1141': ['DS', '1', 'AngularPosition'],\n    '1142': ['DS', '1-n', 'RadialPosition'],\n    '1143': ['DS', '1', 'ScanArc'],\n    '1144': ['DS', '1', 'AngularStep'],\n    '1145': ['DS', '1', 'CenterOfRotationOffset'],\n    '1146': ['DS', '1-n', 'RotationOffset'],\n    '1147': ['CS', '1', 'FieldOfViewShape'],\n    '1149': ['IS', '1-2', 'FieldOfViewDimensions'],\n    '1150': ['IS', '1', 'ExposureTime'],\n    '1151': ['IS', '1', 'XRayTubeCurrent'],\n    '1152': ['IS', '1', 'Exposure'],\n    '1153': ['IS', '1', 'ExposureInuAs'],\n    '1154': ['DS', '1', 'AveragePulseWidth'],\n    '1155': ['CS', '1', 'RadiationSetting'],\n    '1156': ['CS', '1', 'RectificationType'],\n    '115A': ['CS', '1', 'RadiationMode'],\n    '115E': ['DS', '1', 'ImageAndFluoroscopyAreaDoseProduct'],\n    '1160': ['SH', '1', 'FilterType'],\n    '1161': ['LO', '1-n', 'TypeOfFilters'],\n    '1162': ['DS', '1', 'IntensifierSize'],\n    '1164': ['DS', '2', 'ImagerPixelSpacing'],\n    '1166': ['CS', '1-n', 'Grid'],\n    '1170': ['IS', '1', 'GeneratorPower'],\n    '1180': ['SH', '1', 'CollimatorGridName'],\n    '1181': ['CS', '1', 'CollimatorType'],\n    '1182': ['IS', '1-2', 'FocalDistance'],\n    '1183': ['DS', '1-2', 'XFocusCenter'],\n    '1184': ['DS', '1-2', 'YFocusCenter'],\n    '1190': ['DS', '1-n', 'FocalSpots'],\n    '1191': ['CS', '1', 'AnodeTargetMaterial'],\n    '11A0': ['DS', '1', 'BodyPartThickness'],\n    '11A2': ['DS', '1', 'CompressionForce'],\n    '11A3': ['DS', '1', 'CompressionPressure'],\n    '11A4': ['LO', '1', 'PaddleDescription'],\n    '11A5': ['DS', '1', 'CompressionContactArea'],\n    '11B0': ['LO', '1', 'AcquisitionMode'],\n    '11B1': ['LO', '1', 'DoseModeName'],\n    '11B2': ['CS', '1', 'AcquiredSubtractionMaskFlag'],\n    '11B3': ['CS', '1', 'FluoroscopyPersistenceFlag'],\n    '11B4': ['CS', '1', 'FluoroscopyLastImageHoldPersistenceFlag'],\n    '11B5': ['IS', '1', 'UpperLimitNumberOfPersistentFluoroscopyFrames'],\n    '11B6': ['CS', '1', 'ContrastBolusAutoInjectionTriggerFlag'],\n    '11B7': ['FD', '1', 'ContrastBolusInjectionDelay'],\n    '11B8': ['SQ', '1', 'XAAcquisitionPhaseDetailsSequence'],\n    '11B9': ['FD', '1', 'XAAcquisitionFrameRate'],\n    '11BA': ['SQ', '1', 'XAPlaneDetailsSequence'],\n    '11BB': ['LO', '1', 'AcquisitionFieldOfViewLabel'],\n    '11BC': ['SQ', '1', 'XRayFilterDetailsSequence'],\n    '11BD': ['FD', '1', 'XAAcquisitionDuration'],\n    '11BE': ['CS', '1', 'ReconstructionPipelineType'],\n    '11BF': ['SQ', '1', 'ImageFilterDetailsSequence'],\n    '11C0': ['CS', '1', 'AppliedMaskSubtractionFlag'],\n    '11C1': ['SQ', '1', 'RequestedSeriesDescriptionCodeSequence'],\n    '1200': ['DA', '1-n', 'DateOfLastCalibration'],\n    '1201': ['TM', '1-n', 'TimeOfLastCalibration'],\n    '1202': ['DT', '1', 'DateTimeOfLastCalibration'],\n    '1203': ['DT', '1', 'CalibrationDateTime'],\n    '1210': ['SH', '1-n', 'ConvolutionKernel'],\n    '1240': ['IS', '1-n', 'UpperLowerPixelValues'],\n    '1242': ['IS', '1', 'ActualFrameDuration'],\n    '1243': ['IS', '1', 'CountRate'],\n    '1244': ['US', '1', 'PreferredPlaybackSequencing'],\n    '1250': ['SH', '1', 'ReceiveCoilName'],\n    '1251': ['SH', '1', 'TransmitCoilName'],\n    '1260': ['SH', '1', 'PlateType'],\n    '1261': ['LO', '1', 'PhosphorType'],\n    '1271': ['FD', '1', 'WaterEquivalentDiameter'],\n    '1272': ['SQ', '1', 'WaterEquivalentDiameterCalculationMethodCodeSequence'],\n    '1300': ['DS', '1', 'ScanVelocity'],\n    '1301': ['CS', '1-n', 'WholeBodyTechnique'],\n    '1302': ['IS', '1', 'ScanLength'],\n    '1310': ['US', '4', 'AcquisitionMatrix'],\n    '1312': ['CS', '1', 'InPlanePhaseEncodingDirection'],\n    '1314': ['DS', '1', 'FlipAngle'],\n    '1315': ['CS', '1', 'VariableFlipAngleFlag'],\n    '1316': ['DS', '1', 'SAR'],\n    '1318': ['DS', '1', 'dBdt'],\n    '1320': ['FL', '1', 'B1rms'],\n    '1400': ['LO', '1', 'AcquisitionDeviceProcessingDescription'],\n    '1401': ['LO', '1', 'AcquisitionDeviceProcessingCode'],\n    '1402': ['CS', '1', 'CassetteOrientation'],\n    '1403': ['CS', '1', 'CassetteSize'],\n    '1404': ['US', '1', 'ExposuresOnPlate'],\n    '1405': ['IS', '1', 'RelativeXRayExposure'],\n    '1411': ['DS', '1', 'ExposureIndex'],\n    '1412': ['DS', '1', 'TargetExposureIndex'],\n    '1413': ['DS', '1', 'DeviationIndex'],\n    '1450': ['DS', '1', 'ColumnAngulation'],\n    '1460': ['DS', '1', 'TomoLayerHeight'],\n    '1470': ['DS', '1', 'TomoAngle'],\n    '1480': ['DS', '1', 'TomoTime'],\n    '1490': ['CS', '1', 'TomoType'],\n    '1491': ['CS', '1', 'TomoClass'],\n    '1495': ['IS', '1', 'NumberOfTomosynthesisSourceImages'],\n    '1500': ['CS', '1', 'PositionerMotion'],\n    '1508': ['CS', '1', 'PositionerType'],\n    '1510': ['DS', '1', 'PositionerPrimaryAngle'],\n    '1511': ['DS', '1', 'PositionerSecondaryAngle'],\n    '1520': ['DS', '1-n', 'PositionerPrimaryAngleIncrement'],\n    '1521': ['DS', '1-n', 'PositionerSecondaryAngleIncrement'],\n    '1530': ['DS', '1', 'DetectorPrimaryAngle'],\n    '1531': ['DS', '1', 'DetectorSecondaryAngle'],\n    '1600': ['CS', '1-3', 'ShutterShape'],\n    '1602': ['IS', '1', 'ShutterLeftVerticalEdge'],\n    '1604': ['IS', '1', 'ShutterRightVerticalEdge'],\n    '1606': ['IS', '1', 'ShutterUpperHorizontalEdge'],\n    '1608': ['IS', '1', 'ShutterLowerHorizontalEdge'],\n    '1610': ['IS', '2', 'CenterOfCircularShutter'],\n    '1612': ['IS', '1', 'RadiusOfCircularShutter'],\n    '1620': ['IS', '2-2n', 'VerticesOfThePolygonalShutter'],\n    '1622': ['US', '1', 'ShutterPresentationValue'],\n    '1623': ['US', '1', 'ShutterOverlayGroup'],\n    '1624': ['US', '3', 'ShutterPresentationColorCIELabValue'],\n    '1630': ['CS', '1', 'OutlineShapeType'],\n    '1631': ['FD', '1', 'OutlineLeftVerticalEdge'],\n    '1632': ['FD', '1', 'OutlineRightVerticalEdge'],\n    '1633': ['FD', '1', 'OutlineUpperHorizontalEdge'],\n    '1634': ['FD', '1', 'OutlineLowerHorizontalEdge'],\n    '1635': ['FD', '2', 'CenterOfCircularOutline'],\n    '1636': ['FD', '1', 'DiameterOfCircularOutline'],\n    '1637': ['UL', '1', 'NumberOfPolygonalVertices'],\n    '1638': ['OF', '1', 'VerticesOfThePolygonalOutline'],\n    '1700': ['CS', '1-3', 'CollimatorShape'],\n    '1702': ['IS', '1', 'CollimatorLeftVerticalEdge'],\n    '1704': ['IS', '1', 'CollimatorRightVerticalEdge'],\n    '1706': ['IS', '1', 'CollimatorUpperHorizontalEdge'],\n    '1708': ['IS', '1', 'CollimatorLowerHorizontalEdge'],\n    '1710': ['IS', '2', 'CenterOfCircularCollimator'],\n    '1712': ['IS', '1', 'RadiusOfCircularCollimator'],\n    '1720': ['IS', '2-2n', 'VerticesOfThePolygonalCollimator'],\n    '1800': ['CS', '1', 'AcquisitionTimeSynchronized'],\n    '1801': ['SH', '1', 'TimeSource'],\n    '1802': ['CS', '1', 'TimeDistributionProtocol'],\n    '1803': ['LO', '1', 'NTPSourceAddress'],\n    '2001': ['IS', '1-n', 'PageNumberVector'],\n    '2002': ['SH', '1-n', 'FrameLabelVector'],\n    '2003': ['DS', '1-n', 'FramePrimaryAngleVector'],\n    '2004': ['DS', '1-n', 'FrameSecondaryAngleVector'],\n    '2005': ['DS', '1-n', 'SliceLocationVector'],\n    '2006': ['SH', '1-n', 'DisplayWindowLabelVector'],\n    '2010': ['DS', '2', 'NominalScannedPixelSpacing'],\n    '2020': ['CS', '1', 'DigitizingDeviceTransportDirection'],\n    '2030': ['DS', '1', 'RotationOfScannedFilm'],\n    '2041': ['SQ', '1', 'BiopsyTargetSequence'],\n    '2042': ['UI', '1', 'TargetUID'],\n    '2043': ['FL', '2', 'LocalizingCursorPosition'],\n    '2044': ['FL', '3', 'CalculatedTargetPosition'],\n    '2045': ['SH', '1', 'TargetLabel'],\n    '2046': ['FL', '1', 'DisplayedZValue'],\n    '3100': ['CS', '1', 'IVUSAcquisition'],\n    '3101': ['DS', '1', 'IVUSPullbackRate'],\n    '3102': ['DS', '1', 'IVUSGatedRate'],\n    '3103': ['IS', '1', 'IVUSPullbackStartFrameNumber'],\n    '3104': ['IS', '1', 'IVUSPullbackStopFrameNumber'],\n    '3105': ['IS', '1-n', 'LesionNumber'],\n    '4000': ['LT', '1', 'AcquisitionComments'],\n    '5000': ['SH', '1-n', 'OutputPower'],\n    '5010': ['LO', '1-n', 'TransducerData'],\n    '5011': ['SQ', '1', 'TransducerIdentificationSequence'],\n    '5012': ['DS', '1', 'FocusDepth'],\n    '5020': ['LO', '1', 'ProcessingFunction'],\n    '5021': ['LO', '1', 'PostprocessingFunction'],\n    '5022': ['DS', '1', 'MechanicalIndex'],\n    '5024': ['DS', '1', 'BoneThermalIndex'],\n    '5026': ['DS', '1', 'CranialThermalIndex'],\n    '5027': ['DS', '1', 'SoftTissueThermalIndex'],\n    '5028': ['DS', '1', 'SoftTissueFocusThermalIndex'],\n    '5029': ['DS', '1', 'SoftTissueSurfaceThermalIndex'],\n    '5030': ['DS', '1', 'DynamicRange'],\n    '5040': ['DS', '1', 'TotalGain'],\n    '5050': ['IS', '1', 'DepthOfScanField'],\n    '5100': ['CS', '1', 'PatientPosition'],\n    '5101': ['CS', '1', 'ViewPosition'],\n    '5104': ['SQ', '1', 'ProjectionEponymousNameCodeSequence'],\n    '5210': ['DS', '6', 'ImageTransformationMatrix'],\n    '5212': ['DS', '3', 'ImageTranslationVector'],\n    '6000': ['DS', '1', 'Sensitivity'],\n    '6011': ['SQ', '1', 'SequenceOfUltrasoundRegions'],\n    '6012': ['US', '1', 'RegionSpatialFormat'],\n    '6014': ['US', '1', 'RegionDataType'],\n    '6016': ['UL', '1', 'RegionFlags'],\n    '6018': ['UL', '1', 'RegionLocationMinX0'],\n    '601A': ['UL', '1', 'RegionLocationMinY0'],\n    '601C': ['UL', '1', 'RegionLocationMaxX1'],\n    '601E': ['UL', '1', 'RegionLocationMaxY1'],\n    '6020': ['SL', '1', 'ReferencePixelX0'],\n    '6022': ['SL', '1', 'ReferencePixelY0'],\n    '6024': ['US', '1', 'PhysicalUnitsXDirection'],\n    '6026': ['US', '1', 'PhysicalUnitsYDirection'],\n    '6028': ['FD', '1', 'ReferencePixelPhysicalValueX'],\n    '602A': ['FD', '1', 'ReferencePixelPhysicalValueY'],\n    '602C': ['FD', '1', 'PhysicalDeltaX'],\n    '602E': ['FD', '1', 'PhysicalDeltaY'],\n    '6030': ['UL', '1', 'TransducerFrequency'],\n    '6031': ['CS', '1', 'TransducerType'],\n    '6032': ['UL', '1', 'PulseRepetitionFrequency'],\n    '6034': ['FD', '1', 'DopplerCorrectionAngle'],\n    '6036': ['FD', '1', 'SteeringAngle'],\n    '6038': ['UL', '1', 'DopplerSampleVolumeXPositionRetired'],\n    '6039': ['SL', '1', 'DopplerSampleVolumeXPosition'],\n    '603A': ['UL', '1', 'DopplerSampleVolumeYPositionRetired'],\n    '603B': ['SL', '1', 'DopplerSampleVolumeYPosition'],\n    '603C': ['UL', '1', 'TMLinePositionX0Retired'],\n    '603D': ['SL', '1', 'TMLinePositionX0'],\n    '603E': ['UL', '1', 'TMLinePositionY0Retired'],\n    '603F': ['SL', '1', 'TMLinePositionY0'],\n    '6040': ['UL', '1', 'TMLinePositionX1Retired'],\n    '6041': ['SL', '1', 'TMLinePositionX1'],\n    '6042': ['UL', '1', 'TMLinePositionY1Retired'],\n    '6043': ['SL', '1', 'TMLinePositionY1'],\n    '6044': ['US', '1', 'PixelComponentOrganization'],\n    '6046': ['UL', '1', 'PixelComponentMask'],\n    '6048': ['UL', '1', 'PixelComponentRangeStart'],\n    '604A': ['UL', '1', 'PixelComponentRangeStop'],\n    '604C': ['US', '1', 'PixelComponentPhysicalUnits'],\n    '604E': ['US', '1', 'PixelComponentDataType'],\n    '6050': ['UL', '1', 'NumberOfTableBreakPoints'],\n    '6052': ['UL', '1-n', 'TableOfXBreakPoints'],\n    '6054': ['FD', '1-n', 'TableOfYBreakPoints'],\n    '6056': ['UL', '1', 'NumberOfTableEntries'],\n    '6058': ['UL', '1-n', 'TableOfPixelValues'],\n    '605A': ['FL', '1-n', 'TableOfParameterValues'],\n    '6060': ['FL', '1-n', 'RWaveTimeVector'],\n    '6070': ['US', '1', 'ActiveImageAreaOverlayGroup'],\n    '7000': ['CS', '1', 'DetectorConditionsNominalFlag'],\n    '7001': ['DS', '1', 'DetectorTemperature'],\n    '7004': ['CS', '1', 'DetectorType'],\n    '7005': ['CS', '1', 'DetectorConfiguration'],\n    '7006': ['LT', '1', 'DetectorDescription'],\n    '7008': ['LT', '1', 'DetectorMode'],\n    '700A': ['SH', '1', 'DetectorID'],\n    '700C': ['DA', '1', 'DateOfLastDetectorCalibration'],\n    '700E': ['TM', '1', 'TimeOfLastDetectorCalibration'],\n    '7010': ['IS', '1', 'ExposuresOnDetectorSinceLastCalibration'],\n    '7011': ['IS', '1', 'ExposuresOnDetectorSinceManufactured'],\n    '7012': ['DS', '1', 'DetectorTimeSinceLastExposure'],\n    '7014': ['DS', '1', 'DetectorActiveTime'],\n    '7016': ['DS', '1', 'DetectorActivationOffsetFromExposure'],\n    '701A': ['DS', '2', 'DetectorBinning'],\n    '7020': ['DS', '2', 'DetectorElementPhysicalSize'],\n    '7022': ['DS', '2', 'DetectorElementSpacing'],\n    '7024': ['CS', '1', 'DetectorActiveShape'],\n    '7026': ['DS', '1-2', 'DetectorActiveDimensions'],\n    '7028': ['DS', '2', 'DetectorActiveOrigin'],\n    '702A': ['LO', '1', 'DetectorManufacturerName'],\n    '702B': ['LO', '1', 'DetectorManufacturerModelName'],\n    '7030': ['DS', '2', 'FieldOfViewOrigin'],\n    '7032': ['DS', '1', 'FieldOfViewRotation'],\n    '7034': ['CS', '1', 'FieldOfViewHorizontalFlip'],\n    '7036': ['FL', '2', 'PixelDataAreaOriginRelativeToFOV'],\n    '7038': ['FL', '1', 'PixelDataAreaRotationAngleRelativeToFOV'],\n    '7040': ['LT', '1', 'GridAbsorbingMaterial'],\n    '7041': ['LT', '1', 'GridSpacingMaterial'],\n    '7042': ['DS', '1', 'GridThickness'],\n    '7044': ['DS', '1', 'GridPitch'],\n    '7046': ['IS', '2', 'GridAspectRatio'],\n    '7048': ['DS', '1', 'GridPeriod'],\n    '704C': ['DS', '1', 'GridFocalDistance'],\n    '7050': ['CS', '1-n', 'FilterMaterial'],\n    '7052': ['DS', '1-n', 'FilterThicknessMinimum'],\n    '7054': ['DS', '1-n', 'FilterThicknessMaximum'],\n    '7056': ['FL', '1-n', 'FilterBeamPathLengthMinimum'],\n    '7058': ['FL', '1-n', 'FilterBeamPathLengthMaximum'],\n    '7060': ['CS', '1', 'ExposureControlMode'],\n    '7062': ['LT', '1', 'ExposureControlModeDescription'],\n    '7064': ['CS', '1', 'ExposureStatus'],\n    '7065': ['DS', '1', 'PhototimerSetting'],\n    '8150': ['DS', '1', 'ExposureTimeInuS'],\n    '8151': ['DS', '1', 'XRayTubeCurrentInuA'],\n    '9004': ['CS', '1', 'ContentQualification'],\n    '9005': ['SH', '1', 'PulseSequenceName'],\n    '9006': ['SQ', '1', 'MRImagingModifierSequence'],\n    '9008': ['CS', '1', 'EchoPulseSequence'],\n    '9009': ['CS', '1', 'InversionRecovery'],\n    '9010': ['CS', '1', 'FlowCompensation'],\n    '9011': ['CS', '1', 'MultipleSpinEcho'],\n    '9012': ['CS', '1', 'MultiPlanarExcitation'],\n    '9014': ['CS', '1', 'PhaseContrast'],\n    '9015': ['CS', '1', 'TimeOfFlightContrast'],\n    '9016': ['CS', '1', 'Spoiling'],\n    '9017': ['CS', '1', 'SteadyStatePulseSequence'],\n    '9018': ['CS', '1', 'EchoPlanarPulseSequence'],\n    '9019': ['FD', '1', 'TagAngleFirstAxis'],\n    '9020': ['CS', '1', 'MagnetizationTransfer'],\n    '9021': ['CS', '1', 'T2Preparation'],\n    '9022': ['CS', '1', 'BloodSignalNulling'],\n    '9024': ['CS', '1', 'SaturationRecovery'],\n    '9025': ['CS', '1', 'SpectrallySelectedSuppression'],\n    '9026': ['CS', '1', 'SpectrallySelectedExcitation'],\n    '9027': ['CS', '1', 'SpatialPresaturation'],\n    '9028': ['CS', '1', 'Tagging'],\n    '9029': ['CS', '1', 'OversamplingPhase'],\n    '9030': ['FD', '1', 'TagSpacingFirstDimension'],\n    '9032': ['CS', '1', 'GeometryOfKSpaceTraversal'],\n    '9033': ['CS', '1', 'SegmentedKSpaceTraversal'],\n    '9034': ['CS', '1', 'RectilinearPhaseEncodeReordering'],\n    '9035': ['FD', '1', 'TagThickness'],\n    '9036': ['CS', '1', 'PartialFourierDirection'],\n    '9037': ['CS', '1', 'CardiacSynchronizationTechnique'],\n    '9041': ['LO', '1', 'ReceiveCoilManufacturerName'],\n    '9042': ['SQ', '1', 'MRReceiveCoilSequence'],\n    '9043': ['CS', '1', 'ReceiveCoilType'],\n    '9044': ['CS', '1', 'QuadratureReceiveCoil'],\n    '9045': ['SQ', '1', 'MultiCoilDefinitionSequence'],\n    '9046': ['LO', '1', 'MultiCoilConfiguration'],\n    '9047': ['SH', '1', 'MultiCoilElementName'],\n    '9048': ['CS', '1', 'MultiCoilElementUsed'],\n    '9049': ['SQ', '1', 'MRTransmitCoilSequence'],\n    '9050': ['LO', '1', 'TransmitCoilManufacturerName'],\n    '9051': ['CS', '1', 'TransmitCoilType'],\n    '9052': ['FD', '1-2', 'SpectralWidth'],\n    '9053': ['FD', '1-2', 'ChemicalShiftReference'],\n    '9054': ['CS', '1', 'VolumeLocalizationTechnique'],\n    '9058': ['US', '1', 'MRAcquisitionFrequencyEncodingSteps'],\n    '9059': ['CS', '1', 'Decoupling'],\n    '9060': ['CS', '1-2', 'DecoupledNucleus'],\n    '9061': ['FD', '1-2', 'DecouplingFrequency'],\n    '9062': ['CS', '1', 'DecouplingMethod'],\n    '9063': ['FD', '1-2', 'DecouplingChemicalShiftReference'],\n    '9064': ['CS', '1', 'KSpaceFiltering'],\n    '9065': ['CS', '1-2', 'TimeDomainFiltering'],\n    '9066': ['US', '1-2', 'NumberOfZeroFills'],\n    '9067': ['CS', '1', 'BaselineCorrection'],\n    '9069': ['FD', '1', 'ParallelReductionFactorInPlane'],\n    '9070': ['FD', '1', 'CardiacRRIntervalSpecified'],\n    '9073': ['FD', '1', 'AcquisitionDuration'],\n    '9074': ['DT', '1', 'FrameAcquisitionDateTime'],\n    '9075': ['CS', '1', 'DiffusionDirectionality'],\n    '9076': ['SQ', '1', 'DiffusionGradientDirectionSequence'],\n    '9077': ['CS', '1', 'ParallelAcquisition'],\n    '9078': ['CS', '1', 'ParallelAcquisitionTechnique'],\n    '9079': ['FD', '1-n', 'InversionTimes'],\n    '9080': ['ST', '1', 'MetaboliteMapDescription'],\n    '9081': ['CS', '1', 'PartialFourier'],\n    '9082': ['FD', '1', 'EffectiveEchoTime'],\n    '9083': ['SQ', '1', 'MetaboliteMapCodeSequence'],\n    '9084': ['SQ', '1', 'ChemicalShiftSequence'],\n    '9085': ['CS', '1', 'CardiacSignalSource'],\n    '9087': ['FD', '1', 'DiffusionBValue'],\n    '9089': ['FD', '3', 'DiffusionGradientOrientation'],\n    '9090': ['FD', '3', 'VelocityEncodingDirection'],\n    '9091': ['FD', '1', 'VelocityEncodingMinimumValue'],\n    '9092': ['SQ', '1', 'VelocityEncodingAcquisitionSequence'],\n    '9093': ['US', '1', 'NumberOfKSpaceTrajectories'],\n    '9094': ['CS', '1', 'CoverageOfKSpace'],\n    '9095': ['UL', '1', 'SpectroscopyAcquisitionPhaseRows'],\n    '9096': ['FD', '1', 'ParallelReductionFactorInPlaneRetired'],\n    '9098': ['FD', '1-2', 'TransmitterFrequency'],\n    '9100': ['CS', '1-2', 'ResonantNucleus'],\n    '9101': ['CS', '1', 'FrequencyCorrection'],\n    '9103': ['SQ', '1', 'MRSpectroscopyFOVGeometrySequence'],\n    '9104': ['FD', '1', 'SlabThickness'],\n    '9105': ['FD', '3', 'SlabOrientation'],\n    '9106': ['FD', '3', 'MidSlabPosition'],\n    '9107': ['SQ', '1', 'MRSpatialSaturationSequence'],\n    '9112': ['SQ', '1', 'MRTimingAndRelatedParametersSequence'],\n    '9114': ['SQ', '1', 'MREchoSequence'],\n    '9115': ['SQ', '1', 'MRModifierSequence'],\n    '9117': ['SQ', '1', 'MRDiffusionSequence'],\n    '9118': ['SQ', '1', 'CardiacSynchronizationSequence'],\n    '9119': ['SQ', '1', 'MRAveragesSequence'],\n    '9125': ['SQ', '1', 'MRFOVGeometrySequence'],\n    '9126': ['SQ', '1', 'VolumeLocalizationSequence'],\n    '9127': ['UL', '1', 'SpectroscopyAcquisitionDataColumns'],\n    '9147': ['CS', '1', 'DiffusionAnisotropyType'],\n    '9151': ['DT', '1', 'FrameReferenceDateTime'],\n    '9152': ['SQ', '1', 'MRMetaboliteMapSequence'],\n    '9155': ['FD', '1', 'ParallelReductionFactorOutOfPlane'],\n    '9159': ['UL', '1', 'SpectroscopyAcquisitionOutOfPlanePhaseSteps'],\n    '9166': ['CS', '1', 'BulkMotionStatus'],\n    '9168': ['FD', '1', 'ParallelReductionFactorSecondInPlane'],\n    '9169': ['CS', '1', 'CardiacBeatRejectionTechnique'],\n    '9170': ['CS', '1', 'RespiratoryMotionCompensationTechnique'],\n    '9171': ['CS', '1', 'RespiratorySignalSource'],\n    '9172': ['CS', '1', 'BulkMotionCompensationTechnique'],\n    '9173': ['CS', '1', 'BulkMotionSignalSource'],\n    '9174': ['CS', '1', 'ApplicableSafetyStandardAgency'],\n    '9175': ['LO', '1', 'ApplicableSafetyStandardDescription'],\n    '9176': ['SQ', '1', 'OperatingModeSequence'],\n    '9177': ['CS', '1', 'OperatingModeType'],\n    '9178': ['CS', '1', 'OperatingMode'],\n    '9179': ['CS', '1', 'SpecificAbsorptionRateDefinition'],\n    '9180': ['CS', '1', 'GradientOutputType'],\n    '9181': ['FD', '1', 'SpecificAbsorptionRateValue'],\n    '9182': ['FD', '1', 'GradientOutput'],\n    '9183': ['CS', '1', 'FlowCompensationDirection'],\n    '9184': ['FD', '1', 'TaggingDelay'],\n    '9185': ['ST', '1', 'RespiratoryMotionCompensationTechniqueDescription'],\n    '9186': ['SH', '1', 'RespiratorySignalSourceID'],\n    '9195': ['FD', '1', 'ChemicalShiftMinimumIntegrationLimitInHz'],\n    '9196': ['FD', '1', 'ChemicalShiftMaximumIntegrationLimitInHz'],\n    '9197': ['SQ', '1', 'MRVelocityEncodingSequence'],\n    '9198': ['CS', '1', 'FirstOrderPhaseCorrection'],\n    '9199': ['CS', '1', 'WaterReferencedPhaseCorrection'],\n    '9200': ['CS', '1', 'MRSpectroscopyAcquisitionType'],\n    '9214': ['CS', '1', 'RespiratoryCyclePosition'],\n    '9217': ['FD', '1', 'VelocityEncodingMaximumValue'],\n    '9218': ['FD', '1', 'TagSpacingSecondDimension'],\n    '9219': ['SS', '1', 'TagAngleSecondAxis'],\n    '9220': ['FD', '1', 'FrameAcquisitionDuration'],\n    '9226': ['SQ', '1', 'MRImageFrameTypeSequence'],\n    '9227': ['SQ', '1', 'MRSpectroscopyFrameTypeSequence'],\n    '9231': ['US', '1', 'MRAcquisitionPhaseEncodingStepsInPlane'],\n    '9232': ['US', '1', 'MRAcquisitionPhaseEncodingStepsOutOfPlane'],\n    '9234': ['UL', '1', 'SpectroscopyAcquisitionPhaseColumns'],\n    '9236': ['CS', '1', 'CardiacCyclePosition'],\n    '9239': ['SQ', '1', 'SpecificAbsorptionRateSequence'],\n    '9240': ['US', '1', 'RFEchoTrainLength'],\n    '9241': ['US', '1', 'GradientEchoTrainLength'],\n    '9250': ['CS', '1', 'ArterialSpinLabelingContrast'],\n    '9251': ['SQ', '1', 'MRArterialSpinLabelingSequence'],\n    '9252': ['LO', '1', 'ASLTechniqueDescription'],\n    '9253': ['US', '1', 'ASLSlabNumber'],\n    '9254': ['FD', '1', 'ASLSlabThickness'],\n    '9255': ['FD', '3', 'ASLSlabOrientation'],\n    '9256': ['FD', '3', 'ASLMidSlabPosition'],\n    '9257': ['CS', '1', 'ASLContext'],\n    '9258': ['UL', '1', 'ASLPulseTrainDuration'],\n    '9259': ['CS', '1', 'ASLCrusherFlag'],\n    '925A': ['FD', '1', 'ASLCrusherFlowLimit'],\n    '925B': ['LO', '1', 'ASLCrusherDescription'],\n    '925C': ['CS', '1', 'ASLBolusCutoffFlag'],\n    '925D': ['SQ', '1', 'ASLBolusCutoffTimingSequence'],\n    '925E': ['LO', '1', 'ASLBolusCutoffTechnique'],\n    '925F': ['UL', '1', 'ASLBolusCutoffDelayTime'],\n    '9260': ['SQ', '1', 'ASLSlabSequence'],\n    '9295': ['FD', '1', 'ChemicalShiftMinimumIntegrationLimitInppm'],\n    '9296': ['FD', '1', 'ChemicalShiftMaximumIntegrationLimitInppm'],\n    '9297': ['CS', '1', 'WaterReferenceAcquisition'],\n    '9298': ['IS', '1', 'EchoPeakPosition'],\n    '9301': ['SQ', '1', 'CTAcquisitionTypeSequence'],\n    '9302': ['CS', '1', 'AcquisitionType'],\n    '9303': ['FD', '1', 'TubeAngle'],\n    '9304': ['SQ', '1', 'CTAcquisitionDetailsSequence'],\n    '9305': ['FD', '1', 'RevolutionTime'],\n    '9306': ['FD', '1', 'SingleCollimationWidth'],\n    '9307': ['FD', '1', 'TotalCollimationWidth'],\n    '9308': ['SQ', '1', 'CTTableDynamicsSequence'],\n    '9309': ['FD', '1', 'TableSpeed'],\n    '9310': ['FD', '1', 'TableFeedPerRotation'],\n    '9311': ['FD', '1', 'SpiralPitchFactor'],\n    '9312': ['SQ', '1', 'CTGeometrySequence'],\n    '9313': ['FD', '3', 'DataCollectionCenterPatient'],\n    '9314': ['SQ', '1', 'CTReconstructionSequence'],\n    '9315': ['CS', '1', 'ReconstructionAlgorithm'],\n    '9316': ['CS', '1', 'ConvolutionKernelGroup'],\n    '9317': ['FD', '2', 'ReconstructionFieldOfView'],\n    '9318': ['FD', '3', 'ReconstructionTargetCenterPatient'],\n    '9319': ['FD', '1', 'ReconstructionAngle'],\n    '9320': ['SH', '1', 'ImageFilter'],\n    '9321': ['SQ', '1', 'CTExposureSequence'],\n    '9322': ['FD', '2', 'ReconstructionPixelSpacing'],\n    '9323': ['CS', '1-n', 'ExposureModulationType'],\n    '9324': ['FD', '1', 'EstimatedDoseSaving'],\n    '9325': ['SQ', '1', 'CTXRayDetailsSequence'],\n    '9326': ['SQ', '1', 'CTPositionSequence'],\n    '9327': ['FD', '1', 'TablePosition'],\n    '9328': ['FD', '1', 'ExposureTimeInms'],\n    '9329': ['SQ', '1', 'CTImageFrameTypeSequence'],\n    '9330': ['FD', '1', 'XRayTubeCurrentInmA'],\n    '9332': ['FD', '1', 'ExposureInmAs'],\n    '9333': ['CS', '1', 'ConstantVolumeFlag'],\n    '9334': ['CS', '1', 'FluoroscopyFlag'],\n    '9335': ['FD', '1', 'DistanceSourceToDataCollectionCenter'],\n    '9337': ['US', '1', 'ContrastBolusAgentNumber'],\n    '9338': ['SQ', '1', 'ContrastBolusIngredientCodeSequence'],\n    '9340': ['SQ', '1', 'ContrastAdministrationProfileSequence'],\n    '9341': ['SQ', '1', 'ContrastBolusUsageSequence'],\n    '9342': ['CS', '1', 'ContrastBolusAgentAdministered'],\n    '9343': ['CS', '1', 'ContrastBolusAgentDetected'],\n    '9344': ['CS', '1', 'ContrastBolusAgentPhase'],\n    '9345': ['FD', '1', 'CTDIvol'],\n    '9346': ['SQ', '1', 'CTDIPhantomTypeCodeSequence'],\n    '9351': ['FL', '1', 'CalciumScoringMassFactorPatient'],\n    '9352': ['FL', '3', 'CalciumScoringMassFactorDevice'],\n    '9353': ['FL', '1', 'EnergyWeightingFactor'],\n    '9360': ['SQ', '1', 'CTAdditionalXRaySourceSequence'],\n    '9361': ['CS', '1', 'MultienergyCTAcquisition'],\n    '9362': ['SQ', '1', 'MultienergyCTAcquisitionSequence'],\n    '9363': ['SQ', '1', 'MultienergyCTProcessingSequence'],\n    '9364': ['SQ', '1', 'MultienergyCTCharacteristicsSequence'],\n    '9365': ['SQ', '1', 'MultienergyCTXRaySourceSequence'],\n    '9366': ['US', '1', 'XRaySourceIndex'],\n    '9367': ['UC', '1', 'XRaySourceID'],\n    '9368': ['CS', '1', 'MultienergySourceTechnique'],\n    '9369': ['DT', '1', 'SourceStartDateTime'],\n    '936A': ['DT', '1', 'SourceEndDateTime'],\n    '936B': ['US', '1', 'SwitchingPhaseNumber'],\n    '936C': ['DS', '1', 'SwitchingPhaseNominalDuration'],\n    '936D': ['DS', '1', 'SwitchingPhaseTransitionDuration'],\n    '936E': ['DS', '1', 'EffectiveBinEnergy'],\n    '936F': ['SQ', '1', 'MultienergyCTXRayDetectorSequence'],\n    '9370': ['US', '1', 'XRayDetectorIndex'],\n    '9371': ['UC', '1', 'XRayDetectorID'],\n    '9372': ['CS', '1', 'MultienergyDetectorType'],\n    '9373': ['ST', '1', 'XRayDetectorLabel'],\n    '9374': ['DS', '1', 'NominalMaxEnergy'],\n    '9375': ['DS', '1', 'NominalMinEnergy'],\n    '9376': ['US', '1-n', 'ReferencedXRayDetectorIndex'],\n    '9377': ['US', '1-n', 'ReferencedXRaySourceIndex'],\n    '9378': ['US', '1-n', 'ReferencedPathIndex'],\n    '9379': ['SQ', '1', 'MultienergyCTPathSequence'],\n    '937A': ['US', '1', 'MultienergyCTPathIndex'],\n    '937B': ['UT', '1', 'MultienergyAcquisitionDescription'],\n    '937C': ['FD', '1', 'MonoenergeticEnergyEquivalent'],\n    '937D': ['SQ', '1', 'MaterialCodeSequence'],\n    '937E': ['CS', '1', 'DecompositionMethod'],\n    '937F': ['UT', '1', 'DecompositionDescription'],\n    '9380': ['SQ', '1', 'DecompositionAlgorithmIdentificationSequence'],\n    '9381': ['SQ', '1', 'DecompositionMaterialSequence'],\n    '9382': ['SQ', '1', 'MaterialAttenuationSequence'],\n    '9383': ['DS', '1', 'PhotonEnergy'],\n    '9384': ['DS', '1', 'XRayMassAttenuationCoefficient'],\n    '9401': ['SQ', '1', 'ProjectionPixelCalibrationSequence'],\n    '9402': ['FL', '1', 'DistanceSourceToIsocenter'],\n    '9403': ['FL', '1', 'DistanceObjectToTableTop'],\n    '9404': ['FL', '2', 'ObjectPixelSpacingInCenterOfBeam'],\n    '9405': ['SQ', '1', 'PositionerPositionSequence'],\n    '9406': ['SQ', '1', 'TablePositionSequence'],\n    '9407': ['SQ', '1', 'CollimatorShapeSequence'],\n    '9410': ['CS', '1', 'PlanesInAcquisition'],\n    '9412': ['SQ', '1', 'XAXRFFrameCharacteristicsSequence'],\n    '9417': ['SQ', '1', 'FrameAcquisitionSequence'],\n    '9420': ['CS', '1', 'XRayReceptorType'],\n    '9423': ['LO', '1', 'AcquisitionProtocolName'],\n    '9424': ['LT', '1', 'AcquisitionProtocolDescription'],\n    '9425': ['CS', '1', 'ContrastBolusIngredientOpaque'],\n    '9426': ['FL', '1', 'DistanceReceptorPlaneToDetectorHousing'],\n    '9427': ['CS', '1', 'IntensifierActiveShape'],\n    '9428': ['FL', '1-2', 'IntensifierActiveDimensions'],\n    '9429': ['FL', '2', 'PhysicalDetectorSize'],\n    '9430': ['FL', '2', 'PositionOfIsocenterProjection'],\n    '9432': ['SQ', '1', 'FieldOfViewSequence'],\n    '9433': ['LO', '1', 'FieldOfViewDescription'],\n    '9434': ['SQ', '1', 'ExposureControlSensingRegionsSequence'],\n    '9435': ['CS', '1', 'ExposureControlSensingRegionShape'],\n    '9436': ['SS', '1', 'ExposureControlSensingRegionLeftVerticalEdge'],\n    '9437': ['SS', '1', 'ExposureControlSensingRegionRightVerticalEdge'],\n    '9438': ['SS', '1', 'ExposureControlSensingRegionUpperHorizontalEdge'],\n    '9439': ['SS', '1', 'ExposureControlSensingRegionLowerHorizontalEdge'],\n    '9440': ['SS', '2', 'CenterOfCircularExposureControlSensingRegion'],\n    '9441': ['US', '1', 'RadiusOfCircularExposureControlSensingRegion'],\n    '9442': ['SS', '2-n', 'VerticesOfThePolygonalExposureControlSensingRegion'],\n    '9445': ['', '', ''],\n    '9447': ['FL', '1', 'ColumnAngulationPatient'],\n    '9449': ['FL', '1', 'BeamAngle'],\n    '9451': ['SQ', '1', 'FrameDetectorParametersSequence'],\n    '9452': ['FL', '1', 'CalculatedAnatomyThickness'],\n    '9455': ['SQ', '1', 'CalibrationSequence'],\n    '9456': ['SQ', '1', 'ObjectThicknessSequence'],\n    '9457': ['CS', '1', 'PlaneIdentification'],\n    '9461': ['FL', '1-2', 'FieldOfViewDimensionsInFloat'],\n    '9462': ['SQ', '1', 'IsocenterReferenceSystemSequence'],\n    '9463': ['FL', '1', 'PositionerIsocenterPrimaryAngle'],\n    '9464': ['FL', '1', 'PositionerIsocenterSecondaryAngle'],\n    '9465': ['FL', '1', 'PositionerIsocenterDetectorRotationAngle'],\n    '9466': ['FL', '1', 'TableXPositionToIsocenter'],\n    '9467': ['FL', '1', 'TableYPositionToIsocenter'],\n    '9468': ['FL', '1', 'TableZPositionToIsocenter'],\n    '9469': ['FL', '1', 'TableHorizontalRotationAngle'],\n    '9470': ['FL', '1', 'TableHeadTiltAngle'],\n    '9471': ['FL', '1', 'TableCradleTiltAngle'],\n    '9472': ['SQ', '1', 'FrameDisplayShutterSequence'],\n    '9473': ['FL', '1', 'AcquiredImageAreaDoseProduct'],\n    '9474': ['CS', '1', 'CArmPositionerTabletopRelationship'],\n    '9476': ['SQ', '1', 'XRayGeometrySequence'],\n    '9477': ['SQ', '1', 'IrradiationEventIdentificationSequence'],\n    '9504': ['SQ', '1', 'XRay3DFrameTypeSequence'],\n    '9506': ['SQ', '1', 'ContributingSourcesSequence'],\n    '9507': ['SQ', '1', 'XRay3DAcquisitionSequence'],\n    '9508': ['FL', '1', 'PrimaryPositionerScanArc'],\n    '9509': ['FL', '1', 'SecondaryPositionerScanArc'],\n    '9510': ['FL', '1', 'PrimaryPositionerScanStartAngle'],\n    '9511': ['FL', '1', 'SecondaryPositionerScanStartAngle'],\n    '9514': ['FL', '1', 'PrimaryPositionerIncrement'],\n    '9515': ['FL', '1', 'SecondaryPositionerIncrement'],\n    '9516': ['DT', '1', 'StartAcquisitionDateTime'],\n    '9517': ['DT', '1', 'EndAcquisitionDateTime'],\n    '9518': ['SS', '1', 'PrimaryPositionerIncrementSign'],\n    '9519': ['SS', '1', 'SecondaryPositionerIncrementSign'],\n    '9524': ['LO', '1', 'ApplicationName'],\n    '9525': ['LO', '1', 'ApplicationVersion'],\n    '9526': ['LO', '1', 'ApplicationManufacturer'],\n    '9527': ['CS', '1', 'AlgorithmType'],\n    '9528': ['LO', '1', 'AlgorithmDescription'],\n    '9530': ['SQ', '1', 'XRay3DReconstructionSequence'],\n    '9531': ['LO', '1', 'ReconstructionDescription'],\n    '9538': ['SQ', '1', 'PerProjectionAcquisitionSequence'],\n    '9541': ['SQ', '1', 'DetectorPositionSequence'],\n    '9542': ['SQ', '1', 'XRayAcquisitionDoseSequence'],\n    '9543': ['FD', '1', 'XRaySourceIsocenterPrimaryAngle'],\n    '9544': ['FD', '1', 'XRaySourceIsocenterSecondaryAngle'],\n    '9545': ['FD', '1', 'BreastSupportIsocenterPrimaryAngle'],\n    '9546': ['FD', '1', 'BreastSupportIsocenterSecondaryAngle'],\n    '9547': ['FD', '1', 'BreastSupportXPositionToIsocenter'],\n    '9548': ['FD', '1', 'BreastSupportYPositionToIsocenter'],\n    '9549': ['FD', '1', 'BreastSupportZPositionToIsocenter'],\n    '9550': ['FD', '1', 'DetectorIsocenterPrimaryAngle'],\n    '9551': ['FD', '1', 'DetectorIsocenterSecondaryAngle'],\n    '9552': ['FD', '1', 'DetectorXPositionToIsocenter'],\n    '9553': ['FD', '1', 'DetectorYPositionToIsocenter'],\n    '9554': ['FD', '1', 'DetectorZPositionToIsocenter'],\n    '9555': ['SQ', '1', 'XRayGridSequence'],\n    '9556': ['SQ', '1', 'XRayFilterSequence'],\n    '9557': ['FD', '3', 'DetectorActiveAreaTLHCPosition'],\n    '9558': ['FD', '6', 'DetectorActiveAreaOrientation'],\n    '9559': ['CS', '1', 'PositionerPrimaryAngleDirection'],\n    '9601': ['SQ', '1', 'DiffusionBMatrixSequence'],\n    '9602': ['FD', '1', 'DiffusionBValueXX'],\n    '9603': ['FD', '1', 'DiffusionBValueXY'],\n    '9604': ['FD', '1', 'DiffusionBValueXZ'],\n    '9605': ['FD', '1', 'DiffusionBValueYY'],\n    '9606': ['FD', '1', 'DiffusionBValueYZ'],\n    '9607': ['FD', '1', 'DiffusionBValueZZ'],\n    '9621': ['SQ', '1', 'FunctionalMRSequence'],\n    '9622': ['CS', '1', 'FunctionalSettlingPhaseFramesPresent'],\n    '9623': ['DT', '1', 'FunctionalSyncPulse'],\n    '9624': ['CS', '1', 'SettlingPhaseFrame'],\n    '9701': ['DT', '1', 'DecayCorrectionDateTime'],\n    '9715': ['FD', '1', 'StartDensityThreshold'],\n    '9716': ['FD', '1', 'StartRelativeDensityDifferenceThreshold'],\n    '9717': ['FD', '1', 'StartCardiacTriggerCountThreshold'],\n    '9718': ['FD', '1', 'StartRespiratoryTriggerCountThreshold'],\n    '9719': ['FD', '1', 'TerminationCountsThreshold'],\n    '9720': ['FD', '1', 'TerminationDensityThreshold'],\n    '9721': ['FD', '1', 'TerminationRelativeDensityThreshold'],\n    '9722': ['FD', '1', 'TerminationTimeThreshold'],\n    '9723': ['FD', '1', 'TerminationCardiacTriggerCountThreshold'],\n    '9724': ['FD', '1', 'TerminationRespiratoryTriggerCountThreshold'],\n    '9725': ['CS', '1', 'DetectorGeometry'],\n    '9726': ['FD', '1', 'TransverseDetectorSeparation'],\n    '9727': ['FD', '1', 'AxialDetectorDimension'],\n    '9729': ['US', '1', 'RadiopharmaceuticalAgentNumber'],\n    '9732': ['SQ', '1', 'PETFrameAcquisitionSequence'],\n    '9733': ['SQ', '1', 'PETDetectorMotionDetailsSequence'],\n    '9734': ['SQ', '1', 'PETTableDynamicsSequence'],\n    '9735': ['SQ', '1', 'PETPositionSequence'],\n    '9736': ['SQ', '1', 'PETFrameCorrectionFactorsSequence'],\n    '9737': ['SQ', '1', 'RadiopharmaceuticalUsageSequence'],\n    '9738': ['CS', '1', 'AttenuationCorrectionSource'],\n    '9739': ['US', '1', 'NumberOfIterations'],\n    '9740': ['US', '1', 'NumberOfSubsets'],\n    '9749': ['SQ', '1', 'PETReconstructionSequence'],\n    '9751': ['SQ', '1', 'PETFrameTypeSequence'],\n    '9755': ['CS', '1', 'TimeOfFlightInformationUsed'],\n    '9756': ['CS', '1', 'ReconstructionType'],\n    '9758': ['CS', '1', 'DecayCorrected'],\n    '9759': ['CS', '1', 'AttenuationCorrected'],\n    '9760': ['CS', '1', 'ScatterCorrected'],\n    '9761': ['CS', '1', 'DeadTimeCorrected'],\n    '9762': ['CS', '1', 'GantryMotionCorrected'],\n    '9763': ['CS', '1', 'PatientMotionCorrected'],\n    '9764': ['CS', '1', 'CountLossNormalizationCorrected'],\n    '9765': ['CS', '1', 'RandomsCorrected'],\n    '9766': ['CS', '1', 'NonUniformRadialSamplingCorrected'],\n    '9767': ['CS', '1', 'SensitivityCalibrated'],\n    '9768': ['CS', '1', 'DetectorNormalizationCorrection'],\n    '9769': ['CS', '1', 'IterativeReconstructionMethod'],\n    '9770': ['CS', '1', 'AttenuationCorrectionTemporalRelationship'],\n    '9771': ['SQ', '1', 'PatientPhysiologicalStateSequence'],\n    '9772': ['SQ', '1', 'PatientPhysiologicalStateCodeSequence'],\n    '9801': ['FD', '1-n', 'DepthsOfFocus'],\n    '9803': ['SQ', '1', 'ExcludedIntervalsSequence'],\n    '9804': ['DT', '1', 'ExclusionStartDateTime'],\n    '9805': ['FD', '1', 'ExclusionDuration'],\n    '9806': ['SQ', '1', 'USImageDescriptionSequence'],\n    '9807': ['SQ', '1', 'ImageDataTypeSequence'],\n    '9808': ['CS', '1', 'DataType'],\n    '9809': ['SQ', '1', 'TransducerScanPatternCodeSequence'],\n    '980B': ['CS', '1', 'AliasedDataType'],\n    '980C': ['CS', '1', 'PositionMeasuringDeviceUsed'],\n    '980D': ['SQ', '1', 'TransducerGeometryCodeSequence'],\n    '980E': ['SQ', '1', 'TransducerBeamSteeringCodeSequence'],\n    '980F': ['SQ', '1', 'TransducerApplicationCodeSequence'],\n    '9810': ['xs', '1', 'ZeroVelocityPixelValue'],\n    '9900': ['LO', '1', 'ReferenceLocationLabel'],\n    '9901': ['UT', '1', 'ReferenceLocationDescription'],\n    '9902': ['SQ', '1', 'ReferenceBasisCodeSequence'],\n    '9903': ['SQ', '1', 'ReferenceGeometryCodeSequence'],\n    '9904': ['DS', '1', 'OffsetDistance'],\n    '9905': ['CS', '1', 'OffsetDirection'],\n    '9906': ['SQ', '1', 'PotentialScheduledProtocolCodeSequence'],\n    '9907': ['SQ', '1', 'PotentialRequestedProcedureCodeSequence'],\n    '9908': ['UC', '1-n', 'PotentialReasonsForProcedure'],\n    '9909': ['SQ', '1', 'PotentialReasonsForProcedureCodeSequence'],\n    '990A': ['UC', '1-n', 'PotentialDiagnosticTasks'],\n    '990B': ['SQ', '1', 'ContraindicationsCodeSequence'],\n    '990C': ['SQ', '1', 'ReferencedDefinedProtocolSequence'],\n    '990D': ['SQ', '1', 'ReferencedPerformedProtocolSequence'],\n    '990E': ['SQ', '1', 'PredecessorProtocolSequence'],\n    '990F': ['UT', '1', 'ProtocolPlanningInformation'],\n    '9910': ['UT', '1', 'ProtocolDesignRationale'],\n    '9911': ['SQ', '1', 'PatientSpecificationSequence'],\n    '9912': ['SQ', '1', 'ModelSpecificationSequence'],\n    '9913': ['SQ', '1', 'ParametersSpecificationSequence'],\n    '9914': ['SQ', '1', 'InstructionSequence'],\n    '9915': ['US', '1', 'InstructionIndex'],\n    '9916': ['LO', '1', 'InstructionText'],\n    '9917': ['UT', '1', 'InstructionDescription'],\n    '9918': ['CS', '1', 'InstructionPerformedFlag'],\n    '9919': ['DT', '1', 'InstructionPerformedDateTime'],\n    '991A': ['UT', '1', 'InstructionPerformanceComment'],\n    '991B': ['SQ', '1', 'PatientPositioningInstructionSequence'],\n    '991C': ['SQ', '1', 'PositioningMethodCodeSequence'],\n    '991D': ['SQ', '1', 'PositioningLandmarkSequence'],\n    '991E': ['UI', '1', 'TargetFrameOfReferenceUID'],\n    '991F': ['SQ', '1', 'AcquisitionProtocolElementSpecificationSequence'],\n    '9920': ['SQ', '1', 'AcquisitionProtocolElementSequence'],\n    '9921': ['US', '1', 'ProtocolElementNumber'],\n    '9922': ['LO', '1', 'ProtocolElementName'],\n    '9923': ['UT', '1', 'ProtocolElementCharacteristicsSummary'],\n    '9924': ['UT', '1', 'ProtocolElementPurpose'],\n    '9930': ['CS', '1', 'AcquisitionMotion'],\n    '9931': ['SQ', '1', 'AcquisitionStartLocationSequence'],\n    '9932': ['SQ', '1', 'AcquisitionEndLocationSequence'],\n    '9933': ['SQ', '1', 'ReconstructionProtocolElementSpecificationSequence'],\n    '9934': ['SQ', '1', 'ReconstructionProtocolElementSequence'],\n    '9935': ['SQ', '1', 'StorageProtocolElementSpecificationSequence'],\n    '9936': ['SQ', '1', 'StorageProtocolElementSequence'],\n    '9937': ['LO', '1', 'RequestedSeriesDescription'],\n    '9938': ['US', '1-n', 'SourceAcquisitionProtocolElementNumber'],\n    '9939': ['US', '1-n', 'SourceAcquisitionBeamNumber'],\n    '993A': ['US', '1-n', 'SourceReconstructionProtocolElementNumber'],\n    '993B': ['SQ', '1', 'ReconstructionStartLocationSequence'],\n    '993C': ['SQ', '1', 'ReconstructionEndLocationSequence'],\n    '993D': ['SQ', '1', 'ReconstructionAlgorithmSequence'],\n    '993E': ['SQ', '1', 'ReconstructionTargetCenterLocationSequence'],\n    '9941': ['UT', '1', 'ImageFilterDescription'],\n    '9942': ['FD', '1', 'CTDIvolNotificationTrigger'],\n    '9943': ['FD', '1', 'DLPNotificationTrigger'],\n    '9944': ['CS', '1', 'AutoKVPSelectionType'],\n    '9945': ['FD', '1', 'AutoKVPUpperBound'],\n    '9946': ['FD', '1', 'AutoKVPLowerBound'],\n    '9947': ['CS', '1', 'ProtocolDefinedPatientPosition'],\n    'A001': ['SQ', '1', 'ContributingEquipmentSequence'],\n    'A002': ['DT', '1', 'ContributionDateTime'],\n    'A003': ['ST', '1', 'ContributionDescription']\n  },\n  '0020': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '000D': ['UI', '1', 'StudyInstanceUID'],\n    '000E': ['UI', '1', 'SeriesInstanceUID'],\n    '0010': ['SH', '1', 'StudyID'],\n    '0011': ['IS', '1', 'SeriesNumber'],\n    '0012': ['IS', '1', 'AcquisitionNumber'],\n    '0013': ['IS', '1', 'InstanceNumber'],\n    '0014': ['IS', '1', 'IsotopeNumber'],\n    '0015': ['IS', '1', 'PhaseNumber'],\n    '0016': ['IS', '1', 'IntervalNumber'],\n    '0017': ['IS', '1', 'TimeSlotNumber'],\n    '0018': ['IS', '1', 'AngleNumber'],\n    '0019': ['IS', '1', 'ItemNumber'],\n    '0020': ['CS', '2', 'PatientOrientation'],\n    '0022': ['IS', '1', 'OverlayNumber'],\n    '0024': ['IS', '1', 'CurveNumber'],\n    '0026': ['IS', '1', 'LUTNumber'],\n    '0030': ['DS', '3', 'ImagePosition'],\n    '0032': ['DS', '3', 'ImagePositionPatient'],\n    '0035': ['DS', '6', 'ImageOrientation'],\n    '0037': ['DS', '6', 'ImageOrientationPatient'],\n    '0050': ['DS', '1', 'Location'],\n    '0052': ['UI', '1', 'FrameOfReferenceUID'],\n    '0060': ['CS', '1', 'Laterality'],\n    '0062': ['CS', '1', 'ImageLaterality'],\n    '0070': ['LO', '1', 'ImageGeometryType'],\n    '0080': ['CS', '1-n', 'MaskingImage'],\n    '00AA': ['IS', '1', 'ReportNumber'],\n    '0100': ['IS', '1', 'TemporalPositionIdentifier'],\n    '0105': ['IS', '1', 'NumberOfTemporalPositions'],\n    '0110': ['DS', '1', 'TemporalResolution'],\n    '0200': ['UI', '1', 'SynchronizationFrameOfReferenceUID'],\n    '0242': ['UI', '1', 'SOPInstanceUIDOfConcatenationSource'],\n    '1000': ['IS', '1', 'SeriesInStudy'],\n    '1001': ['IS', '1', 'AcquisitionsInSeries'],\n    '1002': ['IS', '1', 'ImagesInAcquisition'],\n    '1003': ['IS', '1', 'ImagesInSeries'],\n    '1004': ['IS', '1', 'AcquisitionsInStudy'],\n    '1005': ['IS', '1', 'ImagesInStudy'],\n    '1020': ['LO', '1-n', 'Reference'],\n    '103F': ['LO', '1', 'TargetPositionReferenceIndicator'],\n    '1040': ['LO', '1', 'PositionReferenceIndicator'],\n    '1041': ['DS', '1', 'SliceLocation'],\n    '1070': ['IS', '1-n', 'OtherStudyNumbers'],\n    '1200': ['IS', '1', 'NumberOfPatientRelatedStudies'],\n    '1202': ['IS', '1', 'NumberOfPatientRelatedSeries'],\n    '1204': ['IS', '1', 'NumberOfPatientRelatedInstances'],\n    '1206': ['IS', '1', 'NumberOfStudyRelatedSeries'],\n    '1208': ['IS', '1', 'NumberOfStudyRelatedInstances'],\n    '1209': ['IS', '1', 'NumberOfSeriesRelatedInstances'],\n    '3100': ['CS', '1-n', 'SourceImageIDs'],\n    '3401': ['CS', '1', 'ModifyingDeviceID'],\n    '3402': ['CS', '1', 'ModifiedImageID'],\n    '3403': ['DA', '1', 'ModifiedImageDate'],\n    '3404': ['LO', '1', 'ModifyingDeviceManufacturer'],\n    '3405': ['TM', '1', 'ModifiedImageTime'],\n    '3406': ['LO', '1', 'ModifiedImageDescription'],\n    '4000': ['LT', '1', 'ImageComments'],\n    '5000': ['AT', '1-n', 'OriginalImageIdentification'],\n    '5002': ['LO', '1-n', 'OriginalImageIdentificationNomenclature'],\n    '9056': ['SH', '1', 'StackID'],\n    '9057': ['UL', '1', 'InStackPositionNumber'],\n    '9071': ['SQ', '1', 'FrameAnatomySequence'],\n    '9072': ['CS', '1', 'FrameLaterality'],\n    '9111': ['SQ', '1', 'FrameContentSequence'],\n    '9113': ['SQ', '1', 'PlanePositionSequence'],\n    '9116': ['SQ', '1', 'PlaneOrientationSequence'],\n    '9128': ['UL', '1', 'TemporalPositionIndex'],\n    '9153': ['FD', '1', 'NominalCardiacTriggerDelayTime'],\n    '9154': ['FL', '1', 'NominalCardiacTriggerTimePriorToRPeak'],\n    '9155': ['FL', '1', 'ActualCardiacTriggerTimePriorToRPeak'],\n    '9156': ['US', '1', 'FrameAcquisitionNumber'],\n    '9157': ['UL', '1-n', 'DimensionIndexValues'],\n    '9158': ['LT', '1', 'FrameComments'],\n    '9161': ['UI', '1', 'ConcatenationUID'],\n    '9162': ['US', '1', 'InConcatenationNumber'],\n    '9163': ['US', '1', 'InConcatenationTotalNumber'],\n    '9164': ['UI', '1', 'DimensionOrganizationUID'],\n    '9165': ['AT', '1', 'DimensionIndexPointer'],\n    '9167': ['AT', '1', 'FunctionalGroupPointer'],\n    '9170': ['SQ', '1', 'UnassignedSharedConvertedAttributesSequence'],\n    '9171': ['SQ', '1', 'UnassignedPerFrameConvertedAttributesSequence'],\n    '9172': ['SQ', '1', 'ConversionSourceAttributesSequence'],\n    '9213': ['LO', '1', 'DimensionIndexPrivateCreator'],\n    '9221': ['SQ', '1', 'DimensionOrganizationSequence'],\n    '9222': ['SQ', '1', 'DimensionIndexSequence'],\n    '9228': ['UL', '1', 'ConcatenationFrameOffsetNumber'],\n    '9238': ['LO', '1', 'FunctionalGroupPrivateCreator'],\n    '9241': ['FL', '1', 'NominalPercentageOfCardiacPhase'],\n    '9245': ['FL', '1', 'NominalPercentageOfRespiratoryPhase'],\n    '9246': ['FL', '1', 'StartingRespiratoryAmplitude'],\n    '9247': ['CS', '1', 'StartingRespiratoryPhase'],\n    '9248': ['FL', '1', 'EndingRespiratoryAmplitude'],\n    '9249': ['CS', '1', 'EndingRespiratoryPhase'],\n    '9250': ['CS', '1', 'RespiratoryTriggerType'],\n    '9251': ['FD', '1', 'RRIntervalTimeNominal'],\n    '9252': ['FD', '1', 'ActualCardiacTriggerDelayTime'],\n    '9253': ['SQ', '1', 'RespiratorySynchronizationSequence'],\n    '9254': ['FD', '1', 'RespiratoryIntervalTime'],\n    '9255': ['FD', '1', 'NominalRespiratoryTriggerDelayTime'],\n    '9256': ['FD', '1', 'RespiratoryTriggerDelayThreshold'],\n    '9257': ['FD', '1', 'ActualRespiratoryTriggerDelayTime'],\n    '9301': ['FD', '3', 'ImagePositionVolume'],\n    '9302': ['FD', '6', 'ImageOrientationVolume'],\n    '9307': ['CS', '1', 'UltrasoundAcquisitionGeometry'],\n    '9308': ['FD', '3', 'ApexPosition'],\n    '9309': ['FD', '16', 'VolumeToTransducerMappingMatrix'],\n    '930A': ['FD', '16', 'VolumeToTableMappingMatrix'],\n    '930B': ['CS', '1', 'VolumeToTransducerRelationship'],\n    '930C': ['CS', '1', 'PatientFrameOfReferenceSource'],\n    '930D': ['FD', '1', 'TemporalPositionTimeOffset'],\n    '930E': ['SQ', '1', 'PlanePositionVolumeSequence'],\n    '930F': ['SQ', '1', 'PlaneOrientationVolumeSequence'],\n    '9310': ['SQ', '1', 'TemporalPositionSequence'],\n    '9311': ['CS', '1', 'DimensionOrganizationType'],\n    '9312': ['UI', '1', 'VolumeFrameOfReferenceUID'],\n    '9313': ['UI', '1', 'TableFrameOfReferenceUID'],\n    '9421': ['LO', '1', 'DimensionDescriptionLabel'],\n    '9450': ['SQ', '1', 'PatientOrientationInFrameSequence'],\n    '9453': ['LO', '1', 'FrameLabel'],\n    '9518': ['US', '1-n', 'AcquisitionIndex'],\n    '9529': ['SQ', '1', 'ContributingSOPInstancesReferenceSequence'],\n    '9536': ['US', '1', 'ReconstructionIndex']\n  },\n  '0022': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['US', '1', 'LightPathFilterPassThroughWavelength'],\n    '0002': ['US', '2', 'LightPathFilterPassBand'],\n    '0003': ['US', '1', 'ImagePathFilterPassThroughWavelength'],\n    '0004': ['US', '2', 'ImagePathFilterPassBand'],\n    '0005': ['CS', '1', 'PatientEyeMovementCommanded'],\n    '0006': ['SQ', '1', 'PatientEyeMovementCommandCodeSequence'],\n    '0007': ['FL', '1', 'SphericalLensPower'],\n    '0008': ['FL', '1', 'CylinderLensPower'],\n    '0009': ['FL', '1', 'CylinderAxis'],\n    '000A': ['FL', '1', 'EmmetropicMagnification'],\n    '000B': ['FL', '1', 'IntraOcularPressure'],\n    '000C': ['FL', '1', 'HorizontalFieldOfView'],\n    '000D': ['CS', '1', 'PupilDilated'],\n    '000E': ['FL', '1', 'DegreeOfDilation'],\n    '0010': ['FL', '1', 'StereoBaselineAngle'],\n    '0011': ['FL', '1', 'StereoBaselineDisplacement'],\n    '0012': ['FL', '1', 'StereoHorizontalPixelOffset'],\n    '0013': ['FL', '1', 'StereoVerticalPixelOffset'],\n    '0014': ['FL', '1', 'StereoRotation'],\n    '0015': ['SQ', '1', 'AcquisitionDeviceTypeCodeSequence'],\n    '0016': ['SQ', '1', 'IlluminationTypeCodeSequence'],\n    '0017': ['SQ', '1', 'LightPathFilterTypeStackCodeSequence'],\n    '0018': ['SQ', '1', 'ImagePathFilterTypeStackCodeSequence'],\n    '0019': ['SQ', '1', 'LensesCodeSequence'],\n    '001A': ['SQ', '1', 'ChannelDescriptionCodeSequence'],\n    '001B': ['SQ', '1', 'RefractiveStateSequence'],\n    '001C': ['SQ', '1', 'MydriaticAgentCodeSequence'],\n    '001D': ['SQ', '1', 'RelativeImagePositionCodeSequence'],\n    '001E': ['FL', '1', 'CameraAngleOfView'],\n    '0020': ['SQ', '1', 'StereoPairsSequence'],\n    '0021': ['SQ', '1', 'LeftImageSequence'],\n    '0022': ['SQ', '1', 'RightImageSequence'],\n    '0028': ['CS', '1', 'StereoPairsPresent'],\n    '0030': ['FL', '1', 'AxialLengthOfTheEye'],\n    '0031': ['SQ', '1', 'OphthalmicFrameLocationSequence'],\n    '0032': ['FL', '2-2n', 'ReferenceCoordinates'],\n    '0035': ['FL', '1', 'DepthSpatialResolution'],\n    '0036': ['FL', '1', 'MaximumDepthDistortion'],\n    '0037': ['FL', '1', 'AlongScanSpatialResolution'],\n    '0038': ['FL', '1', 'MaximumAlongScanDistortion'],\n    '0039': ['CS', '1', 'OphthalmicImageOrientation'],\n    '0041': ['FL', '1', 'DepthOfTransverseImage'],\n    '0042': ['SQ', '1', 'MydriaticAgentConcentrationUnitsSequence'],\n    '0048': ['FL', '1', 'AcrossScanSpatialResolution'],\n    '0049': ['FL', '1', 'MaximumAcrossScanDistortion'],\n    '004E': ['DS', '1', 'MydriaticAgentConcentration'],\n    '0055': ['FL', '1', 'IlluminationWaveLength'],\n    '0056': ['FL', '1', 'IlluminationPower'],\n    '0057': ['FL', '1', 'IlluminationBandwidth'],\n    '0058': ['SQ', '1', 'MydriaticAgentSequence'],\n    '1007': ['SQ', '1', 'OphthalmicAxialMeasurementsRightEyeSequence'],\n    '1008': ['SQ', '1', 'OphthalmicAxialMeasurementsLeftEyeSequence'],\n    '1009': ['CS', '1', 'OphthalmicAxialMeasurementsDeviceType'],\n    '1010': ['CS', '1', 'OphthalmicAxialLengthMeasurementsType'],\n    '1012': ['SQ', '1', 'OphthalmicAxialLengthSequence'],\n    '1019': ['FL', '1', 'OphthalmicAxialLength'],\n    '1024': ['SQ', '1', 'LensStatusCodeSequence'],\n    '1025': ['SQ', '1', 'VitreousStatusCodeSequence'],\n    '1028': ['SQ', '1', 'IOLFormulaCodeSequence'],\n    '1029': ['LO', '1', 'IOLFormulaDetail'],\n    '1033': ['FL', '1', 'KeratometerIndex'],\n    '1035': ['SQ', '1', 'SourceOfOphthalmicAxialLengthCodeSequence'],\n    '1036': ['SQ', '1', 'SourceOfCornealSizeDataCodeSequence'],\n    '1037': ['FL', '1', 'TargetRefraction'],\n    '1039': ['CS', '1', 'RefractiveProcedureOccurred'],\n    '1040': ['SQ', '1', 'RefractiveSurgeryTypeCodeSequence'],\n    '1044': ['SQ', '1', 'OphthalmicUltrasoundMethodCodeSequence'],\n    '1045': ['SQ', '1', 'SurgicallyInducedAstigmatismSequence'],\n    '1046': ['CS', '1', 'TypeOfOpticalCorrection'],\n    '1047': ['SQ', '1', 'ToricIOLPowerSequence'],\n    '1048': ['SQ', '1', 'PredictedToricErrorSequence'],\n    '1049': ['CS', '1', 'PreSelectedForImplantation'],\n    '104A': ['SQ', '1', 'ToricIOLPowerForExactEmmetropiaSequence'],\n    '104B': ['SQ', '1', 'ToricIOLPowerForExactTargetRefractionSequence'],\n    '1050': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSequence'],\n    '1053': ['FL', '1', 'IOLPower'],\n    '1054': ['FL', '1', 'PredictedRefractiveError'],\n    '1059': ['FL', '1', 'OphthalmicAxialLengthVelocity'],\n    '1065': ['LO', '1', 'LensStatusDescription'],\n    '1066': ['LO', '1', 'VitreousStatusDescription'],\n    '1090': ['SQ', '1', 'IOLPowerSequence'],\n    '1092': ['SQ', '1', 'LensConstantSequence'],\n    '1093': ['LO', '1', 'IOLManufacturer'],\n    '1094': ['LO', '1', 'LensConstantDescription'],\n    '1095': ['LO', '1', 'ImplantName'],\n    '1096': ['SQ', '1', 'KeratometryMeasurementTypeCodeSequence'],\n    '1097': ['LO', '1', 'ImplantPartNumber'],\n    '1100': ['SQ', '1', 'ReferencedOphthalmicAxialMeasurementsSequence'],\n    '1101': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSegmentNameCodeSequence'],\n    '1103': ['SQ', '1', 'RefractiveErrorBeforeRefractiveSurgeryCodeSequence'],\n    '1121': ['FL', '1', 'IOLPowerForExactEmmetropia'],\n    '1122': ['FL', '1', 'IOLPowerForExactTargetRefraction'],\n    '1125': ['SQ', '1', 'AnteriorChamberDepthDefinitionCodeSequence'],\n    '1127': ['SQ', '1', 'LensThicknessSequence'],\n    '1128': ['SQ', '1', 'AnteriorChamberDepthSequence'],\n    '112A': ['SQ', '1', 'CalculationCommentSequence'],\n    '112B': ['CS', '1', 'CalculationCommentType'],\n    '112C': ['LT', '1', 'CalculationComment'],\n    '1130': ['FL', '1', 'LensThickness'],\n    '1131': ['FL', '1', 'AnteriorChamberDepth'],\n    '1132': ['SQ', '1', 'SourceOfLensThicknessDataCodeSequence'],\n    '1133': ['SQ', '1', 'SourceOfAnteriorChamberDepthDataCodeSequence'],\n    '1134': ['SQ', '1', 'SourceOfRefractiveMeasurementsSequence'],\n    '1135': ['SQ', '1', 'SourceOfRefractiveMeasurementsCodeSequence'],\n    '1140': ['CS', '1', 'OphthalmicAxialLengthMeasurementModified'],\n    '1150': ['SQ', '1', 'OphthalmicAxialLengthDataSourceCodeSequence'],\n    '1153': ['SQ', '1', 'OphthalmicAxialLengthAcquisitionMethodCodeSequence'],\n    '1155': ['FL', '1', 'SignalToNoiseRatio'],\n    '1159': ['LO', '1', 'OphthalmicAxialLengthDataSourceDescription'],\n    '1210': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsTotalLengthSequence'],\n    '1211': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsSegmentalLengthSequence'],\n    '1212': ['SQ', '1', 'OphthalmicAxialLengthMeasurementsLengthSummationSequence'],\n    '1220': ['SQ', '1', 'UltrasoundOphthalmicAxialLengthMeasurementsSequence'],\n    '1225': ['SQ', '1', 'OpticalOphthalmicAxialLengthMeasurementsSequence'],\n    '1230': ['SQ', '1', 'UltrasoundSelectedOphthalmicAxialLengthSequence'],\n    '1250': ['SQ', '1', 'OphthalmicAxialLengthSelectionMethodCodeSequence'],\n    '1255': ['SQ', '1', 'OpticalSelectedOphthalmicAxialLengthSequence'],\n    '1257': ['SQ', '1', 'SelectedSegmentalOphthalmicAxialLengthSequence'],\n    '1260': ['SQ', '1', 'SelectedTotalOphthalmicAxialLengthSequence'],\n    '1262': ['SQ', '1', 'OphthalmicAxialLengthQualityMetricSequence'],\n    '1265': ['SQ', '1', 'OphthalmicAxialLengthQualityMetricTypeCodeSequence'],\n    '1273': ['LO', '1', 'OphthalmicAxialLengthQualityMetricTypeDescription'],\n    '1300': ['SQ', '1', 'IntraocularLensCalculationsRightEyeSequence'],\n    '1310': ['SQ', '1', 'IntraocularLensCalculationsLeftEyeSequence'],\n    '1330': ['SQ', '1', 'ReferencedOphthalmicAxialLengthMeasurementQCImageSequence'],\n    '1415': ['CS', '1', 'OphthalmicMappingDeviceType'],\n    '1420': ['SQ', '1', 'AcquisitionMethodCodeSequence'],\n    '1423': ['SQ', '1', 'AcquisitionMethodAlgorithmSequence'],\n    '1436': ['SQ', '1', 'OphthalmicThicknessMapTypeCodeSequence'],\n    '1443': ['SQ', '1', 'OphthalmicThicknessMappingNormalsSequence'],\n    '1445': ['SQ', '1', 'RetinalThicknessDefinitionCodeSequence'],\n    '1450': ['SQ', '1', 'PixelValueMappingToCodedConceptSequence'],\n    '1452': ['xs', '1', 'MappedPixelValue'],\n    '1454': ['LO', '1', 'PixelValueMappingExplanation'],\n    '1458': ['SQ', '1', 'OphthalmicThicknessMapQualityThresholdSequence'],\n    '1460': ['FL', '1', 'OphthalmicThicknessMapThresholdQualityRating'],\n    '1463': ['FL', '2', 'AnatomicStructureReferencePoint'],\n    '1465': ['SQ', '1', 'RegistrationToLocalizerSequence'],\n    '1466': ['CS', '1', 'RegisteredLocalizerUnits'],\n    '1467': ['FL', '2', 'RegisteredLocalizerTopLeftHandCorner'],\n    '1468': ['FL', '2', 'RegisteredLocalizerBottomRightHandCorner'],\n    '1470': ['SQ', '1', 'OphthalmicThicknessMapQualityRatingSequence'],\n    '1472': ['SQ', '1', 'RelevantOPTAttributesSequence'],\n    '1512': ['SQ', '1', 'TransformationMethodCodeSequence'],\n    '1513': ['SQ', '1', 'TransformationAlgorithmSequence'],\n    '1515': ['CS', '1', 'OphthalmicAxialLengthMethod'],\n    '1517': ['FL', '1', 'OphthalmicFOV'],\n    '1518': ['SQ', '1', 'TwoDimensionalToThreeDimensionalMapSequence'],\n    '1525': ['SQ', '1', 'WideFieldOphthalmicPhotographyQualityRatingSequence'],\n    '1526': ['SQ', '1', 'WideFieldOphthalmicPhotographyQualityThresholdSequence'],\n    '1527': ['FL', '1', 'WideFieldOphthalmicPhotographyThresholdQualityRating'],\n    '1528': ['FL', '1', 'XCoordinatesCenterPixelViewAngle'],\n    '1529': ['FL', '1', 'YCoordinatesCenterPixelViewAngle'],\n    '1530': ['UL', '1', 'NumberOfMapPoints'],\n    '1531': ['OF', '1', 'TwoDimensionalToThreeDimensionalMapData'],\n    '1612': ['SQ', '1', 'DerivationAlgorithmSequence'],\n    '1615': ['SQ', '1', 'OphthalmicImageTypeCodeSequence'],\n    '1616': ['LO', '1', 'OphthalmicImageTypeDescription'],\n    '1618': ['SQ', '1', 'ScanPatternTypeCodeSequence'],\n    '1620': ['SQ', '1', 'ReferencedSurfaceMeshIdentificationSequence'],\n    '1622': ['CS', '1', 'OphthalmicVolumetricPropertiesFlag'],\n    '1624': ['FL', '1', 'OphthalmicAnatomicReferencePointXCoordinate'],\n    '1626': ['FL', '1', 'OphthalmicAnatomicReferencePointYCoordinate'],\n    '1628': ['SQ', '1', 'OphthalmicEnFaceImageQualityRatingSequence'],\n    '1630': ['DS', '1', 'QualityThreshold'],\n    '1640': ['SQ', '1', 'OCTBscanAnalysisAcquisitionParametersSequence'],\n    '1642': ['UL', '1', 'NumberOfBscansPerFrame'],\n    '1643': ['FL', '1', 'BscanSlabThickness'],\n    '1644': ['FL', '1', 'DistanceBetweenBscanSlabs'],\n    '1645': ['FL', '1', 'BscanCycleTime'],\n    '1646': ['FL', '1-n', 'BscanCycleTimeVector'],\n    '1649': ['FL', '1', 'AscanRate'],\n    '1650': ['FL', '1', 'BscanRate'],\n    '1658': ['UL', '1', 'SurfaceMeshZPixelOffset']\n  },\n  '0024': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['FL', '1', 'VisualFieldHorizontalExtent'],\n    '0011': ['FL', '1', 'VisualFieldVerticalExtent'],\n    '0012': ['CS', '1', 'VisualFieldShape'],\n    '0016': ['SQ', '1', 'ScreeningTestModeCodeSequence'],\n    '0018': ['FL', '1', 'MaximumStimulusLuminance'],\n    '0020': ['FL', '1', 'BackgroundLuminance'],\n    '0021': ['SQ', '1', 'StimulusColorCodeSequence'],\n    '0024': ['SQ', '1', 'BackgroundIlluminationColorCodeSequence'],\n    '0025': ['FL', '1', 'StimulusArea'],\n    '0028': ['FL', '1', 'StimulusPresentationTime'],\n    '0032': ['SQ', '1', 'FixationSequence'],\n    '0033': ['SQ', '1', 'FixationMonitoringCodeSequence'],\n    '0034': ['SQ', '1', 'VisualFieldCatchTrialSequence'],\n    '0035': ['US', '1', 'FixationCheckedQuantity'],\n    '0036': ['US', '1', 'PatientNotProperlyFixatedQuantity'],\n    '0037': ['CS', '1', 'PresentedVisualStimuliDataFlag'],\n    '0038': ['US', '1', 'NumberOfVisualStimuli'],\n    '0039': ['CS', '1', 'ExcessiveFixationLossesDataFlag'],\n    '0040': ['CS', '1', 'ExcessiveFixationLosses'],\n    '0042': ['US', '1', 'StimuliRetestingQuantity'],\n    '0044': ['LT', '1', 'CommentsOnPatientPerformanceOfVisualField'],\n    '0045': ['CS', '1', 'FalseNegativesEstimateFlag'],\n    '0046': ['FL', '1', 'FalseNegativesEstimate'],\n    '0048': ['US', '1', 'NegativeCatchTrialsQuantity'],\n    '0050': ['US', '1', 'FalseNegativesQuantity'],\n    '0051': ['CS', '1', 'ExcessiveFalseNegativesDataFlag'],\n    '0052': ['CS', '1', 'ExcessiveFalseNegatives'],\n    '0053': ['CS', '1', 'FalsePositivesEstimateFlag'],\n    '0054': ['FL', '1', 'FalsePositivesEstimate'],\n    '0055': ['CS', '1', 'CatchTrialsDataFlag'],\n    '0056': ['US', '1', 'PositiveCatchTrialsQuantity'],\n    '0057': ['CS', '1', 'TestPointNormalsDataFlag'],\n    '0058': ['SQ', '1', 'TestPointNormalsSequence'],\n    '0059': ['CS', '1', 'GlobalDeviationProbabilityNormalsFlag'],\n    '0060': ['US', '1', 'FalsePositivesQuantity'],\n    '0061': ['CS', '1', 'ExcessiveFalsePositivesDataFlag'],\n    '0062': ['CS', '1', 'ExcessiveFalsePositives'],\n    '0063': ['CS', '1', 'VisualFieldTestNormalsFlag'],\n    '0064': ['SQ', '1', 'ResultsNormalsSequence'],\n    '0065': ['SQ', '1', 'AgeCorrectedSensitivityDeviationAlgorithmSequence'],\n    '0066': ['FL', '1', 'GlobalDeviationFromNormal'],\n    '0067': ['SQ', '1', 'GeneralizedDefectSensitivityDeviationAlgorithmSequence'],\n    '0068': ['FL', '1', 'LocalizedDeviationFromNormal'],\n    '0069': ['LO', '1', 'PatientReliabilityIndicator'],\n    '0070': ['FL', '1', 'VisualFieldMeanSensitivity'],\n    '0071': ['FL', '1', 'GlobalDeviationProbability'],\n    '0072': ['CS', '1', 'LocalDeviationProbabilityNormalsFlag'],\n    '0073': ['FL', '1', 'LocalizedDeviationProbability'],\n    '0074': ['CS', '1', 'ShortTermFluctuationCalculated'],\n    '0075': ['FL', '1', 'ShortTermFluctuation'],\n    '0076': ['CS', '1', 'ShortTermFluctuationProbabilityCalculated'],\n    '0077': ['FL', '1', 'ShortTermFluctuationProbability'],\n    '0078': ['CS', '1', 'CorrectedLocalizedDeviationFromNormalCalculated'],\n    '0079': ['FL', '1', 'CorrectedLocalizedDeviationFromNormal'],\n    '0080': ['CS', '1', 'CorrectedLocalizedDeviationFromNormalProbabilityCalculated'],\n    '0081': ['FL', '1', 'CorrectedLocalizedDeviationFromNormalProbability'],\n    '0083': ['SQ', '1', 'GlobalDeviationProbabilitySequence'],\n    '0085': ['SQ', '1', 'LocalizedDeviationProbabilitySequence'],\n    '0086': ['CS', '1', 'FovealSensitivityMeasured'],\n    '0087': ['FL', '1', 'FovealSensitivity'],\n    '0088': ['FL', '1', 'VisualFieldTestDuration'],\n    '0089': ['SQ', '1', 'VisualFieldTestPointSequence'],\n    '0090': ['FL', '1', 'VisualFieldTestPointXCoordinate'],\n    '0091': ['FL', '1', 'VisualFieldTestPointYCoordinate'],\n    '0092': ['FL', '1', 'AgeCorrectedSensitivityDeviationValue'],\n    '0093': ['CS', '1', 'StimulusResults'],\n    '0094': ['FL', '1', 'SensitivityValue'],\n    '0095': ['CS', '1', 'RetestStimulusSeen'],\n    '0096': ['FL', '1', 'RetestSensitivityValue'],\n    '0097': ['SQ', '1', 'VisualFieldTestPointNormalsSequence'],\n    '0098': ['FL', '1', 'QuantifiedDefect'],\n    '0100': ['FL', '1', 'AgeCorrectedSensitivityDeviationProbabilityValue'],\n    '0102': ['CS', '1', 'GeneralizedDefectCorrectedSensitivityDeviationFlag'],\n    '0103': ['FL', '1', 'GeneralizedDefectCorrectedSensitivityDeviationValue'],\n    '0104': ['FL', '1', 'GeneralizedDefectCorrectedSensitivityDeviationProbabilityValue'],\n    '0105': ['FL', '1', 'MinimumSensitivityValue'],\n    '0106': ['CS', '1', 'BlindSpotLocalized'],\n    '0107': ['FL', '1', 'BlindSpotXCoordinate'],\n    '0108': ['FL', '1', 'BlindSpotYCoordinate'],\n    '0110': ['SQ', '1', 'VisualAcuityMeasurementSequence'],\n    '0112': ['SQ', '1', 'RefractiveParametersUsedOnPatientSequence'],\n    '0113': ['CS', '1', 'MeasurementLaterality'],\n    '0114': ['SQ', '1', 'OphthalmicPatientClinicalInformationLeftEyeSequence'],\n    '0115': ['SQ', '1', 'OphthalmicPatientClinicalInformationRightEyeSequence'],\n    '0117': ['CS', '1', 'FovealPointNormativeDataFlag'],\n    '0118': ['FL', '1', 'FovealPointProbabilityValue'],\n    '0120': ['CS', '1', 'ScreeningBaselineMeasured'],\n    '0122': ['SQ', '1', 'ScreeningBaselineMeasuredSequence'],\n    '0124': ['CS', '1', 'ScreeningBaselineType'],\n    '0126': ['FL', '1', 'ScreeningBaselineValue'],\n    '0202': ['LO', '1', 'AlgorithmSource'],\n    '0306': ['LO', '1', 'DataSetName'],\n    '0307': ['LO', '1', 'DataSetVersion'],\n    '0308': ['LO', '1', 'DataSetSource'],\n    '0309': ['LO', '1', 'DataSetDescription'],\n    '0317': ['SQ', '1', 'VisualFieldTestReliabilityGlobalIndexSequence'],\n    '0320': ['SQ', '1', 'VisualFieldGlobalResultsIndexSequence'],\n    '0325': ['SQ', '1', 'DataObservationSequence'],\n    '0338': ['CS', '1', 'IndexNormalsFlag'],\n    '0341': ['FL', '1', 'IndexProbability'],\n    '0344': ['SQ', '1', 'IndexProbabilitySequence']\n  },\n  '0028': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['US', '1', 'SamplesPerPixel'],\n    '0003': ['US', '1', 'SamplesPerPixelUsed'],\n    '0004': ['CS', '1', 'PhotometricInterpretation'],\n    '0005': ['US', '1', 'ImageDimensions'],\n    '0006': ['US', '1', 'PlanarConfiguration'],\n    '0008': ['IS', '1', 'NumberOfFrames'],\n    '0009': ['AT', '1-n', 'FrameIncrementPointer'],\n    '000A': ['AT', '1-n', 'FrameDimensionPointer'],\n    '0010': ['US', '1', 'Rows'],\n    '0011': ['US', '1', 'Columns'],\n    '0012': ['US', '1', 'Planes'],\n    '0014': ['US', '1', 'UltrasoundColorDataPresent'],\n    '0020': ['', '', ''],\n    '0030': ['DS', '2', 'PixelSpacing'],\n    '0031': ['DS', '2', 'ZoomFactor'],\n    '0032': ['DS', '2', 'ZoomCenter'],\n    '0034': ['IS', '2', 'PixelAspectRatio'],\n    '0040': ['CS', '1', 'ImageFormat'],\n    '0050': ['LO', '1-n', 'ManipulatedImage'],\n    '0051': ['CS', '1-n', 'CorrectedImage'],\n    '005F': ['LO', '1', 'CompressionRecognitionCode'],\n    '0060': ['CS', '1', 'CompressionCode'],\n    '0061': ['SH', '1', 'CompressionOriginator'],\n    '0062': ['LO', '1', 'CompressionLabel'],\n    '0063': ['SH', '1', 'CompressionDescription'],\n    '0065': ['CS', '1-n', 'CompressionSequence'],\n    '0066': ['AT', '1-n', 'CompressionStepPointers'],\n    '0068': ['US', '1', 'RepeatInterval'],\n    '0069': ['US', '1', 'BitsGrouped'],\n    '0070': ['US', '1-n', 'PerimeterTable'],\n    '0071': ['xs', '1', 'PerimeterValue'],\n    '0080': ['US', '1', 'PredictorRows'],\n    '0081': ['US', '1', 'PredictorColumns'],\n    '0082': ['US', '1-n', 'PredictorConstants'],\n    '0090': ['CS', '1', 'BlockedPixels'],\n    '0091': ['US', '1', 'BlockRows'],\n    '0092': ['US', '1', 'BlockColumns'],\n    '0093': ['US', '1', 'RowOverlap'],\n    '0094': ['US', '1', 'ColumnOverlap'],\n    '0100': ['US', '1', 'BitsAllocated'],\n    '0101': ['US', '1', 'BitsStored'],\n    '0102': ['US', '1', 'HighBit'],\n    '0103': ['US', '1', 'PixelRepresentation'],\n    '0104': ['xs', '1', 'SmallestValidPixelValue'],\n    '0105': ['xs', '1', 'LargestValidPixelValue'],\n    '0106': ['xs', '1', 'SmallestImagePixelValue'],\n    '0107': ['xs', '1', 'LargestImagePixelValue'],\n    '0108': ['xs', '1', 'SmallestPixelValueInSeries'],\n    '0109': ['xs', '1', 'LargestPixelValueInSeries'],\n    '0110': ['xs', '1', 'SmallestImagePixelValueInPlane'],\n    '0111': ['xs', '1', 'LargestImagePixelValueInPlane'],\n    '0120': ['xs', '1', 'PixelPaddingValue'],\n    '0121': ['xs', '1', 'PixelPaddingRangeLimit'],\n    '0122': ['FL', '1', 'FloatPixelPaddingValue'],\n    '0123': ['FD', '1', 'DoubleFloatPixelPaddingValue'],\n    '0124': ['FL', '1', 'FloatPixelPaddingRangeLimit'],\n    '0125': ['FD', '1', 'DoubleFloatPixelPaddingRangeLimit'],\n    '0200': ['US', '1', 'ImageLocation'],\n    '0300': ['CS', '1', 'QualityControlImage'],\n    '0301': ['CS', '1', 'BurnedInAnnotation'],\n    '0302': ['CS', '1', 'RecognizableVisualFeatures'],\n    '0303': ['CS', '1', 'LongitudinalTemporalInformationModified'],\n    '0304': ['UI', '1', 'ReferencedColorPaletteInstanceUID'],\n    '0400': ['LO', '1', 'TransformLabel'],\n    '0401': ['LO', '1', 'TransformVersionNumber'],\n    '0402': ['US', '1', 'NumberOfTransformSteps'],\n    '0403': ['LO', '1-n', 'SequenceOfCompressedData'],\n    '0404': ['AT', '1-n', 'DetailsOfCoefficients'],\n    '04x0': ['US', '1', 'RowsForNthOrderCoefficients'],\n    '04x1': ['US', '1', 'ColumnsForNthOrderCoefficients'],\n    '04x2': ['LO', '1-n', 'CoefficientCoding'],\n    '04x3': ['AT', '1-n', 'CoefficientCodingPointers'],\n    '0700': ['LO', '1', 'DCTLabel'],\n    '0701': ['CS', '1-n', 'DataBlockDescription'],\n    '0702': ['AT', '1-n', 'DataBlock'],\n    '0710': ['US', '1', 'NormalizationFactorFormat'],\n    '0720': ['US', '1', 'ZonalMapNumberFormat'],\n    '0721': ['AT', '1-n', 'ZonalMapLocation'],\n    '0722': ['US', '1', 'ZonalMapFormat'],\n    '0730': ['US', '1', 'AdaptiveMapFormat'],\n    '0740': ['US', '1', 'CodeNumberFormat'],\n    '08x0': ['CS', '1-n', 'CodeLabel'],\n    '08x2': ['US', '1', 'NumberOfTables'],\n    '08x3': ['AT', '1-n', 'CodeTableLocation'],\n    '08x4': ['US', '1', 'BitsForCodeWord'],\n    '08x8': ['AT', '1-n', 'ImageDataLocation'],\n    '0A02': ['CS', '1', 'PixelSpacingCalibrationType'],\n    '0A04': ['LO', '1', 'PixelSpacingCalibrationDescription'],\n    '1040': ['CS', '1', 'PixelIntensityRelationship'],\n    '1041': ['SS', '1', 'PixelIntensityRelationshipSign'],\n    '1050': ['DS', '1-n', 'WindowCenter'],\n    '1051': ['DS', '1-n', 'WindowWidth'],\n    '1052': ['DS', '1', 'RescaleIntercept'],\n    '1053': ['DS', '1', 'RescaleSlope'],\n    '1054': ['LO', '1', 'RescaleType'],\n    '1055': ['LO', '1-n', 'WindowCenterWidthExplanation'],\n    '1056': ['CS', '1', 'VOILUTFunction'],\n    '1080': ['CS', '1', 'GrayScale'],\n    '1090': ['CS', '1', 'RecommendedViewingMode'],\n    '1100': ['xs', '3', 'GrayLookupTableDescriptor'],\n    '1101': ['xs', '3', 'RedPaletteColorLookupTableDescriptor'],\n    '1102': ['xs', '3', 'GreenPaletteColorLookupTableDescriptor'],\n    '1103': ['xs', '3', 'BluePaletteColorLookupTableDescriptor'],\n    '1104': ['US', '3', 'AlphaPaletteColorLookupTableDescriptor'],\n    '1111': ['xs', '4', 'LargeRedPaletteColorLookupTableDescriptor'],\n    '1112': ['xs', '4', 'LargeGreenPaletteColorLookupTableDescriptor'],\n    '1113': ['xs', '4', 'LargeBluePaletteColorLookupTableDescriptor'],\n    '1199': ['UI', '1', 'PaletteColorLookupTableUID'],\n    '1200': ['xs', '1-n or 1', 'GrayLookupTableData'],\n    '1201': ['OW', '1', 'RedPaletteColorLookupTableData'],\n    '1202': ['OW', '1', 'GreenPaletteColorLookupTableData'],\n    '1203': ['OW', '1', 'BluePaletteColorLookupTableData'],\n    '1204': ['OW', '1', 'AlphaPaletteColorLookupTableData'],\n    '1211': ['OW', '1', 'LargeRedPaletteColorLookupTableData'],\n    '1212': ['OW', '1', 'LargeGreenPaletteColorLookupTableData'],\n    '1213': ['OW', '1', 'LargeBluePaletteColorLookupTableData'],\n    '1214': ['UI', '1', 'LargePaletteColorLookupTableUID'],\n    '1221': ['OW', '1', 'SegmentedRedPaletteColorLookupTableData'],\n    '1222': ['OW', '1', 'SegmentedGreenPaletteColorLookupTableData'],\n    '1223': ['OW', '1', 'SegmentedBluePaletteColorLookupTableData'],\n    '1224': ['OW', '1', 'SegmentedAlphaPaletteColorLookupTableData'],\n    '1230': ['SQ', '1', 'StoredValueColorRangeSequence'],\n    '1231': ['FD', '1', 'MinimumStoredValueMapped'],\n    '1232': ['FD', '1', 'MaximumStoredValueMapped'],\n    '1300': ['CS', '1', 'BreastImplantPresent'],\n    '1350': ['CS', '1', 'PartialView'],\n    '1351': ['ST', '1', 'PartialViewDescription'],\n    '1352': ['SQ', '1', 'PartialViewCodeSequence'],\n    '135A': ['CS', '1', 'SpatialLocationsPreserved'],\n    '1401': ['SQ', '1', 'DataFrameAssignmentSequence'],\n    '1402': ['CS', '1', 'DataPathAssignment'],\n    '1403': ['US', '1', 'BitsMappedToColorLookupTable'],\n    '1404': ['SQ', '1', 'BlendingLUT1Sequence'],\n    '1405': ['CS', '1', 'BlendingLUT1TransferFunction'],\n    '1406': ['FD', '1', 'BlendingWeightConstant'],\n    '1407': ['US', '3', 'BlendingLookupTableDescriptor'],\n    '1408': ['OW', '1', 'BlendingLookupTableData'],\n    '140B': ['SQ', '1', 'EnhancedPaletteColorLookupTableSequence'],\n    '140C': ['SQ', '1', 'BlendingLUT2Sequence'],\n    '140D': ['CS', '1', 'BlendingLUT2TransferFunction'],\n    '140E': ['CS', '1', 'DataPathID'],\n    '140F': ['CS', '1', 'RGBLUTTransferFunction'],\n    '1410': ['CS', '1', 'AlphaLUTTransferFunction'],\n    '2000': ['OB', '1', 'ICCProfile'],\n    '2002': ['CS', '1', 'ColorSpace'],\n    '2110': ['CS', '1', 'LossyImageCompression'],\n    '2112': ['DS', '1-n', 'LossyImageCompressionRatio'],\n    '2114': ['CS', '1-n', 'LossyImageCompressionMethod'],\n    '3000': ['SQ', '1', 'ModalityLUTSequence'],\n    '3002': ['xs', '3', 'LUTDescriptor'],\n    '3003': ['LO', '1', 'LUTExplanation'],\n    '3004': ['LO', '1', 'ModalityLUTType'],\n    '3006': ['xx', '1-n or 1', 'LUTData'],\n    '3010': ['SQ', '1', 'VOILUTSequence'],\n    '3110': ['SQ', '1', 'SoftcopyVOILUTSequence'],\n    '4000': ['LT', '1', 'ImagePresentationComments'],\n    '5000': ['SQ', '1', 'BiPlaneAcquisitionSequence'],\n    '6010': ['US', '1', 'RepresentativeFrameNumber'],\n    '6020': ['US', '1-n', 'FrameNumbersOfInterest'],\n    '6022': ['LO', '1-n', 'FrameOfInterestDescription'],\n    '6023': ['CS', '1-n', 'FrameOfInterestType'],\n    '6030': ['US', '1-n', 'MaskPointers'],\n    '6040': ['US', '1-n', 'RWavePointer'],\n    '6100': ['SQ', '1', 'MaskSubtractionSequence'],\n    '6101': ['CS', '1', 'MaskOperation'],\n    '6102': ['US', '2-2n', 'ApplicableFrameRange'],\n    '6110': ['US', '1-n', 'MaskFrameNumbers'],\n    '6112': ['US', '1', 'ContrastFrameAveraging'],\n    '6114': ['FL', '2', 'MaskSubPixelShift'],\n    '6120': ['SS', '1', 'TIDOffset'],\n    '6190': ['ST', '1', 'MaskOperationExplanation'],\n    '7000': ['SQ', '1', 'EquipmentAdministratorSequence'],\n    '7001': ['US', '1', 'NumberOfDisplaySubsystems'],\n    '7002': ['US', '1', 'CurrentConfigurationID'],\n    '7003': ['US', '1', 'DisplaySubsystemID'],\n    '7004': ['SH', '1', 'DisplaySubsystemName'],\n    '7005': ['LO', '1', 'DisplaySubsystemDescription'],\n    '7006': ['CS', '1', 'SystemStatus'],\n    '7007': ['LO', '1', 'SystemStatusComment'],\n    '7008': ['SQ', '1', 'TargetLuminanceCharacteristicsSequence'],\n    '7009': ['US', '1', 'LuminanceCharacteristicsID'],\n    '700A': ['SQ', '1', 'DisplaySubsystemConfigurationSequence'],\n    '700B': ['US', '1', 'ConfigurationID'],\n    '700C': ['SH', '1', 'ConfigurationName'],\n    '700D': ['LO', '1', 'ConfigurationDescription'],\n    '700E': ['US', '1', 'ReferencedTargetLuminanceCharacteristicsID'],\n    '700F': ['SQ', '1', 'QAResultsSequence'],\n    '7010': ['SQ', '1', 'DisplaySubsystemQAResultsSequence'],\n    '7011': ['SQ', '1', 'ConfigurationQAResultsSequence'],\n    '7012': ['SQ', '1', 'MeasurementEquipmentSequence'],\n    '7013': ['CS', '1-n', 'MeasurementFunctions'],\n    '7014': ['CS', '1', 'MeasurementEquipmentType'],\n    '7015': ['SQ', '1', 'VisualEvaluationResultSequence'],\n    '7016': ['SQ', '1', 'DisplayCalibrationResultSequence'],\n    '7017': ['US', '1', 'DDLValue'],\n    '7018': ['FL', '2', 'CIExyWhitePoint'],\n    '7019': ['CS', '1', 'DisplayFunctionType'],\n    '701A': ['FL', '1', 'GammaValue'],\n    '701B': ['US', '1', 'NumberOfLuminancePoints'],\n    '701C': ['SQ', '1', 'LuminanceResponseSequence'],\n    '701D': ['FL', '1', 'TargetMinimumLuminance'],\n    '701E': ['FL', '1', 'TargetMaximumLuminance'],\n    '701F': ['FL', '1', 'LuminanceValue'],\n    '7020': ['LO', '1', 'LuminanceResponseDescription'],\n    '7021': ['CS', '1', 'WhitePointFlag'],\n    '7022': ['SQ', '1', 'DisplayDeviceTypeCodeSequence'],\n    '7023': ['SQ', '1', 'DisplaySubsystemSequence'],\n    '7024': ['SQ', '1', 'LuminanceResultSequence'],\n    '7025': ['CS', '1', 'AmbientLightValueSource'],\n    '7026': ['CS', '1-n', 'MeasuredCharacteristics'],\n    '7027': ['SQ', '1', 'LuminanceUniformityResultSequence'],\n    '7028': ['SQ', '1', 'VisualEvaluationTestSequence'],\n    '7029': ['CS', '1', 'TestResult'],\n    '702A': ['LO', '1', 'TestResultComment'],\n    '702B': ['CS', '1', 'TestImageValidation'],\n    '702C': ['SQ', '1', 'TestPatternCodeSequence'],\n    '702D': ['SQ', '1', 'MeasurementPatternCodeSequence'],\n    '702E': ['SQ', '1', 'VisualEvaluationMethodCodeSequence'],\n    '7FE0': ['UR', '1', 'PixelDataProviderURL'],\n    '9001': ['UL', '1', 'DataPointRows'],\n    '9002': ['UL', '1', 'DataPointColumns'],\n    '9003': ['CS', '1', 'SignalDomainColumns'],\n    '9099': ['US', '1', 'LargestMonochromePixelValue'],\n    '9108': ['CS', '1', 'DataRepresentation'],\n    '9110': ['SQ', '1', 'PixelMeasuresSequence'],\n    '9132': ['SQ', '1', 'FrameVOILUTSequence'],\n    '9145': ['SQ', '1', 'PixelValueTransformationSequence'],\n    '9235': ['CS', '1', 'SignalDomainRows'],\n    '9411': ['FL', '1', 'DisplayFilterPercentage'],\n    '9415': ['SQ', '1', 'FramePixelShiftSequence'],\n    '9416': ['US', '1', 'SubtractionItemID'],\n    '9422': ['SQ', '1', 'PixelIntensityRelationshipLUTSequence'],\n    '9443': ['SQ', '1', 'FramePixelDataPropertiesSequence'],\n    '9444': ['CS', '1', 'GeometricalProperties'],\n    '9445': ['FL', '1', 'GeometricMaximumDistortion'],\n    '9446': ['CS', '1-n', 'ImageProcessingApplied'],\n    '9454': ['CS', '1', 'MaskSelectionMode'],\n    '9474': ['CS', '1', 'LUTFunction'],\n    '9478': ['FL', '1', 'MaskVisibilityPercentage'],\n    '9501': ['SQ', '1', 'PixelShiftSequence'],\n    '9502': ['SQ', '1', 'RegionPixelShiftSequence'],\n    '9503': ['SS', '2-2n', 'VerticesOfTheRegion'],\n    '9505': ['SQ', '1', 'MultiFramePresentationSequence'],\n    '9506': ['US', '2-2n', 'PixelShiftFrameRange'],\n    '9507': ['US', '2-2n', 'LUTFrameRange'],\n    '9520': ['DS', '16', 'ImageToEquipmentMappingMatrix'],\n    '9537': ['CS', '1', 'EquipmentCoordinateSystemIdentification']\n  },\n  '0032': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '000A': ['CS', '1', 'StudyStatusID'],\n    '000C': ['CS', '1', 'StudyPriorityID'],\n    '0012': ['LO', '1', 'StudyIDIssuer'],\n    '0032': ['DA', '1', 'StudyVerifiedDate'],\n    '0033': ['TM', '1', 'StudyVerifiedTime'],\n    '0034': ['DA', '1', 'StudyReadDate'],\n    '0035': ['TM', '1', 'StudyReadTime'],\n    '1000': ['DA', '1', 'ScheduledStudyStartDate'],\n    '1001': ['TM', '1', 'ScheduledStudyStartTime'],\n    '1010': ['DA', '1', 'ScheduledStudyStopDate'],\n    '1011': ['TM', '1', 'ScheduledStudyStopTime'],\n    '1020': ['LO', '1', 'ScheduledStudyLocation'],\n    '1021': ['AE', '1-n', 'ScheduledStudyLocationAETitle'],\n    '1030': ['LO', '1', 'ReasonForStudy'],\n    '1031': ['SQ', '1', 'RequestingPhysicianIdentificationSequence'],\n    '1032': ['PN', '1', 'RequestingPhysician'],\n    '1033': ['LO', '1', 'RequestingService'],\n    '1034': ['SQ', '1', 'RequestingServiceCodeSequence'],\n    '1040': ['DA', '1', 'StudyArrivalDate'],\n    '1041': ['TM', '1', 'StudyArrivalTime'],\n    '1050': ['DA', '1', 'StudyCompletionDate'],\n    '1051': ['TM', '1', 'StudyCompletionTime'],\n    '1055': ['CS', '1', 'StudyComponentStatusID'],\n    '1060': ['LO', '1', 'RequestedProcedureDescription'],\n    '1064': ['SQ', '1', 'RequestedProcedureCodeSequence'],\n    '1065': ['SQ', '1', 'RequestedLateralityCodeSequence'],\n    '1066': ['UT', '1', 'ReasonForVisit'],\n    '1067': ['SQ', '1', 'ReasonForVisitCodeSequence'],\n    '1070': ['LO', '1', 'RequestedContrastAgent'],\n    '4000': ['LT', '1', 'StudyComments']\n  },\n  '0034': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['SQ', '1', 'FlowIdentifierSequence'],\n    '0002': ['OB', '1', 'FlowIdentifier'],\n    '0003': ['UI', '1', 'FlowTransferSyntaxUID'],\n    '0004': ['UL', '1', 'FlowRTPSamplingRate'],\n    '0005': ['OB', '1', 'SourceIdentifier'],\n    '0007': ['OB', '1', 'FrameOriginTimestamp'],\n    '0008': ['CS', '1', 'IncludesImagingSubject'],\n    '0009': ['SQ', '1', 'FrameUsefulnessGroupSequence'],\n    '000A': ['SQ', '1', 'RealTimeBulkDataFlowSequence'],\n    '000B': ['SQ', '1', 'CameraPositionGroupSequence'],\n    '000C': ['CS', '1', 'IncludesInformation'],\n    '000D': ['SQ', '1', 'TimeOfFrameGroupSequence']\n  },\n  '0038': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0004': ['SQ', '1', 'ReferencedPatientAliasSequence'],\n    '0008': ['CS', '1', 'VisitStatusID'],\n    '0010': ['LO', '1', 'AdmissionID'],\n    '0011': ['LO', '1', 'IssuerOfAdmissionID'],\n    '0014': ['SQ', '1', 'IssuerOfAdmissionIDSequence'],\n    '0016': ['LO', '1', 'RouteOfAdmissions'],\n    '001A': ['DA', '1', 'ScheduledAdmissionDate'],\n    '001B': ['TM', '1', 'ScheduledAdmissionTime'],\n    '001C': ['DA', '1', 'ScheduledDischargeDate'],\n    '001D': ['TM', '1', 'ScheduledDischargeTime'],\n    '001E': ['LO', '1', 'ScheduledPatientInstitutionResidence'],\n    '0020': ['DA', '1', 'AdmittingDate'],\n    '0021': ['TM', '1', 'AdmittingTime'],\n    '0030': ['DA', '1', 'DischargeDate'],\n    '0032': ['TM', '1', 'DischargeTime'],\n    '0040': ['LO', '1', 'DischargeDiagnosisDescription'],\n    '0044': ['SQ', '1', 'DischargeDiagnosisCodeSequence'],\n    '0050': ['LO', '1', 'SpecialNeeds'],\n    '0060': ['LO', '1', 'ServiceEpisodeID'],\n    '0061': ['LO', '1', 'IssuerOfServiceEpisodeID'],\n    '0062': ['LO', '1', 'ServiceEpisodeDescription'],\n    '0064': ['SQ', '1', 'IssuerOfServiceEpisodeIDSequence'],\n    '0100': ['SQ', '1', 'PertinentDocumentsSequence'],\n    '0101': ['SQ', '1', 'PertinentResourcesSequence'],\n    '0102': ['LO', '1', 'ResourceDescription'],\n    '0300': ['LO', '1', 'CurrentPatientLocation'],\n    '0400': ['LO', '1', 'PatientInstitutionResidence'],\n    '0500': ['LO', '1', 'PatientState'],\n    '0502': ['SQ', '1', 'PatientClinicalTrialParticipationSequence'],\n    '4000': ['LT', '1', 'VisitComments']\n  },\n  '003A': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0004': ['CS', '1', 'WaveformOriginality'],\n    '0005': ['US', '1', 'NumberOfWaveformChannels'],\n    '0010': ['UL', '1', 'NumberOfWaveformSamples'],\n    '001A': ['DS', '1', 'SamplingFrequency'],\n    '0020': ['SH', '1', 'MultiplexGroupLabel'],\n    '0200': ['SQ', '1', 'ChannelDefinitionSequence'],\n    '0202': ['IS', '1', 'WaveformChannelNumber'],\n    '0203': ['SH', '1', 'ChannelLabel'],\n    '0205': ['CS', '1-n', 'ChannelStatus'],\n    '0208': ['SQ', '1', 'ChannelSourceSequence'],\n    '0209': ['SQ', '1', 'ChannelSourceModifiersSequence'],\n    '020A': ['SQ', '1', 'SourceWaveformSequence'],\n    '020C': ['LO', '1', 'ChannelDerivationDescription'],\n    '0210': ['DS', '1', 'ChannelSensitivity'],\n    '0211': ['SQ', '1', 'ChannelSensitivityUnitsSequence'],\n    '0212': ['DS', '1', 'ChannelSensitivityCorrectionFactor'],\n    '0213': ['DS', '1', 'ChannelBaseline'],\n    '0214': ['DS', '1', 'ChannelTimeSkew'],\n    '0215': ['DS', '1', 'ChannelSampleSkew'],\n    '0218': ['DS', '1', 'ChannelOffset'],\n    '021A': ['US', '1', 'WaveformBitsStored'],\n    '0220': ['DS', '1', 'FilterLowFrequency'],\n    '0221': ['DS', '1', 'FilterHighFrequency'],\n    '0222': ['DS', '1', 'NotchFilterFrequency'],\n    '0223': ['DS', '1', 'NotchFilterBandwidth'],\n    '0230': ['FL', '1', 'WaveformDataDisplayScale'],\n    '0231': ['US', '3', 'WaveformDisplayBackgroundCIELabValue'],\n    '0240': ['SQ', '1', 'WaveformPresentationGroupSequence'],\n    '0241': ['US', '1', 'PresentationGroupNumber'],\n    '0242': ['SQ', '1', 'ChannelDisplaySequence'],\n    '0244': ['US', '3', 'ChannelRecommendedDisplayCIELabValue'],\n    '0245': ['FL', '1', 'ChannelPosition'],\n    '0246': ['CS', '1', 'DisplayShadingFlag'],\n    '0247': ['FL', '1', 'FractionalChannelDisplayScale'],\n    '0248': ['FL', '1', 'AbsoluteChannelDisplayScale'],\n    '0300': ['SQ', '1', 'MultiplexedAudioChannelsDescriptionCodeSequence'],\n    '0301': ['IS', '1', 'ChannelIdentificationCode'],\n    '0302': ['CS', '1', 'ChannelMode'],\n    '0310': ['UI', '1', 'MultiplexGroupUID'],\n    '0311': ['DS', '1', 'PowerlineFrequency'],\n    '0312': ['SQ', '1', 'ChannelImpedanceSequence'],\n    '0313': ['DS', '1', 'ImpedanceValue'],\n    '0314': ['DT', '1', 'ImpedanceMeasurementDateTime'],\n    '0315': ['DS', '1', 'ImpedanceMeasurementFrequency'],\n    '0316': ['CS', '1', 'ImpedanceMeasurementCurrentType']\n  },\n  '0040': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['AE', '1-n', 'ScheduledStationAETitle'],\n    '0002': ['DA', '1', 'ScheduledProcedureStepStartDate'],\n    '0003': ['TM', '1', 'ScheduledProcedureStepStartTime'],\n    '0004': ['DA', '1', 'ScheduledProcedureStepEndDate'],\n    '0005': ['TM', '1', 'ScheduledProcedureStepEndTime'],\n    '0006': ['PN', '1', 'ScheduledPerformingPhysicianName'],\n    '0007': ['LO', '1', 'ScheduledProcedureStepDescription'],\n    '0008': ['SQ', '1', 'ScheduledProtocolCodeSequence'],\n    '0009': ['SH', '1', 'ScheduledProcedureStepID'],\n    '000A': ['SQ', '1', 'StageCodeSequence'],\n    '000B': ['SQ', '1', 'ScheduledPerformingPhysicianIdentificationSequence'],\n    '0010': ['SH', '1-n', 'ScheduledStationName'],\n    '0011': ['SH', '1', 'ScheduledProcedureStepLocation'],\n    '0012': ['LO', '1', 'PreMedication'],\n    '0020': ['CS', '1', 'ScheduledProcedureStepStatus'],\n    '0026': ['SQ', '1', 'OrderPlacerIdentifierSequence'],\n    '0027': ['SQ', '1', 'OrderFillerIdentifierSequence'],\n    '0031': ['UT', '1', 'LocalNamespaceEntityID'],\n    '0032': ['UT', '1', 'UniversalEntityID'],\n    '0033': ['CS', '1', 'UniversalEntityIDType'],\n    '0035': ['CS', '1', 'IdentifierTypeCode'],\n    '0036': ['SQ', '1', 'AssigningFacilitySequence'],\n    '0039': ['SQ', '1', 'AssigningJurisdictionCodeSequence'],\n    '003A': ['SQ', '1', 'AssigningAgencyOrDepartmentCodeSequence'],\n    '0100': ['SQ', '1', 'ScheduledProcedureStepSequence'],\n    '0220': ['SQ', '1', 'ReferencedNonImageCompositeSOPInstanceSequence'],\n    '0241': ['AE', '1', 'PerformedStationAETitle'],\n    '0242': ['SH', '1', 'PerformedStationName'],\n    '0243': ['SH', '1', 'PerformedLocation'],\n    '0244': ['DA', '1', 'PerformedProcedureStepStartDate'],\n    '0245': ['TM', '1', 'PerformedProcedureStepStartTime'],\n    '0250': ['DA', '1', 'PerformedProcedureStepEndDate'],\n    '0251': ['TM', '1', 'PerformedProcedureStepEndTime'],\n    '0252': ['CS', '1', 'PerformedProcedureStepStatus'],\n    '0253': ['SH', '1', 'PerformedProcedureStepID'],\n    '0254': ['LO', '1', 'PerformedProcedureStepDescription'],\n    '0255': ['LO', '1', 'PerformedProcedureTypeDescription'],\n    '0260': ['SQ', '1', 'PerformedProtocolCodeSequence'],\n    '0261': ['CS', '1', 'PerformedProtocolType'],\n    '0270': ['SQ', '1', 'ScheduledStepAttributesSequence'],\n    '0275': ['SQ', '1', 'RequestAttributesSequence'],\n    '0280': ['ST', '1', 'CommentsOnThePerformedProcedureStep'],\n    '0281': ['SQ', '1', 'PerformedProcedureStepDiscontinuationReasonCodeSequence'],\n    '0293': ['SQ', '1', 'QuantitySequence'],\n    '0294': ['DS', '1', 'Quantity'],\n    '0295': ['SQ', '1', 'MeasuringUnitsSequence'],\n    '0296': ['SQ', '1', 'BillingItemSequence'],\n    '0300': ['US', '1', 'TotalTimeOfFluoroscopy'],\n    '0301': ['US', '1', 'TotalNumberOfExposures'],\n    '0302': ['US', '1', 'EntranceDose'],\n    '0303': ['US', '1-2', 'ExposedArea'],\n    '0306': ['DS', '1', 'DistanceSourceToEntrance'],\n    '0307': ['DS', '1', 'DistanceSourceToSupport'],\n    '030E': ['SQ', '1', 'ExposureDoseSequence'],\n    '0310': ['ST', '1', 'CommentsOnRadiationDose'],\n    '0312': ['DS', '1', 'XRayOutput'],\n    '0314': ['DS', '1', 'HalfValueLayer'],\n    '0316': ['DS', '1', 'OrganDose'],\n    '0318': ['CS', '1', 'OrganExposed'],\n    '0320': ['SQ', '1', 'BillingProcedureStepSequence'],\n    '0321': ['SQ', '1', 'FilmConsumptionSequence'],\n    '0324': ['SQ', '1', 'BillingSuppliesAndDevicesSequence'],\n    '0330': ['SQ', '1', 'ReferencedProcedureStepSequence'],\n    '0340': ['SQ', '1', 'PerformedSeriesSequence'],\n    '0400': ['LT', '1', 'CommentsOnTheScheduledProcedureStep'],\n    '0440': ['SQ', '1', 'ProtocolContextSequence'],\n    '0441': ['SQ', '1', 'ContentItemModifierSequence'],\n    '0500': ['SQ', '1', 'ScheduledSpecimenSequence'],\n    '050A': ['LO', '1', 'SpecimenAccessionNumber'],\n    '0512': ['LO', '1', 'ContainerIdentifier'],\n    '0513': ['SQ', '1', 'IssuerOfTheContainerIdentifierSequence'],\n    '0515': ['SQ', '1', 'AlternateContainerIdentifierSequence'],\n    '0518': ['SQ', '1', 'ContainerTypeCodeSequence'],\n    '051A': ['LO', '1', 'ContainerDescription'],\n    '0520': ['SQ', '1', 'ContainerComponentSequence'],\n    '0550': ['SQ', '1', 'SpecimenSequence'],\n    '0551': ['LO', '1', 'SpecimenIdentifier'],\n    '0552': ['SQ', '1', 'SpecimenDescriptionSequenceTrial'],\n    '0553': ['ST', '1', 'SpecimenDescriptionTrial'],\n    '0554': ['UI', '1', 'SpecimenUID'],\n    '0555': ['SQ', '1', 'AcquisitionContextSequence'],\n    '0556': ['ST', '1', 'AcquisitionContextDescription'],\n    '0560': ['SQ', '1', 'SpecimenDescriptionSequence'],\n    '0562': ['SQ', '1', 'IssuerOfTheSpecimenIdentifierSequence'],\n    '059A': ['SQ', '1', 'SpecimenTypeCodeSequence'],\n    '0600': ['LO', '1', 'SpecimenShortDescription'],\n    '0602': ['UT', '1', 'SpecimenDetailedDescription'],\n    '0610': ['SQ', '1', 'SpecimenPreparationSequence'],\n    '0612': ['SQ', '1', 'SpecimenPreparationStepContentItemSequence'],\n    '0620': ['SQ', '1', 'SpecimenLocalizationContentItemSequence'],\n    '06FA': ['LO', '1', 'SlideIdentifier'],\n    '0710': ['SQ', '1', 'WholeSlideMicroscopyImageFrameTypeSequence'],\n    '071A': ['SQ', '1', 'ImageCenterPointCoordinatesSequence'],\n    '072A': ['DS', '1', 'XOffsetInSlideCoordinateSystem'],\n    '073A': ['DS', '1', 'YOffsetInSlideCoordinateSystem'],\n    '074A': ['DS', '1', 'ZOffsetInSlideCoordinateSystem'],\n    '08D8': ['SQ', '1', 'PixelSpacingSequence'],\n    '08DA': ['SQ', '1', 'CoordinateSystemAxisCodeSequence'],\n    '08EA': ['SQ', '1', 'MeasurementUnitsCodeSequence'],\n    '09F8': ['SQ', '1', 'VitalStainCodeSequenceTrial'],\n    '1001': ['SH', '1', 'RequestedProcedureID'],\n    '1002': ['LO', '1', 'ReasonForTheRequestedProcedure'],\n    '1003': ['SH', '1', 'RequestedProcedurePriority'],\n    '1004': ['LO', '1', 'PatientTransportArrangements'],\n    '1005': ['LO', '1', 'RequestedProcedureLocation'],\n    '1006': ['SH', '1', 'PlacerOrderNumberProcedure'],\n    '1007': ['SH', '1', 'FillerOrderNumberProcedure'],\n    '1008': ['LO', '1', 'ConfidentialityCode'],\n    '1009': ['SH', '1', 'ReportingPriority'],\n    '100A': ['SQ', '1', 'ReasonForRequestedProcedureCodeSequence'],\n    '1010': ['PN', '1-n', 'NamesOfIntendedRecipientsOfResults'],\n    '1011': ['SQ', '1', 'IntendedRecipientsOfResultsIdentificationSequence'],\n    '1012': ['SQ', '1', 'ReasonForPerformedProcedureCodeSequence'],\n    '1060': ['LO', '1', 'RequestedProcedureDescriptionTrial'],\n    '1101': ['SQ', '1', 'PersonIdentificationCodeSequence'],\n    '1102': ['ST', '1', 'PersonAddress'],\n    '1103': ['LO', '1-n', 'PersonTelephoneNumbers'],\n    '1104': ['LT', '1', 'PersonTelecomInformation'],\n    '1400': ['LT', '1', 'RequestedProcedureComments'],\n    '2001': ['LO', '1', 'ReasonForTheImagingServiceRequest'],\n    '2004': ['DA', '1', 'IssueDateOfImagingServiceRequest'],\n    '2005': ['TM', '1', 'IssueTimeOfImagingServiceRequest'],\n    '2006': ['SH', '1', 'PlacerOrderNumberImagingServiceRequestRetired'],\n    '2007': ['SH', '1', 'FillerOrderNumberImagingServiceRequestRetired'],\n    '2008': ['PN', '1', 'OrderEnteredBy'],\n    '2009': ['SH', '1', 'OrderEntererLocation'],\n    '2010': ['SH', '1', 'OrderCallbackPhoneNumber'],\n    '2011': ['LT', '1', 'OrderCallbackTelecomInformation'],\n    '2016': ['LO', '1', 'PlacerOrderNumberImagingServiceRequest'],\n    '2017': ['LO', '1', 'FillerOrderNumberImagingServiceRequest'],\n    '2400': ['LT', '1', 'ImagingServiceRequestComments'],\n    '3001': ['LO', '1', 'ConfidentialityConstraintOnPatientDataDescription'],\n    '4001': ['CS', '1', 'GeneralPurposeScheduledProcedureStepStatus'],\n    '4002': ['CS', '1', 'GeneralPurposePerformedProcedureStepStatus'],\n    '4003': ['CS', '1', 'GeneralPurposeScheduledProcedureStepPriority'],\n    '4004': ['SQ', '1', 'ScheduledProcessingApplicationsCodeSequence'],\n    '4005': ['DT', '1', 'ScheduledProcedureStepStartDateTime'],\n    '4006': ['CS', '1', 'MultipleCopiesFlag'],\n    '4007': ['SQ', '1', 'PerformedProcessingApplicationsCodeSequence'],\n    '4008': ['DT', '1', 'ScheduledProcedureStepExpirationDateTime'],\n    '4009': ['SQ', '1', 'HumanPerformerCodeSequence'],\n    '4010': ['DT', '1', 'ScheduledProcedureStepModificationDateTime'],\n    '4011': ['DT', '1', 'ExpectedCompletionDateTime'],\n    '4015': ['SQ', '1', 'ResultingGeneralPurposePerformedProcedureStepsSequence'],\n    '4016': ['SQ', '1', 'ReferencedGeneralPurposeScheduledProcedureStepSequence'],\n    '4018': ['SQ', '1', 'ScheduledWorkitemCodeSequence'],\n    '4019': ['SQ', '1', 'PerformedWorkitemCodeSequence'],\n    '4020': ['CS', '1', 'InputAvailabilityFlag'],\n    '4021': ['SQ', '1', 'InputInformationSequence'],\n    '4022': ['SQ', '1', 'RelevantInformationSequence'],\n    '4023': ['UI', '1', 'ReferencedGeneralPurposeScheduledProcedureStepTransactionUID'],\n    '4025': ['SQ', '1', 'ScheduledStationNameCodeSequence'],\n    '4026': ['SQ', '1', 'ScheduledStationClassCodeSequence'],\n    '4027': ['SQ', '1', 'ScheduledStationGeographicLocationCodeSequence'],\n    '4028': ['SQ', '1', 'PerformedStationNameCodeSequence'],\n    '4029': ['SQ', '1', 'PerformedStationClassCodeSequence'],\n    '4030': ['SQ', '1', 'PerformedStationGeographicLocationCodeSequence'],\n    '4031': ['SQ', '1', 'RequestedSubsequentWorkitemCodeSequence'],\n    '4032': ['SQ', '1', 'NonDICOMOutputCodeSequence'],\n    '4033': ['SQ', '1', 'OutputInformationSequence'],\n    '4034': ['SQ', '1', 'ScheduledHumanPerformersSequence'],\n    '4035': ['SQ', '1', 'ActualHumanPerformersSequence'],\n    '4036': ['LO', '1', 'HumanPerformerOrganization'],\n    '4037': ['PN', '1', 'HumanPerformerName'],\n    '4040': ['CS', '1', 'RawDataHandling'],\n    '4041': ['CS', '1', 'InputReadinessState'],\n    '4050': ['DT', '1', 'PerformedProcedureStepStartDateTime'],\n    '4051': ['DT', '1', 'PerformedProcedureStepEndDateTime'],\n    '4052': ['DT', '1', 'ProcedureStepCancellationDateTime'],\n    '4070': ['SQ', '1', 'OutputDestinationSequence'],\n    '4071': ['SQ', '1', 'DICOMStorageSequence'],\n    '4072': ['SQ', '1', 'STOWRSStorageSequence'],\n    '4073': ['UR', '1', 'StorageURL'],\n    '4074': ['SQ', '1', 'XDSStorageSequence'],\n    '8302': ['DS', '1', 'EntranceDoseInmGy'],\n    '8303': ['CS', '1', 'EntranceDoseDerivation'],\n    '9092': ['SQ', '1', 'ParametricMapFrameTypeSequence'],\n    '9094': ['SQ', '1', 'ReferencedImageRealWorldValueMappingSequence'],\n    '9096': ['SQ', '1', 'RealWorldValueMappingSequence'],\n    '9098': ['SQ', '1', 'PixelValueMappingCodeSequence'],\n    '9210': ['SH', '1', 'LUTLabel'],\n    '9211': ['xs', '1', 'RealWorldValueLastValueMapped'],\n    '9212': ['FD', '1-n', 'RealWorldValueLUTData'],\n    '9213': ['FD', '1', 'DoubleFloatRealWorldValueLastValueMapped'],\n    '9214': ['FD', '1', 'DoubleFloatRealWorldValueFirstValueMapped'],\n    '9216': ['xs', '1', 'RealWorldValueFirstValueMapped'],\n    '9220': ['SQ', '1', 'QuantityDefinitionSequence'],\n    '9224': ['FD', '1', 'RealWorldValueIntercept'],\n    '9225': ['FD', '1', 'RealWorldValueSlope'],\n    'A007': ['CS', '1', 'FindingsFlagTrial'],\n    'A010': ['CS', '1', 'RelationshipType'],\n    'A020': ['SQ', '1', 'FindingsSequenceTrial'],\n    'A021': ['UI', '1', 'FindingsGroupUIDTrial'],\n    'A022': ['UI', '1', 'ReferencedFindingsGroupUIDTrial'],\n    'A023': ['DA', '1', 'FindingsGroupRecordingDateTrial'],\n    'A024': ['TM', '1', 'FindingsGroupRecordingTimeTrial'],\n    'A026': ['SQ', '1', 'FindingsSourceCategoryCodeSequenceTrial'],\n    'A027': ['LO', '1', 'VerifyingOrganization'],\n    'A028': ['SQ', '1', 'DocumentingOrganizationIdentifierCodeSequenceTrial'],\n    'A030': ['DT', '1', 'VerificationDateTime'],\n    'A032': ['DT', '1', 'ObservationDateTime'],\n    'A033': ['DT', '1', 'ObservationStartDateTime'],\n    'A040': ['CS', '1', 'ValueType'],\n    'A043': ['SQ', '1', 'ConceptNameCodeSequence'],\n    'A047': ['LO', '1', 'MeasurementPrecisionDescriptionTrial'],\n    'A050': ['CS', '1', 'ContinuityOfContent'],\n    'A057': ['CS', '1-n', 'UrgencyOrPriorityAlertsTrial'],\n    'A060': ['LO', '1', 'SequencingIndicatorTrial'],\n    'A066': ['SQ', '1', 'DocumentIdentifierCodeSequenceTrial'],\n    'A067': ['PN', '1', 'DocumentAuthorTrial'],\n    'A068': ['SQ', '1', 'DocumentAuthorIdentifierCodeSequenceTrial'],\n    'A070': ['SQ', '1', 'IdentifierCodeSequenceTrial'],\n    'A073': ['SQ', '1', 'VerifyingObserverSequence'],\n    'A074': ['OB', '1', 'ObjectBinaryIdentifierTrial'],\n    'A075': ['PN', '1', 'VerifyingObserverName'],\n    'A076': ['SQ', '1', 'DocumentingObserverIdentifierCodeSequenceTrial'],\n    'A078': ['SQ', '1', 'AuthorObserverSequence'],\n    'A07A': ['SQ', '1', 'ParticipantSequence'],\n    'A07C': ['SQ', '1', 'CustodialOrganizationSequence'],\n    'A080': ['CS', '1', 'ParticipationType'],\n    'A082': ['DT', '1', 'ParticipationDateTime'],\n    'A084': ['CS', '1', 'ObserverType'],\n    'A085': ['SQ', '1', 'ProcedureIdentifierCodeSequenceTrial'],\n    'A088': ['SQ', '1', 'VerifyingObserverIdentificationCodeSequence'],\n    'A089': ['OB', '1', 'ObjectDirectoryBinaryIdentifierTrial'],\n    'A090': ['SQ', '1', 'EquivalentCDADocumentSequence'],\n    'A0B0': ['US', '2-2n', 'ReferencedWaveformChannels'],\n    'A110': ['DA', '1', 'DateOfDocumentOrVerbalTransactionTrial'],\n    'A112': ['TM', '1', 'TimeOfDocumentCreationOrVerbalTransactionTrial'],\n    'A120': ['DT', '1', 'DateTime'],\n    'A121': ['DA', '1', 'Date'],\n    'A122': ['TM', '1', 'Time'],\n    'A123': ['PN', '1', 'PersonName'],\n    'A124': ['UI', '1', 'UID'],\n    'A125': ['CS', '2', 'ReportStatusIDTrial'],\n    'A130': ['CS', '1', 'TemporalRangeType'],\n    'A132': ['UL', '1-n', 'ReferencedSamplePositions'],\n    'A136': ['US', '1-n', 'ReferencedFrameNumbers'],\n    'A138': ['DS', '1-n', 'ReferencedTimeOffsets'],\n    'A13A': ['DT', '1-n', 'ReferencedDateTime'],\n    'A160': ['UT', '1', 'TextValue'],\n    'A161': ['FD', '1-n', 'FloatingPointValue'],\n    'A162': ['SL', '1-n', 'RationalNumeratorValue'],\n    'A163': ['UL', '1-n', 'RationalDenominatorValue'],\n    'A167': ['SQ', '1', 'ObservationCategoryCodeSequenceTrial'],\n    'A168': ['SQ', '1', 'ConceptCodeSequence'],\n    'A16A': ['ST', '1', 'BibliographicCitationTrial'],\n    'A170': ['SQ', '1', 'PurposeOfReferenceCodeSequence'],\n    'A171': ['UI', '1', 'ObservationUID'],\n    'A172': ['UI', '1', 'ReferencedObservationUIDTrial'],\n    'A173': ['CS', '1', 'ReferencedObservationClassTrial'],\n    'A174': ['CS', '1', 'ReferencedObjectObservationClassTrial'],\n    'A180': ['US', '1', 'AnnotationGroupNumber'],\n    'A192': ['DA', '1', 'ObservationDateTrial'],\n    'A193': ['TM', '1', 'ObservationTimeTrial'],\n    'A194': ['CS', '1', 'MeasurementAutomationTrial'],\n    'A195': ['SQ', '1', 'ModifierCodeSequence'],\n    'A224': ['ST', '1', 'IdentificationDescriptionTrial'],\n    'A290': ['CS', '1', 'CoordinatesSetGeometricTypeTrial'],\n    'A296': ['SQ', '1', 'AlgorithmCodeSequenceTrial'],\n    'A297': ['ST', '1', 'AlgorithmDescriptionTrial'],\n    'A29A': ['SL', '2-2n', 'PixelCoordinatesSetTrial'],\n    'A300': ['SQ', '1', 'MeasuredValueSequence'],\n    'A301': ['SQ', '1', 'NumericValueQualifierCodeSequence'],\n    'A307': ['PN', '1', 'CurrentObserverTrial'],\n    'A30A': ['DS', '1-n', 'NumericValue'],\n    'A313': ['SQ', '1', 'ReferencedAccessionSequenceTrial'],\n    'A33A': ['ST', '1', 'ReportStatusCommentTrial'],\n    'A340': ['SQ', '1', 'ProcedureContextSequenceTrial'],\n    'A352': ['PN', '1', 'VerbalSourceTrial'],\n    'A353': ['ST', '1', 'AddressTrial'],\n    'A354': ['LO', '1', 'TelephoneNumberTrial'],\n    'A358': ['SQ', '1', 'VerbalSourceIdentifierCodeSequenceTrial'],\n    'A360': ['SQ', '1', 'PredecessorDocumentsSequence'],\n    'A370': ['SQ', '1', 'ReferencedRequestSequence'],\n    'A372': ['SQ', '1', 'PerformedProcedureCodeSequence'],\n    'A375': ['SQ', '1', 'CurrentRequestedProcedureEvidenceSequence'],\n    'A380': ['SQ', '1', 'ReportDetailSequenceTrial'],\n    'A385': ['SQ', '1', 'PertinentOtherEvidenceSequence'],\n    'A390': ['SQ', '1', 'HL7StructuredDocumentReferenceSequence'],\n    'A402': ['UI', '1', 'ObservationSubjectUIDTrial'],\n    'A403': ['CS', '1', 'ObservationSubjectClassTrial'],\n    'A404': ['SQ', '1', 'ObservationSubjectTypeCodeSequenceTrial'],\n    'A491': ['CS', '1', 'CompletionFlag'],\n    'A492': ['LO', '1', 'CompletionFlagDescription'],\n    'A493': ['CS', '1', 'VerificationFlag'],\n    'A494': ['CS', '1', 'ArchiveRequested'],\n    'A496': ['CS', '1', 'PreliminaryFlag'],\n    'A504': ['SQ', '1', 'ContentTemplateSequence'],\n    'A525': ['SQ', '1', 'IdenticalDocumentsSequence'],\n    'A600': ['CS', '1', 'ObservationSubjectContextFlagTrial'],\n    'A601': ['CS', '1', 'ObserverContextFlagTrial'],\n    'A603': ['CS', '1', 'ProcedureContextFlagTrial'],\n    'A730': ['SQ', '1', 'ContentSequence'],\n    'A731': ['SQ', '1', 'RelationshipSequenceTrial'],\n    'A732': ['SQ', '1', 'RelationshipTypeCodeSequenceTrial'],\n    'A744': ['SQ', '1', 'LanguageCodeSequenceTrial'],\n    'A801': ['SQ', '1', 'TabulatedValuesSequence'],\n    'A802': ['UL', '1', 'NumberOfTableRows'],\n    'A803': ['UL', '1', 'NumberOfTableColumns'],\n    'A804': ['UL', '1', 'TableRowNumber'],\n    'A805': ['UL', '1', 'TableColumnNumber'],\n    'A806': ['SQ', '1', 'TableRowDefinitionSequence'],\n    'A807': ['SQ', '1', 'TableColumnDefinitionSequence'],\n    'A808': ['SQ', '1', 'CellValuesSequence'],\n    'A992': ['ST', '1', 'UniformResourceLocatorTrial'],\n    'B020': ['SQ', '1', 'WaveformAnnotationSequence'],\n    'DB00': ['CS', '1', 'TemplateIdentifier'],\n    'DB06': ['DT', '1', 'TemplateVersion'],\n    'DB07': ['DT', '1', 'TemplateLocalVersion'],\n    'DB0B': ['CS', '1', 'TemplateExtensionFlag'],\n    'DB0C': ['UI', '1', 'TemplateExtensionOrganizationUID'],\n    'DB0D': ['UI', '1', 'TemplateExtensionCreatorUID'],\n    'DB73': ['UL', '1-n', 'ReferencedContentItemIdentifier'],\n    'E001': ['ST', '1', 'HL7InstanceIdentifier'],\n    'E004': ['DT', '1', 'HL7DocumentEffectiveTime'],\n    'E006': ['SQ', '1', 'HL7DocumentTypeCodeSequence'],\n    'E008': ['SQ', '1', 'DocumentClassCodeSequence'],\n    'E010': ['UR', '1', 'RetrieveURI'],\n    'E011': ['UI', '1', 'RetrieveLocationUID'],\n    'E020': ['CS', '1', 'TypeOfInstances'],\n    'E021': ['SQ', '1', 'DICOMRetrievalSequence'],\n    'E022': ['SQ', '1', 'DICOMMediaRetrievalSequence'],\n    'E023': ['SQ', '1', 'WADORetrievalSequence'],\n    'E024': ['SQ', '1', 'XDSRetrievalSequence'],\n    'E025': ['SQ', '1', 'WADORSRetrievalSequence'],\n    'E030': ['UI', '1', 'RepositoryUniqueID'],\n    'E031': ['UI', '1', 'HomeCommunityID']\n  },\n  '0042': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['ST', '1', 'DocumentTitle'],\n    '0011': ['OB', '1', 'EncapsulatedDocument'],\n    '0012': ['LO', '1', 'MIMETypeOfEncapsulatedDocument'],\n    '0013': ['SQ', '1', 'SourceInstanceSequence'],\n    '0014': ['LO', '1-n', 'ListOfMIMETypes'],\n    '0015': ['UL', '1', 'EncapsulatedDocumentLength']\n  },\n  '0044': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['ST', '1', 'ProductPackageIdentifier'],\n    '0002': ['CS', '1', 'SubstanceAdministrationApproval'],\n    '0003': ['LT', '1', 'ApprovalStatusFurtherDescription'],\n    '0004': ['DT', '1', 'ApprovalStatusDateTime'],\n    '0007': ['SQ', '1', 'ProductTypeCodeSequence'],\n    '0008': ['LO', '1-n', 'ProductName'],\n    '0009': ['LT', '1', 'ProductDescription'],\n    '000A': ['LO', '1', 'ProductLotIdentifier'],\n    '000B': ['DT', '1', 'ProductExpirationDateTime'],\n    '0010': ['DT', '1', 'SubstanceAdministrationDateTime'],\n    '0011': ['LO', '1', 'SubstanceAdministrationNotes'],\n    '0012': ['LO', '1', 'SubstanceAdministrationDeviceID'],\n    '0013': ['SQ', '1', 'ProductParameterSequence'],\n    '0019': ['SQ', '1', 'SubstanceAdministrationParameterSequence'],\n    '0100': ['SQ', '1', 'ApprovalSequence'],\n    '0101': ['SQ', '1', 'AssertionCodeSequence'],\n    '0102': ['UI', '1', 'AssertionUID'],\n    '0103': ['SQ', '1', 'AsserterIdentificationSequence'],\n    '0104': ['DT', '1', 'AssertionDateTime'],\n    '0105': ['DT', '1', 'AssertionExpirationDateTime'],\n    '0106': ['UT', '1', 'AssertionComments'],\n    '0107': ['SQ', '1', 'RelatedAssertionSequence'],\n    '0108': ['UI', '1', 'ReferencedAssertionUID'],\n    '0109': ['SQ', '1', 'ApprovalSubjectSequence'],\n    '010A': ['SQ', '1', 'OrganizationalRoleCodeSequence']\n  },\n  '0046': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0012': ['LO', '1', 'LensDescription'],\n    '0014': ['SQ', '1', 'RightLensSequence'],\n    '0015': ['SQ', '1', 'LeftLensSequence'],\n    '0016': ['SQ', '1', 'UnspecifiedLateralityLensSequence'],\n    '0018': ['SQ', '1', 'CylinderSequence'],\n    '0028': ['SQ', '1', 'PrismSequence'],\n    '0030': ['FD', '1', 'HorizontalPrismPower'],\n    '0032': ['CS', '1', 'HorizontalPrismBase'],\n    '0034': ['FD', '1', 'VerticalPrismPower'],\n    '0036': ['CS', '1', 'VerticalPrismBase'],\n    '0038': ['CS', '1', 'LensSegmentType'],\n    '0040': ['FD', '1', 'OpticalTransmittance'],\n    '0042': ['FD', '1', 'ChannelWidth'],\n    '0044': ['FD', '1', 'PupilSize'],\n    '0046': ['FD', '1', 'CornealSize'],\n    '0047': ['SQ', '1', 'CornealSizeSequence'],\n    '0050': ['SQ', '1', 'AutorefractionRightEyeSequence'],\n    '0052': ['SQ', '1', 'AutorefractionLeftEyeSequence'],\n    '0060': ['FD', '1', 'DistancePupillaryDistance'],\n    '0062': ['FD', '1', 'NearPupillaryDistance'],\n    '0063': ['FD', '1', 'IntermediatePupillaryDistance'],\n    '0064': ['FD', '1', 'OtherPupillaryDistance'],\n    '0070': ['SQ', '1', 'KeratometryRightEyeSequence'],\n    '0071': ['SQ', '1', 'KeratometryLeftEyeSequence'],\n    '0074': ['SQ', '1', 'SteepKeratometricAxisSequence'],\n    '0075': ['FD', '1', 'RadiusOfCurvature'],\n    '0076': ['FD', '1', 'KeratometricPower'],\n    '0077': ['FD', '1', 'KeratometricAxis'],\n    '0080': ['SQ', '1', 'FlatKeratometricAxisSequence'],\n    '0092': ['CS', '1', 'BackgroundColor'],\n    '0094': ['CS', '1', 'Optotype'],\n    '0095': ['CS', '1', 'OptotypePresentation'],\n    '0097': ['SQ', '1', 'SubjectiveRefractionRightEyeSequence'],\n    '0098': ['SQ', '1', 'SubjectiveRefractionLeftEyeSequence'],\n    '0100': ['SQ', '1', 'AddNearSequence'],\n    '0101': ['SQ', '1', 'AddIntermediateSequence'],\n    '0102': ['SQ', '1', 'AddOtherSequence'],\n    '0104': ['FD', '1', 'AddPower'],\n    '0106': ['FD', '1', 'ViewingDistance'],\n    '0110': ['SQ', '1', 'CorneaMeasurementsSequence'],\n    '0111': ['SQ', '1', 'SourceOfCorneaMeasurementDataCodeSequence'],\n    '0112': ['SQ', '1', 'SteepCornealAxisSequence'],\n    '0113': ['SQ', '1', 'FlatCornealAxisSequence'],\n    '0114': ['FD', '1', 'CornealPower'],\n    '0115': ['FD', '1', 'CornealAxis'],\n    '0116': ['SQ', '1', 'CorneaMeasurementMethodCodeSequence'],\n    '0117': ['FL', '1', 'RefractiveIndexOfCornea'],\n    '0118': ['FL', '1', 'RefractiveIndexOfAqueousHumor'],\n    '0121': ['SQ', '1', 'VisualAcuityTypeCodeSequence'],\n    '0122': ['SQ', '1', 'VisualAcuityRightEyeSequence'],\n    '0123': ['SQ', '1', 'VisualAcuityLeftEyeSequence'],\n    '0124': ['SQ', '1', 'VisualAcuityBothEyesOpenSequence'],\n    '0125': ['CS', '1', 'ViewingDistanceType'],\n    '0135': ['SS', '2', 'VisualAcuityModifiers'],\n    '0137': ['FD', '1', 'DecimalVisualAcuity'],\n    '0139': ['LO', '1', 'OptotypeDetailedDefinition'],\n    '0145': ['SQ', '1', 'ReferencedRefractiveMeasurementsSequence'],\n    '0146': ['FD', '1', 'SpherePower'],\n    '0147': ['FD', '1', 'CylinderPower'],\n    '0201': ['CS', '1', 'CornealTopographySurface'],\n    '0202': ['FL', '2', 'CornealVertexLocation'],\n    '0203': ['FL', '1', 'PupilCentroidXCoordinate'],\n    '0204': ['FL', '1', 'PupilCentroidYCoordinate'],\n    '0205': ['FL', '1', 'EquivalentPupilRadius'],\n    '0207': ['SQ', '1', 'CornealTopographyMapTypeCodeSequence'],\n    '0208': ['IS', '2-2n', 'VerticesOfTheOutlineOfPupil'],\n    '0210': ['SQ', '1', 'CornealTopographyMappingNormalsSequence'],\n    '0211': ['SQ', '1', 'MaximumCornealCurvatureSequence'],\n    '0212': ['FL', '1', 'MaximumCornealCurvature'],\n    '0213': ['FL', '2', 'MaximumCornealCurvatureLocation'],\n    '0215': ['SQ', '1', 'MinimumKeratometricSequence'],\n    '0218': ['SQ', '1', 'SimulatedKeratometricCylinderSequence'],\n    '0220': ['FL', '1', 'AverageCornealPower'],\n    '0224': ['FL', '1', 'CornealISValue'],\n    '0227': ['FL', '1', 'AnalyzedArea'],\n    '0230': ['FL', '1', 'SurfaceRegularityIndex'],\n    '0232': ['FL', '1', 'SurfaceAsymmetryIndex'],\n    '0234': ['FL', '1', 'CornealEccentricityIndex'],\n    '0236': ['FL', '1', 'KeratoconusPredictionIndex'],\n    '0238': ['FL', '1', 'DecimalPotentialVisualAcuity'],\n    '0242': ['CS', '1', 'CornealTopographyMapQualityEvaluation'],\n    '0244': ['SQ', '1', 'SourceImageCornealProcessedDataSequence'],\n    '0247': ['FL', '3', 'CornealPointLocation'],\n    '0248': ['CS', '1', 'CornealPointEstimated'],\n    '0249': ['FL', '1', 'AxialPower'],\n    '0250': ['FL', '1', 'TangentialPower'],\n    '0251': ['FL', '1', 'RefractivePower'],\n    '0252': ['FL', '1', 'RelativeElevation'],\n    '0253': ['FL', '1', 'CornealWavefront']\n  },\n  '0048': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['FL', '1', 'ImagedVolumeWidth'],\n    '0002': ['FL', '1', 'ImagedVolumeHeight'],\n    '0003': ['FL', '1', 'ImagedVolumeDepth'],\n    '0006': ['UL', '1', 'TotalPixelMatrixColumns'],\n    '0007': ['UL', '1', 'TotalPixelMatrixRows'],\n    '0008': ['SQ', '1', 'TotalPixelMatrixOriginSequence'],\n    '0010': ['CS', '1', 'SpecimenLabelInImage'],\n    '0011': ['CS', '1', 'FocusMethod'],\n    '0012': ['CS', '1', 'ExtendedDepthOfField'],\n    '0013': ['US', '1', 'NumberOfFocalPlanes'],\n    '0014': ['FL', '1', 'DistanceBetweenFocalPlanes'],\n    '0015': ['US', '3', 'RecommendedAbsentPixelCIELabValue'],\n    '0100': ['SQ', '1', 'IlluminatorTypeCodeSequence'],\n    '0102': ['DS', '6', 'ImageOrientationSlide'],\n    '0105': ['SQ', '1', 'OpticalPathSequence'],\n    '0106': ['SH', '1', 'OpticalPathIdentifier'],\n    '0107': ['ST', '1', 'OpticalPathDescription'],\n    '0108': ['SQ', '1', 'IlluminationColorCodeSequence'],\n    '0110': ['SQ', '1', 'SpecimenReferenceSequence'],\n    '0111': ['DS', '1', 'CondenserLensPower'],\n    '0112': ['DS', '1', 'ObjectiveLensPower'],\n    '0113': ['DS', '1', 'ObjectiveLensNumericalAperture'],\n    '0120': ['SQ', '1', 'PaletteColorLookupTableSequence'],\n    '0200': ['SQ', '1', 'ReferencedImageNavigationSequence'],\n    '0201': ['US', '2', 'TopLeftHandCornerOfLocalizerArea'],\n    '0202': ['US', '2', 'BottomRightHandCornerOfLocalizerArea'],\n    '0207': ['SQ', '1', 'OpticalPathIdentificationSequence'],\n    '021A': ['SQ', '1', 'PlanePositionSlideSequence'],\n    '021E': ['SL', '1', 'ColumnPositionInTotalImagePixelMatrix'],\n    '021F': ['SL', '1', 'RowPositionInTotalImagePixelMatrix'],\n    '0301': ['CS', '1', 'PixelOriginInterpretation'],\n    '0302': ['UL', '1', 'NumberOfOpticalPaths'],\n    '0303': ['UL', '1', 'TotalPixelMatrixFocalPlanes']\n  },\n  '0050': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0004': ['CS', '1', 'CalibrationImage'],\n    '0010': ['SQ', '1', 'DeviceSequence'],\n    '0012': ['SQ', '1', 'ContainerComponentTypeCodeSequence'],\n    '0013': ['FD', '1', 'ContainerComponentThickness'],\n    '0014': ['DS', '1', 'DeviceLength'],\n    '0015': ['FD', '1', 'ContainerComponentWidth'],\n    '0016': ['DS', '1', 'DeviceDiameter'],\n    '0017': ['CS', '1', 'DeviceDiameterUnits'],\n    '0018': ['DS', '1', 'DeviceVolume'],\n    '0019': ['DS', '1', 'InterMarkerDistance'],\n    '001A': ['CS', '1', 'ContainerComponentMaterial'],\n    '001B': ['LO', '1', 'ContainerComponentID'],\n    '001C': ['FD', '1', 'ContainerComponentLength'],\n    '001D': ['FD', '1', 'ContainerComponentDiameter'],\n    '001E': ['LO', '1', 'ContainerComponentDescription'],\n    '0020': ['LO', '1', 'DeviceDescription'],\n    '0021': ['ST', '1', 'LongDeviceDescription']\n  },\n  '0052': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['FL', '1', 'ContrastBolusIngredientPercentByVolume'],\n    '0002': ['FD', '1', 'OCTFocalDistance'],\n    '0003': ['FD', '1', 'BeamSpotSize'],\n    '0004': ['FD', '1', 'EffectiveRefractiveIndex'],\n    '0006': ['CS', '1', 'OCTAcquisitionDomain'],\n    '0007': ['FD', '1', 'OCTOpticalCenterWavelength'],\n    '0008': ['FD', '1', 'AxialResolution'],\n    '0009': ['FD', '1', 'RangingDepth'],\n    '0011': ['FD', '1', 'ALineRate'],\n    '0012': ['US', '1', 'ALinesPerFrame'],\n    '0013': ['FD', '1', 'CatheterRotationalRate'],\n    '0014': ['FD', '1', 'ALinePixelSpacing'],\n    '0016': ['SQ', '1', 'ModeOfPercutaneousAccessSequence'],\n    '0025': ['SQ', '1', 'IntravascularOCTFrameTypeSequence'],\n    '0026': ['CS', '1', 'OCTZOffsetApplied'],\n    '0027': ['SQ', '1', 'IntravascularFrameContentSequence'],\n    '0028': ['FD', '1', 'IntravascularLongitudinalDistance'],\n    '0029': ['SQ', '1', 'IntravascularOCTFrameContentSequence'],\n    '0030': ['SS', '1', 'OCTZOffsetCorrection'],\n    '0031': ['CS', '1', 'CatheterDirectionOfRotation'],\n    '0033': ['FD', '1', 'SeamLineLocation'],\n    '0034': ['FD', '1', 'FirstALineLocation'],\n    '0036': ['US', '1', 'SeamLineIndex'],\n    '0038': ['US', '1', 'NumberOfPaddedALines'],\n    '0039': ['CS', '1', 'InterpolationType'],\n    '003A': ['CS', '1', 'RefractiveIndexApplied']\n  },\n  '0054': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['US', '1-n', 'EnergyWindowVector'],\n    '0011': ['US', '1', 'NumberOfEnergyWindows'],\n    '0012': ['SQ', '1', 'EnergyWindowInformationSequence'],\n    '0013': ['SQ', '1', 'EnergyWindowRangeSequence'],\n    '0014': ['DS', '1', 'EnergyWindowLowerLimit'],\n    '0015': ['DS', '1', 'EnergyWindowUpperLimit'],\n    '0016': ['SQ', '1', 'RadiopharmaceuticalInformationSequence'],\n    '0017': ['IS', '1', 'ResidualSyringeCounts'],\n    '0018': ['SH', '1', 'EnergyWindowName'],\n    '0020': ['US', '1-n', 'DetectorVector'],\n    '0021': ['US', '1', 'NumberOfDetectors'],\n    '0022': ['SQ', '1', 'DetectorInformationSequence'],\n    '0030': ['US', '1-n', 'PhaseVector'],\n    '0031': ['US', '1', 'NumberOfPhases'],\n    '0032': ['SQ', '1', 'PhaseInformationSequence'],\n    '0033': ['US', '1', 'NumberOfFramesInPhase'],\n    '0036': ['IS', '1', 'PhaseDelay'],\n    '0038': ['IS', '1', 'PauseBetweenFrames'],\n    '0039': ['CS', '1', 'PhaseDescription'],\n    '0050': ['US', '1-n', 'RotationVector'],\n    '0051': ['US', '1', 'NumberOfRotations'],\n    '0052': ['SQ', '1', 'RotationInformationSequence'],\n    '0053': ['US', '1', 'NumberOfFramesInRotation'],\n    '0060': ['US', '1-n', 'RRIntervalVector'],\n    '0061': ['US', '1', 'NumberOfRRIntervals'],\n    '0062': ['SQ', '1', 'GatedInformationSequence'],\n    '0063': ['SQ', '1', 'DataInformationSequence'],\n    '0070': ['US', '1-n', 'TimeSlotVector'],\n    '0071': ['US', '1', 'NumberOfTimeSlots'],\n    '0072': ['SQ', '1', 'TimeSlotInformationSequence'],\n    '0073': ['DS', '1', 'TimeSlotTime'],\n    '0080': ['US', '1-n', 'SliceVector'],\n    '0081': ['US', '1', 'NumberOfSlices'],\n    '0090': ['US', '1-n', 'AngularViewVector'],\n    '0100': ['US', '1-n', 'TimeSliceVector'],\n    '0101': ['US', '1', 'NumberOfTimeSlices'],\n    '0200': ['DS', '1', 'StartAngle'],\n    '0202': ['CS', '1', 'TypeOfDetectorMotion'],\n    '0210': ['IS', '1-n', 'TriggerVector'],\n    '0211': ['US', '1', 'NumberOfTriggersInPhase'],\n    '0220': ['SQ', '1', 'ViewCodeSequence'],\n    '0222': ['SQ', '1', 'ViewModifierCodeSequence'],\n    '0300': ['SQ', '1', 'RadionuclideCodeSequence'],\n    '0302': ['SQ', '1', 'AdministrationRouteCodeSequence'],\n    '0304': ['SQ', '1', 'RadiopharmaceuticalCodeSequence'],\n    '0306': ['SQ', '1', 'CalibrationDataSequence'],\n    '0308': ['US', '1', 'EnergyWindowNumber'],\n    '0400': ['SH', '1', 'ImageID'],\n    '0410': ['SQ', '1', 'PatientOrientationCodeSequence'],\n    '0412': ['SQ', '1', 'PatientOrientationModifierCodeSequence'],\n    '0414': ['SQ', '1', 'PatientGantryRelationshipCodeSequence'],\n    '0500': ['CS', '1', 'SliceProgressionDirection'],\n    '0501': ['CS', '1', 'ScanProgressionDirection'],\n    '1000': ['CS', '2', 'SeriesType'],\n    '1001': ['CS', '1', 'Units'],\n    '1002': ['CS', '1', 'CountsSource'],\n    '1004': ['CS', '1', 'ReprojectionMethod'],\n    '1006': ['CS', '1', 'SUVType'],\n    '1100': ['CS', '1', 'RandomsCorrectionMethod'],\n    '1101': ['LO', '1', 'AttenuationCorrectionMethod'],\n    '1102': ['CS', '1', 'DecayCorrection'],\n    '1103': ['LO', '1', 'ReconstructionMethod'],\n    '1104': ['LO', '1', 'DetectorLinesOfResponseUsed'],\n    '1105': ['LO', '1', 'ScatterCorrectionMethod'],\n    '1200': ['DS', '1', 'AxialAcceptance'],\n    '1201': ['IS', '2', 'AxialMash'],\n    '1202': ['IS', '1', 'TransverseMash'],\n    '1203': ['DS', '2', 'DetectorElementSize'],\n    '1210': ['DS', '1', 'CoincidenceWindowWidth'],\n    '1220': ['CS', '1-n', 'SecondaryCountsType'],\n    '1300': ['DS', '1', 'FrameReferenceTime'],\n    '1310': ['IS', '1', 'PrimaryPromptsCountsAccumulated'],\n    '1311': ['IS', '1-n', 'SecondaryCountsAccumulated'],\n    '1320': ['DS', '1', 'SliceSensitivityFactor'],\n    '1321': ['DS', '1', 'DecayFactor'],\n    '1322': ['DS', '1', 'DoseCalibrationFactor'],\n    '1323': ['DS', '1', 'ScatterFractionFactor'],\n    '1324': ['DS', '1', 'DeadTimeFactor'],\n    '1330': ['US', '1', 'ImageIndex'],\n    '1400': ['CS', '1-n', 'CountsIncluded'],\n    '1401': ['CS', '1', 'DeadTimeCorrectionFlag']\n  },\n  '0060': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '3000': ['SQ', '1', 'HistogramSequence'],\n    '3002': ['US', '1', 'HistogramNumberOfBins'],\n    '3004': ['xs', '1', 'HistogramFirstBinValue'],\n    '3006': ['xs', '1', 'HistogramLastBinValue'],\n    '3008': ['US', '1', 'HistogramBinWidth'],\n    '3010': ['LO', '1', 'HistogramExplanation'],\n    '3020': ['UL', '1-n', 'HistogramData']\n  },\n  '0062': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['CS', '1', 'SegmentationType'],\n    '0002': ['SQ', '1', 'SegmentSequence'],\n    '0003': ['SQ', '1', 'SegmentedPropertyCategoryCodeSequence'],\n    '0004': ['US', '1', 'SegmentNumber'],\n    '0005': ['LO', '1', 'SegmentLabel'],\n    '0006': ['ST', '1', 'SegmentDescription'],\n    '0007': ['SQ', '1', 'SegmentationAlgorithmIdentificationSequence'],\n    '0008': ['CS', '1', 'SegmentAlgorithmType'],\n    '0009': ['LO', '1-n', 'SegmentAlgorithmName'],\n    '000A': ['SQ', '1', 'SegmentIdentificationSequence'],\n    '000B': ['US', '1-n', 'ReferencedSegmentNumber'],\n    '000C': ['US', '1', 'RecommendedDisplayGrayscaleValue'],\n    '000D': ['US', '3', 'RecommendedDisplayCIELabValue'],\n    '000E': ['US', '1', 'MaximumFractionalValue'],\n    '000F': ['SQ', '1', 'SegmentedPropertyTypeCodeSequence'],\n    '0010': ['CS', '1', 'SegmentationFractionalType'],\n    '0011': ['SQ', '1', 'SegmentedPropertyTypeModifierCodeSequence'],\n    '0012': ['SQ', '1', 'UsedSegmentsSequence'],\n    '0013': ['CS', '1', 'SegmentsOverlap'],\n    '0020': ['UT', '1', 'TrackingID'],\n    '0021': ['UI', '1', 'TrackingUID']\n  },\n  '0064': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['SQ', '1', 'DeformableRegistrationSequence'],\n    '0003': ['UI', '1', 'SourceFrameOfReferenceUID'],\n    '0005': ['SQ', '1', 'DeformableRegistrationGridSequence'],\n    '0007': ['UL', '3', 'GridDimensions'],\n    '0008': ['FD', '3', 'GridResolution'],\n    '0009': ['OF', '1', 'VectorGridData'],\n    '000F': ['SQ', '1', 'PreDeformationMatrixRegistrationSequence'],\n    '0010': ['SQ', '1', 'PostDeformationMatrixRegistrationSequence']\n  },\n  '0066': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['UL', '1', 'NumberOfSurfaces'],\n    '0002': ['SQ', '1', 'SurfaceSequence'],\n    '0003': ['UL', '1', 'SurfaceNumber'],\n    '0004': ['LT', '1', 'SurfaceComments'],\n    '0009': ['CS', '1', 'SurfaceProcessing'],\n    '000A': ['FL', '1', 'SurfaceProcessingRatio'],\n    '000B': ['LO', '1', 'SurfaceProcessingDescription'],\n    '000C': ['FL', '1', 'RecommendedPresentationOpacity'],\n    '000D': ['CS', '1', 'RecommendedPresentationType'],\n    '000E': ['CS', '1', 'FiniteVolume'],\n    '0010': ['CS', '1', 'Manifold'],\n    '0011': ['SQ', '1', 'SurfacePointsSequence'],\n    '0012': ['SQ', '1', 'SurfacePointsNormalsSequence'],\n    '0013': ['SQ', '1', 'SurfaceMeshPrimitivesSequence'],\n    '0015': ['UL', '1', 'NumberOfSurfacePoints'],\n    '0016': ['OF', '1', 'PointCoordinatesData'],\n    '0017': ['FL', '3', 'PointPositionAccuracy'],\n    '0018': ['FL', '1', 'MeanPointDistance'],\n    '0019': ['FL', '1', 'MaximumPointDistance'],\n    '001A': ['FL', '6', 'PointsBoundingBoxCoordinates'],\n    '001B': ['FL', '3', 'AxisOfRotation'],\n    '001C': ['FL', '3', 'CenterOfRotation'],\n    '001E': ['UL', '1', 'NumberOfVectors'],\n    '001F': ['US', '1', 'VectorDimensionality'],\n    '0020': ['FL', '1-n', 'VectorAccuracy'],\n    '0021': ['OF', '1', 'VectorCoordinateData'],\n    '0022': ['OD', '1', 'DoublePointCoordinatesData'],\n    '0023': ['OW', '1', 'TrianglePointIndexList'],\n    '0024': ['OW', '1', 'EdgePointIndexList'],\n    '0025': ['OW', '1', 'VertexPointIndexList'],\n    '0026': ['SQ', '1', 'TriangleStripSequence'],\n    '0027': ['SQ', '1', 'TriangleFanSequence'],\n    '0028': ['SQ', '1', 'LineSequence'],\n    '0029': ['OW', '1', 'PrimitivePointIndexList'],\n    '002A': ['UL', '1', 'SurfaceCount'],\n    '002B': ['SQ', '1', 'ReferencedSurfaceSequence'],\n    '002C': ['UL', '1', 'ReferencedSurfaceNumber'],\n    '002D': ['SQ', '1', 'SegmentSurfaceGenerationAlgorithmIdentificationSequence'],\n    '002E': ['SQ', '1', 'SegmentSurfaceSourceInstanceSequence'],\n    '002F': ['SQ', '1', 'AlgorithmFamilyCodeSequence'],\n    '0030': ['SQ', '1', 'AlgorithmNameCodeSequence'],\n    '0031': ['LO', '1', 'AlgorithmVersion'],\n    '0032': ['LT', '1', 'AlgorithmParameters'],\n    '0034': ['SQ', '1', 'FacetSequence'],\n    '0035': ['SQ', '1', 'SurfaceProcessingAlgorithmIdentificationSequence'],\n    '0036': ['LO', '1', 'AlgorithmName'],\n    '0037': ['FL', '1', 'RecommendedPointRadius'],\n    '0038': ['FL', '1', 'RecommendedLineThickness'],\n    '0040': ['OL', '1', 'LongPrimitivePointIndexList'],\n    '0041': ['OL', '1', 'LongTrianglePointIndexList'],\n    '0042': ['OL', '1', 'LongEdgePointIndexList'],\n    '0043': ['OL', '1', 'LongVertexPointIndexList'],\n    '0101': ['SQ', '1', 'TrackSetSequence'],\n    '0102': ['SQ', '1', 'TrackSequence'],\n    '0103': ['OW', '1', 'RecommendedDisplayCIELabValueList'],\n    '0104': ['SQ', '1', 'TrackingAlgorithmIdentificationSequence'],\n    '0105': ['UL', '1', 'TrackSetNumber'],\n    '0106': ['LO', '1', 'TrackSetLabel'],\n    '0107': ['UT', '1', 'TrackSetDescription'],\n    '0108': ['SQ', '1', 'TrackSetAnatomicalTypeCodeSequence'],\n    '0121': ['SQ', '1', 'MeasurementsSequence'],\n    '0124': ['SQ', '1', 'TrackSetStatisticsSequence'],\n    '0125': ['OF', '1', 'FloatingPointValues'],\n    '0129': ['OL', '1', 'TrackPointIndexList'],\n    '0130': ['SQ', '1', 'TrackStatisticsSequence'],\n    '0132': ['SQ', '1', 'MeasurementValuesSequence'],\n    '0133': ['SQ', '1', 'DiffusionAcquisitionCodeSequence'],\n    '0134': ['SQ', '1', 'DiffusionModelCodeSequence']\n  },\n  '0068': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '6210': ['LO', '1', 'ImplantSize'],\n    '6221': ['LO', '1', 'ImplantTemplateVersion'],\n    '6222': ['SQ', '1', 'ReplacedImplantTemplateSequence'],\n    '6223': ['CS', '1', 'ImplantType'],\n    '6224': ['SQ', '1', 'DerivationImplantTemplateSequence'],\n    '6225': ['SQ', '1', 'OriginalImplantTemplateSequence'],\n    '6226': ['DT', '1', 'EffectiveDateTime'],\n    '6230': ['SQ', '1', 'ImplantTargetAnatomySequence'],\n    '6260': ['SQ', '1', 'InformationFromManufacturerSequence'],\n    '6265': ['SQ', '1', 'NotificationFromManufacturerSequence'],\n    '6270': ['DT', '1', 'InformationIssueDateTime'],\n    '6280': ['ST', '1', 'InformationSummary'],\n    '62A0': ['SQ', '1', 'ImplantRegulatoryDisapprovalCodeSequence'],\n    '62A5': ['FD', '1', 'OverallTemplateSpatialTolerance'],\n    '62C0': ['SQ', '1', 'HPGLDocumentSequence'],\n    '62D0': ['US', '1', 'HPGLDocumentID'],\n    '62D5': ['LO', '1', 'HPGLDocumentLabel'],\n    '62E0': ['SQ', '1', 'ViewOrientationCodeSequence'],\n    '62F0': ['SQ', '1', 'ViewOrientationModifierCodeSequence'],\n    '62F2': ['FD', '1', 'HPGLDocumentScaling'],\n    '6300': ['OB', '1', 'HPGLDocument'],\n    '6310': ['US', '1', 'HPGLContourPenNumber'],\n    '6320': ['SQ', '1', 'HPGLPenSequence'],\n    '6330': ['US', '1', 'HPGLPenNumber'],\n    '6340': ['LO', '1', 'HPGLPenLabel'],\n    '6345': ['ST', '1', 'HPGLPenDescription'],\n    '6346': ['FD', '2', 'RecommendedRotationPoint'],\n    '6347': ['FD', '4', 'BoundingRectangle'],\n    '6350': ['US', '1-n', 'ImplantTemplate3DModelSurfaceNumber'],\n    '6360': ['SQ', '1', 'SurfaceModelDescriptionSequence'],\n    '6380': ['LO', '1', 'SurfaceModelLabel'],\n    '6390': ['FD', '1', 'SurfaceModelScalingFactor'],\n    '63A0': ['SQ', '1', 'MaterialsCodeSequence'],\n    '63A4': ['SQ', '1', 'CoatingMaterialsCodeSequence'],\n    '63A8': ['SQ', '1', 'ImplantTypeCodeSequence'],\n    '63AC': ['SQ', '1', 'FixationMethodCodeSequence'],\n    '63B0': ['SQ', '1', 'MatingFeatureSetsSequence'],\n    '63C0': ['US', '1', 'MatingFeatureSetID'],\n    '63D0': ['LO', '1', 'MatingFeatureSetLabel'],\n    '63E0': ['SQ', '1', 'MatingFeatureSequence'],\n    '63F0': ['US', '1', 'MatingFeatureID'],\n    '6400': ['SQ', '1', 'MatingFeatureDegreeOfFreedomSequence'],\n    '6410': ['US', '1', 'DegreeOfFreedomID'],\n    '6420': ['CS', '1', 'DegreeOfFreedomType'],\n    '6430': ['SQ', '1', 'TwoDMatingFeatureCoordinatesSequence'],\n    '6440': ['US', '1', 'ReferencedHPGLDocumentID'],\n    '6450': ['FD', '2', 'TwoDMatingPoint'],\n    '6460': ['FD', '4', 'TwoDMatingAxes'],\n    '6470': ['SQ', '1', 'TwoDDegreeOfFreedomSequence'],\n    '6490': ['FD', '3', 'ThreeDDegreeOfFreedomAxis'],\n    '64A0': ['FD', '2', 'RangeOfFreedom'],\n    '64C0': ['FD', '3', 'ThreeDMatingPoint'],\n    '64D0': ['FD', '9', 'ThreeDMatingAxes'],\n    '64F0': ['FD', '3', 'TwoDDegreeOfFreedomAxis'],\n    '6500': ['SQ', '1', 'PlanningLandmarkPointSequence'],\n    '6510': ['SQ', '1', 'PlanningLandmarkLineSequence'],\n    '6520': ['SQ', '1', 'PlanningLandmarkPlaneSequence'],\n    '6530': ['US', '1', 'PlanningLandmarkID'],\n    '6540': ['LO', '1', 'PlanningLandmarkDescription'],\n    '6545': ['SQ', '1', 'PlanningLandmarkIdentificationCodeSequence'],\n    '6550': ['SQ', '1', 'TwoDPointCoordinatesSequence'],\n    '6560': ['FD', '2', 'TwoDPointCoordinates'],\n    '6590': ['FD', '3', 'ThreeDPointCoordinates'],\n    '65A0': ['SQ', '1', 'TwoDLineCoordinatesSequence'],\n    '65B0': ['FD', '4', 'TwoDLineCoordinates'],\n    '65D0': ['FD', '6', 'ThreeDLineCoordinates'],\n    '65E0': ['SQ', '1', 'TwoDPlaneCoordinatesSequence'],\n    '65F0': ['FD', '4', 'TwoDPlaneIntersection'],\n    '6610': ['FD', '3', 'ThreeDPlaneOrigin'],\n    '6620': ['FD', '3', 'ThreeDPlaneNormal'],\n    '7001': ['CS', '1', 'ModelModification'],\n    '7002': ['CS', '1', 'ModelMirroring'],\n    '7003': ['SQ', '1', 'ModelUsageCodeSequence'],\n    '7004': ['UI', '1', 'ModelGroupUID'],\n    '7005': ['UR', '1', 'RelativeURIReferenceWithinEncapsulatedDocument']\n  },\n  '006A': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['CS', '1', 'AnnotationCoordinateType'],\n    '0002': ['SQ', '1', 'AnnotationGroupSequence'],\n    '0003': ['UI', '1', 'AnnotationGroupUID'],\n    '0005': ['LO', '1', 'AnnotationGroupLabel'],\n    '0006': ['UT', '1', 'AnnotationGroupDescription'],\n    '0007': ['CS', '1', 'AnnotationGroupGenerationType'],\n    '0008': ['SQ', '1', 'AnnotationGroupAlgorithmIdentificationSequence'],\n    '0009': ['SQ', '1', 'AnnotationPropertyCategoryCodeSequence'],\n    '000A': ['SQ', '1', 'AnnotationPropertyTypeCodeSequence'],\n    '000B': ['SQ', '1', 'AnnotationPropertyTypeModifierCodeSequence'],\n    '000C': ['UL', '1', 'NumberOfAnnotations'],\n    '000D': ['CS', '1', 'AnnotationAppliesToAllOpticalPaths'],\n    '000E': ['SH', '1-n', 'ReferencedOpticalPathIdentifier'],\n    '000F': ['CS', '1', 'AnnotationAppliesToAllZPlanes'],\n    '0010': ['FD', '1-n', 'CommonZCoordinateValue'],\n    '0011': ['OL', '1', 'AnnotationIndexList']\n  },\n  '0070': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['SQ', '1', 'GraphicAnnotationSequence'],\n    '0002': ['CS', '1', 'GraphicLayer'],\n    '0003': ['CS', '1', 'BoundingBoxAnnotationUnits'],\n    '0004': ['CS', '1', 'AnchorPointAnnotationUnits'],\n    '0005': ['CS', '1', 'GraphicAnnotationUnits'],\n    '0006': ['ST', '1', 'UnformattedTextValue'],\n    '0008': ['SQ', '1', 'TextObjectSequence'],\n    '0009': ['SQ', '1', 'GraphicObjectSequence'],\n    '0010': ['FL', '2', 'BoundingBoxTopLeftHandCorner'],\n    '0011': ['FL', '2', 'BoundingBoxBottomRightHandCorner'],\n    '0012': ['CS', '1', 'BoundingBoxTextHorizontalJustification'],\n    '0014': ['FL', '2', 'AnchorPoint'],\n    '0015': ['CS', '1', 'AnchorPointVisibility'],\n    '0020': ['US', '1', 'GraphicDimensions'],\n    '0021': ['US', '1', 'NumberOfGraphicPoints'],\n    '0022': ['FL', '2-n', 'GraphicData'],\n    '0023': ['CS', '1', 'GraphicType'],\n    '0024': ['CS', '1', 'GraphicFilled'],\n    '0040': ['IS', '1', 'ImageRotationRetired'],\n    '0041': ['CS', '1', 'ImageHorizontalFlip'],\n    '0042': ['US', '1', 'ImageRotation'],\n    '0050': ['US', '2', 'DisplayedAreaTopLeftHandCornerTrial'],\n    '0051': ['US', '2', 'DisplayedAreaBottomRightHandCornerTrial'],\n    '0052': ['SL', '2', 'DisplayedAreaTopLeftHandCorner'],\n    '0053': ['SL', '2', 'DisplayedAreaBottomRightHandCorner'],\n    '005A': ['SQ', '1', 'DisplayedAreaSelectionSequence'],\n    '0060': ['SQ', '1', 'GraphicLayerSequence'],\n    '0062': ['IS', '1', 'GraphicLayerOrder'],\n    '0066': ['US', '1', 'GraphicLayerRecommendedDisplayGrayscaleValue'],\n    '0067': ['US', '3', 'GraphicLayerRecommendedDisplayRGBValue'],\n    '0068': ['LO', '1', 'GraphicLayerDescription'],\n    '0080': ['CS', '1', 'ContentLabel'],\n    '0081': ['LO', '1', 'ContentDescription'],\n    '0082': ['DA', '1', 'PresentationCreationDate'],\n    '0083': ['TM', '1', 'PresentationCreationTime'],\n    '0084': ['PN', '1', 'ContentCreatorName'],\n    '0086': ['SQ', '1', 'ContentCreatorIdentificationCodeSequence'],\n    '0087': ['SQ', '1', 'AlternateContentDescriptionSequence'],\n    '0100': ['CS', '1', 'PresentationSizeMode'],\n    '0101': ['DS', '2', 'PresentationPixelSpacing'],\n    '0102': ['IS', '2', 'PresentationPixelAspectRatio'],\n    '0103': ['FL', '1', 'PresentationPixelMagnificationRatio'],\n    '0207': ['LO', '1', 'GraphicGroupLabel'],\n    '0208': ['ST', '1', 'GraphicGroupDescription'],\n    '0209': ['SQ', '1', 'CompoundGraphicSequence'],\n    '0226': ['UL', '1', 'CompoundGraphicInstanceID'],\n    '0227': ['LO', '1', 'FontName'],\n    '0228': ['CS', '1', 'FontNameType'],\n    '0229': ['LO', '1', 'CSSFontName'],\n    '0230': ['FD', '1', 'RotationAngle'],\n    '0231': ['SQ', '1', 'TextStyleSequence'],\n    '0232': ['SQ', '1', 'LineStyleSequence'],\n    '0233': ['SQ', '1', 'FillStyleSequence'],\n    '0234': ['SQ', '1', 'GraphicGroupSequence'],\n    '0241': ['US', '3', 'TextColorCIELabValue'],\n    '0242': ['CS', '1', 'HorizontalAlignment'],\n    '0243': ['CS', '1', 'VerticalAlignment'],\n    '0244': ['CS', '1', 'ShadowStyle'],\n    '0245': ['FL', '1', 'ShadowOffsetX'],\n    '0246': ['FL', '1', 'ShadowOffsetY'],\n    '0247': ['US', '3', 'ShadowColorCIELabValue'],\n    '0248': ['CS', '1', 'Underlined'],\n    '0249': ['CS', '1', 'Bold'],\n    '0250': ['CS', '1', 'Italic'],\n    '0251': ['US', '3', 'PatternOnColorCIELabValue'],\n    '0252': ['US', '3', 'PatternOffColorCIELabValue'],\n    '0253': ['FL', '1', 'LineThickness'],\n    '0254': ['CS', '1', 'LineDashingStyle'],\n    '0255': ['UL', '1', 'LinePattern'],\n    '0256': ['OB', '1', 'FillPattern'],\n    '0257': ['CS', '1', 'FillMode'],\n    '0258': ['FL', '1', 'ShadowOpacity'],\n    '0261': ['FL', '1', 'GapLength'],\n    '0262': ['FL', '1', 'DiameterOfVisibility'],\n    '0273': ['FL', '2', 'RotationPoint'],\n    '0274': ['CS', '1', 'TickAlignment'],\n    '0278': ['CS', '1', 'ShowTickLabel'],\n    '0279': ['CS', '1', 'TickLabelAlignment'],\n    '0282': ['CS', '1', 'CompoundGraphicUnits'],\n    '0284': ['FL', '1', 'PatternOnOpacity'],\n    '0285': ['FL', '1', 'PatternOffOpacity'],\n    '0287': ['SQ', '1', 'MajorTicksSequence'],\n    '0288': ['FL', '1', 'TickPosition'],\n    '0289': ['SH', '1', 'TickLabel'],\n    '0294': ['CS', '1', 'CompoundGraphicType'],\n    '0295': ['UL', '1', 'GraphicGroupID'],\n    '0306': ['CS', '1', 'ShapeType'],\n    '0308': ['SQ', '1', 'RegistrationSequence'],\n    '0309': ['SQ', '1', 'MatrixRegistrationSequence'],\n    '030A': ['SQ', '1', 'MatrixSequence'],\n    '030B': ['FD', '16', 'FrameOfReferenceToDisplayedCoordinateSystemTransformationMatrix'],\n    '030C': ['CS', '1', 'FrameOfReferenceTransformationMatrixType'],\n    '030D': ['SQ', '1', 'RegistrationTypeCodeSequence'],\n    '030F': ['ST', '1', 'FiducialDescription'],\n    '0310': ['SH', '1', 'FiducialIdentifier'],\n    '0311': ['SQ', '1', 'FiducialIdentifierCodeSequence'],\n    '0312': ['FD', '1', 'ContourUncertaintyRadius'],\n    '0314': ['SQ', '1', 'UsedFiducialsSequence'],\n    '0318': ['SQ', '1', 'GraphicCoordinatesDataSequence'],\n    '031A': ['UI', '1', 'FiducialUID'],\n    '031B': ['UI', '1', 'ReferencedFiducialUID'],\n    '031C': ['SQ', '1', 'FiducialSetSequence'],\n    '031E': ['SQ', '1', 'FiducialSequence'],\n    '031F': ['SQ', '1', 'FiducialsPropertyCategoryCodeSequence'],\n    '0401': ['US', '3', 'GraphicLayerRecommendedDisplayCIELabValue'],\n    '0402': ['SQ', '1', 'BlendingSequence'],\n    '0403': ['FL', '1', 'RelativeOpacity'],\n    '0404': ['SQ', '1', 'ReferencedSpatialRegistrationSequence'],\n    '0405': ['CS', '1', 'BlendingPosition'],\n    '1101': ['UI', '1', 'PresentationDisplayCollectionUID'],\n    '1102': ['UI', '1', 'PresentationSequenceCollectionUID'],\n    '1103': ['US', '1', 'PresentationSequencePositionIndex'],\n    '1104': ['SQ', '1', 'RenderedImageReferenceSequence'],\n    '1201': ['SQ', '1', 'VolumetricPresentationStateInputSequence'],\n    '1202': ['CS', '1', 'PresentationInputType'],\n    '1203': ['US', '1', 'InputSequencePositionIndex'],\n    '1204': ['CS', '1', 'Crop'],\n    '1205': ['US', '1-n', 'CroppingSpecificationIndex'],\n    '1206': ['CS', '1', 'CompositingMethod'],\n    '1207': ['US', '1', 'VolumetricPresentationInputNumber'],\n    '1208': ['CS', '1', 'ImageVolumeGeometry'],\n    '1209': ['UI', '1', 'VolumetricPresentationInputSetUID'],\n    '120A': ['SQ', '1', 'VolumetricPresentationInputSetSequence'],\n    '120B': ['CS', '1', 'GlobalCrop'],\n    '120C': ['US', '1-n', 'GlobalCroppingSpecificationIndex'],\n    '120D': ['CS', '1', 'RenderingMethod'],\n    '1301': ['SQ', '1', 'VolumeCroppingSequence'],\n    '1302': ['CS', '1', 'VolumeCroppingMethod'],\n    '1303': ['FD', '6', 'BoundingBoxCrop'],\n    '1304': ['SQ', '1', 'ObliqueCroppingPlaneSequence'],\n    '1305': ['FD', '4', 'Plane'],\n    '1306': ['FD', '3', 'PlaneNormal'],\n    '1309': ['US', '1', 'CroppingSpecificationNumber'],\n    '1501': ['CS', '1', 'MultiPlanarReconstructionStyle'],\n    '1502': ['CS', '1', 'MPRThicknessType'],\n    '1503': ['FD', '1', 'MPRSlabThickness'],\n    '1505': ['FD', '3', 'MPRTopLeftHandCorner'],\n    '1507': ['FD', '3', 'MPRViewWidthDirection'],\n    '1508': ['FD', '1', 'MPRViewWidth'],\n    '150C': ['UL', '1', 'NumberOfVolumetricCurvePoints'],\n    '150D': ['OD', '1', 'VolumetricCurvePoints'],\n    '1511': ['FD', '3', 'MPRViewHeightDirection'],\n    '1512': ['FD', '1', 'MPRViewHeight'],\n    '1602': ['CS', '1', 'RenderProjection'],\n    '1603': ['FD', '3', 'ViewpointPosition'],\n    '1604': ['FD', '3', 'ViewpointLookAtPoint'],\n    '1605': ['FD', '3', 'ViewpointUpDirection'],\n    '1606': ['FD', '6', 'RenderFieldOfView'],\n    '1607': ['FD', '1', 'SamplingStepSize'],\n    '1701': ['CS', '1', 'ShadingStyle'],\n    '1702': ['FD', '1', 'AmbientReflectionIntensity'],\n    '1703': ['FD', '3', 'LightDirection'],\n    '1704': ['FD', '1', 'DiffuseReflectionIntensity'],\n    '1705': ['FD', '1', 'SpecularReflectionIntensity'],\n    '1706': ['FD', '1', 'Shininess'],\n    '1801': ['SQ', '1', 'PresentationStateClassificationComponentSequence'],\n    '1802': ['CS', '1', 'ComponentType'],\n    '1803': ['SQ', '1', 'ComponentInputSequence'],\n    '1804': ['US', '1', 'VolumetricPresentationInputIndex'],\n    '1805': ['SQ', '1', 'PresentationStateCompositorComponentSequence'],\n    '1806': ['SQ', '1', 'WeightingTransferFunctionSequence'],\n    '1807': ['US', '3', 'WeightingLookupTableDescriptor'],\n    '1808': ['OB', '1', 'WeightingLookupTableData'],\n    '1901': ['SQ', '1', 'VolumetricAnnotationSequence'],\n    '1903': ['SQ', '1', 'ReferencedStructuredContextSequence'],\n    '1904': ['UI', '1', 'ReferencedContentItem'],\n    '1905': ['SQ', '1', 'VolumetricPresentationInputAnnotationSequence'],\n    '1907': ['CS', '1', 'AnnotationClipping'],\n    '1A01': ['CS', '1', 'PresentationAnimationStyle'],\n    '1A03': ['FD', '1', 'RecommendedAnimationRate'],\n    '1A04': ['SQ', '1', 'AnimationCurveSequence'],\n    '1A05': ['FD', '1', 'AnimationStepSize'],\n    '1A06': ['FD', '1', 'SwivelRange'],\n    '1A07': ['OD', '1', 'VolumetricCurveUpDirections'],\n    '1A08': ['SQ', '1', 'VolumeStreamSequence'],\n    '1A09': ['LO', '1', 'RGBATransferFunctionDescription'],\n    '1B01': ['SQ', '1', 'AdvancedBlendingSequence'],\n    '1B02': ['US', '1', 'BlendingInputNumber'],\n    '1B03': ['SQ', '1', 'BlendingDisplayInputSequence'],\n    '1B04': ['SQ', '1', 'BlendingDisplaySequence'],\n    '1B06': ['CS', '1', 'BlendingMode'],\n    '1B07': ['CS', '1', 'TimeSeriesBlending'],\n    '1B08': ['CS', '1', 'GeometryForDisplay'],\n    '1B11': ['SQ', '1', 'ThresholdSequence'],\n    '1B12': ['SQ', '1', 'ThresholdValueSequence'],\n    '1B13': ['CS', '1', 'ThresholdType'],\n    '1B14': ['FD', '1', 'ThresholdValue']\n  },\n  '0072': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['SH', '1', 'HangingProtocolName'],\n    '0004': ['LO', '1', 'HangingProtocolDescription'],\n    '0006': ['CS', '1', 'HangingProtocolLevel'],\n    '0008': ['LO', '1', 'HangingProtocolCreator'],\n    '000A': ['DT', '1', 'HangingProtocolCreationDateTime'],\n    '000C': ['SQ', '1', 'HangingProtocolDefinitionSequence'],\n    '000E': ['SQ', '1', 'HangingProtocolUserIdentificationCodeSequence'],\n    '0010': ['LO', '1', 'HangingProtocolUserGroupName'],\n    '0012': ['SQ', '1', 'SourceHangingProtocolSequence'],\n    '0014': ['US', '1', 'NumberOfPriorsReferenced'],\n    '0020': ['SQ', '1', 'ImageSetsSequence'],\n    '0022': ['SQ', '1', 'ImageSetSelectorSequence'],\n    '0024': ['CS', '1', 'ImageSetSelectorUsageFlag'],\n    '0026': ['AT', '1', 'SelectorAttribute'],\n    '0028': ['US', '1', 'SelectorValueNumber'],\n    '0030': ['SQ', '1', 'TimeBasedImageSetsSequence'],\n    '0032': ['US', '1', 'ImageSetNumber'],\n    '0034': ['CS', '1', 'ImageSetSelectorCategory'],\n    '0038': ['US', '2', 'RelativeTime'],\n    '003A': ['CS', '1', 'RelativeTimeUnits'],\n    '003C': ['SS', '2', 'AbstractPriorValue'],\n    '003E': ['SQ', '1', 'AbstractPriorCodeSequence'],\n    '0040': ['LO', '1', 'ImageSetLabel'],\n    '0050': ['CS', '1', 'SelectorAttributeVR'],\n    '0052': ['AT', '1-n', 'SelectorSequencePointer'],\n    '0054': ['LO', '1-n', 'SelectorSequencePointerPrivateCreator'],\n    '0056': ['LO', '1', 'SelectorAttributePrivateCreator'],\n    '005E': ['AE', '1-n', 'SelectorAEValue'],\n    '005F': ['AS', '1-n', 'SelectorASValue'],\n    '0060': ['AT', '1-n', 'SelectorATValue'],\n    '0061': ['DA', '1-n', 'SelectorDAValue'],\n    '0062': ['CS', '1-n', 'SelectorCSValue'],\n    '0063': ['DT', '1-n', 'SelectorDTValue'],\n    '0064': ['IS', '1-n', 'SelectorISValue'],\n    '0065': ['OB', '1', 'SelectorOBValue'],\n    '0066': ['LO', '1-n', 'SelectorLOValue'],\n    '0067': ['OF', '1', 'SelectorOFValue'],\n    '0068': ['LT', '1', 'SelectorLTValue'],\n    '0069': ['OW', '1', 'SelectorOWValue'],\n    '006A': ['PN', '1-n', 'SelectorPNValue'],\n    '006B': ['TM', '1-n', 'SelectorTMValue'],\n    '006C': ['SH', '1-n', 'SelectorSHValue'],\n    '006D': ['UN', '1', 'SelectorUNValue'],\n    '006E': ['ST', '1', 'SelectorSTValue'],\n    '006F': ['UC', '1-n', 'SelectorUCValue'],\n    '0070': ['UT', '1', 'SelectorUTValue'],\n    '0071': ['UR', '1', 'SelectorURValue'],\n    '0072': ['DS', '1-n', 'SelectorDSValue'],\n    '0073': ['OD', '1', 'SelectorODValue'],\n    '0074': ['FD', '1-n', 'SelectorFDValue'],\n    '0075': ['OL', '1', 'SelectorOLValue'],\n    '0076': ['FL', '1-n', 'SelectorFLValue'],\n    '0078': ['UL', '1-n', 'SelectorULValue'],\n    '007A': ['US', '1-n', 'SelectorUSValue'],\n    '007C': ['SL', '1-n', 'SelectorSLValue'],\n    '007E': ['SS', '1-n', 'SelectorSSValue'],\n    '007F': ['UI', '1-n', 'SelectorUIValue'],\n    '0080': ['SQ', '1', 'SelectorCodeSequenceValue'],\n    '0081': ['OV', '1', 'SelectorOVValue'],\n    '0082': ['SV', '1-n', 'SelectorSVValue'],\n    '0083': ['UV', '1-n', 'SelectorUVValue'],\n    '0100': ['US', '1', 'NumberOfScreens'],\n    '0102': ['SQ', '1', 'NominalScreenDefinitionSequence'],\n    '0104': ['US', '1', 'NumberOfVerticalPixels'],\n    '0106': ['US', '1', 'NumberOfHorizontalPixels'],\n    '0108': ['FD', '4', 'DisplayEnvironmentSpatialPosition'],\n    '010A': ['US', '1', 'ScreenMinimumGrayscaleBitDepth'],\n    '010C': ['US', '1', 'ScreenMinimumColorBitDepth'],\n    '010E': ['US', '1', 'ApplicationMaximumRepaintTime'],\n    '0200': ['SQ', '1', 'DisplaySetsSequence'],\n    '0202': ['US', '1', 'DisplaySetNumber'],\n    '0203': ['LO', '1', 'DisplaySetLabel'],\n    '0204': ['US', '1', 'DisplaySetPresentationGroup'],\n    '0206': ['LO', '1', 'DisplaySetPresentationGroupDescription'],\n    '0208': ['CS', '1', 'PartialDataDisplayHandling'],\n    '0210': ['SQ', '1', 'SynchronizedScrollingSequence'],\n    '0212': ['US', '2-n', 'DisplaySetScrollingGroup'],\n    '0214': ['SQ', '1', 'NavigationIndicatorSequence'],\n    '0216': ['US', '1', 'NavigationDisplaySet'],\n    '0218': ['US', '1-n', 'ReferenceDisplaySets'],\n    '0300': ['SQ', '1', 'ImageBoxesSequence'],\n    '0302': ['US', '1', 'ImageBoxNumber'],\n    '0304': ['CS', '1', 'ImageBoxLayoutType'],\n    '0306': ['US', '1', 'ImageBoxTileHorizontalDimension'],\n    '0308': ['US', '1', 'ImageBoxTileVerticalDimension'],\n    '0310': ['CS', '1', 'ImageBoxScrollDirection'],\n    '0312': ['CS', '1', 'ImageBoxSmallScrollType'],\n    '0314': ['US', '1', 'ImageBoxSmallScrollAmount'],\n    '0316': ['CS', '1', 'ImageBoxLargeScrollType'],\n    '0318': ['US', '1', 'ImageBoxLargeScrollAmount'],\n    '0320': ['US', '1', 'ImageBoxOverlapPriority'],\n    '0330': ['FD', '1', 'CineRelativeToRealTime'],\n    '0400': ['SQ', '1', 'FilterOperationsSequence'],\n    '0402': ['CS', '1', 'FilterByCategory'],\n    '0404': ['CS', '1', 'FilterByAttributePresence'],\n    '0406': ['CS', '1', 'FilterByOperator'],\n    '0420': ['US', '3', 'StructuredDisplayBackgroundCIELabValue'],\n    '0421': ['US', '3', 'EmptyImageBoxCIELabValue'],\n    '0422': ['SQ', '1', 'StructuredDisplayImageBoxSequence'],\n    '0424': ['SQ', '1', 'StructuredDisplayTextBoxSequence'],\n    '0427': ['SQ', '1', 'ReferencedFirstFrameSequence'],\n    '0430': ['SQ', '1', 'ImageBoxSynchronizationSequence'],\n    '0432': ['US', '2-n', 'SynchronizedImageBoxList'],\n    '0434': ['CS', '1', 'TypeOfSynchronization'],\n    '0500': ['CS', '1', 'BlendingOperationType'],\n    '0510': ['CS', '1', 'ReformattingOperationType'],\n    '0512': ['FD', '1', 'ReformattingThickness'],\n    '0514': ['FD', '1', 'ReformattingInterval'],\n    '0516': ['CS', '1', 'ReformattingOperationInitialViewDirection'],\n    '0520': ['CS', '1-n', 'ThreeDRenderingType'],\n    '0600': ['SQ', '1', 'SortingOperationsSequence'],\n    '0602': ['CS', '1', 'SortByCategory'],\n    '0604': ['CS', '1', 'SortingDirection'],\n    '0700': ['CS', '2', 'DisplaySetPatientOrientation'],\n    '0702': ['CS', '1', 'VOIType'],\n    '0704': ['CS', '1', 'PseudoColorType'],\n    '0705': ['SQ', '1', 'PseudoColorPaletteInstanceReferenceSequence'],\n    '0706': ['CS', '1', 'ShowGrayscaleInverted'],\n    '0710': ['CS', '1', 'ShowImageTrueSizeFlag'],\n    '0712': ['CS', '1', 'ShowGraphicAnnotationFlag'],\n    '0714': ['CS', '1', 'ShowPatientDemographicsFlag'],\n    '0716': ['CS', '1', 'ShowAcquisitionTechniquesFlag'],\n    '0717': ['CS', '1', 'DisplaySetHorizontalJustification'],\n    '0718': ['CS', '1', 'DisplaySetVerticalJustification']\n  },\n  '0074': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0120': ['FD', '1', 'ContinuationStartMeterset'],\n    '0121': ['FD', '1', 'ContinuationEndMeterset'],\n    '1000': ['CS', '1', 'ProcedureStepState'],\n    '1002': ['SQ', '1', 'ProcedureStepProgressInformationSequence'],\n    '1004': ['DS', '1', 'ProcedureStepProgress'],\n    '1006': ['ST', '1', 'ProcedureStepProgressDescription'],\n    '1007': ['SQ', '1', 'ProcedureStepProgressParametersSequence'],\n    '1008': ['SQ', '1', 'ProcedureStepCommunicationsURISequence'],\n    '100A': ['UR', '1', 'ContactURI'],\n    '100C': ['LO', '1', 'ContactDisplayName'],\n    '100E': ['SQ', '1', 'ProcedureStepDiscontinuationReasonCodeSequence'],\n    '1020': ['SQ', '1', 'BeamTaskSequence'],\n    '1022': ['CS', '1', 'BeamTaskType'],\n    '1024': ['IS', '1', 'BeamOrderIndexTrial'],\n    '1025': ['CS', '1', 'AutosequenceFlag'],\n    '1026': ['FD', '1', 'TableTopVerticalAdjustedPosition'],\n    '1027': ['FD', '1', 'TableTopLongitudinalAdjustedPosition'],\n    '1028': ['FD', '1', 'TableTopLateralAdjustedPosition'],\n    '102A': ['FD', '1', 'PatientSupportAdjustedAngle'],\n    '102B': ['FD', '1', 'TableTopEccentricAdjustedAngle'],\n    '102C': ['FD', '1', 'TableTopPitchAdjustedAngle'],\n    '102D': ['FD', '1', 'TableTopRollAdjustedAngle'],\n    '1030': ['SQ', '1', 'DeliveryVerificationImageSequence'],\n    '1032': ['CS', '1', 'VerificationImageTiming'],\n    '1034': ['CS', '1', 'DoubleExposureFlag'],\n    '1036': ['CS', '1', 'DoubleExposureOrdering'],\n    '1038': ['DS', '1', 'DoubleExposureMetersetTrial'],\n    '103A': ['DS', '4', 'DoubleExposureFieldDeltaTrial'],\n    '1040': ['SQ', '1', 'RelatedReferenceRTImageSequence'],\n    '1042': ['SQ', '1', 'GeneralMachineVerificationSequence'],\n    '1044': ['SQ', '1', 'ConventionalMachineVerificationSequence'],\n    '1046': ['SQ', '1', 'IonMachineVerificationSequence'],\n    '1048': ['SQ', '1', 'FailedAttributesSequence'],\n    '104A': ['SQ', '1', 'OverriddenAttributesSequence'],\n    '104C': ['SQ', '1', 'ConventionalControlPointVerificationSequence'],\n    '104E': ['SQ', '1', 'IonControlPointVerificationSequence'],\n    '1050': ['SQ', '1', 'AttributeOccurrenceSequence'],\n    '1052': ['AT', '1', 'AttributeOccurrencePointer'],\n    '1054': ['UL', '1', 'AttributeItemSelector'],\n    '1056': ['LO', '1', 'AttributeOccurrencePrivateCreator'],\n    '1057': ['IS', '1-n', 'SelectorSequencePointerItems'],\n    '1200': ['CS', '1', 'ScheduledProcedureStepPriority'],\n    '1202': ['LO', '1', 'WorklistLabel'],\n    '1204': ['LO', '1', 'ProcedureStepLabel'],\n    '1210': ['SQ', '1', 'ScheduledProcessingParametersSequence'],\n    '1212': ['SQ', '1', 'PerformedProcessingParametersSequence'],\n    '1216': ['SQ', '1', 'UnifiedProcedureStepPerformedProcedureSequence'],\n    '1220': ['SQ', '1', 'RelatedProcedureStepSequence'],\n    '1222': ['LO', '1', 'ProcedureStepRelationshipType'],\n    '1224': ['SQ', '1', 'ReplacedProcedureStepSequence'],\n    '1230': ['LO', '1', 'DeletionLock'],\n    '1234': ['AE', '1', 'ReceivingAE'],\n    '1236': ['AE', '1', 'RequestingAE'],\n    '1238': ['LT', '1', 'ReasonForCancellation'],\n    '1242': ['CS', '1', 'SCPStatus'],\n    '1244': ['CS', '1', 'SubscriptionListStatus'],\n    '1246': ['CS', '1', 'UnifiedProcedureStepListStatus'],\n    '1324': ['UL', '1', 'BeamOrderIndex'],\n    '1338': ['FD', '1', 'DoubleExposureMeterset'],\n    '133A': ['FD', '4', 'DoubleExposureFieldDelta'],\n    '1401': ['SQ', '1', 'BrachyTaskSequence'],\n    '1402': ['DS', '1', 'ContinuationStartTotalReferenceAirKerma'],\n    '1403': ['DS', '1', 'ContinuationEndTotalReferenceAirKerma'],\n    '1404': ['IS', '1', 'ContinuationPulseNumber'],\n    '1405': ['SQ', '1', 'ChannelDeliveryOrderSequence'],\n    '1406': ['IS', '1', 'ReferencedChannelNumber'],\n    '1407': ['DS', '1', 'StartCumulativeTimeWeight'],\n    '1408': ['DS', '1', 'EndCumulativeTimeWeight'],\n    '1409': ['SQ', '1', 'OmittedChannelSequence'],\n    '140A': ['CS', '1', 'ReasonForChannelOmission'],\n    '140B': ['LO', '1', 'ReasonForChannelOmissionDescription'],\n    '140C': ['IS', '1', 'ChannelDeliveryOrderIndex'],\n    '140D': ['SQ', '1', 'ChannelDeliveryContinuationSequence'],\n    '140E': ['SQ', '1', 'OmittedApplicationSetupSequence']\n  },\n  '0076': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['LO', '1', 'ImplantAssemblyTemplateName'],\n    '0003': ['LO', '1', 'ImplantAssemblyTemplateIssuer'],\n    '0006': ['LO', '1', 'ImplantAssemblyTemplateVersion'],\n    '0008': ['SQ', '1', 'ReplacedImplantAssemblyTemplateSequence'],\n    '000A': ['CS', '1', 'ImplantAssemblyTemplateType'],\n    '000C': ['SQ', '1', 'OriginalImplantAssemblyTemplateSequence'],\n    '000E': ['SQ', '1', 'DerivationImplantAssemblyTemplateSequence'],\n    '0010': ['SQ', '1', 'ImplantAssemblyTemplateTargetAnatomySequence'],\n    '0020': ['SQ', '1', 'ProcedureTypeCodeSequence'],\n    '0030': ['LO', '1', 'SurgicalTechnique'],\n    '0032': ['SQ', '1', 'ComponentTypesSequence'],\n    '0034': ['SQ', '1', 'ComponentTypeCodeSequence'],\n    '0036': ['CS', '1', 'ExclusiveComponentType'],\n    '0038': ['CS', '1', 'MandatoryComponentType'],\n    '0040': ['SQ', '1', 'ComponentSequence'],\n    '0055': ['US', '1', 'ComponentID'],\n    '0060': ['SQ', '1', 'ComponentAssemblySequence'],\n    '0070': ['US', '1', 'Component1ReferencedID'],\n    '0080': ['US', '1', 'Component1ReferencedMatingFeatureSetID'],\n    '0090': ['US', '1', 'Component1ReferencedMatingFeatureID'],\n    '00A0': ['US', '1', 'Component2ReferencedID'],\n    '00B0': ['US', '1', 'Component2ReferencedMatingFeatureSetID'],\n    '00C0': ['US', '1', 'Component2ReferencedMatingFeatureID']\n  },\n  '0078': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['LO', '1', 'ImplantTemplateGroupName'],\n    '0010': ['ST', '1', 'ImplantTemplateGroupDescription'],\n    '0020': ['LO', '1', 'ImplantTemplateGroupIssuer'],\n    '0024': ['LO', '1', 'ImplantTemplateGroupVersion'],\n    '0026': ['SQ', '1', 'ReplacedImplantTemplateGroupSequence'],\n    '0028': ['SQ', '1', 'ImplantTemplateGroupTargetAnatomySequence'],\n    '002A': ['SQ', '1', 'ImplantTemplateGroupMembersSequence'],\n    '002E': ['US', '1', 'ImplantTemplateGroupMemberID'],\n    '0050': ['FD', '3', 'ThreeDImplantTemplateGroupMemberMatchingPoint'],\n    '0060': ['FD', '9', 'ThreeDImplantTemplateGroupMemberMatchingAxes'],\n    '0070': ['SQ', '1', 'ImplantTemplateGroupMemberMatching2DCoordinatesSequence'],\n    '0090': ['FD', '2', 'TwoDImplantTemplateGroupMemberMatchingPoint'],\n    '00A0': ['FD', '4', 'TwoDImplantTemplateGroupMemberMatchingAxes'],\n    '00B0': ['SQ', '1', 'ImplantTemplateGroupVariationDimensionSequence'],\n    '00B2': ['LO', '1', 'ImplantTemplateGroupVariationDimensionName'],\n    '00B4': ['SQ', '1', 'ImplantTemplateGroupVariationDimensionRankSequence'],\n    '00B6': ['US', '1', 'ReferencedImplantTemplateGroupMemberID'],\n    '00B8': ['US', '1', 'ImplantTemplateGroupVariationDimensionRank']\n  },\n  '0080': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['SQ', '1', 'SurfaceScanAcquisitionTypeCodeSequence'],\n    '0002': ['SQ', '1', 'SurfaceScanModeCodeSequence'],\n    '0003': ['SQ', '1', 'RegistrationMethodCodeSequence'],\n    '0004': ['FD', '1', 'ShotDurationTime'],\n    '0005': ['FD', '1', 'ShotOffsetTime'],\n    '0006': ['US', '1-n', 'SurfacePointPresentationValueData'],\n    '0007': ['US', '3-3n', 'SurfacePointColorCIELabValueData'],\n    '0008': ['SQ', '1', 'UVMappingSequence'],\n    '0009': ['SH', '1', 'TextureLabel'],\n    '0010': ['OF', '1', 'UValueData'],\n    '0011': ['OF', '1', 'VValueData'],\n    '0012': ['SQ', '1', 'ReferencedTextureSequence'],\n    '0013': ['SQ', '1', 'ReferencedSurfaceDataSequence']\n  },\n  '0082': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['CS', '1', 'AssessmentSummary'],\n    '0003': ['UT', '1', 'AssessmentSummaryDescription'],\n    '0004': ['SQ', '1', 'AssessedSOPInstanceSequence'],\n    '0005': ['SQ', '1', 'ReferencedComparisonSOPInstanceSequence'],\n    '0006': ['UL', '1', 'NumberOfAssessmentObservations'],\n    '0007': ['SQ', '1', 'AssessmentObservationsSequence'],\n    '0008': ['CS', '1', 'ObservationSignificance'],\n    '000A': ['UT', '1', 'ObservationDescription'],\n    '000C': ['SQ', '1', 'StructuredConstraintObservationSequence'],\n    '0010': ['SQ', '1', 'AssessedAttributeValueSequence'],\n    '0016': ['LO', '1', 'AssessmentSetID'],\n    '0017': ['SQ', '1', 'AssessmentRequesterSequence'],\n    '0018': ['LO', '1', 'SelectorAttributeName'],\n    '0019': ['LO', '1', 'SelectorAttributeKeyword'],\n    '0021': ['SQ', '1', 'AssessmentTypeCodeSequence'],\n    '0022': ['SQ', '1', 'ObservationBasisCodeSequence'],\n    '0023': ['LO', '1', 'AssessmentLabel'],\n    '0032': ['CS', '1', 'ConstraintType'],\n    '0033': ['UT', '1', 'SpecificationSelectionGuidance'],\n    '0034': ['SQ', '1', 'ConstraintValueSequence'],\n    '0035': ['SQ', '1', 'RecommendedDefaultValueSequence'],\n    '0036': ['CS', '1', 'ConstraintViolationSignificance'],\n    '0037': ['UT', '1', 'ConstraintViolationCondition'],\n    '0038': ['CS', '1', 'ModifiableConstraintFlag']\n  },\n  '0088': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0130': ['SH', '1', 'StorageMediaFileSetID'],\n    '0140': ['UI', '1', 'StorageMediaFileSetUID'],\n    '0200': ['SQ', '1', 'IconImageSequence'],\n    '0904': ['LO', '1', 'TopicTitle'],\n    '0906': ['ST', '1', 'TopicSubject'],\n    '0910': ['LO', '1', 'TopicAuthor'],\n    '0912': ['LO', '1-32', 'TopicKeywords']\n  },\n  '0100': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0410': ['CS', '1', 'SOPInstanceStatus'],\n    '0420': ['DT', '1', 'SOPAuthorizationDateTime'],\n    '0424': ['LT', '1', 'SOPAuthorizationComment'],\n    '0426': ['LO', '1', 'AuthorizationEquipmentCertificationNumber']\n  },\n  '0400': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0005': ['US', '1', 'MACIDNumber'],\n    '0010': ['UI', '1', 'MACCalculationTransferSyntaxUID'],\n    '0015': ['CS', '1', 'MACAlgorithm'],\n    '0020': ['AT', '1-n', 'DataElementsSigned'],\n    '0100': ['UI', '1', 'DigitalSignatureUID'],\n    '0105': ['DT', '1', 'DigitalSignatureDateTime'],\n    '0110': ['CS', '1', 'CertificateType'],\n    '0115': ['OB', '1', 'CertificateOfSigner'],\n    '0120': ['OB', '1', 'Signature'],\n    '0305': ['CS', '1', 'CertifiedTimestampType'],\n    '0310': ['OB', '1', 'CertifiedTimestamp'],\n    '0315': ['FL', '1', ''],\n    '0401': ['SQ', '1', 'DigitalSignaturePurposeCodeSequence'],\n    '0402': ['SQ', '1', 'ReferencedDigitalSignatureSequence'],\n    '0403': ['SQ', '1', 'ReferencedSOPInstanceMACSequence'],\n    '0404': ['OB', '1', 'MAC'],\n    '0500': ['SQ', '1', 'EncryptedAttributesSequence'],\n    '0510': ['UI', '1', 'EncryptedContentTransferSyntaxUID'],\n    '0520': ['OB', '1', 'EncryptedContent'],\n    '0550': ['SQ', '1', 'ModifiedAttributesSequence'],\n    '0551': ['SQ', '1', 'NonconformingModifiedAttributesSequence'],\n    '0552': ['OB', '1', 'NonconformingDataElementValue'],\n    '0561': ['SQ', '1', 'OriginalAttributesSequence'],\n    '0562': ['DT', '1', 'AttributeModificationDateTime'],\n    '0563': ['LO', '1', 'ModifyingSystem'],\n    '0564': ['LO', '1', 'SourceOfPreviousValues'],\n    '0565': ['CS', '1', 'ReasonForTheAttributeModification'],\n    '0600': ['CS', '1', 'InstanceOriginStatus']\n  },\n  '1000': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['US', '3', 'EscapeTriplet'],\n    '0011': ['US', '3', 'RunLengthTriplet'],\n    '0012': ['US', '1', 'HuffmanTableSize'],\n    '0013': ['US', '3', 'HuffmanTableTriplet'],\n    '0014': ['US', '1', 'ShiftTableSize'],\n    '0015': ['US', '3', 'ShiftTableTriplet']\n  },\n  '1010': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0004': ['US', '1-n', 'ZonalMap']\n  },\n  '2000': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['IS', '1', 'NumberOfCopies'],\n    '001E': ['SQ', '1', 'PrinterConfigurationSequence'],\n    '0020': ['CS', '1', 'PrintPriority'],\n    '0030': ['CS', '1', 'MediumType'],\n    '0040': ['CS', '1', 'FilmDestination'],\n    '0050': ['LO', '1', 'FilmSessionLabel'],\n    '0060': ['IS', '1', 'MemoryAllocation'],\n    '0061': ['IS', '1', 'MaximumMemoryAllocation'],\n    '0062': ['CS', '1', 'ColorImagePrintingFlag'],\n    '0063': ['CS', '1', 'CollationFlag'],\n    '0065': ['CS', '1', 'AnnotationFlag'],\n    '0067': ['CS', '1', 'ImageOverlayFlag'],\n    '0069': ['CS', '1', 'PresentationLUTFlag'],\n    '006A': ['CS', '1', 'ImageBoxPresentationLUTFlag'],\n    '00A0': ['US', '1', 'MemoryBitDepth'],\n    '00A1': ['US', '1', 'PrintingBitDepth'],\n    '00A2': ['SQ', '1', 'MediaInstalledSequence'],\n    '00A4': ['SQ', '1', 'OtherMediaAvailableSequence'],\n    '00A8': ['SQ', '1', 'SupportedImageDisplayFormatsSequence'],\n    '0500': ['SQ', '1', 'ReferencedFilmBoxSequence'],\n    '0510': ['SQ', '1', 'ReferencedStoredPrintSequence']\n  },\n  '2010': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['ST', '1', 'ImageDisplayFormat'],\n    '0030': ['CS', '1', 'AnnotationDisplayFormatID'],\n    '0040': ['CS', '1', 'FilmOrientation'],\n    '0050': ['CS', '1', 'FilmSizeID'],\n    '0052': ['CS', '1', 'PrinterResolutionID'],\n    '0054': ['CS', '1', 'DefaultPrinterResolutionID'],\n    '0060': ['CS', '1', 'MagnificationType'],\n    '0080': ['CS', '1', 'SmoothingType'],\n    '00A6': ['CS', '1', 'DefaultMagnificationType'],\n    '00A7': ['CS', '1-n', 'OtherMagnificationTypesAvailable'],\n    '00A8': ['CS', '1', 'DefaultSmoothingType'],\n    '00A9': ['CS', '1-n', 'OtherSmoothingTypesAvailable'],\n    '0100': ['CS', '1', 'BorderDensity'],\n    '0110': ['CS', '1', 'EmptyImageDensity'],\n    '0120': ['US', '1', 'MinDensity'],\n    '0130': ['US', '1', 'MaxDensity'],\n    '0140': ['CS', '1', 'Trim'],\n    '0150': ['ST', '1', 'ConfigurationInformation'],\n    '0152': ['LT', '1', 'ConfigurationInformationDescription'],\n    '0154': ['IS', '1', 'MaximumCollatedFilms'],\n    '015E': ['US', '1', 'Illumination'],\n    '0160': ['US', '1', 'ReflectedAmbientLight'],\n    '0376': ['DS', '2', 'PrinterPixelSpacing'],\n    '0500': ['SQ', '1', 'ReferencedFilmSessionSequence'],\n    '0510': ['SQ', '1', 'ReferencedImageBoxSequence'],\n    '0520': ['SQ', '1', 'ReferencedBasicAnnotationBoxSequence']\n  },\n  '2020': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['US', '1', 'ImageBoxPosition'],\n    '0020': ['CS', '1', 'Polarity'],\n    '0030': ['DS', '1', 'RequestedImageSize'],\n    '0040': ['CS', '1', 'RequestedDecimateCropBehavior'],\n    '0050': ['CS', '1', 'RequestedResolutionID'],\n    '00A0': ['CS', '1', 'RequestedImageSizeFlag'],\n    '00A2': ['CS', '1', 'DecimateCropResult'],\n    '0110': ['SQ', '1', 'BasicGrayscaleImageSequence'],\n    '0111': ['SQ', '1', 'BasicColorImageSequence'],\n    '0130': ['SQ', '1', 'ReferencedImageOverlayBoxSequence'],\n    '0140': ['SQ', '1', 'ReferencedVOILUTBoxSequence']\n  },\n  '2030': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['US', '1', 'AnnotationPosition'],\n    '0020': ['LO', '1', 'TextString']\n  },\n  '2040': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['SQ', '1', 'ReferencedOverlayPlaneSequence'],\n    '0011': ['US', '1-99', 'ReferencedOverlayPlaneGroups'],\n    '0020': ['SQ', '1', 'OverlayPixelDataSequence'],\n    '0060': ['CS', '1', 'OverlayMagnificationType'],\n    '0070': ['CS', '1', 'OverlaySmoothingType'],\n    '0072': ['CS', '1', 'OverlayOrImageMagnification'],\n    '0074': ['US', '1', 'MagnifyToNumberOfColumns'],\n    '0080': ['CS', '1', 'OverlayForegroundDensity'],\n    '0082': ['CS', '1', 'OverlayBackgroundDensity'],\n    '0090': ['CS', '1', 'OverlayMode'],\n    '0100': ['CS', '1', 'ThresholdDensity'],\n    '0500': ['SQ', '1', 'ReferencedImageBoxSequenceRetired']\n  },\n  '2050': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['SQ', '1', 'PresentationLUTSequence'],\n    '0020': ['CS', '1', 'PresentationLUTShape'],\n    '0500': ['SQ', '1', 'ReferencedPresentationLUTSequence']\n  },\n  '2100': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['SH', '1', 'PrintJobID'],\n    '0020': ['CS', '1', 'ExecutionStatus'],\n    '0030': ['CS', '1', 'ExecutionStatusInfo'],\n    '0040': ['DA', '1', 'CreationDate'],\n    '0050': ['TM', '1', 'CreationTime'],\n    '0070': ['AE', '1', 'Originator'],\n    '0140': ['AE', '1', 'DestinationAE'],\n    '0160': ['SH', '1', 'OwnerID'],\n    '0170': ['IS', '1', 'NumberOfFilms'],\n    '0500': ['SQ', '1', 'ReferencedPrintJobSequencePullStoredPrint']\n  },\n  '2110': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['CS', '1', 'PrinterStatus'],\n    '0020': ['CS', '1', 'PrinterStatusInfo'],\n    '0030': ['LO', '1', 'PrinterName'],\n    '0099': ['SH', '1', 'PrintQueueID']\n  },\n  '2120': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['CS', '1', 'QueueStatus'],\n    '0050': ['SQ', '1', 'PrintJobDescriptionSequence'],\n    '0070': ['SQ', '1', 'ReferencedPrintJobSequence']\n  },\n  '2130': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['SQ', '1', 'PrintManagementCapabilitiesSequence'],\n    '0015': ['SQ', '1', 'PrinterCharacteristicsSequence'],\n    '0030': ['SQ', '1', 'FilmBoxContentSequence'],\n    '0040': ['SQ', '1', 'ImageBoxContentSequence'],\n    '0050': ['SQ', '1', 'AnnotationContentSequence'],\n    '0060': ['SQ', '1', 'ImageOverlayBoxContentSequence'],\n    '0080': ['SQ', '1', 'PresentationLUTContentSequence'],\n    '00A0': ['SQ', '1', 'ProposedStudySequence'],\n    '00C0': ['SQ', '1', 'OriginalImageSequence']\n  },\n  '2200': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['CS', '1', 'LabelUsingInformationExtractedFromInstances'],\n    '0002': ['UT', '1', 'LabelText'],\n    '0003': ['CS', '1', 'LabelStyleSelection'],\n    '0004': ['LT', '1', 'MediaDisposition'],\n    '0005': ['LT', '1', 'BarcodeValue'],\n    '0006': ['CS', '1', 'BarcodeSymbology'],\n    '0007': ['CS', '1', 'AllowMediaSplitting'],\n    '0008': ['CS', '1', 'IncludeNonDICOMObjects'],\n    '0009': ['CS', '1', 'IncludeDisplayApplication'],\n    '000A': ['CS', '1', 'PreserveCompositeInstancesAfterMediaCreation'],\n    '000B': ['US', '1', 'TotalNumberOfPiecesOfMediaCreated'],\n    '000C': ['LO', '1', 'RequestedMediaApplicationProfile'],\n    '000D': ['SQ', '1', 'ReferencedStorageMediaSequence'],\n    '000E': ['AT', '1-n', 'FailureAttributes'],\n    '000F': ['CS', '1', 'AllowLossyCompression'],\n    '0020': ['CS', '1', 'RequestPriority']\n  },\n  '3002': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['SH', '1', 'RTImageLabel'],\n    '0003': ['LO', '1', 'RTImageName'],\n    '0004': ['ST', '1', 'RTImageDescription'],\n    '000A': ['CS', '1', 'ReportedValuesOrigin'],\n    '000C': ['CS', '1', 'RTImagePlane'],\n    '000D': ['DS', '3', 'XRayImageReceptorTranslation'],\n    '000E': ['DS', '1', 'XRayImageReceptorAngle'],\n    '0010': ['DS', '6', 'RTImageOrientation'],\n    '0011': ['DS', '2', 'ImagePlanePixelSpacing'],\n    '0012': ['DS', '2', 'RTImagePosition'],\n    '0020': ['SH', '1', 'RadiationMachineName'],\n    '0022': ['DS', '1', 'RadiationMachineSAD'],\n    '0024': ['DS', '1', 'RadiationMachineSSD'],\n    '0026': ['DS', '1', 'RTImageSID'],\n    '0028': ['DS', '1', 'SourceToReferenceObjectDistance'],\n    '0029': ['IS', '1', 'FractionNumber'],\n    '0030': ['SQ', '1', 'ExposureSequence'],\n    '0032': ['DS', '1', 'MetersetExposure'],\n    '0034': ['DS', '4', 'DiaphragmPosition'],\n    '0040': ['SQ', '1', 'FluenceMapSequence'],\n    '0041': ['CS', '1', 'FluenceDataSource'],\n    '0042': ['DS', '1', 'FluenceDataScale'],\n    '0050': ['SQ', '1', 'PrimaryFluenceModeSequence'],\n    '0051': ['CS', '1', 'FluenceMode'],\n    '0052': ['SH', '1', 'FluenceModeID']\n  },\n  '3004': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['CS', '1', 'DVHType'],\n    '0002': ['CS', '1', 'DoseUnits'],\n    '0004': ['CS', '1', 'DoseType'],\n    '0005': ['CS', '1', 'SpatialTransformOfDose'],\n    '0006': ['LO', '1', 'DoseComment'],\n    '0008': ['DS', '3', 'NormalizationPoint'],\n    '000A': ['CS', '1', 'DoseSummationType'],\n    '000C': ['DS', '2-n', 'GridFrameOffsetVector'],\n    '000E': ['DS', '1', 'DoseGridScaling'],\n    '0010': ['SQ', '1', 'RTDoseROISequence'],\n    '0012': ['DS', '1', 'DoseValue'],\n    '0014': ['CS', '1-3', 'TissueHeterogeneityCorrection'],\n    '0040': ['DS', '3', 'DVHNormalizationPoint'],\n    '0042': ['DS', '1', 'DVHNormalizationDoseValue'],\n    '0050': ['SQ', '1', 'DVHSequence'],\n    '0052': ['DS', '1', 'DVHDoseScaling'],\n    '0054': ['CS', '1', 'DVHVolumeUnits'],\n    '0056': ['IS', '1', 'DVHNumberOfBins'],\n    '0058': ['DS', '2-2n', 'DVHData'],\n    '0060': ['SQ', '1', 'DVHReferencedROISequence'],\n    '0062': ['CS', '1', 'DVHROIContributionType'],\n    '0070': ['DS', '1', 'DVHMinimumDose'],\n    '0072': ['DS', '1', 'DVHMaximumDose'],\n    '0074': ['DS', '1', 'DVHMeanDose']\n  },\n  '3006': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['SH', '1', 'StructureSetLabel'],\n    '0004': ['LO', '1', 'StructureSetName'],\n    '0006': ['ST', '1', 'StructureSetDescription'],\n    '0008': ['DA', '1', 'StructureSetDate'],\n    '0009': ['TM', '1', 'StructureSetTime'],\n    '0010': ['SQ', '1', 'ReferencedFrameOfReferenceSequence'],\n    '0012': ['SQ', '1', 'RTReferencedStudySequence'],\n    '0014': ['SQ', '1', 'RTReferencedSeriesSequence'],\n    '0016': ['SQ', '1', 'ContourImageSequence'],\n    '0018': ['SQ', '1', 'PredecessorStructureSetSequence'],\n    '0020': ['SQ', '1', 'StructureSetROISequence'],\n    '0022': ['IS', '1', 'ROINumber'],\n    '0024': ['UI', '1', 'ReferencedFrameOfReferenceUID'],\n    '0026': ['LO', '1', 'ROIName'],\n    '0028': ['ST', '1', 'ROIDescription'],\n    '002A': ['IS', '3', 'ROIDisplayColor'],\n    '002C': ['DS', '1', 'ROIVolume'],\n    '0030': ['SQ', '1', 'RTRelatedROISequence'],\n    '0033': ['CS', '1', 'RTROIRelationship'],\n    '0036': ['CS', '1', 'ROIGenerationAlgorithm'],\n    '0037': ['SQ', '1', 'ROIDerivationAlgorithmIdentificationSequence'],\n    '0038': ['LO', '1', 'ROIGenerationDescription'],\n    '0039': ['SQ', '1', 'ROIContourSequence'],\n    '0040': ['SQ', '1', 'ContourSequence'],\n    '0042': ['CS', '1', 'ContourGeometricType'],\n    '0044': ['DS', '1', 'ContourSlabThickness'],\n    '0045': ['DS', '3', 'ContourOffsetVector'],\n    '0046': ['IS', '1', 'NumberOfContourPoints'],\n    '0048': ['IS', '1', 'ContourNumber'],\n    '0049': ['IS', '1-n', 'AttachedContours'],\n    '004A': ['SQ', '1', 'SourcePixelPlanesCharacteristicsSequence'],\n    '0050': ['DS', '3-3n', 'ContourData'],\n    '0080': ['SQ', '1', 'RTROIObservationsSequence'],\n    '0082': ['IS', '1', 'ObservationNumber'],\n    '0084': ['IS', '1', 'ReferencedROINumber'],\n    '0085': ['SH', '1', 'ROIObservationLabel'],\n    '0086': ['SQ', '1', 'RTROIIdentificationCodeSequence'],\n    '0088': ['ST', '1', 'ROIObservationDescription'],\n    '00A0': ['SQ', '1', 'RelatedRTROIObservationsSequence'],\n    '00A4': ['CS', '1', 'RTROIInterpretedType'],\n    '00A6': ['PN', '1', 'ROIInterpreter'],\n    '00B0': ['SQ', '1', 'ROIPhysicalPropertiesSequence'],\n    '00B2': ['CS', '1', 'ROIPhysicalProperty'],\n    '00B4': ['DS', '1', 'ROIPhysicalPropertyValue'],\n    '00B6': ['SQ', '1', 'ROIElementalCompositionSequence'],\n    '00B7': ['US', '1', 'ROIElementalCompositionAtomicNumber'],\n    '00B8': ['FL', '1', 'ROIElementalCompositionAtomicMassFraction'],\n    '00B9': ['SQ', '1', 'AdditionalRTROIIdentificationCodeSequence'],\n    '00C0': ['SQ', '1', 'FrameOfReferenceRelationshipSequence'],\n    '00C2': ['UI', '1', 'RelatedFrameOfReferenceUID'],\n    '00C4': ['CS', '1', 'FrameOfReferenceTransformationType'],\n    '00C6': ['DS', '16', 'FrameOfReferenceTransformationMatrix'],\n    '00C8': ['LO', '1', 'FrameOfReferenceTransformationComment'],\n    '00C9': ['SQ', '1', 'PatientLocationCoordinatesSequence'],\n    '00CA': ['SQ', '1', 'PatientLocationCoordinatesCodeSequence'],\n    '00CB': ['SQ', '1', 'PatientSupportPositionSequence']\n  },\n  '3008': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['SQ', '1', 'MeasuredDoseReferenceSequence'],\n    '0012': ['ST', '1', 'MeasuredDoseDescription'],\n    '0014': ['CS', '1', 'MeasuredDoseType'],\n    '0016': ['DS', '1', 'MeasuredDoseValue'],\n    '0020': ['SQ', '1', 'TreatmentSessionBeamSequence'],\n    '0021': ['SQ', '1', 'TreatmentSessionIonBeamSequence'],\n    '0022': ['IS', '1', 'CurrentFractionNumber'],\n    '0024': ['DA', '1', 'TreatmentControlPointDate'],\n    '0025': ['TM', '1', 'TreatmentControlPointTime'],\n    '002A': ['CS', '1', 'TreatmentTerminationStatus'],\n    '002B': ['SH', '1', 'TreatmentTerminationCode'],\n    '002C': ['CS', '1', 'TreatmentVerificationStatus'],\n    '0030': ['SQ', '1', 'ReferencedTreatmentRecordSequence'],\n    '0032': ['DS', '1', 'SpecifiedPrimaryMeterset'],\n    '0033': ['DS', '1', 'SpecifiedSecondaryMeterset'],\n    '0036': ['DS', '1', 'DeliveredPrimaryMeterset'],\n    '0037': ['DS', '1', 'DeliveredSecondaryMeterset'],\n    '003A': ['DS', '1', 'SpecifiedTreatmentTime'],\n    '003B': ['DS', '1', 'DeliveredTreatmentTime'],\n    '0040': ['SQ', '1', 'ControlPointDeliverySequence'],\n    '0041': ['SQ', '1', 'IonControlPointDeliverySequence'],\n    '0042': ['DS', '1', 'SpecifiedMeterset'],\n    '0044': ['DS', '1', 'DeliveredMeterset'],\n    '0045': ['FL', '1', 'MetersetRateSet'],\n    '0046': ['FL', '1', 'MetersetRateDelivered'],\n    '0047': ['FL', '1-n', 'ScanSpotMetersetsDelivered'],\n    '0048': ['DS', '1', 'DoseRateDelivered'],\n    '0050': ['SQ', '1', 'TreatmentSummaryCalculatedDoseReferenceSequence'],\n    '0052': ['DS', '1', 'CumulativeDoseToDoseReference'],\n    '0054': ['DA', '1', 'FirstTreatmentDate'],\n    '0056': ['DA', '1', 'MostRecentTreatmentDate'],\n    '005A': ['IS', '1', 'NumberOfFractionsDelivered'],\n    '0060': ['SQ', '1', 'OverrideSequence'],\n    '0061': ['AT', '1', 'ParameterSequencePointer'],\n    '0062': ['AT', '1', 'OverrideParameterPointer'],\n    '0063': ['IS', '1', 'ParameterItemIndex'],\n    '0064': ['IS', '1', 'MeasuredDoseReferenceNumber'],\n    '0065': ['AT', '1', 'ParameterPointer'],\n    '0066': ['ST', '1', 'OverrideReason'],\n    '0067': ['US', '1', 'ParameterValueNumber'],\n    '0068': ['SQ', '1', 'CorrectedParameterSequence'],\n    '006A': ['FL', '1', 'CorrectionValue'],\n    '0070': ['SQ', '1', 'CalculatedDoseReferenceSequence'],\n    '0072': ['IS', '1', 'CalculatedDoseReferenceNumber'],\n    '0074': ['ST', '1', 'CalculatedDoseReferenceDescription'],\n    '0076': ['DS', '1', 'CalculatedDoseReferenceDoseValue'],\n    '0078': ['DS', '1', 'StartMeterset'],\n    '007A': ['DS', '1', 'EndMeterset'],\n    '0080': ['SQ', '1', 'ReferencedMeasuredDoseReferenceSequence'],\n    '0082': ['IS', '1', 'ReferencedMeasuredDoseReferenceNumber'],\n    '0090': ['SQ', '1', 'ReferencedCalculatedDoseReferenceSequence'],\n    '0092': ['IS', '1', 'ReferencedCalculatedDoseReferenceNumber'],\n    '00A0': ['SQ', '1', 'BeamLimitingDeviceLeafPairsSequence'],\n    '00B0': ['SQ', '1', 'RecordedWedgeSequence'],\n    '00C0': ['SQ', '1', 'RecordedCompensatorSequence'],\n    '00D0': ['SQ', '1', 'RecordedBlockSequence'],\n    '00D1': ['SQ', '1', 'RecordedBlockSlabSequence'],\n    '00E0': ['SQ', '1', 'TreatmentSummaryMeasuredDoseReferenceSequence'],\n    '00F0': ['SQ', '1', 'RecordedSnoutSequence'],\n    '00F2': ['SQ', '1', 'RecordedRangeShifterSequence'],\n    '00F4': ['SQ', '1', 'RecordedLateralSpreadingDeviceSequence'],\n    '00F6': ['SQ', '1', 'RecordedRangeModulatorSequence'],\n    '0100': ['SQ', '1', 'RecordedSourceSequence'],\n    '0105': ['LO', '1', 'SourceSerialNumber'],\n    '0110': ['SQ', '1', 'TreatmentSessionApplicationSetupSequence'],\n    '0116': ['CS', '1', 'ApplicationSetupCheck'],\n    '0120': ['SQ', '1', 'RecordedBrachyAccessoryDeviceSequence'],\n    '0122': ['IS', '1', 'ReferencedBrachyAccessoryDeviceNumber'],\n    '0130': ['SQ', '1', 'RecordedChannelSequence'],\n    '0132': ['DS', '1', 'SpecifiedChannelTotalTime'],\n    '0134': ['DS', '1', 'DeliveredChannelTotalTime'],\n    '0136': ['IS', '1', 'SpecifiedNumberOfPulses'],\n    '0138': ['IS', '1', 'DeliveredNumberOfPulses'],\n    '013A': ['DS', '1', 'SpecifiedPulseRepetitionInterval'],\n    '013C': ['DS', '1', 'DeliveredPulseRepetitionInterval'],\n    '0140': ['SQ', '1', 'RecordedSourceApplicatorSequence'],\n    '0142': ['IS', '1', 'ReferencedSourceApplicatorNumber'],\n    '0150': ['SQ', '1', 'RecordedChannelShieldSequence'],\n    '0152': ['IS', '1', 'ReferencedChannelShieldNumber'],\n    '0160': ['SQ', '1', 'BrachyControlPointDeliveredSequence'],\n    '0162': ['DA', '1', 'SafePositionExitDate'],\n    '0164': ['TM', '1', 'SafePositionExitTime'],\n    '0166': ['DA', '1', 'SafePositionReturnDate'],\n    '0168': ['TM', '1', 'SafePositionReturnTime'],\n    '0171': ['SQ', '1', 'PulseSpecificBrachyControlPointDeliveredSequence'],\n    '0172': ['US', '1', 'PulseNumber'],\n    '0173': ['SQ', '1', 'BrachyPulseControlPointDeliveredSequence'],\n    '0200': ['CS', '1', 'CurrentTreatmentStatus'],\n    '0202': ['ST', '1', 'TreatmentStatusComment'],\n    '0220': ['SQ', '1', 'FractionGroupSummarySequence'],\n    '0223': ['IS', '1', 'ReferencedFractionNumber'],\n    '0224': ['CS', '1', 'FractionGroupType'],\n    '0230': ['CS', '1', 'BeamStopperPosition'],\n    '0240': ['SQ', '1', 'FractionStatusSummarySequence'],\n    '0250': ['DA', '1', 'TreatmentDate'],\n    '0251': ['TM', '1', 'TreatmentTime']\n  },\n  '300A': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['SH', '1', 'RTPlanLabel'],\n    '0003': ['LO', '1', 'RTPlanName'],\n    '0004': ['ST', '1', 'RTPlanDescription'],\n    '0006': ['DA', '1', 'RTPlanDate'],\n    '0007': ['TM', '1', 'RTPlanTime'],\n    '0009': ['LO', '1-n', 'TreatmentProtocols'],\n    '000A': ['CS', '1', 'PlanIntent'],\n    '000B': ['LO', '1-n', 'TreatmentSites'],\n    '000C': ['CS', '1', 'RTPlanGeometry'],\n    '000E': ['ST', '1', 'PrescriptionDescription'],\n    '0010': ['SQ', '1', 'DoseReferenceSequence'],\n    '0012': ['IS', '1', 'DoseReferenceNumber'],\n    '0013': ['UI', '1', 'DoseReferenceUID'],\n    '0014': ['CS', '1', 'DoseReferenceStructureType'],\n    '0015': ['CS', '1', 'NominalBeamEnergyUnit'],\n    '0016': ['LO', '1', 'DoseReferenceDescription'],\n    '0018': ['DS', '3', 'DoseReferencePointCoordinates'],\n    '001A': ['DS', '1', 'NominalPriorDose'],\n    '0020': ['CS', '1', 'DoseReferenceType'],\n    '0021': ['DS', '1', 'ConstraintWeight'],\n    '0022': ['DS', '1', 'DeliveryWarningDose'],\n    '0023': ['DS', '1', 'DeliveryMaximumDose'],\n    '0025': ['DS', '1', 'TargetMinimumDose'],\n    '0026': ['DS', '1', 'TargetPrescriptionDose'],\n    '0027': ['DS', '1', 'TargetMaximumDose'],\n    '0028': ['DS', '1', 'TargetUnderdoseVolumeFraction'],\n    '002A': ['DS', '1', 'OrganAtRiskFullVolumeDose'],\n    '002B': ['DS', '1', 'OrganAtRiskLimitDose'],\n    '002C': ['DS', '1', 'OrganAtRiskMaximumDose'],\n    '002D': ['DS', '1', 'OrganAtRiskOverdoseVolumeFraction'],\n    '0040': ['SQ', '1', 'ToleranceTableSequence'],\n    '0042': ['IS', '1', 'ToleranceTableNumber'],\n    '0043': ['SH', '1', 'ToleranceTableLabel'],\n    '0044': ['DS', '1', 'GantryAngleTolerance'],\n    '0046': ['DS', '1', 'BeamLimitingDeviceAngleTolerance'],\n    '0048': ['SQ', '1', 'BeamLimitingDeviceToleranceSequence'],\n    '004A': ['DS', '1', 'BeamLimitingDevicePositionTolerance'],\n    '004B': ['FL', '1', 'SnoutPositionTolerance'],\n    '004C': ['DS', '1', 'PatientSupportAngleTolerance'],\n    '004E': ['DS', '1', 'TableTopEccentricAngleTolerance'],\n    '004F': ['FL', '1', 'TableTopPitchAngleTolerance'],\n    '0050': ['FL', '1', 'TableTopRollAngleTolerance'],\n    '0051': ['DS', '1', 'TableTopVerticalPositionTolerance'],\n    '0052': ['DS', '1', 'TableTopLongitudinalPositionTolerance'],\n    '0053': ['DS', '1', 'TableTopLateralPositionTolerance'],\n    '0055': ['CS', '1', 'RTPlanRelationship'],\n    '0070': ['SQ', '1', 'FractionGroupSequence'],\n    '0071': ['IS', '1', 'FractionGroupNumber'],\n    '0072': ['LO', '1', 'FractionGroupDescription'],\n    '0078': ['IS', '1', 'NumberOfFractionsPlanned'],\n    '0079': ['IS', '1', 'NumberOfFractionPatternDigitsPerDay'],\n    '007A': ['IS', '1', 'RepeatFractionCycleLength'],\n    '007B': ['LT', '1', 'FractionPattern'],\n    '0080': ['IS', '1', 'NumberOfBeams'],\n    '0082': ['DS', '3', 'BeamDoseSpecificationPoint'],\n    '0083': ['UI', '1', 'ReferencedDoseReferenceUID'],\n    '0084': ['DS', '1', 'BeamDose'],\n    '0086': ['DS', '1', 'BeamMeterset'],\n    '0088': ['FL', '1', 'BeamDosePointDepth'],\n    '0089': ['FL', '1', 'BeamDosePointEquivalentDepth'],\n    '008A': ['FL', '1', 'BeamDosePointSSD'],\n    '008B': ['CS', '1', 'BeamDoseMeaning'],\n    '008C': ['SQ', '1', 'BeamDoseVerificationControlPointSequence'],\n    '008D': ['FL', '1', 'AverageBeamDosePointDepth'],\n    '008E': ['FL', '1', 'AverageBeamDosePointEquivalentDepth'],\n    '008F': ['FL', '1', 'AverageBeamDosePointSSD'],\n    '0090': ['CS', '1', 'BeamDoseType'],\n    '0091': ['DS', '1', 'AlternateBeamDose'],\n    '0092': ['CS', '1', 'AlternateBeamDoseType'],\n    '0093': ['CS', '1', 'DepthValueAveragingFlag'],\n    '0094': ['DS', '1', 'BeamDosePointSourceToExternalContourDistance'],\n    '00A0': ['IS', '1', 'NumberOfBrachyApplicationSetups'],\n    '00A2': ['DS', '3', 'BrachyApplicationSetupDoseSpecificationPoint'],\n    '00A4': ['DS', '1', 'BrachyApplicationSetupDose'],\n    '00B0': ['SQ', '1', 'BeamSequence'],\n    '00B2': ['SH', '1', 'TreatmentMachineName'],\n    '00B3': ['CS', '1', 'PrimaryDosimeterUnit'],\n    '00B4': ['DS', '1', 'SourceAxisDistance'],\n    '00B6': ['SQ', '1', 'BeamLimitingDeviceSequence'],\n    '00B8': ['CS', '1', 'RTBeamLimitingDeviceType'],\n    '00BA': ['DS', '1', 'SourceToBeamLimitingDeviceDistance'],\n    '00BB': ['FL', '1', 'IsocenterToBeamLimitingDeviceDistance'],\n    '00BC': ['IS', '1', 'NumberOfLeafJawPairs'],\n    '00BE': ['DS', '3-n', 'LeafPositionBoundaries'],\n    '00C0': ['IS', '1', 'BeamNumber'],\n    '00C2': ['LO', '1', 'BeamName'],\n    '00C3': ['ST', '1', 'BeamDescription'],\n    '00C4': ['CS', '1', 'BeamType'],\n    '00C5': ['FD', '1', 'BeamDeliveryDurationLimit'],\n    '00C6': ['CS', '1', 'RadiationType'],\n    '00C7': ['CS', '1', 'HighDoseTechniqueType'],\n    '00C8': ['IS', '1', 'ReferenceImageNumber'],\n    '00CA': ['SQ', '1', 'PlannedVerificationImageSequence'],\n    '00CC': ['LO', '1-n', 'ImagingDeviceSpecificAcquisitionParameters'],\n    '00CE': ['CS', '1', 'TreatmentDeliveryType'],\n    '00D0': ['IS', '1', 'NumberOfWedges'],\n    '00D1': ['SQ', '1', 'WedgeSequence'],\n    '00D2': ['IS', '1', 'WedgeNumber'],\n    '00D3': ['CS', '1', 'WedgeType'],\n    '00D4': ['SH', '1', 'WedgeID'],\n    '00D5': ['IS', '1', 'WedgeAngle'],\n    '00D6': ['DS', '1', 'WedgeFactor'],\n    '00D7': ['FL', '1', 'TotalWedgeTrayWaterEquivalentThickness'],\n    '00D8': ['DS', '1', 'WedgeOrientation'],\n    '00D9': ['FL', '1', 'IsocenterToWedgeTrayDistance'],\n    '00DA': ['DS', '1', 'SourceToWedgeTrayDistance'],\n    '00DB': ['FL', '1', 'WedgeThinEdgePosition'],\n    '00DC': ['SH', '1', 'BolusID'],\n    '00DD': ['ST', '1', 'BolusDescription'],\n    '00DE': ['DS', '1', 'EffectiveWedgeAngle'],\n    '00E0': ['IS', '1', 'NumberOfCompensators'],\n    '00E1': ['SH', '1', 'MaterialID'],\n    '00E2': ['DS', '1', 'TotalCompensatorTrayFactor'],\n    '00E3': ['SQ', '1', 'CompensatorSequence'],\n    '00E4': ['IS', '1', 'CompensatorNumber'],\n    '00E5': ['SH', '1', 'CompensatorID'],\n    '00E6': ['DS', '1', 'SourceToCompensatorTrayDistance'],\n    '00E7': ['IS', '1', 'CompensatorRows'],\n    '00E8': ['IS', '1', 'CompensatorColumns'],\n    '00E9': ['DS', '2', 'CompensatorPixelSpacing'],\n    '00EA': ['DS', '2', 'CompensatorPosition'],\n    '00EB': ['DS', '1-n', 'CompensatorTransmissionData'],\n    '00EC': ['DS', '1-n', 'CompensatorThicknessData'],\n    '00ED': ['IS', '1', 'NumberOfBoli'],\n    '00EE': ['CS', '1', 'CompensatorType'],\n    '00EF': ['SH', '1', 'CompensatorTrayID'],\n    '00F0': ['IS', '1', 'NumberOfBlocks'],\n    '00F2': ['DS', '1', 'TotalBlockTrayFactor'],\n    '00F3': ['FL', '1', 'TotalBlockTrayWaterEquivalentThickness'],\n    '00F4': ['SQ', '1', 'BlockSequence'],\n    '00F5': ['SH', '1', 'BlockTrayID'],\n    '00F6': ['DS', '1', 'SourceToBlockTrayDistance'],\n    '00F7': ['FL', '1', 'IsocenterToBlockTrayDistance'],\n    '00F8': ['CS', '1', 'BlockType'],\n    '00F9': ['LO', '1', 'AccessoryCode'],\n    '00FA': ['CS', '1', 'BlockDivergence'],\n    '00FB': ['CS', '1', 'BlockMountingPosition'],\n    '00FC': ['IS', '1', 'BlockNumber'],\n    '00FE': ['LO', '1', 'BlockName'],\n    '0100': ['DS', '1', 'BlockThickness'],\n    '0102': ['DS', '1', 'BlockTransmission'],\n    '0104': ['IS', '1', 'BlockNumberOfPoints'],\n    '0106': ['DS', '2-2n', 'BlockData'],\n    '0107': ['SQ', '1', 'ApplicatorSequence'],\n    '0108': ['SH', '1', 'ApplicatorID'],\n    '0109': ['CS', '1', 'ApplicatorType'],\n    '010A': ['LO', '1', 'ApplicatorDescription'],\n    '010C': ['DS', '1', 'CumulativeDoseReferenceCoefficient'],\n    '010E': ['DS', '1', 'FinalCumulativeMetersetWeight'],\n    '0110': ['IS', '1', 'NumberOfControlPoints'],\n    '0111': ['SQ', '1', 'ControlPointSequence'],\n    '0112': ['IS', '1', 'ControlPointIndex'],\n    '0114': ['DS', '1', 'NominalBeamEnergy'],\n    '0115': ['DS', '1', 'DoseRateSet'],\n    '0116': ['SQ', '1', 'WedgePositionSequence'],\n    '0118': ['CS', '1', 'WedgePosition'],\n    '011A': ['SQ', '1', 'BeamLimitingDevicePositionSequence'],\n    '011C': ['DS', '2-2n', 'LeafJawPositions'],\n    '011E': ['DS', '1', 'GantryAngle'],\n    '011F': ['CS', '1', 'GantryRotationDirection'],\n    '0120': ['DS', '1', 'BeamLimitingDeviceAngle'],\n    '0121': ['CS', '1', 'BeamLimitingDeviceRotationDirection'],\n    '0122': ['DS', '1', 'PatientSupportAngle'],\n    '0123': ['CS', '1', 'PatientSupportRotationDirection'],\n    '0124': ['DS', '1', 'TableTopEccentricAxisDistance'],\n    '0125': ['DS', '1', 'TableTopEccentricAngle'],\n    '0126': ['CS', '1', 'TableTopEccentricRotationDirection'],\n    '0128': ['DS', '1', 'TableTopVerticalPosition'],\n    '0129': ['DS', '1', 'TableTopLongitudinalPosition'],\n    '012A': ['DS', '1', 'TableTopLateralPosition'],\n    '012C': ['DS', '3', 'IsocenterPosition'],\n    '012E': ['DS', '3', 'SurfaceEntryPoint'],\n    '0130': ['DS', '1', 'SourceToSurfaceDistance'],\n    '0131': ['FL', '1', 'AverageBeamDosePointSourceToExternalContourDistance'],\n    '0132': ['FL', '1', 'SourceToExternalContourDistance'],\n    '0133': ['FL', '3', 'ExternalContourEntryPoint'],\n    '0134': ['DS', '1', 'CumulativeMetersetWeight'],\n    '0140': ['FL', '1', 'TableTopPitchAngle'],\n    '0142': ['CS', '1', 'TableTopPitchRotationDirection'],\n    '0144': ['FL', '1', 'TableTopRollAngle'],\n    '0146': ['CS', '1', 'TableTopRollRotationDirection'],\n    '0148': ['FL', '1', 'HeadFixationAngle'],\n    '014A': ['FL', '1', 'GantryPitchAngle'],\n    '014C': ['CS', '1', 'GantryPitchRotationDirection'],\n    '014E': ['FL', '1', 'GantryPitchAngleTolerance'],\n    '0150': ['CS', '1', 'FixationEye'],\n    '0151': ['DS', '1', 'ChairHeadFramePosition'],\n    '0152': ['DS', '1', 'HeadFixationAngleTolerance'],\n    '0153': ['DS', '1', 'ChairHeadFramePositionTolerance'],\n    '0154': ['DS', '1', 'FixationLightAzimuthalAngleTolerance'],\n    '0155': ['DS', '1', 'FixationLightPolarAngleTolerance'],\n    '0180': ['SQ', '1', 'PatientSetupSequence'],\n    '0182': ['IS', '1', 'PatientSetupNumber'],\n    '0183': ['LO', '1', 'PatientSetupLabel'],\n    '0184': ['LO', '1', 'PatientAdditionalPosition'],\n    '0190': ['SQ', '1', 'FixationDeviceSequence'],\n    '0192': ['CS', '1', 'FixationDeviceType'],\n    '0194': ['SH', '1', 'FixationDeviceLabel'],\n    '0196': ['ST', '1', 'FixationDeviceDescription'],\n    '0198': ['SH', '1', 'FixationDevicePosition'],\n    '0199': ['FL', '1', 'FixationDevicePitchAngle'],\n    '019A': ['FL', '1', 'FixationDeviceRollAngle'],\n    '01A0': ['SQ', '1', 'ShieldingDeviceSequence'],\n    '01A2': ['CS', '1', 'ShieldingDeviceType'],\n    '01A4': ['SH', '1', 'ShieldingDeviceLabel'],\n    '01A6': ['ST', '1', 'ShieldingDeviceDescription'],\n    '01A8': ['SH', '1', 'ShieldingDevicePosition'],\n    '01B0': ['CS', '1', 'SetupTechnique'],\n    '01B2': ['ST', '1', 'SetupTechniqueDescription'],\n    '01B4': ['SQ', '1', 'SetupDeviceSequence'],\n    '01B6': ['CS', '1', 'SetupDeviceType'],\n    '01B8': ['SH', '1', 'SetupDeviceLabel'],\n    '01BA': ['ST', '1', 'SetupDeviceDescription'],\n    '01BC': ['DS', '1', 'SetupDeviceParameter'],\n    '01D0': ['ST', '1', 'SetupReferenceDescription'],\n    '01D2': ['DS', '1', 'TableTopVerticalSetupDisplacement'],\n    '01D4': ['DS', '1', 'TableTopLongitudinalSetupDisplacement'],\n    '01D6': ['DS', '1', 'TableTopLateralSetupDisplacement'],\n    '0200': ['CS', '1', 'BrachyTreatmentTechnique'],\n    '0202': ['CS', '1', 'BrachyTreatmentType'],\n    '0206': ['SQ', '1', 'TreatmentMachineSequence'],\n    '0210': ['SQ', '1', 'SourceSequence'],\n    '0212': ['IS', '1', 'SourceNumber'],\n    '0214': ['CS', '1', 'SourceType'],\n    '0216': ['LO', '1', 'SourceManufacturer'],\n    '0218': ['DS', '1', 'ActiveSourceDiameter'],\n    '021A': ['DS', '1', 'ActiveSourceLength'],\n    '021B': ['SH', '1', 'SourceModelID'],\n    '021C': ['LO', '1', 'SourceDescription'],\n    '0222': ['DS', '1', 'SourceEncapsulationNominalThickness'],\n    '0224': ['DS', '1', 'SourceEncapsulationNominalTransmission'],\n    '0226': ['LO', '1', 'SourceIsotopeName'],\n    '0228': ['DS', '1', 'SourceIsotopeHalfLife'],\n    '0229': ['CS', '1', 'SourceStrengthUnits'],\n    '022A': ['DS', '1', 'ReferenceAirKermaRate'],\n    '022B': ['DS', '1', 'SourceStrength'],\n    '022C': ['DA', '1', 'SourceStrengthReferenceDate'],\n    '022E': ['TM', '1', 'SourceStrengthReferenceTime'],\n    '0230': ['SQ', '1', 'ApplicationSetupSequence'],\n    '0232': ['CS', '1', 'ApplicationSetupType'],\n    '0234': ['IS', '1', 'ApplicationSetupNumber'],\n    '0236': ['LO', '1', 'ApplicationSetupName'],\n    '0238': ['LO', '1', 'ApplicationSetupManufacturer'],\n    '0240': ['IS', '1', 'TemplateNumber'],\n    '0242': ['SH', '1', 'TemplateType'],\n    '0244': ['LO', '1', 'TemplateName'],\n    '0250': ['DS', '1', 'TotalReferenceAirKerma'],\n    '0260': ['SQ', '1', 'BrachyAccessoryDeviceSequence'],\n    '0262': ['IS', '1', 'BrachyAccessoryDeviceNumber'],\n    '0263': ['SH', '1', 'BrachyAccessoryDeviceID'],\n    '0264': ['CS', '1', 'BrachyAccessoryDeviceType'],\n    '0266': ['LO', '1', 'BrachyAccessoryDeviceName'],\n    '026A': ['DS', '1', 'BrachyAccessoryDeviceNominalThickness'],\n    '026C': ['DS', '1', 'BrachyAccessoryDeviceNominalTransmission'],\n    '0271': ['DS', '1', 'ChannelEffectiveLength'],\n    '0272': ['DS', '1', 'ChannelInnerLength'],\n    '0273': ['SH', '1', 'AfterloaderChannelID'],\n    '0274': ['DS', '1', 'SourceApplicatorTipLength'],\n    '0280': ['SQ', '1', 'ChannelSequence'],\n    '0282': ['IS', '1', 'ChannelNumber'],\n    '0284': ['DS', '1', 'ChannelLength'],\n    '0286': ['DS', '1', 'ChannelTotalTime'],\n    '0288': ['CS', '1', 'SourceMovementType'],\n    '028A': ['IS', '1', 'NumberOfPulses'],\n    '028C': ['DS', '1', 'PulseRepetitionInterval'],\n    '0290': ['IS', '1', 'SourceApplicatorNumber'],\n    '0291': ['SH', '1', 'SourceApplicatorID'],\n    '0292': ['CS', '1', 'SourceApplicatorType'],\n    '0294': ['LO', '1', 'SourceApplicatorName'],\n    '0296': ['DS', '1', 'SourceApplicatorLength'],\n    '0298': ['LO', '1', 'SourceApplicatorManufacturer'],\n    '029C': ['DS', '1', 'SourceApplicatorWallNominalThickness'],\n    '029E': ['DS', '1', 'SourceApplicatorWallNominalTransmission'],\n    '02A0': ['DS', '1', 'SourceApplicatorStepSize'],\n    '02A1': ['IS', '1', 'ApplicatorShapeReferencedROINumber'],\n    '02A2': ['IS', '1', 'TransferTubeNumber'],\n    '02A4': ['DS', '1', 'TransferTubeLength'],\n    '02B0': ['SQ', '1', 'ChannelShieldSequence'],\n    '02B2': ['IS', '1', 'ChannelShieldNumber'],\n    '02B3': ['SH', '1', 'ChannelShieldID'],\n    '02B4': ['LO', '1', 'ChannelShieldName'],\n    '02B8': ['DS', '1', 'ChannelShieldNominalThickness'],\n    '02BA': ['DS', '1', 'ChannelShieldNominalTransmission'],\n    '02C8': ['DS', '1', 'FinalCumulativeTimeWeight'],\n    '02D0': ['SQ', '1', 'BrachyControlPointSequence'],\n    '02D2': ['DS', '1', 'ControlPointRelativePosition'],\n    '02D4': ['DS', '3', 'ControlPoint3DPosition'],\n    '02D6': ['DS', '1', 'CumulativeTimeWeight'],\n    '02E0': ['CS', '1', 'CompensatorDivergence'],\n    '02E1': ['CS', '1', 'CompensatorMountingPosition'],\n    '02E2': ['DS', '1-n', 'SourceToCompensatorDistance'],\n    '02E3': ['FL', '1', 'TotalCompensatorTrayWaterEquivalentThickness'],\n    '02E4': ['FL', '1', 'IsocenterToCompensatorTrayDistance'],\n    '02E5': ['FL', '1', 'CompensatorColumnOffset'],\n    '02E6': ['FL', '1-n', 'IsocenterToCompensatorDistances'],\n    '02E7': ['FL', '1', 'CompensatorRelativeStoppingPowerRatio'],\n    '02E8': ['FL', '1', 'CompensatorMillingToolDiameter'],\n    '02EA': ['SQ', '1', 'IonRangeCompensatorSequence'],\n    '02EB': ['LT', '1', 'CompensatorDescription'],\n    '0302': ['IS', '1', 'RadiationMassNumber'],\n    '0304': ['IS', '1', 'RadiationAtomicNumber'],\n    '0306': ['SS', '1', 'RadiationChargeState'],\n    '0308': ['CS', '1', 'ScanMode'],\n    '0309': ['CS', '1', 'ModulatedScanModeType'],\n    '030A': ['FL', '2', 'VirtualSourceAxisDistances'],\n    '030C': ['SQ', '1', 'SnoutSequence'],\n    '030D': ['FL', '1', 'SnoutPosition'],\n    '030F': ['SH', '1', 'SnoutID'],\n    '0312': ['IS', '1', 'NumberOfRangeShifters'],\n    '0314': ['SQ', '1', 'RangeShifterSequence'],\n    '0316': ['IS', '1', 'RangeShifterNumber'],\n    '0318': ['SH', '1', 'RangeShifterID'],\n    '0320': ['CS', '1', 'RangeShifterType'],\n    '0322': ['LO', '1', 'RangeShifterDescription'],\n    '0330': ['IS', '1', 'NumberOfLateralSpreadingDevices'],\n    '0332': ['SQ', '1', 'LateralSpreadingDeviceSequence'],\n    '0334': ['IS', '1', 'LateralSpreadingDeviceNumber'],\n    '0336': ['SH', '1', 'LateralSpreadingDeviceID'],\n    '0338': ['CS', '1', 'LateralSpreadingDeviceType'],\n    '033A': ['LO', '1', 'LateralSpreadingDeviceDescription'],\n    '033C': ['FL', '1', 'LateralSpreadingDeviceWaterEquivalentThickness'],\n    '0340': ['IS', '1', 'NumberOfRangeModulators'],\n    '0342': ['SQ', '1', 'RangeModulatorSequence'],\n    '0344': ['IS', '1', 'RangeModulatorNumber'],\n    '0346': ['SH', '1', 'RangeModulatorID'],\n    '0348': ['CS', '1', 'RangeModulatorType'],\n    '034A': ['LO', '1', 'RangeModulatorDescription'],\n    '034C': ['SH', '1', 'BeamCurrentModulationID'],\n    '0350': ['CS', '1', 'PatientSupportType'],\n    '0352': ['SH', '1', 'PatientSupportID'],\n    '0354': ['LO', '1', 'PatientSupportAccessoryCode'],\n    '0355': ['LO', '1', 'TrayAccessoryCode'],\n    '0356': ['FL', '1', 'FixationLightAzimuthalAngle'],\n    '0358': ['FL', '1', 'FixationLightPolarAngle'],\n    '035A': ['FL', '1', 'MetersetRate'],\n    '0360': ['SQ', '1', 'RangeShifterSettingsSequence'],\n    '0362': ['LO', '1', 'RangeShifterSetting'],\n    '0364': ['FL', '1', 'IsocenterToRangeShifterDistance'],\n    '0366': ['FL', '1', 'RangeShifterWaterEquivalentThickness'],\n    '0370': ['SQ', '1', 'LateralSpreadingDeviceSettingsSequence'],\n    '0372': ['LO', '1', 'LateralSpreadingDeviceSetting'],\n    '0374': ['FL', '1', 'IsocenterToLateralSpreadingDeviceDistance'],\n    '0380': ['SQ', '1', 'RangeModulatorSettingsSequence'],\n    '0382': ['FL', '1', 'RangeModulatorGatingStartValue'],\n    '0384': ['FL', '1', 'RangeModulatorGatingStopValue'],\n    '0386': ['FL', '1', 'RangeModulatorGatingStartWaterEquivalentThickness'],\n    '0388': ['FL', '1', 'RangeModulatorGatingStopWaterEquivalentThickness'],\n    '038A': ['FL', '1', 'IsocenterToRangeModulatorDistance'],\n    '038F': ['FL', '1-n', 'ScanSpotTimeOffset'],\n    '0390': ['SH', '1', 'ScanSpotTuneID'],\n    '0391': ['IS', '1-n', 'ScanSpotPrescribedIndices'],\n    '0392': ['IS', '1', 'NumberOfScanSpotPositions'],\n    '0393': ['CS', '1', 'ScanSpotReordered'],\n    '0394': ['FL', '1-n', 'ScanSpotPositionMap'],\n    '0395': ['CS', '1', 'ScanSpotReorderingAllowed'],\n    '0396': ['FL', '1-n', 'ScanSpotMetersetWeights'],\n    '0398': ['FL', '2', 'ScanningSpotSize'],\n    '0399': ['FL', '2-2n', 'ScanSpotSizesDelivered'],\n    '039A': ['IS', '1', 'NumberOfPaintings'],\n    '03A0': ['SQ', '1', 'IonToleranceTableSequence'],\n    '03A2': ['SQ', '1', 'IonBeamSequence'],\n    '03A4': ['SQ', '1', 'IonBeamLimitingDeviceSequence'],\n    '03A6': ['SQ', '1', 'IonBlockSequence'],\n    '03A8': ['SQ', '1', 'IonControlPointSequence'],\n    '03AA': ['SQ', '1', 'IonWedgeSequence'],\n    '03AC': ['SQ', '1', 'IonWedgePositionSequence'],\n    '0401': ['SQ', '1', 'ReferencedSetupImageSequence'],\n    '0402': ['ST', '1', 'SetupImageComment'],\n    '0410': ['SQ', '1', 'MotionSynchronizationSequence'],\n    '0412': ['FL', '3', 'ControlPointOrientation'],\n    '0420': ['SQ', '1', 'GeneralAccessorySequence'],\n    '0421': ['SH', '1', 'GeneralAccessoryID'],\n    '0422': ['ST', '1', 'GeneralAccessoryDescription'],\n    '0423': ['CS', '1', 'GeneralAccessoryType'],\n    '0424': ['IS', '1', 'GeneralAccessoryNumber'],\n    '0425': ['FL', '1', 'SourceToGeneralAccessoryDistance'],\n    '0426': ['DS', '1', 'IsocenterToGeneralAccessoryDistance'],\n    '0431': ['SQ', '1', 'ApplicatorGeometrySequence'],\n    '0432': ['CS', '1', 'ApplicatorApertureShape'],\n    '0433': ['FL', '1', 'ApplicatorOpening'],\n    '0434': ['FL', '1', 'ApplicatorOpeningX'],\n    '0435': ['FL', '1', 'ApplicatorOpeningY'],\n    '0436': ['FL', '1', 'SourceToApplicatorMountingPositionDistance'],\n    '0440': ['IS', '1', 'NumberOfBlockSlabItems'],\n    '0441': ['SQ', '1', 'BlockSlabSequence'],\n    '0442': ['DS', '1', 'BlockSlabThickness'],\n    '0443': ['US', '1', 'BlockSlabNumber'],\n    '0450': ['SQ', '1', 'DeviceMotionControlSequence'],\n    '0451': ['CS', '1', 'DeviceMotionExecutionMode'],\n    '0452': ['CS', '1', 'DeviceMotionObservationMode'],\n    '0453': ['SQ', '1', 'DeviceMotionParameterCodeSequence'],\n    '0501': ['FL', '1', 'DistalDepthFraction'],\n    '0502': ['FL', '1', 'DistalDepth'],\n    '0503': ['FL', '2', 'NominalRangeModulationFractions'],\n    '0504': ['FL', '2', 'NominalRangeModulatedRegionDepths'],\n    '0505': ['SQ', '1', 'DepthDoseParametersSequence'],\n    '0506': ['SQ', '1', 'DeliveredDepthDoseParametersSequence'],\n    '0507': ['FL', '1', 'DeliveredDistalDepthFraction'],\n    '0508': ['FL', '1', 'DeliveredDistalDepth'],\n    '0509': ['FL', '2', 'DeliveredNominalRangeModulationFractions'],\n    '0510': ['FL', '2', 'DeliveredNominalRangeModulatedRegionDepths'],\n    '0511': ['CS', '1', 'DeliveredReferenceDoseDefinition'],\n    '0512': ['CS', '1', 'ReferenceDoseDefinition'],\n    '0600': ['US', '1', 'RTControlPointIndex'],\n    '0601': ['US', '1', 'RadiationGenerationModeIndex'],\n    '0602': ['US', '1', 'ReferencedDefinedDeviceIndex'],\n    '0603': ['US', '1', 'RadiationDoseIdentificationIndex'],\n    '0604': ['US', '1', 'NumberOfRTControlPoints'],\n    '0605': ['US', '1', 'ReferencedRadiationGenerationModeIndex'],\n    '0606': ['US', '1', 'TreatmentPositionIndex'],\n    '0607': ['US', '1', 'ReferencedDeviceIndex'],\n    '0608': ['LO', '1', 'TreatmentPositionGroupLabel'],\n    '0609': ['UI', '1', 'TreatmentPositionGroupUID'],\n    '060A': ['SQ', '1', 'TreatmentPositionGroupSequence'],\n    '060B': ['US', '1', 'ReferencedTreatmentPositionIndex'],\n    '060C': ['US', '1', 'ReferencedRadiationDoseIdentificationIndex'],\n    '060D': ['FD', '1', 'RTAccessoryHolderWaterEquivalentThickness'],\n    '060E': ['US', '1', 'ReferencedRTAccessoryHolderDeviceIndex'],\n    '060F': ['CS', '1', 'RTAccessoryHolderSlotExistenceFlag'],\n    '0610': ['SQ', '1', 'RTAccessoryHolderSlotSequence'],\n    '0611': ['LO', '1', 'RTAccessoryHolderSlotID'],\n    '0612': ['FD', '1', 'RTAccessoryHolderSlotDistance'],\n    '0613': ['FD', '1', 'RTAccessorySlotDistance'],\n    '0614': ['SQ', '1', 'RTAccessoryHolderDefinitionSequence'],\n    '0615': ['LO', '1', 'RTAccessoryDeviceSlotID'],\n    '0616': ['SQ', '1', 'RTRadiationSequence'],\n    '0617': ['SQ', '1', 'RadiationDoseSequence'],\n    '0618': ['SQ', '1', 'RadiationDoseIdentificationSequence'],\n    '0619': ['LO', '1', 'RadiationDoseIdentificationLabel'],\n    '061A': ['CS', '1', 'ReferenceDoseType'],\n    '061B': ['CS', '1', 'PrimaryDoseValueIndicator'],\n    '061C': ['SQ', '1', 'DoseValuesSequence'],\n    '061D': ['CS', '1-n', 'DoseValuePurpose'],\n    '061E': ['FD', '3', 'ReferenceDosePointCoordinates'],\n    '061F': ['SQ', '1', 'RadiationDoseValuesParametersSequence'],\n    '0620': ['SQ', '1', 'MetersetToDoseMappingSequence'],\n    '0621': ['SQ', '1', 'ExpectedInVivoMeasurementValuesSequence'],\n    '0622': ['US', '1', 'ExpectedInVivoMeasurementValueIndex'],\n    '0623': ['LO', '1', 'RadiationDoseInVivoMeasurementLabel'],\n    '0624': ['FD', '2', 'RadiationDoseCentralAxisDisplacement'],\n    '0625': ['FD', '1', 'RadiationDoseValue'],\n    '0626': ['FD', '1', 'RadiationDoseSourceToSkinDistance'],\n    '0627': ['FD', '3', 'RadiationDoseMeasurementPointCoordinates'],\n    '0628': ['FD', '1', 'RadiationDoseSourceToExternalContourDistance'],\n    '0629': ['SQ', '1', 'RTToleranceSetSequence'],\n    '062A': ['LO', '1', 'RTToleranceSetLabel'],\n    '062B': ['SQ', '1', 'AttributeToleranceValuesSequence'],\n    '062C': ['FD', '1', 'ToleranceValue'],\n    '062D': ['SQ', '1', 'PatientSupportPositionToleranceSequence'],\n    '062E': ['FD', '1', 'TreatmentTimeLimit'],\n    '062F': ['SQ', '1', 'CArmPhotonElectronControlPointSequence'],\n    '0630': ['SQ', '1', 'ReferencedRTRadiationSequence'],\n    '0631': ['SQ', '1', 'ReferencedRTInstanceSequence'],\n    '0632': ['SQ', '1', 'ReferencedRTPatientSetupSequence'],\n    '0634': ['FD', '1', 'SourceToPatientSurfaceDistance'],\n    '0635': ['SQ', '1', 'TreatmentMachineSpecialModeCodeSequence'],\n    '0636': ['US', '1', 'IntendedNumberOfFractions'],\n    '0637': ['CS', '1', 'RTRadiationSetIntent'],\n    '0638': ['CS', '1', 'RTRadiationPhysicalAndGeometricContentDetailFlag'],\n    '0639': ['CS', '1', 'RTRecordFlag'],\n    '063A': ['SQ', '1', 'TreatmentDeviceIdentificationSequence'],\n    '063B': ['SQ', '1', 'ReferencedRTPhysicianIntentSequence'],\n    '063C': ['FD', '1', 'CumulativeMeterset'],\n    '063D': ['FD', '1', 'DeliveryRate'],\n    '063E': ['SQ', '1', 'DeliveryRateUnitSequence'],\n    '063F': ['SQ', '1', 'TreatmentPositionSequence'],\n    '0640': ['FD', '1', 'RadiationSourceAxisDistance'],\n    '0641': ['US', '1', 'NumberOfRTBeamLimitingDevices'],\n    '0642': ['FD', '1', 'RTBeamLimitingDeviceProximalDistance'],\n    '0643': ['FD', '1', 'RTBeamLimitingDeviceDistalDistance'],\n    '0644': ['SQ', '1', 'ParallelRTBeamDelimiterDeviceOrientationLabelCodeSequence'],\n    '0645': ['FD', '1', 'BeamModifierOrientationAngle'],\n    '0646': ['SQ', '1', 'FixedRTBeamDelimiterDeviceSequence'],\n    '0647': ['SQ', '1', 'ParallelRTBeamDelimiterDeviceSequence'],\n    '0648': ['US', '1', 'NumberOfParallelRTBeamDelimiters'],\n    '0649': ['FD', '2-n', 'ParallelRTBeamDelimiterBoundaries'],\n    '064A': ['FD', '2-n', 'ParallelRTBeamDelimiterPositions'],\n    '064B': ['FD', '2', 'RTBeamLimitingDeviceOffset'],\n    '064C': ['SQ', '1', 'RTBeamDelimiterGeometrySequence'],\n    '064D': ['SQ', '1', 'RTBeamLimitingDeviceDefinitionSequence'],\n    '064E': ['CS', '1', 'ParallelRTBeamDelimiterOpeningMode'],\n    '064F': ['CS', '1-n', 'ParallelRTBeamDelimiterLeafMountingSide'],\n    '0650': ['UI', '1', 'PatientSetupUID'],\n    '0651': ['SQ', '1', 'WedgeDefinitionSequence'],\n    '0652': ['FD', '1', 'RadiationBeamWedgeAngle'],\n    '0653': ['FD', '1', 'RadiationBeamWedgeThinEdgeDistance'],\n    '0654': ['FD', '1', 'RadiationBeamEffectiveWedgeAngle'],\n    '0655': ['US', '1', 'NumberOfWedgePositions'],\n    '0656': ['SQ', '1', 'RTBeamLimitingDeviceOpeningSequence'],\n    '0657': ['US', '1', 'NumberOfRTBeamLimitingDeviceOpenings'],\n    '0658': ['SQ', '1', 'RadiationDosimeterUnitSequence'],\n    '0659': ['SQ', '1', 'RTDeviceDistanceReferenceLocationCodeSequence'],\n    '065A': ['SQ', '1', 'RadiationDeviceConfigurationAndCommissioningKeySequence'],\n    '065B': ['SQ', '1', 'PatientSupportPositionParameterSequence'],\n    '065C': ['CS', '1', 'PatientSupportPositionSpecificationMethod'],\n    '065D': ['SQ', '1', 'PatientSupportPositionDeviceParameterSequence'],\n    '065E': ['US', '1', 'DeviceOrderIndex'],\n    '065F': ['US', '1', 'PatientSupportPositionParameterOrderIndex'],\n    '0660': ['SQ', '1', 'PatientSupportPositionDeviceToleranceSequence'],\n    '0661': ['US', '1', 'PatientSupportPositionToleranceOrderIndex'],\n    '0662': ['SQ', '1', 'CompensatorDefinitionSequence'],\n    '0663': ['CS', '1', 'CompensatorMapOrientation'],\n    '0664': ['OF', '1', 'CompensatorProximalThicknessMap'],\n    '0665': ['OF', '1', 'CompensatorDistalThicknessMap'],\n    '0666': ['FD', '1', 'CompensatorBasePlaneOffset'],\n    '0667': ['SQ', '1', 'CompensatorShapeFabricationCodeSequence'],\n    '0668': ['SQ', '1', 'CompensatorShapeSequence'],\n    '0669': ['FD', '1', 'RadiationBeamCompensatorMillingToolDiameter'],\n    '066A': ['SQ', '1', 'BlockDefinitionSequence'],\n    '066B': ['OF', '1', 'BlockEdgeData'],\n    '066C': ['CS', '1', 'BlockOrientation'],\n    '066D': ['FD', '1', 'RadiationBeamBlockThickness'],\n    '066E': ['FD', '1', 'RadiationBeamBlockSlabThickness'],\n    '066F': ['SQ', '1', 'BlockEdgeDataSequence'],\n    '0670': ['US', '1', 'NumberOfRTAccessoryHolders'],\n    '0671': ['SQ', '1', 'GeneralAccessoryDefinitionSequence'],\n    '0672': ['US', '1', 'NumberOfGeneralAccessories'],\n    '0673': ['SQ', '1', 'BolusDefinitionSequence'],\n    '0674': ['US', '1', 'NumberOfBoluses'],\n    '0675': ['UI', '1', 'EquipmentFrameOfReferenceUID'],\n    '0676': ['ST', '1', 'EquipmentFrameOfReferenceDescription'],\n    '0677': ['SQ', '1', 'EquipmentReferencePointCoordinatesSequence'],\n    '0678': ['SQ', '1', 'EquipmentReferencePointCodeSequence'],\n    '0679': ['FD', '1', 'RTBeamLimitingDeviceAngle'],\n    '067A': ['FD', '1', 'SourceRollAngle'],\n    '067B': ['SQ', '1', 'RadiationGenerationModeSequence'],\n    '067C': ['SH', '1', 'RadiationGenerationModeLabel'],\n    '067D': ['ST', '1', 'RadiationGenerationModeDescription'],\n    '067E': ['SQ', '1', 'RadiationGenerationModeMachineCodeSequence'],\n    '067F': ['SQ', '1', 'RadiationTypeCodeSequence'],\n    '0680': ['DS', '1', 'NominalEnergy'],\n    '0681': ['DS', '1', 'MinimumNominalEnergy'],\n    '0682': ['DS', '1', 'MaximumNominalEnergy'],\n    '0683': ['SQ', '1', 'RadiationFluenceModifierCodeSequence'],\n    '0684': ['SQ', '1', 'EnergyUnitCodeSequence'],\n    '0685': ['US', '1', 'NumberOfRadiationGenerationModes'],\n    '0686': ['SQ', '1', 'PatientSupportDevicesSequence'],\n    '0687': ['US', '1', 'NumberOfPatientSupportDevices'],\n    '0688': ['FD', '1', 'RTBeamModifierDefinitionDistance'],\n    '0689': ['SQ', '1', 'BeamAreaLimitSequence'],\n    '068A': ['SQ', '1', 'ReferencedRTPrescriptionSequence'],\n    '0700': ['UI', '1', 'TreatmentSessionUID'],\n    '0701': ['CS', '1', 'RTRadiationUsage'],\n    '0702': ['SQ', '1', 'ReferencedRTRadiationSetSequence'],\n    '0703': ['SQ', '1', 'ReferencedRTRadiationRecordSequence'],\n    '0704': ['US', '1', 'RTRadiationSetDeliveryNumber'],\n    '0705': ['US', '1', 'ClinicalFractionNumber'],\n    '0706': ['CS', '1', 'RTTreatmentFractionCompletionStatus'],\n    '0707': ['CS', '1', 'RTRadiationSetUsage'],\n    '0708': ['CS', '1', 'TreatmentDeliveryContinuationFlag'],\n    '0709': ['CS', '1', 'TreatmentRecordContentOrigin'],\n    '0714': ['CS', '1', 'RTTreatmentTerminationStatus'],\n    '0715': ['SQ', '1', 'RTTreatmentTerminationReasonCodeSequence'],\n    '0716': ['SQ', '1', 'MachineSpecificTreatmentTerminationCodeSequence'],\n    '0722': ['SQ', '1', 'RTRadiationSalvageRecordControlPointSequence'],\n    '0723': ['CS', '1', 'StartingMetersetValueKnownFlag'],\n    '0730': ['ST', '1', 'TreatmentTerminationDescription'],\n    '0731': ['SQ', '1', 'TreatmentToleranceViolationSequence'],\n    '0732': ['CS', '1', 'TreatmentToleranceViolationCategory'],\n    '0733': ['SQ', '1', 'TreatmentToleranceViolationAttributeSequence'],\n    '0734': ['ST', '1', 'TreatmentToleranceViolationDescription'],\n    '0735': ['ST', '1', 'TreatmentToleranceViolationIdentification'],\n    '0736': ['DT', '1', 'TreatmentToleranceViolationDateTime'],\n    '073A': ['DT', '1', 'RecordedRTControlPointDateTime'],\n    '073B': ['US', '1', 'ReferencedRadiationRTControlPointIndex'],\n    '073E': ['SQ', '1', 'AlternateValueSequence'],\n    '073F': ['SQ', '1', 'ConfirmationSequence'],\n    '0740': ['SQ', '1', 'InterlockSequence'],\n    '0741': ['DT', '1', 'InterlockDateTime'],\n    '0742': ['ST', '1', 'InterlockDescription'],\n    '0743': ['SQ', '1', 'InterlockOriginatingDeviceSequence'],\n    '0744': ['SQ', '1', 'InterlockCodeSequence'],\n    '0745': ['SQ', '1', 'InterlockResolutionCodeSequence'],\n    '0746': ['SQ', '1', 'InterlockResolutionUserSequence'],\n    '0760': ['DT', '1', 'OverrideDateTime'],\n    '0761': ['SQ', '1', 'TreatmentToleranceViolationTypeCodeSequence'],\n    '0762': ['SQ', '1', 'TreatmentToleranceViolationCauseCodeSequence'],\n    '0772': ['SQ', '1', 'MeasuredMetersetToDoseMappingSequence'],\n    '0773': ['US', '1', 'ReferencedExpectedInVivoMeasurementValueIndex'],\n    '0774': ['SQ', '1', 'DoseMeasurementDeviceCodeSequence'],\n    '0780': ['SQ', '1', 'AdditionalParameterRecordingInstanceSequence'],\n    '0782': ['US', '1', ''],\n    '0783': ['ST', '1', 'InterlockOriginDescription'],\n    '0784': ['SQ', '1', 'RTPatientPositionScopeSequence'],\n    '0785': ['UI', '1', 'ReferencedTreatmentPositionGroupUID'],\n    '0786': ['US', '1', 'RadiationOrderIndex'],\n    '0787': ['SQ', '1', 'OmittedRadiationSequence'],\n    '0788': ['SQ', '1', 'ReasonForOmissionCodeSequence'],\n    '0789': ['SQ', '1', 'RTDeliveryStartPatientPositionSequence'],\n    '078A': ['SQ', '1', 'RTTreatmentPreparationPatientPositionSequence'],\n    '078B': ['SQ', '1', 'ReferencedRTTreatmentPreparationSequence'],\n    '078C': ['SQ', '1', 'ReferencedPatientSetupPhotoSequence'],\n    '078D': ['SQ', '1', 'PatientTreatmentPreparationMethodCodeSequence'],\n    '078E': ['LT', '1', 'PatientTreatmentPreparationProcedureParameterDescription'],\n    '078F': ['SQ', '1', 'PatientTreatmentPreparationDeviceSequence'],\n    '0790': ['SQ', '1', 'PatientTreatmentPreparationProcedureSequence'],\n    '0791': ['SQ', '1', 'PatientTreatmentPreparationProcedureCodeSequence'],\n    '0792': ['LT', '1', 'PatientTreatmentPreparationMethodDescription'],\n    '0793': ['SQ', '1', 'PatientTreatmentPreparationProcedureParameterSequence'],\n    '0794': ['LT', '1', 'PatientSetupPhotoDescription'],\n    '0795': ['US', '1', 'PatientTreatmentPreparationProcedureIndex'],\n    '0796': ['US', '1', 'ReferencedPatientSetupProcedureIndex'],\n    '0797': ['SQ', '1', 'RTRadiationTaskSequence'],\n    '0798': ['SQ', '1', 'RTPatientPositionDisplacementSequence'],\n    '0799': ['SQ', '1', 'RTPatientPositionSequence'],\n    '079A': ['LO', '1', 'DisplacementReferenceLabel'],\n    '079B': ['FD', '16', 'DisplacementMatrix'],\n    '079C': ['SQ', '1', 'PatientSupportDisplacementSequence'],\n    '079D': ['SQ', '1', 'DisplacementReferenceLocationCodeSequence'],\n    '079E': ['CS', '1', 'RTRadiationSetDeliveryUsage']\n  },\n  '300C': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['SQ', '1', 'ReferencedRTPlanSequence'],\n    '0004': ['SQ', '1', 'ReferencedBeamSequence'],\n    '0006': ['IS', '1', 'ReferencedBeamNumber'],\n    '0007': ['IS', '1', 'ReferencedReferenceImageNumber'],\n    '0008': ['DS', '1', 'StartCumulativeMetersetWeight'],\n    '0009': ['DS', '1', 'EndCumulativeMetersetWeight'],\n    '000A': ['SQ', '1', 'ReferencedBrachyApplicationSetupSequence'],\n    '000C': ['IS', '1', 'ReferencedBrachyApplicationSetupNumber'],\n    '000E': ['IS', '1', 'ReferencedSourceNumber'],\n    '0020': ['SQ', '1', 'ReferencedFractionGroupSequence'],\n    '0022': ['IS', '1', 'ReferencedFractionGroupNumber'],\n    '0040': ['SQ', '1', 'ReferencedVerificationImageSequence'],\n    '0042': ['SQ', '1', 'ReferencedReferenceImageSequence'],\n    '0050': ['SQ', '1', 'ReferencedDoseReferenceSequence'],\n    '0051': ['IS', '1', 'ReferencedDoseReferenceNumber'],\n    '0055': ['SQ', '1', 'BrachyReferencedDoseReferenceSequence'],\n    '0060': ['SQ', '1', 'ReferencedStructureSetSequence'],\n    '006A': ['IS', '1', 'ReferencedPatientSetupNumber'],\n    '0080': ['SQ', '1', 'ReferencedDoseSequence'],\n    '00A0': ['IS', '1', 'ReferencedToleranceTableNumber'],\n    '00B0': ['SQ', '1', 'ReferencedBolusSequence'],\n    '00C0': ['IS', '1', 'ReferencedWedgeNumber'],\n    '00D0': ['IS', '1', 'ReferencedCompensatorNumber'],\n    '00E0': ['IS', '1', 'ReferencedBlockNumber'],\n    '00F0': ['IS', '1', 'ReferencedControlPointIndex'],\n    '00F2': ['SQ', '1', 'ReferencedControlPointSequence'],\n    '00F4': ['IS', '1', 'ReferencedStartControlPointIndex'],\n    '00F6': ['IS', '1', 'ReferencedStopControlPointIndex'],\n    '0100': ['IS', '1', 'ReferencedRangeShifterNumber'],\n    '0102': ['IS', '1', 'ReferencedLateralSpreadingDeviceNumber'],\n    '0104': ['IS', '1', 'ReferencedRangeModulatorNumber'],\n    '0111': ['SQ', '1', 'OmittedBeamTaskSequence'],\n    '0112': ['CS', '1', 'ReasonForOmission'],\n    '0113': ['LO', '1', 'ReasonForOmissionDescription'],\n    '0114': ['SQ', '1', 'PrescriptionOverviewSequence'],\n    '0115': ['FL', '1', 'TotalPrescriptionDose'],\n    '0116': ['SQ', '1', 'PlanOverviewSequence'],\n    '0117': ['US', '1', 'PlanOverviewIndex'],\n    '0118': ['US', '1', 'ReferencedPlanOverviewIndex'],\n    '0119': ['US', '1', 'NumberOfFractionsIncluded'],\n    '0120': ['SQ', '1', 'DoseCalibrationConditionsSequence'],\n    '0121': ['FD', '1', 'AbsorbedDoseToMetersetRatio'],\n    '0122': ['FD', '2', 'DelineatedRadiationFieldSize'],\n    '0123': ['CS', '1', 'DoseCalibrationConditionsVerifiedFlag'],\n    '0124': ['FD', '1', 'CalibrationReferencePointDepth'],\n    '0125': ['SQ', '1', 'GatingBeamHoldTransitionSequence'],\n    '0126': ['CS', '1', 'BeamHoldTransition'],\n    '0127': ['DT', '1', 'BeamHoldTransitionDateTime'],\n    '0128': ['SQ', '1', 'BeamHoldOriginatingDeviceSequence']\n  },\n  '300E': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0002': ['CS', '1', 'ApprovalStatus'],\n    '0004': ['DA', '1', 'ReviewDate'],\n    '0005': ['TM', '1', 'ReviewTime'],\n    '0008': ['PN', '1', 'ReviewerName']\n  },\n  '3010': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['SQ', '1', 'RadiobiologicalDoseEffectSequence'],\n    '0002': ['CS', '1', 'RadiobiologicalDoseEffectFlag'],\n    '0003': ['SQ', '1', 'EffectiveDoseCalculationMethodCategoryCodeSequence'],\n    '0004': ['SQ', '1', 'EffectiveDoseCalculationMethodCodeSequence'],\n    '0005': ['LO', '1', 'EffectiveDoseCalculationMethodDescription'],\n    '0006': ['UI', '1', 'ConceptualVolumeUID'],\n    '0007': ['SQ', '1', 'OriginatingSOPInstanceReferenceSequence'],\n    '0008': ['SQ', '1', 'ConceptualVolumeConstituentSequence'],\n    '0009': ['SQ', '1', 'EquivalentConceptualVolumeInstanceReferenceSequence'],\n    '000A': ['SQ', '1', 'EquivalentConceptualVolumesSequence'],\n    '000B': ['UI', '1', 'ReferencedConceptualVolumeUID'],\n    '000C': ['UT', '1', 'ConceptualVolumeCombinationExpression'],\n    '000D': ['US', '1', 'ConceptualVolumeConstituentIndex'],\n    '000E': ['CS', '1', 'ConceptualVolumeCombinationFlag'],\n    '000F': ['ST', '1', 'ConceptualVolumeCombinationDescription'],\n    '0010': ['CS', '1', 'ConceptualVolumeSegmentationDefinedFlag'],\n    '0011': ['SQ', '1', 'ConceptualVolumeSegmentationReferenceSequence'],\n    '0012': ['SQ', '1', 'ConceptualVolumeConstituentSegmentationReferenceSequence'],\n    '0013': ['UI', '1', 'ConstituentConceptualVolumeUID'],\n    '0014': ['SQ', '1', 'DerivationConceptualVolumeSequence'],\n    '0015': ['UI', '1', 'SourceConceptualVolumeUID'],\n    '0016': ['SQ', '1', 'ConceptualVolumeDerivationAlgorithmSequence'],\n    '0017': ['ST', '1', 'ConceptualVolumeDescription'],\n    '0018': ['SQ', '1', 'SourceConceptualVolumeSequence'],\n    '0019': ['SQ', '1', 'AuthorIdentificationSequence'],\n    '001A': ['LO', '1', 'ManufacturerModelVersion'],\n    '001B': ['UC', '1', 'DeviceAlternateIdentifier'],\n    '001C': ['CS', '1', 'DeviceAlternateIdentifierType'],\n    '001D': ['LT', '1', 'DeviceAlternateIdentifierFormat'],\n    '001E': ['LO', '1', 'SegmentationCreationTemplateLabel'],\n    '001F': ['UI', '1', 'SegmentationTemplateUID'],\n    '0020': ['US', '1', 'ReferencedSegmentReferenceIndex'],\n    '0021': ['SQ', '1', 'SegmentReferenceSequence'],\n    '0022': ['US', '1', 'SegmentReferenceIndex'],\n    '0023': ['SQ', '1', 'DirectSegmentReferenceSequence'],\n    '0024': ['SQ', '1', 'CombinationSegmentReferenceSequence'],\n    '0025': ['SQ', '1', 'ConceptualVolumeSequence'],\n    '0026': ['SQ', '1', 'SegmentedRTAccessoryDeviceSequence'],\n    '0027': ['SQ', '1', 'SegmentCharacteristicsSequence'],\n    '0028': ['SQ', '1', 'RelatedSegmentCharacteristicsSequence'],\n    '0029': ['US', '1', 'SegmentCharacteristicsPrecedence'],\n    '002A': ['SQ', '1', 'RTSegmentAnnotationSequence'],\n    '002B': ['SQ', '1', 'SegmentAnnotationCategoryCodeSequence'],\n    '002C': ['SQ', '1', 'SegmentAnnotationTypeCodeSequence'],\n    '002D': ['LO', '1', 'DeviceLabel'],\n    '002E': ['SQ', '1', 'DeviceTypeCodeSequence'],\n    '002F': ['SQ', '1', 'SegmentAnnotationTypeModifierCodeSequence'],\n    '0030': ['SQ', '1', 'PatientEquipmentRelationshipCodeSequence'],\n    '0031': ['UI', '1', 'ReferencedFiducialsUID'],\n    '0032': ['SQ', '1', 'PatientTreatmentOrientationSequence'],\n    '0033': ['SH', '1', 'UserContentLabel'],\n    '0034': ['LO', '1', 'UserContentLongLabel'],\n    '0035': ['SH', '1', 'EntityLabel'],\n    '0036': ['LO', '1', 'EntityName'],\n    '0037': ['ST', '1', 'EntityDescription'],\n    '0038': ['LO', '1', 'EntityLongLabel'],\n    '0039': ['US', '1', 'DeviceIndex'],\n    '003A': ['US', '1', 'RTTreatmentPhaseIndex'],\n    '003B': ['UI', '1', 'RTTreatmentPhaseUID'],\n    '003C': ['US', '1', 'RTPrescriptionIndex'],\n    '003D': ['US', '1', 'RTSegmentAnnotationIndex'],\n    '003E': ['US', '1', 'BasisRTTreatmentPhaseIndex'],\n    '003F': ['US', '1', 'RelatedRTTreatmentPhaseIndex'],\n    '0040': ['US', '1', 'ReferencedRTTreatmentPhaseIndex'],\n    '0041': ['US', '1', 'ReferencedRTPrescriptionIndex'],\n    '0042': ['US', '1', 'ReferencedParentRTPrescriptionIndex'],\n    '0043': ['ST', '1', 'ManufacturerDeviceIdentifier'],\n    '0044': ['SQ', '1', 'InstanceLevelReferencedPerformedProcedureStepSequence'],\n    '0045': ['CS', '1', 'RTTreatmentPhaseIntentPresenceFlag'],\n    '0046': ['CS', '1', 'RadiotherapyTreatmentType'],\n    '0047': ['CS', '1-n', 'TeletherapyRadiationType'],\n    '0048': ['CS', '1-n', 'BrachytherapySourceType'],\n    '0049': ['SQ', '1', 'ReferencedRTTreatmentPhaseSequence'],\n    '004A': ['SQ', '1', 'ReferencedDirectSegmentInstanceSequence'],\n    '004B': ['SQ', '1', 'IntendedRTTreatmentPhaseSequence'],\n    '004C': ['DA', '1', 'IntendedPhaseStartDate'],\n    '004D': ['DA', '1', 'IntendedPhaseEndDate'],\n    '004E': ['SQ', '1', 'RTTreatmentPhaseIntervalSequence'],\n    '004F': ['CS', '1', 'TemporalRelationshipIntervalAnchor'],\n    '0050': ['FD', '1', 'MinimumNumberOfIntervalDays'],\n    '0051': ['FD', '1', 'MaximumNumberOfIntervalDays'],\n    '0052': ['UI', '1-n', 'PertinentSOPClassesInStudy'],\n    '0053': ['UI', '1-n', 'PertinentSOPClassesInSeries'],\n    '0054': ['LO', '1', 'RTPrescriptionLabel'],\n    '0055': ['SQ', '1', 'RTPhysicianIntentPredecessorSequence'],\n    '0056': ['LO', '1', 'RTTreatmentApproachLabel'],\n    '0057': ['SQ', '1', 'RTPhysicianIntentSequence'],\n    '0058': ['US', '1', 'RTPhysicianIntentIndex'],\n    '0059': ['CS', '1', 'RTTreatmentIntentType'],\n    '005A': ['UT', '1', 'RTPhysicianIntentNarrative'],\n    '005B': ['SQ', '1', 'RTProtocolCodeSequence'],\n    '005C': ['ST', '1', 'ReasonForSuperseding'],\n    '005D': ['SQ', '1', 'RTDiagnosisCodeSequence'],\n    '005E': ['US', '1', 'ReferencedRTPhysicianIntentIndex'],\n    '005F': ['SQ', '1', 'RTPhysicianIntentInputInstanceSequence'],\n    '0060': ['SQ', '1', 'RTAnatomicPrescriptionSequence'],\n    '0061': ['UT', '1', 'PriorTreatmentDoseDescription'],\n    '0062': ['SQ', '1', 'PriorTreatmentReferenceSequence'],\n    '0063': ['CS', '1', 'DosimetricObjectiveEvaluationScope'],\n    '0064': ['SQ', '1', 'TherapeuticRoleCategoryCodeSequence'],\n    '0065': ['SQ', '1', 'TherapeuticRoleTypeCodeSequence'],\n    '0066': ['US', '1', 'ConceptualVolumeOptimizationPrecedence'],\n    '0067': ['SQ', '1', 'ConceptualVolumeCategoryCodeSequence'],\n    '0068': ['CS', '1', 'ConceptualVolumeBlockingConstraint'],\n    '0069': ['SQ', '1', 'ConceptualVolumeTypeCodeSequence'],\n    '006A': ['SQ', '1', 'ConceptualVolumeTypeModifierCodeSequence'],\n    '006B': ['SQ', '1', 'RTPrescriptionSequence'],\n    '006C': ['SQ', '1', 'DosimetricObjectiveSequence'],\n    '006D': ['SQ', '1', 'DosimetricObjectiveTypeCodeSequence'],\n    '006E': ['UI', '1', 'DosimetricObjectiveUID'],\n    '006F': ['UI', '1', 'ReferencedDosimetricObjectiveUID'],\n    '0070': ['SQ', '1', 'DosimetricObjectiveParameterSequence'],\n    '0071': ['SQ', '1', 'ReferencedDosimetricObjectivesSequence'],\n    '0073': ['CS', '1', 'AbsoluteDosimetricObjectiveFlag'],\n    '0074': ['FD', '1', 'DosimetricObjectiveWeight'],\n    '0075': ['CS', '1', 'DosimetricObjectivePurpose'],\n    '0076': ['SQ', '1', 'PlanningInputInformationSequence'],\n    '0077': ['LO', '1', 'TreatmentSite'],\n    '0078': ['SQ', '1', 'TreatmentSiteCodeSequence'],\n    '0079': ['SQ', '1', 'FractionPatternSequence'],\n    '007A': ['UT', '1', 'TreatmentTechniqueNotes'],\n    '007B': ['UT', '1', 'PrescriptionNotes'],\n    '007C': ['IS', '1', 'NumberOfIntervalFractions'],\n    '007D': ['US', '1', 'NumberOfFractions'],\n    '007E': ['US', '1', 'IntendedDeliveryDuration'],\n    '007F': ['UT', '1', 'FractionationNotes'],\n    '0080': ['SQ', '1', 'RTTreatmentTechniqueCodeSequence'],\n    '0081': ['SQ', '1', 'PrescriptionNotesSequence'],\n    '0082': ['SQ', '1', 'FractionBasedRelationshipSequence'],\n    '0083': ['CS', '1', 'FractionBasedRelationshipIntervalAnchor'],\n    '0084': ['FD', '1', 'MinimumHoursBetweenFractions'],\n    '0085': ['TM', '1-n', 'IntendedFractionStartTime'],\n    '0086': ['LT', '1', 'IntendedStartDayOfWeek'],\n    '0087': ['SQ', '1', 'WeekdayFractionPatternSequence'],\n    '0088': ['SQ', '1', 'DeliveryTimeStructureCodeSequence'],\n    '0089': ['SQ', '1', 'TreatmentSiteModifierCodeSequence'],\n    '0090': ['CS', '1', 'RoboticBaseLocationIndicator'],\n    '0091': ['SQ', '1', 'RoboticPathNodeSetCodeSequence'],\n    '0092': ['UL', '1', 'RoboticNodeIdentifier'],\n    '0093': ['FD', '3', 'RTTreatmentSourceCoordinates'],\n    '0094': ['FD', '1', 'RadiationSourceCoordinateSystemYawAngle'],\n    '0095': ['FD', '1', 'RadiationSourceCoordinateSystemRollAngle'],\n    '0096': ['FD', '1', 'RadiationSourceCoordinateSystemPitchAngle'],\n    '0097': ['SQ', '1', 'RoboticPathControlPointSequence'],\n    '0098': ['SQ', '1', 'TomotherapeuticControlPointSequence'],\n    '0099': ['FD', '1-n', 'TomotherapeuticLeafOpenDurations'],\n    '009A': ['FD', '1-n', 'TomotherapeuticLeafInitialClosedDurations']\n  },\n  '4000': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['LT', '1', 'Arbitrary'],\n    '4000': ['LT', '1', 'TextComments']\n  },\n  '4008': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0040': ['SH', '1', 'ResultsID'],\n    '0042': ['LO', '1', 'ResultsIDIssuer'],\n    '0050': ['SQ', '1', 'ReferencedInterpretationSequence'],\n    '00FF': ['CS', '1', 'ReportProductionStatusTrial'],\n    '0100': ['DA', '1', 'InterpretationRecordedDate'],\n    '0101': ['TM', '1', 'InterpretationRecordedTime'],\n    '0102': ['PN', '1', 'InterpretationRecorder'],\n    '0103': ['LO', '1', 'ReferenceToRecordedSound'],\n    '0108': ['DA', '1', 'InterpretationTranscriptionDate'],\n    '0109': ['TM', '1', 'InterpretationTranscriptionTime'],\n    '010A': ['PN', '1', 'InterpretationTranscriber'],\n    '010B': ['ST', '1', 'InterpretationText'],\n    '010C': ['PN', '1', 'InterpretationAuthor'],\n    '0111': ['SQ', '1', 'InterpretationApproverSequence'],\n    '0112': ['DA', '1', 'InterpretationApprovalDate'],\n    '0113': ['TM', '1', 'InterpretationApprovalTime'],\n    '0114': ['PN', '1', 'PhysicianApprovingInterpretation'],\n    '0115': ['LT', '1', 'InterpretationDiagnosisDescription'],\n    '0117': ['SQ', '1', 'InterpretationDiagnosisCodeSequence'],\n    '0118': ['SQ', '1', 'ResultsDistributionListSequence'],\n    '0119': ['PN', '1', 'DistributionName'],\n    '011A': ['LO', '1', 'DistributionAddress'],\n    '0200': ['SH', '1', 'InterpretationID'],\n    '0202': ['LO', '1', 'InterpretationIDIssuer'],\n    '0210': ['CS', '1', 'InterpretationTypeID'],\n    '0212': ['CS', '1', 'InterpretationStatusID'],\n    '0300': ['ST', '1', 'Impressions'],\n    '4000': ['ST', '1', 'ResultsComments']\n  },\n  '4010': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['CS', '1', 'LowEnergyDetectors'],\n    '0002': ['CS', '1', 'HighEnergyDetectors'],\n    '0004': ['SQ', '1', 'DetectorGeometrySequence'],\n    '1001': ['SQ', '1', 'ThreatROIVoxelSequence'],\n    '1004': ['FL', '3', 'ThreatROIBase'],\n    '1005': ['FL', '3', 'ThreatROIExtents'],\n    '1006': ['OB', '1', 'ThreatROIBitmap'],\n    '1007': ['SH', '1', 'RouteSegmentID'],\n    '1008': ['CS', '1', 'GantryType'],\n    '1009': ['CS', '1', 'OOIOwnerType'],\n    '100A': ['SQ', '1', 'RouteSegmentSequence'],\n    '1010': ['US', '1', 'PotentialThreatObjectID'],\n    '1011': ['SQ', '1', 'ThreatSequence'],\n    '1012': ['CS', '1', 'ThreatCategory'],\n    '1013': ['LT', '1', 'ThreatCategoryDescription'],\n    '1014': ['CS', '1', 'ATDAbilityAssessment'],\n    '1015': ['CS', '1', 'ATDAssessmentFlag'],\n    '1016': ['FL', '1', 'ATDAssessmentProbability'],\n    '1017': ['FL', '1', 'Mass'],\n    '1018': ['FL', '1', 'Density'],\n    '1019': ['FL', '1', 'ZEffective'],\n    '101A': ['SH', '1', 'BoardingPassID'],\n    '101B': ['FL', '3', 'CenterOfMass'],\n    '101C': ['FL', '3', 'CenterOfPTO'],\n    '101D': ['FL', '6-n', 'BoundingPolygon'],\n    '101E': ['SH', '1', 'RouteSegmentStartLocationID'],\n    '101F': ['SH', '1', 'RouteSegmentEndLocationID'],\n    '1020': ['CS', '1', 'RouteSegmentLocationIDType'],\n    '1021': ['CS', '1-n', 'AbortReason'],\n    '1023': ['FL', '1', 'VolumeOfPTO'],\n    '1024': ['CS', '1', 'AbortFlag'],\n    '1025': ['DT', '1', 'RouteSegmentStartTime'],\n    '1026': ['DT', '1', 'RouteSegmentEndTime'],\n    '1027': ['CS', '1', 'TDRType'],\n    '1028': ['CS', '1', 'InternationalRouteSegment'],\n    '1029': ['LO', '1-n', 'ThreatDetectionAlgorithmAndVersion'],\n    '102A': ['SH', '1', 'AssignedLocation'],\n    '102B': ['DT', '1', 'AlarmDecisionTime'],\n    '1031': ['CS', '1', 'AlarmDecision'],\n    '1033': ['US', '1', 'NumberOfTotalObjects'],\n    '1034': ['US', '1', 'NumberOfAlarmObjects'],\n    '1037': ['SQ', '1', 'PTORepresentationSequence'],\n    '1038': ['SQ', '1', 'ATDAssessmentSequence'],\n    '1039': ['CS', '1', 'TIPType'],\n    '103A': ['CS', '1', 'DICOSVersion'],\n    '1041': ['DT', '1', 'OOIOwnerCreationTime'],\n    '1042': ['CS', '1', 'OOIType'],\n    '1043': ['FL', '3', 'OOISize'],\n    '1044': ['CS', '1', 'AcquisitionStatus'],\n    '1045': ['SQ', '1', 'BasisMaterialsCodeSequence'],\n    '1046': ['CS', '1', 'PhantomType'],\n    '1047': ['SQ', '1', 'OOIOwnerSequence'],\n    '1048': ['CS', '1', 'ScanType'],\n    '1051': ['LO', '1', 'ItineraryID'],\n    '1052': ['SH', '1', 'ItineraryIDType'],\n    '1053': ['LO', '1', 'ItineraryIDAssigningAuthority'],\n    '1054': ['SH', '1', 'RouteID'],\n    '1055': ['SH', '1', 'RouteIDAssigningAuthority'],\n    '1056': ['CS', '1', 'InboundArrivalType'],\n    '1058': ['SH', '1', 'CarrierID'],\n    '1059': ['CS', '1', 'CarrierIDAssigningAuthority'],\n    '1060': ['FL', '3', 'SourceOrientation'],\n    '1061': ['FL', '3', 'SourcePosition'],\n    '1062': ['FL', '1', 'BeltHeight'],\n    '1064': ['SQ', '1', 'AlgorithmRoutingCodeSequence'],\n    '1067': ['CS', '1', 'TransportClassification'],\n    '1068': ['LT', '1', 'OOITypeDescriptor'],\n    '1069': ['FL', '1', 'TotalProcessingTime'],\n    '106C': ['OB', '1', 'DetectorCalibrationData'],\n    '106D': ['CS', '1', 'AdditionalScreeningPerformed'],\n    '106E': ['CS', '1', 'AdditionalInspectionSelectionCriteria'],\n    '106F': ['SQ', '1', 'AdditionalInspectionMethodSequence'],\n    '1070': ['CS', '1', 'AITDeviceType'],\n    '1071': ['SQ', '1', 'QRMeasurementsSequence'],\n    '1072': ['SQ', '1', 'TargetMaterialSequence'],\n    '1073': ['FD', '1', 'SNRThreshold'],\n    '1075': ['DS', '1', 'ImageScaleRepresentation'],\n    '1076': ['SQ', '1', 'ReferencedPTOSequence'],\n    '1077': ['SQ', '1', 'ReferencedTDRInstanceSequence'],\n    '1078': ['ST', '1', 'PTOLocationDescription'],\n    '1079': ['SQ', '1', 'AnomalyLocatorIndicatorSequence'],\n    '107A': ['FL', '3', 'AnomalyLocatorIndicator'],\n    '107B': ['SQ', '1', 'PTORegionSequence'],\n    '107C': ['CS', '1', 'InspectionSelectionCriteria'],\n    '107D': ['SQ', '1', 'SecondaryInspectionMethodSequence'],\n    '107E': ['DS', '6', 'PRCSToRCSOrientation']\n  },\n  '4FFE': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['SQ', '1', 'MACParametersSequence']\n  },\n  '5000': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0005': ['US', '1', 'CurveDimensions'],\n    '0010': ['US', '1', 'NumberOfPoints'],\n    '0020': ['CS', '1', 'TypeOfData'],\n    '0022': ['LO', '1', 'CurveDescription'],\n    '0030': ['SH', '1-n', 'AxisUnits'],\n    '0040': ['SH', '1-n', 'AxisLabels'],\n    '0103': ['US', '1', 'DataValueRepresentation'],\n    '0104': ['US', '1-n', 'MinimumCoordinateValue'],\n    '0105': ['US', '1-n', 'MaximumCoordinateValue'],\n    '0106': ['SH', '1-n', 'CurveRange'],\n    '0110': ['US', '1-n', 'CurveDataDescriptor'],\n    '0112': ['US', '1-n', 'CoordinateStartValue'],\n    '0114': ['US', '1-n', 'CoordinateStepValue'],\n    '1001': ['CS', '1', 'CurveActivationLayer'],\n    '2000': ['US', '1', 'AudioType'],\n    '2002': ['US', '1', 'AudioSampleFormat'],\n    '2004': ['US', '1', 'NumberOfChannels'],\n    '2006': ['UL', '1', 'NumberOfSamples'],\n    '2008': ['UL', '1', 'SampleRate'],\n    '200A': ['UL', '1', 'TotalTime'],\n    '200C': ['ox', '1', 'AudioSampleData'],\n    '200E': ['LT', '1', 'AudioComments'],\n    '2500': ['LO', '1', 'CurveLabel'],\n    '2600': ['SQ', '1', 'CurveReferencedOverlaySequence'],\n    '2610': ['US', '1', 'CurveReferencedOverlayGroup'],\n    '3000': ['ox', '1', 'CurveData']\n  },\n  '5200': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '9229': ['SQ', '1', 'SharedFunctionalGroupsSequence'],\n    '9230': ['SQ', '1', 'PerFrameFunctionalGroupsSequence']\n  },\n  '5400': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0100': ['SQ', '1', 'WaveformSequence'],\n    '0110': ['ox', '1', 'ChannelMinimumValue'],\n    '0112': ['ox', '1', 'ChannelMaximumValue'],\n    '1004': ['US', '1', 'WaveformBitsAllocated'],\n    '1006': ['CS', '1', 'WaveformSampleInterpretation'],\n    '100A': ['ox', '1', 'WaveformPaddingValue'],\n    '1010': ['ox', '1', 'WaveformData']\n  },\n  '5600': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['OF', '1', 'FirstOrderPhaseCorrectionAngle'],\n    '0020': ['OF', '1', 'SpectroscopyData']\n  },\n  '6000': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['US', '1', 'OverlayRows'],\n    '0011': ['US', '1', 'OverlayColumns'],\n    '0012': ['US', '1', 'OverlayPlanes'],\n    '0015': ['IS', '1', 'NumberOfFramesInOverlay'],\n    '0022': ['LO', '1', 'OverlayDescription'],\n    '0040': ['CS', '1', 'OverlayType'],\n    '0045': ['LO', '1', 'OverlaySubtype'],\n    '0050': ['SS', '2', 'OverlayOrigin'],\n    '0051': ['US', '1', 'ImageFrameOrigin'],\n    '0052': ['US', '1', 'OverlayPlaneOrigin'],\n    '0060': ['CS', '1', 'OverlayCompressionCode'],\n    '0061': ['SH', '1', 'OverlayCompressionOriginator'],\n    '0062': ['SH', '1', 'OverlayCompressionLabel'],\n    '0063': ['CS', '1', 'OverlayCompressionDescription'],\n    '0066': ['AT', '1-n', 'OverlayCompressionStepPointers'],\n    '0068': ['US', '1', 'OverlayRepeatInterval'],\n    '0069': ['US', '1', 'OverlayBitsGrouped'],\n    '0100': ['US', '1', 'OverlayBitsAllocated'],\n    '0102': ['US', '1', 'OverlayBitPosition'],\n    '0110': ['CS', '1', 'OverlayFormat'],\n    '0200': ['US', '1', 'OverlayLocation'],\n    '0800': ['CS', '1-n', 'OverlayCodeLabel'],\n    '0802': ['US', '1', 'OverlayNumberOfTables'],\n    '0803': ['AT', '1-n', 'OverlayCodeTableLocation'],\n    '0804': ['US', '1', 'OverlayBitsForCodeWord'],\n    '1001': ['CS', '1', 'OverlayActivationLayer'],\n    '1100': ['US', '1', 'OverlayDescriptorGray'],\n    '1101': ['US', '1', 'OverlayDescriptorRed'],\n    '1102': ['US', '1', 'OverlayDescriptorGreen'],\n    '1103': ['US', '1', 'OverlayDescriptorBlue'],\n    '1200': ['US', '1-n', 'OverlaysGray'],\n    '1201': ['US', '1-n', 'OverlaysRed'],\n    '1202': ['US', '1-n', 'OverlaysGreen'],\n    '1203': ['US', '1-n', 'OverlaysBlue'],\n    '1301': ['IS', '1', 'ROIArea'],\n    '1302': ['DS', '1', 'ROIMean'],\n    '1303': ['DS', '1', 'ROIStandardDeviation'],\n    '1500': ['LO', '1', 'OverlayLabel'],\n    '3000': ['ox', '1', 'OverlayData'],\n    '4000': ['LT', '1', 'OverlayComments']\n  },\n  '7F00': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0010': ['ox', '1', 'VariablePixelData'],\n    '0011': ['US', '1', 'VariableNextDataGroup'],\n    '0020': ['OW', '1', 'VariableCoefficientsSDVN'],\n    '0030': ['OW', '1', 'VariableCoefficientsSDHN'],\n    '0040': ['OW', '1', 'VariableCoefficientsSDDN']\n  },\n  '7FE0': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    '0001': ['OV', '1', 'ExtendedOffsetTable'],\n    '0002': ['OV', '1', 'ExtendedOffsetTableLengths'],\n    '0008': ['OF', '1', 'FloatPixelData'],\n    '0009': ['OD', '1', 'DoubleFloatPixelData'],\n    '0010': ['ox', '1', 'PixelData'],\n    '0020': ['OW', '1', 'CoefficientsSDVN'],\n    '0030': ['OW', '1', 'CoefficientsSDHN'],\n    '0040': ['OW', '1', 'CoefficientsSDDN']\n  },\n  'FFFA': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    'FFFA': ['SQ', '1', 'DigitalSignaturesSequence']\n  },\n  'FFFC': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    'FFFC': ['OB', '1', 'DataSetTrailingPadding']\n  },\n  'FFFE': {\n    '0000': ['UL', '1', 'GenericGroupLength'],\n    'E000': ['NONE', '1', 'Item'],\n    'E00D': ['NONE', '1', 'ItemDelimitationItem'],\n    'E0DD': ['NONE', '1', 'SequenceDelimitationItem']\n  }\n}; // Dictionary\n\n/**\n * Add tags to the dictionary.\n *\n * @param {string} group The group key.\n * @param {object} tags The tags to add.\n */\nexport function addTagsToDictionary(group, tags) {\n  // TODO: add checks!\n  dictionary[group] = tags;\n}\n\n// taken from gdcm-2.6.1\\Source\\DataDictionary\\GroupName.dic\n// -> removed duplicates (commented)\nexport const tagGroups = {\n  '0000': 'Command',\n  '0002': 'Meta Element',\n  '0004': 'File Set',\n  //'0004': 'Directory',\n  '0008': 'Identifying',\n  '0009': 'SPI Identifying',\n  '0010': 'Patient',\n  '0012': 'Clinical Trial',\n  '0018': 'Acquisition',\n  '0019': 'SPI Acquisition',\n  '0020': 'Image',\n  '0021': 'SPI Image',\n  '0022': 'Ophtalmology',\n  '0028': 'Image Presentation',\n  '0032': 'Study',\n  '0038': 'Visit',\n  '003A': 'Waveform',\n  '0040': 'Procedure',\n  //'0040': ''Modality Worklist',\n  '0042': 'Encapsulated Document',\n  '0050': 'Device Informations',\n  //'0050': 'XRay Angio Device',\n  '0054': 'Nuclear Medicine',\n  '0060': 'Histogram',\n  '0070': 'Presentation State',\n  '0072': 'Hanging Protocol',\n  '0088': 'Storage',\n  //'0088': 'Medicine',\n  '0100': 'Authorization',\n  '0400': 'Digital Signature',\n  '1000': 'Code Table',\n  '1010': 'Zonal Map',\n  '2000': 'Film Session',\n  '2010': 'Film Box',\n  '2020': 'Image Box',\n  '2030': 'Annotation',\n  '2040': 'Overlay Box',\n  '2050': 'Presentation LUT',\n  '2100': 'Print Job',\n  '2110': 'Printer',\n  '2120': 'Queue',\n  '2130': 'Print Content',\n  '2200': 'Media Creation',\n  '3002': 'RT Image',\n  '3004': 'RT Dose',\n  '3006': 'RT StructureSet',\n  '3008': 'RT Treatment',\n  '300A': 'RT Plan',\n  '300C': 'RT Relationship',\n  '300E': 'RT Approval',\n  '4000': 'Text',\n  '4008': 'Results',\n  '4FFE': 'MAC Parameters',\n  '5000': 'Curve',\n  '5002': 'Curve',\n  '5004': 'Curve',\n  '5006': 'Curve',\n  '5008': 'Curve',\n  '500A': 'Curve',\n  '500C': 'Curve',\n  '500E': 'Curve',\n  '5400': 'Waveform Data',\n  '6000': 'Overlays',\n  '6002': 'Overlays',\n  '6004': 'Overlays',\n  '6008': 'Overlays',\n  '600A': 'Overlays',\n  '600C': 'Overlays',\n  '600E': 'Overlays',\n  'FFFC': 'Generic',\n  '7FE0': 'Pixel Data',\n  'FFFF': 'Unknown'\n};\n\n// Value Representation (VR) with 32bit Value Length (VL)\n// Added locally used 'ox'\n// see http://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_7.html#table_7.1-1\nconst vr32bitVL = {\n  OB: true,\n  OD: true,\n  OF: true,\n  OL: true,\n  OV: true,\n  OW: true,\n  SQ: true,\n  SV: true,\n  UC: true,\n  UN: true,\n  UR: true,\n  UT: true,\n  UV: true,\n  ox: true\n};\n\n/**\n * Does the input Value Representation (VR) have a 32bit Value Length (VL).\n *\n * @param {string} vr The data Value Representation (VR).\n * @returns {boolean} True if this VR has a 32-bit VL.\n */\nexport function is32bitVLVR(vr) {\n  return typeof vr32bitVL[vr] !== 'undefined';\n}\n\n// String VR with extended or replaced default character repertoire defined in\n// Specific Character Set (0008,0005)\n// see https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/chapter_6.html#sect_6.1.2.2\nconst vrCharSetString = {\n  SH: true,\n  LO: true,\n  UC: true,\n  ST: true,\n  LT: true,\n  UT: true,\n  PN: true\n};\n\n/**\n * Does the input Value Representation (VR) have an special character repertoire.\n *\n * @param {string} vr The data VR.\n * @returns {boolean} True if this VR has a special char set.\n */\nexport function isCharSetStringVR(vr) {\n  return typeof vrCharSetString[vr] !== 'undefined';\n}\n\n// VR types\n// see https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_6.2.html#table_6.2-1\nexport const vrTypes = {\n  AE: 'string',\n  AS: 'string',\n  AT: undefined,\n  CS: 'string',\n  DA: 'string',\n  DS: 'string',\n  DT: 'string',\n  FL: 'Float32',\n  FD: 'Float64',\n  IS: 'string',\n  LO: 'string',\n  LT: 'string',\n  OB: 'Uint8',\n  OD: 'Uint64',\n  OF: 'Uint32',\n  OL: 'Uint32',\n  OV: 'Uint64',\n  OW: 'Uint16',\n  PN: 'string',\n  SH: 'string',\n  SL: 'Int32',\n  SQ: undefined,\n  SS: 'Int16',\n  ST: 'string',\n  SV: 'Int64',\n  TM: 'string',\n  UC: 'string',\n  UI: 'string',\n  UL: 'Uint32',\n  UN: 'Uint8',\n  UR: 'string',\n  US: 'Uint16',\n  UT: 'string',\n  UV: 'Uint64'\n};\n","import {\n  dictionary,\n  tagGroups\n} from './dictionary';\n\n/**\n * Immutable tag.\n */\nexport class Tag {\n\n  /**\n   * The tag group.\n   *\n   * @type {string}\n   */\n  #group;\n\n  /**\n   * The tag element.\n   *\n   * @type {string}\n   */\n  #element;\n\n  /**\n   * @param {string} group The tag group as '####'.\n   * @param {string} element The tag element as '####'.\n   */\n  constructor(group, element) {\n    if (!group || typeof group === 'undefined') {\n      throw new Error('Cannot create tag with no group.');\n    }\n    if (group.length !== 4) {\n      throw new Error('Cannot create tag with badly sized group.');\n    }\n    if (!element || typeof element === 'undefined') {\n      throw new Error('Cannot create tag with no element.');\n    }\n    if (element.length !== 4) {\n      throw new Error('Cannot create tag with badly sized element.');\n    }\n    this.#group = group;\n    this.#element = element;\n  }\n\n  /**\n   * Get the tag group.\n   *\n   * @returns {string} The tag group.\n   */\n  getGroup() {\n    return this.#group;\n  }\n\n  /**\n   * Get the tag element.\n   *\n   * @returns {string} The tag element.\n   */\n  getElement() {\n    return this.#element;\n  }\n\n  /**\n   * Get as string representation of the tag: 'key: name'.\n   *\n   * @returns {string} A string representing the tag.\n   */\n  toString() {\n    return this.getKey() + ': ' + this.getNameFromDictionary();\n  }\n\n  /**\n   * Check for Tag equality.\n   *\n   * @param {Tag} rhs The other tag to compare to.\n   * @returns {boolean} True if both tags are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      typeof rhs !== 'undefined' &&\n      this.#group === rhs.getGroup() &&\n      this.#element === rhs.getElement();\n  }\n\n  /**\n   * Get the group-element key used to store DICOM elements.\n   *\n   * @returns {string} The key as '########'.\n   */\n  getKey() {\n    return this.#group + this.#element;\n  }\n\n  /**\n   * Get the group name as defined in TagGroups.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return tagGroups[this.#group];\n  }\n\n  /**\n   * Does this tag have a VR.\n   * Basically not the Item, ItemDelimitationItem nor\n   *  SequenceDelimitationItem tags.\n   *\n   * @returns {boolean} True if this tag has a VR.\n   */\n  isWithVR() {\n    return !(this.#group === 'FFFE' &&\n      (this.#element === 'E000' ||\n      this.#element === 'E00D' ||\n      this.#element === 'E0DD')\n    );\n  }\n\n  /**\n   * Is the tag group a private tag group ?\n   * see: http://dicom.nema.org/medical/dicom/2015a/output/html/part05.html#sect_7.8\n   *\n   * @returns {boolean} True if the tag group is private,\n   *   ie if its group is an odd number.\n   */\n  isPrivate() {\n    return parseInt(this.#group, 16) % 2 === 1;\n  }\n\n  /**\n   * Get the tag info from the dicom dictionary.\n   *\n   * @returns {Array|undefined} The info as [vr, multiplicity, name].\n   */\n  getInfoFromDictionary() {\n    let info;\n    if (typeof dictionary[this.#group] !== 'undefined' &&\n      typeof dictionary[this.#group][this.#element] !==\n        'undefined') {\n      info = dictionary[this.#group][this.#element];\n    }\n    return info;\n  }\n\n  /**\n   * Get the tag Value Representation (VR) from the dicom dictionary.\n   *\n   * @returns {string|undefined} The VR.\n   */\n  getVrFromDictionary() {\n    let vr;\n    const info = this.getInfoFromDictionary();\n    if (typeof info !== 'undefined') {\n      vr = info[0];\n    }\n    return vr;\n  }\n\n  /**\n   * Get the tag name from the dicom dictionary.\n   *\n   * @returns {string|undefined} The VR.\n   */\n  getNameFromDictionary() {\n    let name;\n    const info = this.getInfoFromDictionary();\n    if (typeof info !== 'undefined') {\n      name = info[2];\n    }\n    return name;\n  }\n\n} // Tag class\n\n/**\n * Tag compare function.\n *\n * @param {Tag} a The first tag.\n * @param {Tag} b The second tag.\n * @returns {number} The result of the tag comparison,\n *   positive for b before a, negative for a before b and\n *   zero to keep same order.\n */\nexport function tagCompareFunction(a, b) {\n  // first by group\n  let res = parseInt(a.getGroup(), 16) - parseInt(b.getGroup(), 16);\n  if (res === 0) {\n    // by element if same group\n    res = parseInt(a.getElement(), 16) - parseInt(b.getElement(), 16);\n  }\n  return res;\n}\n\n/**\n * Split a group-element key used to store DICOM elements.\n *\n * @param {string} key The key in form \"00280102\" as generated by tag::getKey.\n * @returns {Tag} The DICOM tag.\n */\nexport function getTagFromKey(key) {\n  if (!key || typeof key === 'undefined') {\n    throw new Error('Cannot create tag with no key.');\n  }\n  if (key.length !== 8) {\n    throw new Error('Cannot create tag with badly sized key.');\n  }\n  return new Tag(key.substring(0, 4), key.substring(4, 8));\n}\n\n/**\n * Get the TransferSyntaxUID Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getTransferSyntaxUIDTag() {\n  return new Tag('0002', '0010');\n}\n\n/**\n * Get the FileMetaInformationGroupLength Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getFileMetaInformationGroupLengthTag() {\n  return new Tag('0002', '0000');\n}\n\n/**\n * Is the input tag the FileMetaInformationGroupLength Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isFileMetaInformationGroupLengthTag(tag) {\n  return tag.equals(getFileMetaInformationGroupLengthTag());\n}\n\n/**\n * Get the Item Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getItemTag() {\n  return new Tag('FFFE', 'E000');\n}\n\n/**\n * Is the input tag the Item Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isItemTag(tag) {\n  // faster than tag.equals(getItemTag());\n  return tag.getKey() === 'FFFEE000';\n}\n\n/**\n * Get the ItemDelimitationItem Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getItemDelimitationItemTag() {\n  return new Tag('FFFE', 'E00D');\n}\n\n/**\n * Is the input tag the ItemDelimitationItem Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isItemDelimitationItemTag(tag) {\n  // faster than tag.equals(getItemDelimitationItemTag());\n  return tag.getKey() === 'FFFEE00D';\n}\n\n/**\n * Get the SequenceDelimitationItem Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getSequenceDelimitationItemTag() {\n  return new Tag('FFFE', 'E0DD');\n}\n\n/**\n * Is the input tag the SequenceDelimitationItem Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isSequenceDelimitationItemTag(tag) {\n  // faster than tag.equals(getSequenceDelimitationItemTag());\n  return tag.getKey() === 'FFFEE0DD';\n}\n\n/**\n * Get the PixelData Tag.\n *\n * @returns {Tag} The tag.\n */\nexport function getPixelDataTag() {\n  return new Tag('7FE0', '0010');\n}\n\n/**\n * Is the input tag the PixelData Tag.\n *\n * @param {Tag} tag The tag to test.\n * @returns {boolean} True if the asked tag.\n */\nexport function isPixelDataTag(tag) {\n  // faster than tag.equals(getPixelDataTag());\n  return tag.getKey() === '7FE00010';\n}\n\n/**\n * Get a tag from the dictionary using a tag string name.\n *\n * @param {string} tagName The tag string name.\n * @returns {Tag|undefined} The tag object or null if not found.\n */\nexport function getTagFromDictionary(tagName) {\n  if (typeof tagName === 'undefined' || tagName === null) {\n    return null;\n  }\n  let group = null;\n  let element = null;\n  const dict = dictionary;\n  const keys0 = Object.keys(dict);\n  let keys1 = null;\n  let foundTag = false;\n  // search through dictionary\n  for (let k0 = 0, lenK0 = keys0.length; k0 < lenK0; ++k0) {\n    group = keys0[k0];\n    keys1 = Object.keys(dict[group]);\n    for (let k1 = 0, lenK1 = keys1.length; k1 < lenK1; ++k1) {\n      element = keys1[k1];\n      if (dict[group][element][2] === tagName) {\n        foundTag = true;\n        break;\n      }\n    }\n    if (foundTag) {\n      break;\n    }\n  }\n  let tag;\n  if (foundTag) {\n    tag = new Tag(group, element);\n  }\n  return tag;\n}\n","/**\n * Is the Native endianness Little Endian.\n *\n * @returns {boolean} True if little endian.\n */\nexport function isNativeLittleEndian() {\n  return new Int8Array(new Int16Array([1]).buffer)[0] > 0;\n}\n\n/**\n * Flip an array's endianness.\n * Inspired from [DataStream.js]{@link https://github.com/kig/DataStream.js}.\n *\n * @param {object} array The array to flip (modified).\n */\nfunction flipArrayEndianness(array) {\n  const blen = array.byteLength;\n  const u8 = new Uint8Array(array.buffer, array.byteOffset, blen);\n  const bpe = array.BYTES_PER_ELEMENT;\n  let tmp;\n  for (let i = 0; i < blen; i += bpe) {\n    for (let j = i + bpe - 1, k = i; j > k; j--, k++) {\n      tmp = u8[k];\n      u8[k] = u8[j];\n      u8[j] = tmp;\n    }\n  }\n}\n\n/**\n * Data reader.\n */\nexport class DataReader {\n\n  /**\n   * The input buffer.\n   *\n   * @type {ArrayBuffer}\n   */\n  #buffer;\n\n  /**\n   * Is the endianness Little Endian.\n   *\n   * @type {boolean}\n   */\n  #isLittleEndian = true;\n\n  /**\n   * Is the Native endianness Little Endian.\n   *\n   * @type {boolean}\n   */\n  #isNativeLittleEndian = isNativeLittleEndian();\n\n  /**\n   * Flag to know if the TypedArray data needs flipping.\n   *\n   * @type {boolean}\n   */\n  #needFlip;\n\n  /**\n   * The main data view.\n   *\n   * @type {DataView}\n   */\n  #view;\n\n  /**\n   * @param {ArrayBuffer} buffer The input array buffer.\n   * @param {boolean} [isLittleEndian] Flag to tell if the data is little\n   *   or big endian (default: true).\n   */\n  constructor(buffer, isLittleEndian) {\n    this.#buffer = buffer;\n    // Set endian flag if not defined.\n    if (typeof isLittleEndian !== 'undefined') {\n      this.#isLittleEndian = isLittleEndian;\n    }\n    this.#needFlip = (this.#isLittleEndian !== this.#isNativeLittleEndian);\n    this.#view = new DataView(buffer);\n  }\n\n  /**\n   * Read Uint16 (2 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {number} The read data.\n   */\n  readUint16(byteOffset) {\n    return this.#view.getUint16(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read Int16 (2 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {number} The read data.\n   */\n  readInt16(byteOffset) {\n    return this.#view.getInt16(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read Uint32 (4 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {number} The read data.\n   */\n  readUint32(byteOffset) {\n    return this.#view.getUint32(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read BigUint64 (8 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {bigint} The read data.\n   */\n  readBigUint64(byteOffset) {\n    return this.#view.getBigUint64(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read Int32 (4 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {number} The read data.\n   */\n  readInt32(byteOffset) {\n    return this.#view.getInt32(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read BigInt64 (8 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {bigint} The read data.\n   */\n  readBigInt64(byteOffset) {\n    return this.#view.getBigInt64(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read Float32 (4 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {number} The read data.\n   */\n  readFloat32(byteOffset) {\n    return this.#view.getFloat32(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read Float64 (8 bytes) data.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {number} The read data.\n   */\n  readFloat64(byteOffset) {\n    return this.#view.getFloat64(byteOffset, this.#isLittleEndian);\n  }\n\n  /**\n   * Read binary (0/1) array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Uint8Array} The read data.\n   */\n  readBinaryArray(byteOffset, size) {\n    // input\n    const bitArray = new Uint8Array(this.#buffer, byteOffset, size);\n    // result\n    const byteArrayLength = 8 * bitArray.length;\n    const data = new Uint8Array(byteArrayLength);\n    let bitNumber = 0;\n    let bitIndex = 0;\n    for (let i = 0; i < byteArrayLength; ++i) {\n      bitNumber = i % 8;\n      bitIndex = Math.floor(i / 8);\n      // see https://stackoverflow.com/questions/4854207/get-a-specific-bit-from-byte/4854257\n      // @ts-ignore\n      data[i] = 255 * ((bitArray[bitIndex] & (1 << bitNumber)) !== 0);\n    }\n    return data;\n  }\n\n  /**\n   * Read Uint8 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Uint8Array} The read data.\n   */\n  readUint8Array(byteOffset, size) {\n    return new Uint8Array(this.#buffer, byteOffset, size);\n  }\n\n  /**\n   * Read Int8 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Int8Array} The read data.\n   */\n  readInt8Array(byteOffset, size) {\n    return new Int8Array(this.#buffer, byteOffset, size);\n  }\n\n  /**\n   * Read Uint16 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Uint16Array} The read data.\n   */\n  readUint16Array(byteOffset, size) {\n    const bpe = Uint16Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of Uint16Array.BYTES_PER_ELEMENT (=2)\n    if (byteOffset % bpe === 0) {\n      data = new Uint16Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new Uint16Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readUint16(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read Int16 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Int16Array} The read data.\n   */\n  readInt16Array(byteOffset, size) {\n    const bpe = Int16Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of Int16Array.BYTES_PER_ELEMENT (=2)\n    if (byteOffset % bpe === 0) {\n      data = new Int16Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new Int16Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readInt16(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read Uint32 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Uint32Array} The read data.\n   */\n  readUint32Array(byteOffset, size) {\n    const bpe = Uint32Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of Uint32Array.BYTES_PER_ELEMENT (=4)\n    if (byteOffset % bpe === 0) {\n      data = new Uint32Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new Uint32Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readUint32(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read Uint64 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {BigUint64Array} The read data.\n   */\n  readUint64Array(byteOffset, size) {\n    const bpe = BigUint64Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of BigUint64Array.BYTES_PER_ELEMENT (=8)\n    if (byteOffset % bpe === 0) {\n      data = new BigUint64Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new BigUint64Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readBigUint64(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read Int32 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Int32Array} The read data.\n   */\n  readInt32Array(byteOffset, size) {\n    const bpe = Int32Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of Int32Array.BYTES_PER_ELEMENT (=4)\n    if (byteOffset % bpe === 0) {\n      data = new Int32Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new Int32Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readInt32(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read Int64 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {BigInt64Array} The read data.\n   */\n  readInt64Array(byteOffset, size) {\n    const bpe = BigInt64Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of BigInt64Array.BYTES_PER_ELEMENT (=8)\n    if (byteOffset % bpe === 0) {\n      data = new BigInt64Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new BigInt64Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readBigInt64(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read Float32 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Float32Array} The read data.\n   */\n  readFloat32Array(byteOffset, size) {\n    const bpe = Float32Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of Float32Array.BYTES_PER_ELEMENT (=4)\n    if (byteOffset % bpe === 0) {\n      data = new Float32Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new Float32Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readFloat32(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read Float64 array.\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @param {number} size The size of the array.\n   * @returns {Float64Array} The read data.\n   */\n  readFloat64Array(byteOffset, size) {\n    const bpe = Float64Array.BYTES_PER_ELEMENT;\n    const arraySize = size / bpe;\n    let data = null;\n    // byteOffset should be a multiple of Float64Array.BYTES_PER_ELEMENT (=8)\n    if (byteOffset % bpe === 0) {\n      data = new Float64Array(this.#buffer, byteOffset, arraySize);\n      if (this.#needFlip) {\n        flipArrayEndianness(data);\n      }\n    } else {\n      data = new Float64Array(arraySize);\n      let index = byteOffset;\n      for (let i = 0; i < arraySize; ++i) {\n        data[i] = this.readFloat64(index);\n        index += bpe;\n      }\n    }\n    return data;\n  }\n\n  /**\n   * Read data as an hexadecimal string of length 4 (no '0x' prefix).\n   *\n   * @param {number} byteOffset The offset to start reading from.\n   * @returns {string} The read data ('####').\n   */\n  readHex(byteOffset) {\n    // read and convert to hex string\n    const str = this.readUint16(byteOffset).toString(16);\n    // return padded\n    return '0000'.substring(0, 4 - str.length) + str.toUpperCase();\n  }\n\n} // class DataReader\n","/**\n * Capitalise the first letter of a string.\n *\n * @param {string} string The string to capitalise the first letter.\n * @returns {string} The new string.\n */\nexport function capitaliseFirstLetter(string) {\n  let res = string;\n  if (string) {\n    res = string.charAt(0).toUpperCase() + string.slice(1);\n  }\n  return res;\n}\n\n/**\n * Check if a string starts with the input element.\n *\n * @param {string} str The input string.\n * @param {string} search The searched start.\n * @param {number} [rawPos] The position in this string at which to begin\n *  searching for searchString. Defaults to 0.\n * @returns {boolean} True if the input string starts with the searched string.\n */\nexport function startsWith(str, search, rawPos) {\n  if (typeof str === 'undefined' || str === null ||\n    typeof search === 'undefined' || search === null) {\n    return false;\n  }\n  const pos = rawPos > 0 ? rawPos | 0 : 0;\n  return str.substring(pos, pos + search.length) === search;\n}\n\n/**\n * Check if a string ends with the input element.\n *\n * @param {string} str The input string.\n * @param {string} search The searched ending.\n * @returns {boolean} True if the input string ends with the searched string.\n */\nexport function endsWith(str, search) {\n  if (typeof str === 'undefined' || str === null ||\n    typeof search === 'undefined' || search === null) {\n    return false;\n  }\n  return str.substring(str.length - search.length) === search;\n}\n\n/**\n * Split key/value string:\n *  key0=val00&key0=val01&key1=val10 returns\n *  { key0 : [val00, val01], key1 : val1 }\n *\n * @param {string} inputStr The string to split.\n * @returns {object} The split string.\n */\nexport function splitKeyValueString(inputStr) {\n  // result\n  const result = {};\n  // check input string\n  if (inputStr) {\n    // split key/value pairs\n    const pairs = inputStr.split('&');\n    for (let i = 0; i < pairs.length; ++i) {\n      const pair = pairs[i].split('=');\n      // if the key does not exist, create it\n      if (!result[pair[0]]) {\n        result[pair[0]] = pair[1];\n      } else {\n        // make it an array\n        if (!(result[pair[0]] instanceof Array)) {\n          result[pair[0]] = [result[pair[0]]];\n        }\n        result[pair[0]].push(pair[1]);\n      }\n    }\n  }\n  return result;\n}\n\n/**\n * Get flags from an input string. Flags are words surrounded with curly\n * braces.\n *\n * @param {string} inputStr The input string.\n * @returns {Array} An array of found flags.\n */\nexport function getFlags(inputStr) {\n  const flags = [];\n  // check input string\n  if (inputStr === null || typeof inputStr === 'undefined') {\n    return flags;\n  }\n\n  // word surrounded by curly braces\n  const regex = /{(\\w+)}/g;\n\n  let match = regex.exec(inputStr);\n  while (match) {\n    flags.push(match[1]); // first matching group\n    match = regex.exec(inputStr);\n  }\n  return flags;\n}\n\n/**\n * Replace flags in a input string. Flags are keywords surrounded with curly\n * braces.\n *\n * @param {string} inputStr The input string.\n * @param {object} values A object of {value, unit}.\n * @returns {string} The result string.\n */\nexport function replaceFlags(inputStr, values) {\n  let res = '';\n  // check input string\n  if (inputStr === null || typeof inputStr === 'undefined') {\n    return res;\n  }\n  res = inputStr;\n  // check values\n  if (values === null || typeof values === 'undefined') {\n    return res;\n  }\n\n  // loop through flags\n  const keys = getFlags(inputStr);\n  for (let i = 0; i < keys.length; ++i) {\n    const valueObj = values[keys[i]];\n    if (valueObj !== null && typeof valueObj !== 'undefined' &&\n      valueObj.value !== null && typeof valueObj.value !== 'undefined') {\n      // value string\n      let valueStr = valueObj.value.toPrecision(4);\n      // add unit if available\n      // space or no space? Yes apart from degree...\n      // check: https://en.wikipedia.org/wiki/Space_(punctuation)#Spaces_and_unit_symbols\n      if (valueObj.unit !== null &&\n        typeof valueObj.unit !== 'undefined' &&\n        valueObj.unit.length !== 0) {\n        if (valueObj.unit !== 'degree') {\n          valueStr += ' ';\n        }\n        valueStr += valueObj.unit;\n      }\n      // flag to replace\n      const flag = '{' + keys[i] + '}';\n      // replace\n      res = res.replace(flag, valueStr);\n    }\n  }\n  // return\n  return res;\n}\n\n/**\n * Get the root of an input path.\n * Splits using `/` as separator.\n *\n * @param {string} path The input path\n * @returns {string} The input path without its last part.\n */\nexport function getRootPath(path) {\n  return path.split('/').slice(0, -1).join('/');\n}\n\n/**\n * Get a file extension: anything after the last dot.\n * File name starting with a dot are discarded.\n * Extensions are expected to contain at least one letter.\n *\n * @param {string} filePath The file path containing the file name.\n * @returns {string} The lower case file extension or null for none.\n */\nexport function getFileExtension(filePath) {\n  let ext = null;\n  if (typeof filePath !== 'undefined' &&\n    filePath !== null &&\n    filePath[0] !== '.') {\n    const pathSplit = filePath.toLowerCase().split('.');\n    if (pathSplit.length !== 1) {\n      ext = pathSplit.pop();\n      // extension should contain at least one letter and no slash\n      const regExp = /[a-z]/;\n      if (!regExp.test(ext) || ext.includes('/')) {\n        ext = null;\n      }\n    }\n  }\n  return ext;\n}\n\n/**\n * Convert a string to a Uint8Array.\n *\n * @param {string} str The string to convert.\n * @returns {Uint8Array} The Uint8Array.\n */\nexport function stringToUint8Array(str) {\n  const arr = new Uint8Array(str.length);\n  for (let i = 0, leni = str.length; i < leni; i++) {\n    arr[i] = str.charCodeAt(i);\n  }\n  return arr;\n}\n\n/**\n * Round a float number to a given precision.\n * Inspired from https://stackoverflow.com/a/49729715/3639892.\n * Can be a solution to not have trailing zero as when\n * using toFixed or toPrecision.\n * '+number.toFixed(precision)' does not pass all the tests...\n *\n * @param {number} number The number to round.\n * @param {number} precision The rounding precision.\n * @returns {number} The rounded number.\n */\nexport function precisionRound(number, precision) {\n  const factor = Math.pow(10, precision);\n  const delta = 0.01 / factor; // fixes precisionRound(1.005, 2)\n  return Math.round(number * factor + delta) / factor;\n}\n","import {stringToUint8Array} from './string';\n\n/**\n * Check for array equality after sorting.\n *\n * @param {Array} arr0 First array.\n * @param {*} arr1 Second array.\n * @returns {boolean} True if both array are defined and contain same values.\n */\nexport function arraySortEquals(arr0, arr1) {\n  if (arr0 === null ||\n    arr1 === null ||\n    typeof arr0 === 'undefined' ||\n    typeof arr1 === 'undefined') {\n    return false;\n  }\n  const arr0sorted = arr0.slice().sort();\n  const arr1sorted = arr1.slice().sort();\n  return arrayEquals(arr0sorted, arr1sorted);\n}\n\n/**\n * Check for array equality.\n *\n * @param {Array} arr0 First array.\n * @param {*} arr1 Second array.\n * @returns {boolean} True if both array are defined and contain same values.\n */\nexport function arrayEquals(arr0, arr1) {\n  if (arr0 === null ||\n    arr1 === null ||\n    typeof arr0 === 'undefined' ||\n    typeof arr1 === 'undefined') {\n    return false;\n  }\n  if (arr0.length !== arr1.length) {\n    return false;\n  }\n  return arr0.every(function (element, index) {\n    return element === arr1[index];\n  });\n}\n\n/**\n * Convert a Uint8Array to a string.\n *\n * @param {Uint8Array} arr The array to convert.\n * @returns {string} The array as string.\n */\nexport function uint8ArrayToString(arr) {\n  return String.fromCharCode.apply(String, arr);\n}\n\n/**\n * Array find in a subset of the input array.\n * Equivalent to: arr.slice(start, end).find(callbackFn)\n *\n * @param {Uint8Array} arr The input array to search.\n * @param {Function} callbackFn The find function.\n * @param {number|undefined} start The array start index.\n * @param {number|undefined} [end] The array end index.\n * @returns {number|undefined} The index where the element was found.\n */\nexport function findInArraySubset(arr, callbackFn, start, end) {\n  // check inputs\n  if (typeof start === 'undefined' ||\n    start < 0 ||\n    start >= arr.length\n  ) {\n    start = 0;\n  }\n  if (typeof end === 'undefined' ||\n    end <= start ||\n    end > arr.length) {\n    end = arr.length;\n  }\n  // run\n  for (let i = start; i < end; ++i) {\n    if (callbackFn(arr[i], i, arr)) {\n      return i;\n    }\n  }\n  return undefined;\n}\n\n/**\n * Get a find in array callback.\n *\n * @param {Uint8Array} arr1 The array to find.\n * @returns {Function} The find callback function.\n */\nexport function getFindArrayInArrayCallback(arr1) {\n  return function (element, index, arr0) {\n    for (let i = 0; i < arr1.length; ++i) {\n      if (arr0[index + i] !== arr1[i]) {\n        return false;\n      }\n    }\n    return true;\n  };\n}\n\n/**\n * Extract each element of a multipart ArrayBuffer.\n * https://en.wikipedia.org/wiki/MIME#Multipart_messages\n *\n * @param {ArrayBuffer} arr The multipart array.\n * @returns {Array} The multipart parts as an array of object as\n *  {'Content-Type', ..., data} (depending on header tags)\n */\nexport function parseMultipart(arr) {\n  const u8Array = new Uint8Array(arr);\n\n  const parts = [];\n  // check input\n  if (u8Array.length === 0) {\n    return parts;\n  }\n\n  // \\r\\n\\r\\n\n  const doubleReturnNew = new Uint8Array([0x0d, 0x0a, 0x0d, 0x0a]);\n  const partHeaderEndCb = getFindArrayInArrayCallback(doubleReturnNew);\n\n  // look for boundary in first part header\n  let partHeaderEndIndex = findInArraySubset(\n    u8Array, partHeaderEndCb, 0\n  );\n  if (typeof partHeaderEndIndex === 'undefined') {\n    throw new Error('Can\\'t find the end of the first multipart header');\n  }\n  const firstPartHeader = u8Array.slice(0, partHeaderEndIndex);\n  // switch to string to use split\n  const lines = uint8ArrayToString(firstPartHeader).split('\\r\\n');\n  // boundary should start with '--'\n  let boundaryStr;\n  for (let i = 0; i < lines.length; ++i) {\n    if (lines[i][0] === '-' && lines[i][1] === '-') {\n      boundaryStr = lines[i];\n      break;\n    }\n  }\n  if (typeof boundaryStr === 'undefined') {\n    throw new Error('Can\\'t find the boundary between multi-parts');\n  }\n  const boundary = stringToUint8Array(boundaryStr);\n  const boundaryCb = getFindArrayInArrayCallback(boundary);\n  const boundaryLen = boundaryStr.length;\n\n  // skip mime header\n  let nextBoundaryIndex = findInArraySubset(\n    u8Array, boundaryCb, 0\n  );\n\n  // loop through content\n  while (typeof partHeaderEndIndex !== 'undefined') {\n    const part = {};\n\n    // header\n    const partHeader = u8Array.slice(\n      nextBoundaryIndex + boundaryLen, partHeaderEndIndex);\n    // split into object\n    const partHeaderLines =\n      uint8ArrayToString(partHeader).split('\\r\\n');\n    for (let l = 0; l < partHeaderLines.length; ++l) {\n      const line = partHeaderLines[l];\n      const semiColonIndex = line.indexOf(':');\n      if (semiColonIndex !== -1) {\n        const key = line.substring(0, semiColonIndex).trim();\n        const val = line.substring(semiColonIndex + 1).trim();\n        part[key] = val;\n      }\n    }\n\n    // find next boundary\n    nextBoundaryIndex = findInArraySubset(\n      u8Array, boundaryCb, partHeaderEndIndex\n    );\n    // exit if none\n    if (typeof nextBoundaryIndex === 'undefined') {\n      break;\n    }\n\n    // get part\n    // partHeaderEndIndex plus the size of the '\\r\\n\\r\\n' separator\n    const dataBeginIndex = partHeaderEndIndex + 4;\n    // nextBoundaryIndex minus the previous '\\r\\n'\n    const dataEndIndex = nextBoundaryIndex - 2;\n    if (dataBeginIndex < dataEndIndex) {\n      part.data = u8Array.slice(dataBeginIndex, dataEndIndex).buffer;\n    } else {\n      part.data = new Uint8Array();\n    }\n\n    // store part\n    parts.push(part);\n\n    // find next part header end\n    partHeaderEndIndex = findInArraySubset(\n      u8Array, partHeaderEndCb,\n      nextBoundaryIndex + boundaryLen\n    );\n  }\n\n  return parts;\n}\n\n/**\n * Build a multipart message.\n * See: https://en.wikipedia.org/wiki/MIME#Multipart_messages\n * See: https://hg.orthanc-server.com/orthanc-dicomweb/file/tip/Resources/Samples/JavaScript/stow-rs.js\n *\n * @param {Array} parts The message parts as an array of object containing\n *   content headers and messages as the data property (as returned by parse).\n * @param {string} boundary The message boundary.\n * @returns {Uint8Array} The full multipart message.\n */\nexport function buildMultipart(parts, boundary) {\n  const lineBreak = '\\r\\n';\n  // build headers and calculate size\n  let partsSize = 0;\n  const headers = [];\n  for (let i = 0; i < parts.length; ++i) {\n    let headerStr = '';\n    if (i !== 0) {\n      headerStr += lineBreak;\n    }\n    headerStr += '--' + boundary + lineBreak;\n    const partKeys = Object.keys(parts[i]);\n    for (let k = 0; k < partKeys.length; ++k) {\n      const key = partKeys[k];\n      if (key !== 'data') {\n        headerStr += key + ': ' + parts[i][key] + lineBreak;\n      }\n    }\n    headerStr += lineBreak;\n    const header = stringToUint8Array(headerStr);\n    headers.push(header);\n    partsSize += header.byteLength + parts[i].data.byteLength;\n  }\n  // build trailer\n  const trailerStr = lineBreak + '--' + boundary + '--' + lineBreak;\n  const trailer = stringToUint8Array(trailerStr);\n\n  // final buffer\n  const buffer = new Uint8Array(partsSize + trailer.byteLength);\n  let offset = 0;\n  // concatenate parts\n  for (let j = 0; j < parts.length; ++j) {\n    buffer.set(headers[j], offset);\n    offset += headers[j].byteLength;\n    buffer.set(new Uint8Array(parts[j].data), offset);\n    offset += parts[j].data.byteLength;\n  }\n  // end buffer with trailer\n  buffer.set(trailer, offset);\n\n  // return\n  return buffer;\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Tag} from './dicomTag';\n/* eslint-enable no-unused-vars */\n\n/**\n * DICOM data element.\n */\nexport class DataElement {\n  /**\n   * The element Value Representation.\n   *\n   * @type {string}\n   */\n  vr;\n  /**\n   * The element value.\n   *\n   * @type {Array}\n   */\n  value;\n\n  // [start] internal values\n  // only present during parsing or writing otherwise not set\n\n  /**\n   * The element dicom tag.\n   *\n   * @type {Tag}\n   */\n  tag;\n\n  /**\n   * The element Value Length.\n   *\n   * @type {number}\n   */\n  vl;\n\n  /**\n   * Flag to know if defined or undefined sequence length.\n   *\n   * @type {boolean}\n   */\n  undefinedLength;\n\n  /**\n   * The element start offset.\n   *\n   * @type {number}\n   */\n  startOffset;\n\n  /**\n   * The element end offset.\n   *\n   * @type {number}\n   */\n  endOffset;\n\n  /**\n   * The sequence items.\n   *\n   * @type {Array}\n   */\n  items;\n\n  // [end] internal values\n\n  /**\n   * @param {string} vr The element VR (Value Representation).\n   */\n  constructor(vr) {\n    this.vr = vr;\n  }\n}","import {\n  Tag,\n  isSequenceDelimitationItemTag,\n  isItemDelimitationItemTag,\n  isPixelDataTag\n} from './dicomTag';\nimport {\n  is32bitVLVR,\n  isCharSetStringVR,\n  vrTypes,\n} from './dictionary';\nimport {DataReader} from './dataReader';\nimport {logger} from '../utils/logger';\nimport {arrayEquals} from '../utils/array';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * List of DICOM data elements indexed via a 8 character string formed from\n * the group and element numbers.\n *\n * @typedef {Object<string, DataElement>} DataElements\n */\n\n/**\n * Get the version of the library.\n *\n * @returns {string} The version of the library.\n */\nexport function getDwvVersion() {\n  return '0.32.6';\n}\n\n/**\n * Check that an input buffer includes the DICOM prefix 'DICM'\n * after the 128 bytes preamble.\n * Ref: [DICOM File Meta]{@link https://dicom.nema.org/dicom/2013/output/chtml/part10/chapter_7.html#sect_7.1}\n *\n * @param {ArrayBuffer} buffer The buffer to check.\n * @returns {boolean} True if the buffer includes the prefix.\n */\nexport function hasDicomPrefix(buffer) {\n  const prefixArray = new Uint8Array(buffer, 128, 4);\n  const stringReducer = function (previous, current) {\n    return previous += String.fromCharCode(current);\n  };\n  return prefixArray.reduce(stringReducer, '') === 'DICM';\n}\n\n// Zero-width space (u200B)\n// @ts-ignore\nconst ZWS = String.fromCharCode('u200B');\n\n/**\n * Clean string: remove zero-width space ending and trim.\n * Warning: no tests are done on the input, will fail if\n *   null or undefined or not string.\n * (exported for tests only)\n *\n * @param {string} inputStr The string to clean.\n * @returns {string} The cleaned string.\n */\nexport function cleanString(inputStr) {\n  let res = inputStr;\n  // get rid of ending zero-width space\n  const lastIndex = inputStr.length - 1;\n  if (inputStr[lastIndex] === ZWS) {\n    res = inputStr.substring(0, lastIndex);\n  }\n  // trim spaces\n  res = res.trim();\n  // return\n  return res;\n}\n\n/**\n * Get the utfLabel (used by the TextDecoder) from a character set term\n * References:\n * - DICOM [Value Encoding]{@link http://dicom.nema.org/dicom/2013/output/chtml/part05/chapter_6.html}\n * - DICOM [Specific Character Set]{@link http://dicom.nema.org/dicom/2013/output/chtml/part03/sect_C.12.html#sect_C.12.1.1.2}\n * - [TextDecoder#Parameters]{@link https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/TextDecoder#Parameters}\n *\n * @param {string} charSetTerm The DICOM character set.\n * @returns {string} The corresponding UTF label.\n */\nfunction getUtfLabel(charSetTerm) {\n  let label = 'utf-8';\n  if (charSetTerm === 'ISO_IR 100') {\n    label = 'iso-8859-1';\n  } else if (charSetTerm === 'ISO_IR 101') {\n    label = 'iso-8859-2';\n  } else if (charSetTerm === 'ISO_IR 109') {\n    label = 'iso-8859-3';\n  } else if (charSetTerm === 'ISO_IR 110') {\n    label = 'iso-8859-4';\n  } else if (charSetTerm === 'ISO_IR 144') {\n    label = 'iso-8859-5';\n  } else if (charSetTerm === 'ISO_IR 127') {\n    label = 'iso-8859-6';\n  } else if (charSetTerm === 'ISO_IR 126') {\n    label = 'iso-8859-7';\n  } else if (charSetTerm === 'ISO_IR 138') {\n    label = 'iso-8859-8';\n  } else if (charSetTerm === 'ISO_IR 148') {\n    label = 'iso-8859-9';\n  } else if (charSetTerm === 'ISO_IR 13') {\n    label = 'shift-jis';\n  } else if (charSetTerm === 'ISO_IR 166') {\n    label = 'iso-8859-11';\n  } else if (charSetTerm === 'ISO 2022 IR 87') {\n    label = 'iso-2022-jp';\n  } else if (charSetTerm === 'ISO 2022 IR 149') {\n    // not supported by TextDecoder when it says it should...\n    //label = \"iso-2022-kr\";\n  } else if (charSetTerm === 'ISO 2022 IR 58') {\n    // not supported by TextDecoder...\n    //label = \"iso-2022-cn\";\n  } else if (charSetTerm === 'ISO_IR 192') {\n    label = 'utf-8';\n  } else if (charSetTerm === 'GB18030') {\n    label = 'gb18030';\n  } else if (charSetTerm === 'GB2312') {\n    label = 'gb2312';\n  } else if (charSetTerm === 'GBK') {\n    label = 'chinese';\n  }\n  return label;\n}\n\n/**\n * Default text decoder\n */\nclass DefaultTextDecoder {\n  /**\n   * Decode an input string buffer.\n   *\n   * @param {Uint8Array} buffer The buffer to decode.\n   * @returns {string} The decoded string.\n   */\n  decode(buffer) {\n    let result = '';\n    for (let i = 0, leni = buffer.length; i < leni; ++i) {\n      result += String.fromCharCode(buffer[i]);\n    }\n    return result;\n  }\n}\n\n/**\n * Get patient orientation label in the reverse direction.\n *\n * @param {string} ori Patient Orientation value.\n * @returns {string} Reverse Orientation Label.\n */\nexport function getReverseOrientation(ori) {\n  if (!ori) {\n    return null;\n  }\n  // reverse labels\n  const rlabels = {\n    L: 'R',\n    R: 'L',\n    A: 'P',\n    P: 'A',\n    H: 'F',\n    F: 'H'\n  };\n\n  let rori = '';\n  for (let n = 0; n < ori.length; n++) {\n    const o = ori.substring(n, n + 1);\n    const r = rlabels[o];\n    if (r) {\n      rori += r;\n    }\n  }\n  // return\n  return rori;\n}\n\n/**\n * Get the name of an image orientation patient.\n *\n * @param {Array} orientation The image orientation patient.\n * @returns {string} The orientation name: axial, coronal or sagittal.\n */\nexport function getOrientationName(orientation) {\n  const axialOrientation = [1, 0, 0, 0, 1, 0];\n  const coronalOrientation = [1, 0, 0, 0, 0, -1];\n  const sagittalOrientation = [0, 1, 0, 0, 0, -1];\n  let name;\n  if (arrayEquals(orientation, axialOrientation)) {\n    name = 'axial';\n  } else if (arrayEquals(orientation, coronalOrientation)) {\n    name = 'coronal';\n  } else if (arrayEquals(orientation, sagittalOrientation)) {\n    name = 'sagittal';\n  }\n  return name;\n}\n\n/**\n * Tell if a given syntax is an implicit one (element with no VR).\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if an implicit syntax.\n */\nexport function isImplicitTransferSyntax(syntax) {\n  return syntax === '1.2.840.10008.1.2';\n}\n\n/**\n * Tell if a given syntax is a big endian syntax.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a big endian syntax.\n */\nexport function isBigEndianTransferSyntax(syntax) {\n  return syntax === '1.2.840.10008.1.2.2';\n}\n\n/**\n * Tell if a given syntax is a JPEG baseline one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg baseline syntax.\n */\nexport function isJpegBaselineTransferSyntax(syntax) {\n  return syntax === '1.2.840.10008.1.2.4.50' ||\n    syntax === '1.2.840.10008.1.2.4.51';\n}\n\n/**\n * Tell if a given syntax is a retired JPEG one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a retired jpeg syntax.\n */\nfunction isJpegRetiredTransferSyntax(syntax) {\n  return (syntax.match(/1.2.840.10008.1.2.4.5/) !== null &&\n    !isJpegBaselineTransferSyntax(syntax) &&\n    !isJpegLosslessTransferSyntax(syntax)) ||\n    syntax.match(/1.2.840.10008.1.2.4.6/) !== null;\n}\n\n/**\n * Tell if a given syntax is a JPEG Lossless one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg lossless syntax.\n */\nexport function isJpegLosslessTransferSyntax(syntax) {\n  return syntax === '1.2.840.10008.1.2.4.57' ||\n    syntax === '1.2.840.10008.1.2.4.70';\n}\n\n/**\n * Tell if a given syntax is a JPEG-LS one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg-ls syntax.\n */\nfunction isJpeglsTransferSyntax(syntax) {\n  return syntax.match(/1.2.840.10008.1.2.4.8/) !== null;\n}\n\n/**\n * Tell if a given syntax is a JPEG 2000 one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a jpeg 2000 syntax.\n */\nexport function isJpeg2000TransferSyntax(syntax) {\n  return syntax.match(/1.2.840.10008.1.2.4.9/) !== null;\n}\n\n/**\n * Tell if a given syntax is a RLE (Run-length encoding) one.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a RLE syntax.\n */\nfunction isRleTransferSyntax(syntax) {\n  return syntax.match(/1.2.840.10008.1.2.5/) !== null;\n}\n\n/**\n * Tell if a given syntax needs decompression.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {string} The name of the decompression algorithm.\n */\nexport function getSyntaxDecompressionName(syntax) {\n  let algo = null;\n  if (isJpeg2000TransferSyntax(syntax)) {\n    algo = 'jpeg2000';\n  } else if (isJpegBaselineTransferSyntax(syntax)) {\n    algo = 'jpeg-baseline';\n  } else if (isJpegLosslessTransferSyntax(syntax)) {\n    algo = 'jpeg-lossless';\n  } else if (isRleTransferSyntax(syntax)) {\n    algo = 'rle';\n  }\n  return algo;\n}\n\n/**\n * Tell if a given syntax is supported for reading.\n *\n * @param {string} syntax The transfer syntax to test.\n * @returns {boolean} True if a supported syntax.\n */\nfunction isReadSupportedTransferSyntax(syntax) {\n\n  // Unsupported:\n  // \"1.2.840.10008.1.2.1.99\": Deflated Explicit VR - Little Endian\n  // \"1.2.840.10008.1.2.4.100\": MPEG2 Image Compression\n  // isJpegRetiredTransferSyntax(syntax): non supported JPEG\n  // isJpeglsTransferSyntax(syntax): JPEG-LS\n\n  return (syntax === '1.2.840.10008.1.2' || // Implicit VR - Little Endian\n    syntax === '1.2.840.10008.1.2.1' || // Explicit VR - Little Endian\n    syntax === '1.2.840.10008.1.2.2' || // Explicit VR - Big Endian\n    isJpegBaselineTransferSyntax(syntax) || // JPEG baseline\n    isJpegLosslessTransferSyntax(syntax) || // JPEG Lossless\n    isJpeg2000TransferSyntax(syntax) || // JPEG 2000\n    isRleTransferSyntax(syntax)); // RLE\n}\n\n/**\n * Get the transfer syntax name.\n * Reference: [UID Values]{@link http://dicom.nema.org/dicom/2013/output/chtml/part06/chapter_A.html}.\n *\n * @param {string} syntax The transfer syntax.\n * @returns {string} The name of the transfer syntax.\n */\nexport function getTransferSyntaxName(syntax) {\n  let name = 'Unknown';\n  if (syntax === '1.2.840.10008.1.2') {\n    // Implicit VR - Little Endian\n    name = 'Little Endian Implicit';\n  } else if (syntax === '1.2.840.10008.1.2.1') {\n    // Explicit VR - Little Endian\n    name = 'Little Endian Explicit';\n  } else if (syntax === '1.2.840.10008.1.2.1.99') {\n    // Deflated Explicit VR - Little Endian\n    name = 'Little Endian Deflated Explicit';\n  } else if (syntax === '1.2.840.10008.1.2.2') {\n    // Explicit VR - Big Endian\n    name = 'Big Endian Explicit';\n  } else if (isJpegBaselineTransferSyntax(syntax)) {\n    // JPEG baseline\n    if (syntax === '1.2.840.10008.1.2.4.50') {\n      name = 'JPEG Baseline';\n    } else { // *.51\n      name = 'JPEG Extended, Process 2+4';\n    }\n  } else if (isJpegLosslessTransferSyntax(syntax)) {\n    // JPEG Lossless\n    if (syntax === '1.2.840.10008.1.2.4.57') {\n      name = 'JPEG Lossless, Nonhierarchical (Processes 14)';\n    } else { // *.70\n      name = 'JPEG Lossless, Non-hierarchical, 1st Order Prediction';\n    }\n  } else if (isJpegRetiredTransferSyntax(syntax)) {\n    // Retired JPEG\n    name = 'Retired JPEG';\n  } else if (isJpeglsTransferSyntax(syntax)) {\n    // JPEG-LS\n    name = 'JPEG-LS';\n  } else if (isJpeg2000TransferSyntax(syntax)) {\n    // JPEG 2000\n    if (syntax === '1.2.840.10008.1.2.4.91') {\n      name = 'JPEG 2000 (Lossless or Lossy)';\n    } else { // *.90\n      name = 'JPEG 2000 (Lossless only)';\n    }\n  } else if (syntax === '1.2.840.10008.1.2.4.100') {\n    // MPEG2 Image Compression\n    name = 'MPEG2';\n  } else if (isRleTransferSyntax(syntax)) {\n    // RLE (lossless)\n    name = 'RLE';\n  }\n  // return\n  return name;\n}\n\n/**\n * Guess the transfer syntax from the first data element.\n * See https://github.com/ivmartel/dwv/issues/188\n *   (Allow to load DICOM with no DICM preamble) for more details.\n *\n * @param {DataElement} firstDataElement The first data element\n *   of the DICOM header.\n * @returns {DataElement} The transfer syntax data element.\n */\nfunction guessTransferSyntax(firstDataElement) {\n  const oEightGroupBigEndian = '0800';\n  const oEightGroupLittleEndian = '0008';\n  // check that group is 0008\n  const group = firstDataElement.tag.getGroup();\n  if (group !== oEightGroupBigEndian &&\n    group !== oEightGroupLittleEndian) {\n    throw new Error(\n      'Not a valid DICOM file (no magic DICM word found' +\n        ' and first element not in 0008 group)'\n    );\n  }\n  // reasonable assumption: 2 uppercase characters => explicit vr\n  const vr = firstDataElement.vr;\n  const vr0 = vr.charCodeAt(0);\n  const vr1 = vr.charCodeAt(1);\n  const implicit = (vr0 >= 65 && vr0 <= 90 && vr1 >= 65 && vr1 <= 90)\n    ? false : true;\n  // guess transfer syntax\n  let syntax = null;\n  if (group === oEightGroupLittleEndian) {\n    if (implicit) {\n      // ImplicitVRLittleEndian\n      syntax = '1.2.840.10008.1.2';\n    } else {\n      // ExplicitVRLittleEndian\n      syntax = '1.2.840.10008.1.2.1';\n    }\n  } else {\n    if (implicit) {\n      // ImplicitVRBigEndian: impossible\n      throw new Error(\n        'Not a valid DICOM file (no magic DICM word found' +\n        'and implicit VR big endian detected)'\n      );\n    } else {\n      // ExplicitVRBigEndian\n      syntax = '1.2.840.10008.1.2.2';\n    }\n  }\n  // set transfer syntax data element\n  const dataElement = new DataElement('UI');\n  dataElement.tag = new Tag('0002', '0010');\n  dataElement.value = [syntax + ' ']; // even length\n  dataElement.vl = dataElement.value[0].length;\n  dataElement.startOffset = firstDataElement.startOffset;\n  dataElement.endOffset = dataElement.startOffset + dataElement.vl;\n\n  return dataElement;\n}\n\n/**\n * Get the appropriate TypedArray in function of arguments.\n *\n * @param {number} bitsAllocated The number of bites used to store\n *   the data: [8, 16, 32].\n * @param {number} pixelRepresentation The pixel representation,\n *   0:unsigned;1:signed.\n * @param {number} size The size of the new array.\n * @returns {Uint8Array|Int8Array|Uint16Array|Int16Array|Uint32Array|Int32Array}\n *   The good typed array.\n */\nexport function getTypedArray(bitsAllocated, pixelRepresentation, size) {\n  let res = null;\n  try {\n    if (bitsAllocated === 8) {\n      if (pixelRepresentation === 0) {\n        res = new Uint8Array(size);\n      } else {\n        res = new Int8Array(size);\n      }\n    } else if (bitsAllocated === 16) {\n      if (pixelRepresentation === 0) {\n        res = new Uint16Array(size);\n      } else {\n        res = new Int16Array(size);\n      }\n    } else if (bitsAllocated === 32) {\n      if (pixelRepresentation === 0) {\n        res = new Uint32Array(size);\n      } else {\n        res = new Int32Array(size);\n      }\n    }\n  } catch (error) {\n    if (error instanceof RangeError) {\n      const powerOf2 = Math.floor(Math.log(size) / Math.log(2));\n      logger.error('Cannot allocate array of size: ' +\n        size + ' (>2^' + powerOf2 + ').');\n    }\n  }\n  return res;\n}\n\n/**\n * Get the number of bytes occupied by a data element prefix,\n *   i.e. without its value.\n *\n * @param {string} vr The Value Representation of the element.\n * @param {boolean} isImplicit Does the data use implicit VR?\n * @returns {number} The size of the element prefix.\n * WARNING: this is valid for tags with a VR, if not sure use\n *   the 'isTagWithVR' function first.\n * Reference:\n * - [Data Element explicit]{@link http://dicom.nema.org/dicom/2013/output/chtml/part05/chapter_7.html#table_7.1-1},\n * - [Data Element implicit]{@link http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_7.5.html#table_7.5-1}.\n *\n * | Tag | VR  | VL | Value |\n * | 4   | 2   | 2  | X     | -> regular explicit: 8 + X\n * | 4   | 2+2 | 4  | X     | -> 32bit VL: 12 + X\n *\n * | Tag | VL | Value |\n * | 4   | 4  | X     | -> implicit (32bit VL): 8 + X\n *\n * | Tag | Len | Value |\n * | 4   | 4   | X     | -> item: 8 + X\n */\nexport function getDataElementPrefixByteSize(vr, isImplicit) {\n  return isImplicit ? 8 : is32bitVLVR(vr) ? 12 : 8;\n}\n\n/**\n * Is the input VR a known VR.\n *\n * @param {string} vr The vr to test.\n * @returns {boolean} True if known.\n */\nfunction isKnownVR(vr) {\n  const extraVrTypes = ['NONE', 'ox', 'xx', 'xs'];\n  const knownTypes = Object.keys(vrTypes).concat(extraVrTypes);\n  return knownTypes.includes(vr);\n}\n\n/**\n * DicomParser class.\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n *   // setup the dicom parser\n *   const dicomParser = new dwv.DicomParser();\n *   // parse the buffer\n *   dicomParser.parse(event.target.response);\n *   // get the dicom tags\n *   const tags = dicomParser.getDicomElements();\n *   // display the modality\n *   const div = document.getElementById('dwv');\n *   div.appendChild(document.createTextNode(\n *     'Modality: ' + tags['00080060'].value[0]\n *   ));\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class DicomParser {\n\n  /**\n   * The list of DICOM elements.\n   *\n   * @type {DataElements}\n   */\n  #dataElements = {};\n\n  /**\n   * Default character set (optional).\n   *\n   * @type {string}\n   */\n  #defaultCharacterSet;\n\n  /**\n   * Default text decoder.\n   *\n   * @type {DefaultTextDecoder}\n   */\n  #defaultTextDecoder = new DefaultTextDecoder();\n\n  /**\n   * Special text decoder.\n   *\n   * @type {DefaultTextDecoder|TextDecoder}\n   */\n  #textDecoder = this.#defaultTextDecoder;\n\n  /**\n   * Decode an input string buffer using the default text decoder.\n   *\n   * @param {Uint8Array} buffer The buffer to decode.\n   * @returns {string} The decoded string.\n   */\n  #decodeString(buffer) {\n    return this.#defaultTextDecoder.decode(buffer);\n  }\n\n  /**\n   * Decode an input string buffer using the 'special' text decoder.\n   *\n   * @param {Uint8Array} buffer The buffer to decode.\n   * @returns {string} The decoded string.\n   */\n  #decodeSpecialString(buffer) {\n    return this.#textDecoder.decode(buffer);\n  }\n\n  /**\n   * Get the default character set.\n   *\n   * @returns {string} The default character set.\n   */\n  getDefaultCharacterSet() {\n    return this.#defaultCharacterSet;\n  }\n\n  /**\n   * Set the default character set.\n   *\n   * @param {string} characterSet The input character set.\n   */\n  setDefaultCharacterSet(characterSet) {\n    this.#defaultCharacterSet = characterSet;\n  }\n\n  /**\n   * Set the text decoder character set.\n   *\n   * @param {string} characterSet The input character set.\n   */\n  setDecoderCharacterSet(characterSet) {\n    /**\n     * The text decoder.\n     *\n     * @external TextDecoder\n     * @see https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder\n     */\n    this.#textDecoder = new TextDecoder(characterSet);\n  }\n\n  // not using type DataElements since the typedef is not exported with the API\n\n  /**\n   * Get the DICOM data elements.\n   *\n   * @returns {Object<string, DataElement>} The data elements.\n   */\n  getDicomElements() {\n    return this.#dataElements;\n  }\n\n  /**\n   * Read a DICOM tag.\n   *\n   * @param {DataReader} reader The raw data reader.\n   * @param {number} offset The offset where to start to read.\n   * @returns {object} An object containing the tag and the end offset.\n   */\n  #readTag(reader, offset) {\n    // group\n    const group = reader.readHex(offset);\n    offset += Uint16Array.BYTES_PER_ELEMENT;\n    // element\n    const element = reader.readHex(offset);\n    offset += Uint16Array.BYTES_PER_ELEMENT;\n    // return\n    return {\n      tag: new Tag(group, element),\n      endOffset: offset\n    };\n  }\n\n  /**\n   * Read an item data element.\n   *\n   * @param {DataReader} reader The raw data reader.\n   * @param {number} offset The offset where to start to read.\n   * @param {boolean} implicit Is the DICOM VR implicit?\n   * @returns {object} The item data as a list of data elements.\n   */\n  #readItemDataElement(reader, offset, implicit) {\n    const itemData = {};\n\n    // read the first item\n    let item = this.#readDataElement(reader, offset, implicit);\n    offset = item.endOffset;\n\n    // exit if it is a sequence delimitation item\n    if (isSequenceDelimitationItemTag(item.tag)) {\n      return {\n        data: itemData,\n        endOffset: item.endOffset,\n        isSeqDelim: true\n      };\n    }\n\n    // store item (mainly to keep vl)\n    itemData[item.tag.getKey()] = {\n      tag: item.tag,\n      vr: 'NONE',\n      vl: item.vl,\n      undefinedLength: item.undefinedLength\n    };\n\n    if (!item.undefinedLength) {\n      // explicit VR item: read until the end offset\n      const endOffset = offset;\n      offset -= item.vl;\n      while (offset < endOffset) {\n        item = this.#readDataElement(reader, offset, implicit);\n        offset = item.endOffset;\n        itemData[item.tag.getKey()] = item;\n      }\n    } else {\n      // implicit VR item: read until the item delimitation item\n      let isItemDelim = false;\n      while (!isItemDelim) {\n        item = this.#readDataElement(reader, offset, implicit);\n        offset = item.endOffset;\n        isItemDelim = isItemDelimitationItemTag(item.tag);\n        if (!isItemDelim) {\n          itemData[item.tag.getKey()] = item;\n        }\n      }\n    }\n\n    return {\n      data: itemData,\n      endOffset: offset,\n      isSeqDelim: false\n    };\n  }\n\n  /**\n   * Read the pixel item data element.\n   * Ref: [Single frame fragments]{@link http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_A.4.html#table_A.4-1}.\n   *\n   * @param {DataReader} reader The raw data reader.\n   * @param {number} offset The offset where to start to read.\n   * @param {boolean} implicit Is the DICOM VR implicit?\n   * @returns {object} The item data as an array of data elements.\n   */\n  #readPixelItemDataElement(\n    reader, offset, implicit) {\n    const itemData = [];\n\n    // first item: basic offset table\n    let item = this.#readDataElement(reader, offset, implicit);\n    const offsetTableVl = item.vl;\n    offset = item.endOffset;\n\n    // read until the sequence delimitation item\n    let isSeqDelim = false;\n    while (!isSeqDelim) {\n      item = this.#readDataElement(reader, offset, implicit);\n      offset = item.endOffset;\n      isSeqDelim = isSequenceDelimitationItemTag(item.tag);\n      if (!isSeqDelim) {\n        // force pixel item vr to OB\n        item.vr = 'OB';\n        itemData.push(item);\n      }\n    }\n\n    return {\n      data: itemData,\n      endOffset: offset,\n      offsetTableVl: offsetTableVl\n    };\n  }\n\n  /**\n   * Read a DICOM data element.\n   * Reference: [DICOM VRs]{@link http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html#table_6.2-1}.\n   *\n   * @param {DataReader} reader The raw data reader.\n   * @param {number} offset The offset where to start to read.\n   * @param {boolean} implicit Is the DICOM VR implicit?\n   * @returns {DataElement} The data element.\n   */\n  #readDataElement(reader, offset, implicit) {\n    // Tag: group, element\n    const readTagRes = this.#readTag(reader, offset);\n    const tag = readTagRes.tag;\n    offset = readTagRes.endOffset;\n\n    // Value Representation (VR)\n    let vr = null;\n    let is32bitVL = false;\n    if (tag.isWithVR()) {\n      // implicit VR\n      if (implicit) {\n        vr = tag.getVrFromDictionary();\n        if (typeof vr === 'undefined') {\n          vr = 'UN';\n        }\n        is32bitVL = true;\n      } else {\n        vr = this.#decodeString(reader.readUint8Array(offset, 2));\n        offset += 2 * Uint8Array.BYTES_PER_ELEMENT;\n        is32bitVL = is32bitVLVR(vr);\n        // reserved 2 bytes\n        if (is32bitVL) {\n          offset += 2 * Uint8Array.BYTES_PER_ELEMENT;\n        }\n      }\n    } else {\n      vr = 'NONE';\n      is32bitVL = true;\n    }\n\n    // check vr\n    if (!isKnownVR(vr)) {\n      logger.warn('Unknown VR: ' + vr +\n        ' (for tag ' + tag.getKey() + '), treating as \\'UN\\'');\n      vr = 'UN';\n    }\n\n    // Value Length (VL)\n    let vl = 0;\n    if (is32bitVL) {\n      vl = reader.readUint32(offset);\n      offset += Uint32Array.BYTES_PER_ELEMENT;\n    } else {\n      vl = reader.readUint16(offset);\n      offset += Uint16Array.BYTES_PER_ELEMENT;\n    }\n\n    // check the value of VL\n    let undefinedLength = false;\n    if (vl === 0xffffffff) {\n      undefinedLength = true;\n      vl = 0;\n    }\n\n    // treat private tag with unknown VR and zero VL as a sequence (see #799)\n    if (tag.isPrivate() && vr === 'UN' && vl === 0) {\n      vr = 'SQ';\n    }\n\n    let startOffset = offset;\n    let endOffset = startOffset + vl;\n\n    // read sequence elements\n    let data;\n    if (isPixelDataTag(tag) && undefinedLength) {\n      // pixel data sequence (implicit)\n      const pixItemData =\n        this.#readPixelItemDataElement(reader, offset, implicit);\n      offset = pixItemData.endOffset;\n      startOffset += pixItemData.offsetTableVl;\n      data = pixItemData.data;\n      endOffset = offset;\n      vl = offset - startOffset;\n    } else if (vr === 'SQ') {\n      // sequence\n      data = [];\n      let itemData;\n      if (!undefinedLength) {\n        if (vl !== 0) {\n          // explicit VR sequence: read until the end offset\n          const sqEndOffset = offset + vl;\n          while (offset < sqEndOffset) {\n            itemData = this.#readItemDataElement(reader, offset, implicit);\n            data.push(itemData.data);\n            offset = itemData.endOffset;\n          }\n          endOffset = offset;\n          vl = offset - startOffset;\n        }\n      } else {\n        // implicit VR sequence: read until the sequence delimitation item\n        let isSeqDelim = false;\n        while (!isSeqDelim) {\n          itemData = this.#readItemDataElement(reader, offset, implicit);\n          isSeqDelim = itemData.isSeqDelim;\n          offset = itemData.endOffset;\n          // do not store the delimitation item\n          if (!isSeqDelim) {\n            data.push(itemData.data);\n          }\n        }\n        endOffset = offset;\n        vl = offset - startOffset;\n      }\n    }\n\n    // return\n    const element = new DataElement(vr);\n    element.tag = tag;\n    element.vl = vl;\n    element.startOffset = startOffset;\n    element.endOffset = endOffset;\n    // only set if true (only for sequences and items)\n    if (undefinedLength) {\n      element.undefinedLength = undefinedLength;\n    }\n    if (data) {\n      element.items = data;\n    }\n    return element;\n  }\n\n  /**\n   * Interpret the data of an element.\n   *\n   * @param {DataElement} element The data element.\n   * @param {DataReader} reader The raw data reader.\n   * @param {number} [pixelRepresentation] PixelRepresentation 0->unsigned,\n   *   1->signed (needed for pixel data or VR=xs).\n   * @param {number} [bitsAllocated] Bits allocated (needed for pixel data).\n   * @returns {object} The interpreted data.\n   */\n  #interpretElement(\n    element, reader, pixelRepresentation, bitsAllocated) {\n\n    const tag = element.tag;\n    const vl = element.vl;\n    const vr = element.vr;\n    const offset = element.startOffset;\n\n    // data\n    let data = null;\n    const vrType = vrTypes[vr];\n    if (isPixelDataTag(tag)) {\n      if (element.undefinedLength) {\n        // implicit pixel data sequence\n        data = [];\n        for (let j = 0; j < element.items.length; ++j) {\n          data.push(this.#interpretElement(\n            element.items[j], reader,\n            pixelRepresentation, bitsAllocated));\n        }\n        // remove non parsed items\n        delete element.items;\n      } else {\n        // check bits allocated and VR\n        // https://dicom.nema.org/medical/dicom/2022a/output/chtml/part05/sect_A.2.html\n        if (bitsAllocated > 8 && vr === 'OB') {\n          logger.warn(\n            'Reading DICOM pixel data with bitsAllocated>8 and OB VR.'\n          );\n        }\n        // read\n        data = [];\n        if (bitsAllocated === 1) {\n          data.push(reader.readBinaryArray(offset, vl));\n        } else if (bitsAllocated === 8) {\n          if (pixelRepresentation === 0) {\n            data.push(reader.readUint8Array(offset, vl));\n          } else {\n            data.push(reader.readInt8Array(offset, vl));\n          }\n        } else if (bitsAllocated === 16) {\n          if (pixelRepresentation === 0) {\n            data.push(reader.readUint16Array(offset, vl));\n          } else {\n            data.push(reader.readInt16Array(offset, vl));\n          }\n        } else {\n          throw new Error('Unsupported bits allocated: ' + bitsAllocated);\n        }\n      }\n    } else if (typeof vrType !== 'undefined') {\n      if (vrType === 'Uint8') {\n        data = reader.readUint8Array(offset, vl);\n      } else if (vrType === 'Uint16') {\n        data = reader.readUint16Array(offset, vl);\n        // keep as binary for 'O*' VR\n        if (vr[0] !== 'O') {\n          data = Array.from(data);\n        }\n      } else if (vrType === 'Uint32') {\n        data = reader.readUint32Array(offset, vl);\n        // keep as binary for 'O*' VR\n        if (vr[0] !== 'O') {\n          data = Array.from(data);\n        }\n      } else if (vrType === 'Uint64') {\n        data = reader.readUint64Array(offset, vl);\n      } else if (vrType === 'Int16') {\n        data = Array.from(reader.readInt16Array(offset, vl));\n      } else if (vrType === 'Int32') {\n        data = Array.from(reader.readInt32Array(offset, vl));\n      } else if (vrType === 'Int64') {\n        data = reader.readInt64Array(offset, vl);\n      } else if (vrType === 'Float32') {\n        data = Array.from(reader.readFloat32Array(offset, vl));\n      } else if (vrType === 'Float64') {\n        data = Array.from(reader.readFloat64Array(offset, vl));\n      } else if (vrType === 'string') {\n        const stream = reader.readUint8Array(offset, vl);\n        if (isCharSetStringVR(vr)) {\n          data = this.#decodeSpecialString(stream);\n        } else {\n          data = this.#decodeString(stream);\n        }\n        data = cleanString(data).split('\\\\');\n      } else {\n        throw Error('Unknown VR type: ' + vrType);\n      }\n    } else if (vr === 'xx') {\n      // US or OW\n      data = Array.from(reader.readUint16Array(offset, vl));\n    } else if (vr === 'ox') {\n      // OB or OW\n      if (bitsAllocated === 8) {\n        data = Array.from(reader.readUint8Array(offset, vl));\n      } else {\n        data = Array.from(reader.readUint16Array(offset, vl));\n      }\n    } else if (vr === 'xs') {\n      // (US or SS) or (US or SS or OW)\n      if (pixelRepresentation === 0) {\n        data = Array.from(reader.readUint16Array(offset, vl));\n      } else {\n        data = Array.from(reader.readInt16Array(offset, vl));\n      }\n    } else if (vr === 'AT') {\n      // attribute\n      const raw = reader.readUint16Array(offset, vl);\n      data = [];\n      for (let i = 0, leni = raw.length; i < leni; i += 2) {\n        const stri = raw[i].toString(16);\n        const stri1 = raw[i + 1].toString(16);\n        let str = '(';\n        str += '0000'.substring(0, 4 - stri.length) + stri.toUpperCase();\n        str += ',';\n        str += '0000'.substring(0, 4 - stri1.length) + stri1.toUpperCase();\n        str += ')';\n        data.push(str);\n      }\n    } else if (vr === 'SQ') {\n      // sequence\n      data = [];\n      for (let k = 0; k < element.items.length; ++k) {\n        const item = element.items[k];\n        const itemData = {};\n        const keys = Object.keys(item);\n        for (let l = 0; l < keys.length; ++l) {\n          const subElement = item[keys[l]];\n          subElement.value = this.#interpretElement(\n            subElement, reader,\n            pixelRepresentation, bitsAllocated);\n          delete subElement.tag;\n          delete subElement.vl;\n          delete subElement.startOffset;\n          delete subElement.endOffset;\n          itemData[keys[l]] = subElement;\n        }\n        data.push(itemData);\n      }\n      // remove non parsed elements\n      delete element.items;\n    } else if (vr === 'NONE') {\n      // no VR -> no data\n      data = [];\n    } else {\n      logger.warn('Unknown VR: ' + vr +\n        ' (for tag ' + element.tag.getKey() + ')');\n      // empty data...\n      data = [];\n    }\n\n    return data;\n  }\n\n  /**\n   * Interpret the data of a list of elements.\n   *\n   * @param {DataElements} elements A list of data elements.\n   * @param {DataReader} reader The raw data reader.\n   * @param {number} pixelRepresentation PixelRepresentation 0->unsigned,\n   *   1->signed.\n   * @param {number} bitsAllocated Bits allocated.\n   */\n  #interpret(\n    elements, reader,\n    pixelRepresentation, bitsAllocated) {\n\n    const keys = Object.keys(elements);\n    for (let i = 0; i < keys.length; ++i) {\n      const element = elements[keys[i]];\n      if (typeof element.value === 'undefined') {\n        element.value = this.#interpretElement(\n          element, reader, pixelRepresentation, bitsAllocated);\n      }\n      // delete interpretation specific properties\n      delete element.tag;\n      delete element.vl;\n      delete element.startOffset;\n      delete element.endOffset;\n    }\n  }\n\n  /**\n   * Parse the complete DICOM file (given as input to the class).\n   * Fills in the member object 'dataElements'.\n   *\n   * @param {ArrayBuffer} buffer The input array buffer.\n   */\n  parse(buffer) {\n    let offset = 0;\n    let syntax = '';\n    let dataElement = null;\n    // default readers\n    const metaReader = new DataReader(buffer);\n    let dataReader = new DataReader(buffer);\n\n    // 128 -> 132: magic word\n    offset = 128;\n    const magicword = this.#decodeString(metaReader.readUint8Array(offset, 4));\n    offset += 4 * Uint8Array.BYTES_PER_ELEMENT;\n    if (magicword === 'DICM') {\n      // 0002, 0000: FileMetaInformationGroupLength (vr='UL')\n      dataElement = this.#readDataElement(metaReader, offset, false);\n      dataElement.value = this.#interpretElement(dataElement, metaReader);\n      // increment offset\n      offset = dataElement.endOffset;\n      // store the data element\n      this.#dataElements[dataElement.tag.getKey()] = dataElement;\n      // get meta length\n      const metaLength = dataElement.value[0];\n\n      // meta elements\n      const metaEnd = offset + metaLength;\n      while (offset < metaEnd) {\n        // get the data element\n        dataElement = this.#readDataElement(metaReader, offset, false);\n        offset = dataElement.endOffset;\n        // store the data element\n        this.#dataElements[dataElement.tag.getKey()] = dataElement;\n      }\n\n      // check the TransferSyntaxUID (has to be there!)\n      dataElement = this.#dataElements['00020010'];\n      if (typeof dataElement === 'undefined') {\n        throw new Error('Not a valid DICOM file (no TransferSyntaxUID found)');\n      }\n      dataElement.value = this.#interpretElement(dataElement, metaReader);\n      syntax = dataElement.value[0];\n\n    } else {\n      logger.warn('No DICM prefix, trying to guess tansfer syntax.');\n      // read first element\n      dataElement = this.#readDataElement(dataReader, 0, false);\n      // guess transfer syntax\n      const tsElement = guessTransferSyntax(dataElement);\n      // store\n      this.#dataElements[tsElement.tag.getKey()] = tsElement;\n      syntax = tsElement.value[0];\n      // reset offset\n      offset = 0;\n    }\n\n    // check transfer syntax support\n    if (!isReadSupportedTransferSyntax(syntax)) {\n      throw new Error('Unsupported DICOM transfer syntax: \\'' + syntax +\n        '\\' (' + getTransferSyntaxName(syntax) + ')');\n    }\n\n    // set implicit flag\n    let implicit = false;\n    if (isImplicitTransferSyntax(syntax)) {\n      implicit = true;\n    }\n\n    // Big Endian\n    if (isBigEndianTransferSyntax(syntax)) {\n      dataReader = new DataReader(buffer, false);\n    }\n\n    // DICOM data elements\n    while (offset < buffer.byteLength) {\n      // get the data element\n      dataElement = this.#readDataElement(dataReader, offset, implicit);\n      // increment offset\n      offset = dataElement.endOffset;\n      // store the data element\n      const key = dataElement.tag.getKey();\n      if (typeof this.#dataElements[key] === 'undefined') {\n        this.#dataElements[key] = dataElement;\n      } else {\n        logger.warn('Not saving duplicate tag: ' + key);\n      }\n    }\n\n    // safety checks...\n    if (isNaN(offset)) {\n      throw new Error('Problem while parsing, bad offset');\n    }\n    if (buffer.byteLength !== offset) {\n      logger.warn('Did not reach the end of the buffer: ' +\n        offset + ' != ' + buffer.byteLength);\n    }\n\n    //-------------------------------------------------\n    // values needed for data interpretation\n\n    // pixel specific\n    let pixelRepresentation = 0;\n    let bitsAllocated = 16;\n    if (typeof this.#dataElements['7FE00010'] !== 'undefined') {\n      // PixelRepresentation 0->unsigned, 1->signed\n      dataElement = this.#dataElements['00280103'];\n      if (typeof dataElement !== 'undefined') {\n        dataElement.value = this.#interpretElement(dataElement, dataReader);\n        pixelRepresentation = dataElement.value[0];\n      } else {\n        logger.warn(\n          'Reading DICOM pixel data with default pixelRepresentation.');\n      }\n\n      // BitsAllocated\n      dataElement = this.#dataElements['00280100'];\n      if (typeof dataElement !== 'undefined') {\n        dataElement.value = this.#interpretElement(dataElement, dataReader);\n        bitsAllocated = dataElement.value[0];\n      } else {\n        logger.warn('Reading DICOM pixel data with default bitsAllocated.');\n      }\n    }\n\n    // default character set\n    if (typeof this.#defaultCharacterSet !== 'undefined') {\n      this.setDecoderCharacterSet(this.#defaultCharacterSet);\n    }\n\n    // SpecificCharacterSet\n    dataElement = this.#dataElements['00080005'];\n    if (typeof dataElement !== 'undefined') {\n      dataElement.value = this.#interpretElement(dataElement, dataReader);\n      let charSetTerm;\n      if (dataElement.value.length === 1) {\n        charSetTerm = dataElement.value[0];\n      } else {\n        charSetTerm = dataElement.value[1];\n        logger.warn('Unsupported character set with code extensions: \\'' +\n          charSetTerm + '\\'.');\n      }\n      this.setDecoderCharacterSet(getUtfLabel(charSetTerm));\n    }\n\n    // interpret the dicom elements\n    this.#interpret(\n      this.#dataElements, dataReader,\n      pixelRepresentation, bitsAllocated\n    );\n\n    // handle fragmented pixel buffer\n    // Reference: http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_8.2.html\n    // (third note, \"Depending on the transfer syntax...\")\n    dataElement = this.#dataElements['7FE00010'];\n    if (typeof dataElement !== 'undefined') {\n      if (dataElement.undefinedLength) {\n        let numberOfFrames = 1;\n        if (typeof this.#dataElements['00280008'] !== 'undefined') {\n          numberOfFrames = Number(this.#dataElements['00280008'].value[0]);\n        }\n        const pixItems = dataElement.value;\n        if (pixItems.length > 1 && pixItems.length > numberOfFrames) {\n          // concatenate pixel data items\n          // concat does not work on typed arrays\n          //this.pixelBuffer = this.pixelBuffer.concat( dataElement.data );\n          // manual concat...\n          const nItemPerFrame = pixItems.length / numberOfFrames;\n          const newPixItems = [];\n          let index = 0;\n          for (let f = 0; f < numberOfFrames; ++f) {\n            index = f * nItemPerFrame;\n            // calculate the size of a frame\n            let size = 0;\n            for (let i = 0; i < nItemPerFrame; ++i) {\n              size += pixItems[index + i].length;\n            }\n            // create new buffer\n            const newBuffer = new pixItems[0].constructor(size);\n            // fill new buffer\n            let fragOffset = 0;\n            for (let j = 0; j < nItemPerFrame; ++j) {\n              newBuffer.set(pixItems[index + j], fragOffset);\n              fragOffset += pixItems[index + j].length;\n            }\n            newPixItems[f] = newBuffer;\n          }\n          // store as pixel data\n          dataElement.value = newPixItems;\n        }\n      }\n    }\n  }\n\n} // class DicomParser\n","/**\n * ListenerHandler class: handles add/removing and firing listeners.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget#example\n */\nexport class ListenerHandler {\n  /**\n   * listeners.\n   *\n   * @type {object}\n   */\n  #listeners = {};\n\n  /**\n   * Add an event listener.\n   *\n   * @param {string} type The event type.\n   * @param {object} callback The method associated with the provided\n   *    event type, will be called with the fired event.\n   */\n  add(type, callback) {\n    // create array if not present\n    if (typeof this.#listeners[type] === 'undefined') {\n      this.#listeners[type] = [];\n    }\n    // add callback to listeners array\n    this.#listeners[type].push(callback);\n  }\n\n  /**\n   * Remove an event listener.\n   *\n   * @param {string} type The event type.\n   * @param {object} callback The method associated with the provided\n   *   event type.\n   */\n  remove(type, callback) {\n    // check if the type is present\n    if (typeof this.#listeners[type] === 'undefined') {\n      return;\n    }\n    // remove from listeners array\n    for (let i = 0; i < this.#listeners[type].length; ++i) {\n      if (this.#listeners[type][i] === callback) {\n        this.#listeners[type].splice(i, 1);\n      }\n    }\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  fireEvent = (event) => {\n    // check if they are listeners for the event type\n    if (typeof this.#listeners[event.type] === 'undefined') {\n      return;\n    }\n    // fire events from a copy of the listeners array\n    // to avoid interference from possible add/remove\n    const stack = this.#listeners[event.type].slice();\n    for (let i = 0; i < stack.length; ++i) {\n      stack[i](event);\n    }\n  };\n}\n","import {Index} from '../math/index';\nimport {Point2D} from '../math/point';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {Point} from '../math/point';\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get an simple iterator for a given range for a one component data.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} [increment] The increment between indicies (default=1).\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function simpleRange(dataAccessor, start, end, increment) {\n  if (typeof increment === 'undefined') {\n    increment = 1;\n  }\n  let nextIndex = start;\n  // result\n  return {\n    next: function () {\n      if (nextIndex < end) {\n        const result = {\n          value: dataAccessor(nextIndex),\n          done: false,\n          index: nextIndex\n        };\n        nextIndex += increment;\n        return result;\n      }\n      return {\n        done: true,\n        index: end\n      };\n    }\n  };\n}\n\n/**\n * Get an iterator for a given range for a one component data.\n *\n * Using 'maxIter' and not an 'end' index since it fails in some edge cases\n * (for ex coronal2, ie zxy)\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start Zero-based index at which to start the iteration.\n * @param {number} maxIter The maximum number of iterations.\n * @param {number} increment Increment between indicies.\n * @param {number} blockMaxIter Number of applied increment after which\n *   blockIncrement is applied.\n * @param {number} blockIncrement Increment after blockMaxIter is reached,\n *   the value is from block start to the next block start.\n * @param {boolean} reverse1 If true, loop from end to start.\n *   WARN: don't forget to set the value of start as the last index!\n * @param {boolean} reverse2 If true, loop from block end to block start.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function range(dataAccessor, start, maxIter, increment,\n  blockMaxIter, blockIncrement, reverse1, reverse2) {\n  if (typeof reverse1 === 'undefined') {\n    reverse1 = false;\n  }\n  if (typeof reverse2 === 'undefined') {\n    reverse2 = false;\n  }\n\n  // first index of the iteration\n  let nextIndex = start;\n  // adapt first index and increments to reverse values\n  if (reverse1) {\n    blockIncrement *= -1;\n    if (reverse2) {\n      // start at end of line\n      nextIndex -= (blockMaxIter - 1) * increment;\n    } else {\n      increment *= -1;\n    }\n  } else {\n    if (reverse2) {\n      // start at end of line\n      nextIndex += (blockMaxIter - 1) * increment;\n      increment *= -1;\n    }\n  }\n  const finalBlockIncrement = blockIncrement - blockMaxIter * increment;\n\n  // counters\n  let mainCount = 0;\n  let blockCount = 0;\n  // result\n  return {\n    next: function () {\n      if (mainCount < maxIter) {\n        const result = {\n          value: dataAccessor(nextIndex),\n          done: false,\n          index: nextIndex\n        };\n        nextIndex += increment;\n        ++mainCount;\n        ++blockCount;\n        if (blockCount === blockMaxIter) {\n          blockCount = 0;\n          nextIndex += finalBlockIncrement;\n        }\n        return result;\n      }\n      return {\n        done: true,\n        index: nextIndex\n      };\n    }\n  };\n}\n\n/**\n * Get an iterator for a given range with bounds (for a one component data).\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} increment The increment between indicies.\n * @param {number} regionSize The size of the region to iterate through.\n * @param {number} regionOffset The offset between regions.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function rangeRegion(\n  dataAccessor, start, end, increment, regionSize, regionOffset) {\n  let nextIndex = start;\n  let regionElementCount = 0;\n  // result\n  return {\n    next: function () {\n      if (nextIndex < end) {\n        const result = {\n          value: dataAccessor(nextIndex),\n          done: false,\n          index: nextIndex\n        };\n        regionElementCount += 1;\n        nextIndex += increment;\n        if (regionElementCount === regionSize) {\n          regionElementCount = 0;\n          nextIndex += regionOffset;\n        }\n        return result;\n      }\n      return {\n        done: true,\n        index: end\n      };\n    }\n  };\n}\n\n/**\n * Get an iterator for a given range with bounds (for a one component data).\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n * @param {number} increment The increment between indicies.\n * @param {Array} regions An array of regions: [off0, size, off1].\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function rangeRegions(\n  dataAccessor, start, end, increment, regions) {\n  let nextIndex = start;\n  let regionCount = 0;\n  let regionElementCount = 0;\n  // result\n  return {\n    next: function () {\n      if (nextIndex < end) {\n        const result = {\n          value: dataAccessor(nextIndex),\n          done: false,\n          index: nextIndex\n        };\n        regionElementCount += 1;\n        nextIndex += increment;\n        if (regionElementCount === regions[regionCount][1]) {\n          regionElementCount = 0;\n          // off1 of current group\n          nextIndex += regions[regionCount][2];\n          regionCount += 1;\n          // off0 of next group\n          if (regionCount < regions.length) {\n            nextIndex += regions[regionCount][0];\n          }\n        }\n        return result;\n      }\n      return {\n        done: true,\n        index: end\n      };\n    }\n  };\n}\n\n/**\n * Get an iterator for a given range for a 3 components data.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start The start of the range (included).\n * @param {number} end The end of the range (excluded).\n *   (end - start) needs to be a multiple of 3...\n * @param {number} increment The increment between indicies (default=1).\n * @param {boolean} isPlanar A flag to know if the data is planar\n *   (RRRR...GGGG...BBBB...) or not (RGBRGBRGBRGB...), defaults to false.\n * @returns {object} A 3 components iterator folowing the iterator and iterable\n *   protocol, the value is an array of size 3 with each component.\n */\nexport function simpleRange3d(\n  dataAccessor, start, end, increment, isPlanar) {\n  if (typeof increment === 'undefined') {\n    increment = 1;\n  }\n  if (typeof isPlanar === 'undefined') {\n    isPlanar = false;\n  }\n  let nextIndex = start;\n  let componentIncrement = 1;\n  if (isPlanar) {\n    componentIncrement = (end - start) / 3;\n  } else {\n    increment *= 3;\n  }\n  let nextIndex1 = nextIndex + componentIncrement;\n  let nextIndex2 = nextIndex + 2 * componentIncrement;\n\n  // result\n  return {\n    next: function () {\n      if (nextIndex < end) {\n        const result = {\n          value: [\n            dataAccessor(nextIndex),\n            dataAccessor(nextIndex1),\n            dataAccessor(nextIndex2)\n          ],\n          done: false,\n          index: [nextIndex, nextIndex1, nextIndex2]\n        };\n        nextIndex += increment;\n        nextIndex1 += increment;\n        nextIndex2 += increment;\n        return result;\n      }\n      return {\n        done: true,\n        index: [end]\n      };\n    }\n  };\n}\n\n/**\n * Get an iterator for a given range for a 3 components data.\n *\n * Using 'maxIter' and not an 'end' index since it fails in some edge cases\n * (for ex coronal2, ie zxy)\n *\n * @param {Function} dataAccessor Function to access data.\n * @param {number} start Zero-based index at which to start the iteration.\n * @param {number} maxIter The maximum number of iterations.\n * @param {number} increment Increment between indicies.\n * @param {number} blockMaxIter Number of applied increment after which\n *   blockIncrement is applied.\n * @param {number} blockIncrement Increment after blockMaxIter is reached,\n *   the value is from block start to the next block start.\n * @param {boolean} reverse1 If true, loop from end to start.\n *   WARN: don't forget to set the value of start as the last index!\n * @param {boolean} reverse2 If true, loop from block end to block start.\n * @param {boolean} isPlanar A flag to know if the data is planar\n *   (RRRR...GGGG...BBBB...) or not (RGBRGBRGBRGB...), defaults to false.\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function range3d(dataAccessor, start, maxIter, increment,\n  blockMaxIter, blockIncrement, reverse1, reverse2, isPlanar) {\n  const iters = [];\n  if (isPlanar) {\n    iters.push(range(\n      dataAccessor, start, maxIter, increment,\n      blockMaxIter, blockIncrement, reverse1, reverse2\n    ));\n    iters.push(range(\n      dataAccessor, start + maxIter * increment, maxIter, increment,\n      blockMaxIter, blockIncrement, reverse1, reverse2\n    ));\n    iters.push(range(\n      dataAccessor, start + 2 * maxIter * increment, maxIter, increment,\n      blockMaxIter, blockIncrement, reverse1, reverse2\n    ));\n  } else {\n    increment *= 3;\n    blockIncrement *= 3;\n    iters.push(range(\n      dataAccessor, start, maxIter, increment,\n      blockMaxIter, blockIncrement, reverse1, reverse2\n    ));\n    iters.push(range(\n      dataAccessor, start + 1, maxIter, increment,\n      blockMaxIter, blockIncrement, reverse1, reverse2\n    ));\n    iters.push(range(\n      dataAccessor, start + 2, maxIter, increment,\n      blockMaxIter, blockIncrement, reverse1, reverse2\n    ));\n  }\n\n  // result\n  return {\n    next: function () {\n      const r0 = iters[0].next();\n      const r1 = iters[1].next();\n      const r2 = iters[2].next();\n      if (!r0.done) {\n        return {\n          value: [\n            r0.value,\n            r1.value,\n            r2.value\n          ],\n          done: false,\n          index: [\n            r0.index,\n            r1.index,\n            r2.index\n          ]\n        };\n      }\n      return {\n        done: true,\n        index: r2.index\n      };\n    }\n  };\n}\n\n/**\n * Get a list of values for a given iterator.\n *\n * @param {object} iterator The iterator to use to loop through data.\n * @returns {Array} The list of values.\n */\nexport function getIteratorValues(iterator) {\n  const values = [];\n  let ival = iterator.next();\n  while (!ival.done) {\n    values.push(ival.value);\n    ival = iterator.next();\n  }\n  return values;\n}\n\n/**\n * Get a slice index iterator.\n *\n * @param {Image} image The image to parse.\n * @param {Index} position The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {object} The slice iterator.\n */\nexport function getSliceIterator(\n  image, position, isRescaled, viewOrientation) {\n  const size = image.getGeometry().getSize();\n  // zero-ify non direction index\n  let dirMax2Index = 2;\n  if (viewOrientation && typeof viewOrientation !== 'undefined') {\n    dirMax2Index = viewOrientation.getColAbsMax(2).index;\n  }\n  const posValues = position.getValues();\n  // keep the main direction and any other than 3D\n  const indexFilter = function (element, index) {\n    return (index === dirMax2Index || index > 2) ? element : 0;\n  };\n  const posStart = new Index(posValues.map(indexFilter));\n  let start = size.indexToOffset(posStart);\n\n  // default to non rescaled data\n  if (typeof isRescaled === 'undefined') {\n    isRescaled = false;\n  }\n  let dataAccessor = null;\n  if (isRescaled) {\n    dataAccessor = function (offset) {\n      return image.getRescaledValueAtOffset(offset);\n    };\n  } else {\n    dataAccessor = function (offset) {\n      return image.getValueAtOffset(offset);\n    };\n  }\n\n  const ncols = size.get(0);\n  const nrows = size.get(1);\n  const nslices = size.get(2);\n  let sliceSize = size.getDimSize(2);\n\n  const ncomp = image.getNumberOfComponents();\n  const isPlanar = image.getPlanarConfiguration() === 1;\n  const getRange = function (\n    dataAccessor, start, maxIter, increment,\n    blockMaxIter, blockIncrement, reverse1, reverse2) {\n    if (ncomp === 1) {\n      return range(dataAccessor, start, maxIter, increment,\n        blockMaxIter, blockIncrement, reverse1, reverse2);\n    } else if (ncomp === 3) {\n      return range3d(dataAccessor, 3 * start, maxIter, increment,\n        blockMaxIter, blockIncrement, reverse1, reverse2, isPlanar);\n    }\n  };\n\n  let rangeObj = null;\n  if (viewOrientation && typeof viewOrientation !== 'undefined') {\n    const dirMax0 = viewOrientation.getColAbsMax(0);\n    const dirMax2 = viewOrientation.getColAbsMax(2);\n\n    // default reverse\n    const reverse1 = false;\n    const reverse2 = false;\n\n    let maxIter = null;\n    if (dirMax2.index === 2) {\n      // axial\n      maxIter = ncols * nrows;\n      if (dirMax0.index === 0) {\n        // xyz\n        rangeObj = getRange(dataAccessor,\n          start, maxIter, 1, ncols, ncols, reverse1, reverse2);\n      } else {\n        // yxz\n        rangeObj = getRange(dataAccessor,\n          start, maxIter, ncols, nrows, 1, reverse1, reverse2);\n      }\n    } else if (dirMax2.index === 0) {\n      // sagittal\n      maxIter = nslices * nrows;\n      if (dirMax0.index === 1) {\n        // yzx\n        rangeObj = getRange(dataAccessor,\n          start, maxIter, ncols, nrows, sliceSize, reverse1, reverse2);\n      } else {\n        // zyx\n        rangeObj = getRange(dataAccessor,\n          start, maxIter, sliceSize, nslices, ncols, reverse1, reverse2);\n      }\n    } else if (dirMax2.index === 1) {\n      // coronal\n      maxIter = nslices * ncols;\n      if (dirMax0.index === 0) {\n        // xzy\n        rangeObj = getRange(dataAccessor,\n          start, maxIter, 1, ncols, sliceSize, reverse1, reverse2);\n      } else {\n        // zxy\n        rangeObj = getRange(dataAccessor,\n          start, maxIter, sliceSize, nslices, 1, reverse1, reverse2);\n      }\n    } else {\n      throw new Error('Unknown direction: ' + dirMax2.index);\n    }\n  } else {\n    if (image.getNumberOfComponents() === 1) {\n      rangeObj = simpleRange(dataAccessor, start, start + sliceSize);\n    } else if (image.getNumberOfComponents() === 3) {\n      // 3 times bigger...\n      start *= 3;\n      sliceSize *= 3;\n      rangeObj = simpleRange3d(\n        dataAccessor, start, start + sliceSize, 1, isPlanar);\n    } else {\n      throw new Error('Unsupported number of components: ' +\n        image.getNumberOfComponents());\n    }\n  }\n\n  return rangeObj;\n}\n\n/**\n * Get a slice index iterator for a rectangular region.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Point2D} min The minimum position (optional).\n * @param {Point2D} max The maximum position (optional).\n * @returns {object} The slice iterator.\n */\nexport function getRegionSliceIterator(\n  image, index, isRescaled, min, max) {\n  if (image.getNumberOfComponents() !== 1) {\n    throw new Error('Unsupported number of components for region iterator: ' +\n      image.getNumberOfComponents());\n  }\n\n  // default to non rescaled data\n  if (typeof isRescaled === 'undefined') {\n    isRescaled = false;\n  }\n  let dataAccessor = null;\n  if (isRescaled) {\n    dataAccessor = function (offset) {\n      return image.getRescaledValueAtOffset(offset);\n    };\n  } else {\n    dataAccessor = function (offset) {\n      return image.getValueAtOffset(offset);\n    };\n  }\n\n  const size = image.getGeometry().getSize();\n  if (typeof min === 'undefined') {\n    min = new Point2D(0, 0);\n  }\n  if (typeof max === 'undefined') {\n    max = new Point2D(\n      size.get(0) - 1,\n      size.get(1)\n    );\n  }\n  // position to pixel for max: extra X is ok, remove extra Y\n  const startOffset = size.indexToOffset(index.getWithNew2D(\n    min.getX(), min.getY()\n  ));\n  const endOffset = size.indexToOffset(index.getWithNew2D(\n    max.getX(), max.getY() - 1\n  ));\n\n  // minimum 1 column\n  const rangeNumberOfColumns = Math.max(1, max.getX() - min.getX());\n  const rowIncrement = size.get(0) - rangeNumberOfColumns;\n\n  return rangeRegion(\n    dataAccessor, startOffset, endOffset + 1,\n    1, rangeNumberOfColumns, rowIncrement);\n}\n\n/**\n * Get a slice index iterator for a rectangular region.\n *\n * @param {Image} image The image to parse.\n * @param {Index} index The current position.\n * @param {boolean} isRescaled Flag for rescaled values (default false).\n * @param {Array} regions An array of regions.\n * @returns {object|undefined} The slice iterator.\n */\nexport function getVariableRegionSliceIterator(\n  image, index, isRescaled, regions) {\n  if (image.getNumberOfComponents() !== 1) {\n    throw new Error('Unsupported number of components for region iterator: ' +\n      image.getNumberOfComponents());\n  }\n\n  // default to non rescaled data\n  if (typeof isRescaled === 'undefined') {\n    isRescaled = false;\n  }\n  let dataAccessor = null;\n  if (isRescaled) {\n    dataAccessor = function (offset) {\n      return image.getRescaledValueAtOffset(offset);\n    };\n  } else {\n    dataAccessor = function (offset) {\n      return image.getValueAtOffset(offset);\n    };\n  }\n\n  const size = image.getGeometry().getSize();\n\n  const offsetRegions = [];\n  let region;\n  let min = null;\n  let max = null;\n  let regionIndex = null;\n  for (let i = 0; i < regions.length; ++i) {\n    region = regions[i];\n    const width = region[1][0] - region[0][0];\n    if (width !== 0) {\n      regionIndex = i;\n      if (!min) {\n        min = region[0];\n      }\n      offsetRegions.push([\n        region[0][0],\n        width,\n        size.get(0) - region[1][0]\n      ]);\n    }\n  }\n  if (regionIndex !== null) {\n    max = regions[regionIndex][1];\n  }\n\n  // exit if no offsets\n  if (offsetRegions.length === 0) {\n    return undefined;\n  }\n\n  const startOffset = size.indexToOffset(index.getWithNew2D(\n    min[0], min[1]\n  ));\n  const endOffset = size.indexToOffset(index.getWithNew2D(\n    max[0], max[1]\n  ));\n\n  return rangeRegions(\n    dataAccessor, startOffset, endOffset + 1,\n    1, offsetRegions);\n}\n\n/**\n * Get a colour iterator. The input array defines the colours and\n * their start index.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols\n * @param {Array} colours An array of {index, colour} pairs.\n * @param {number} end The end of the range (excluded).\n * @returns {object} An iterator folowing the iterator and iterable protocol.\n */\nexport function colourRange(colours, end) {\n  let nextIndex = 0;\n  let nextColourIndex = 0;\n  // result\n  return {\n    next: function () {\n      if (nextIndex < end) {\n        if (nextColourIndex + 1 < colours.length &&\n          nextIndex >= colours[nextColourIndex + 1].index) {\n          ++nextColourIndex;\n        }\n        const result = {\n          value: colours[nextColourIndex].colour,\n          done: false,\n          index: nextIndex\n        };\n        ++nextIndex;\n        return result;\n      }\n      return {\n        done: true,\n        index: end\n      };\n    }\n  };\n}\n","/**\n * Rescale Slope and Intercept\n */\nexport class RescaleSlopeAndIntercept {\n\n  /**\n   * The slope.\n   *\n   * @type {number}\n   */\n  #slope;\n\n  /**\n   * The intercept.\n   *\n   * @type {number}\n   */\n  #intercept;\n\n  /**\n   * @param {number} slope The slope of the RSI.\n   * @param {number} intercept The intercept of the RSI.\n   */\n  constructor(slope, intercept) {\n    /*// Check the rescale slope.\n      if(typeof(slope) === 'undefined') {\n          slope = 1;\n      }\n      // Check the rescale intercept.\n      if(typeof(intercept) === 'undefined') {\n          intercept = 0;\n      }*/\n    this.#slope = slope;\n    this.#intercept = intercept;\n  }\n\n  /**\n   * Get the slope of the RSI.\n   *\n   * @returns {number} The slope of the RSI.\n   */\n  getSlope() {\n    return this.#slope;\n  }\n\n  /**\n   * Get the intercept of the RSI.\n   *\n   * @returns {number} The intercept of the RSI.\n   */\n  getIntercept() {\n    return this.#intercept;\n  }\n\n  /**\n   * Apply the RSI on an input value.\n   *\n   * @param {number} value The input value.\n   * @returns {number} The value to rescale.\n   */\n  apply(value) {\n    return value * this.#slope + this.#intercept;\n  }\n\n  /**\n   * Check for RSI equality.\n   *\n   * @param {RescaleSlopeAndIntercept} rhs The other RSI to compare to.\n   * @returns {boolean} True if both RSI are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n          this.getSlope() === rhs.getSlope() &&\n          this.getIntercept() === rhs.getIntercept();\n  }\n\n  /**\n   * Get a string representation of the RSI.\n   *\n   * @returns {string} The RSI as a string.\n   */\n  toString() {\n    return (this.getSlope() + ', ' + this.getIntercept());\n  }\n\n  /**\n   * Is this RSI an ID RSI.\n   *\n   * @returns {boolean} True if the RSI has a slope of 1 and no intercept.\n   */\n  isID() {\n    return (this.getSlope() === 1 && this.getIntercept() === 0);\n  }\n\n} // class RescaleSlopeAndIntercept\n","import {Index} from '../math/index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * Immutable Size class.\n * Warning: the input array is NOT cloned, modifying it will\n *  modify the index values.\n */\nexport class Size {\n\n  /**\n   * The size values.\n   *\n   * @type {Array}\n   */\n  #values;\n\n  /**\n   * @param {Array} values The size values.\n   */\n  constructor(values) {\n    if (!values || typeof values === 'undefined') {\n      throw new Error('Cannot create size with no values.');\n    }\n    if (values.length === 0) {\n      throw new Error('Cannot create size with empty values.');\n    }\n    const valueCheck = function (val) {\n      return !isNaN(val) && val !== 0;\n    };\n    if (!values.every(valueCheck)) {\n      throw new Error('Cannot create size with non number or zero values.');\n    }\n    this.#values = values;\n  }\n\n  /**\n   * Get the size value at the given array index.\n   *\n   * @param {number} i The index to get.\n   * @returns {number} The value.\n   */\n  get(i) {\n    return this.#values[i];\n  }\n\n  /**\n   * Get the length of the index.\n   *\n   * @returns {number} The length.\n   */\n  length() {\n    return this.#values.length;\n  }\n\n  /**\n   * Get a string representation of the size.\n   *\n   * @returns {string} The Size as a string.\n   */\n  toString() {\n    return '(' + this.#values.toString() + ')';\n  }\n\n  /**\n   * Get the values of this index.\n   *\n   * @returns {Array} The array of values.\n   */\n  getValues() {\n    return this.#values.slice();\n  }\n\n  /**\n   * Check if a dimension exists and has more than one element.\n   *\n   * @param {number} dimension The dimension to check.\n   * @returns {boolean} True if the size is more than one.\n   */\n  moreThanOne(dimension) {\n    return this.length() >= dimension + 1 && this.get(dimension) !== 1;\n  }\n\n  /**\n   * Check if the associated data is scrollable in 3D.\n   *\n   * @param {Matrix33} [viewOrientation] The orientation matrix.\n   * @returns {boolean} True if scrollable.\n   */\n  canScroll3D(viewOrientation) {\n    let dimension = 2;\n    if (typeof viewOrientation !== 'undefined') {\n      dimension = viewOrientation.getThirdColMajorDirection();\n    }\n    return this.moreThanOne(dimension);\n  }\n\n  /**\n   * Check if the associated data is scrollable: either in 3D or\n   * in other directions.\n   *\n   * @param {Matrix33} viewOrientation The orientation matrix.\n   * @returns {boolean} True if scrollable.\n   */\n  canScroll(viewOrientation) {\n    let canScroll = this.canScroll3D(viewOrientation);\n    // check possible other dimensions\n    for (let i = 3; i < this.length(); ++i) {\n      canScroll = canScroll || this.moreThanOne(i);\n    }\n    return canScroll;\n  }\n\n  /**\n   * Get the size of a given dimension.\n   *\n   * @param {number} dimension The dimension.\n   * @param {number} [start] Optional start dimension to start counting from.\n   * @returns {number} The size.\n   */\n  getDimSize(dimension, start) {\n    if (dimension > this.length()) {\n      return null;\n    }\n    if (typeof start === 'undefined') {\n      start = 0;\n    } else {\n      if (start < 0 || start > dimension) {\n        throw new Error('Invalid start value for getDimSize');\n      }\n    }\n    let size = 1;\n    for (let i = start; i < dimension; ++i) {\n      size *= this.get(i);\n    }\n    return size;\n  }\n\n  /**\n   * Get the total size.\n   *\n   * @param {number} [start] Optional start dimension to base the offset on.\n   * @returns {number} The total size.\n   */\n  getTotalSize(start) {\n    return this.getDimSize(this.length(), start);\n  }\n\n  /**\n   * Check for equality.\n   *\n   * @param {Size} rhs The object to compare to.\n   * @returns {boolean} True if both objects are equal.\n   */\n  equals(rhs) {\n    // check input\n    if (!rhs) {\n      return false;\n    }\n    // check length\n    const length = this.length();\n    if (length !== rhs.length()) {\n      return false;\n    }\n    // check values\n    for (let i = 0; i < length; ++i) {\n      if (this.get(i) !== rhs.get(i)) {\n        return false;\n      }\n    }\n    // seems ok!\n    return true;\n  }\n\n  /**\n   * Check that an index is within bounds.\n   *\n   * @param {Index} index The index to check.\n   * @param {Array} dirs Optional list of directions to check.\n   * @returns {boolean} True if the given coordinates are within bounds.\n   */\n  isInBounds(index, dirs) {\n    // check input\n    if (!index) {\n      return false;\n    }\n    // check length\n    const length = this.length();\n    if (length !== index.length()) {\n      return false;\n    }\n    // create dirs if not there\n    if (typeof dirs === 'undefined') {\n      dirs = [];\n      for (let j = 0; j < length; ++j) {\n        dirs.push(j);\n      }\n    } else {\n      for (let k = 0; k < length; ++k) {\n        if (dirs[k] > length - 1) {\n          throw new Error('Wrong input dir value: ' + dirs[k]);\n        }\n      }\n    }\n    // check values is 0 <= v < size\n    const inBound = function (value, size) {\n      return value >= 0 && value < size;\n    };\n    // check\n    for (let i = 0; i < dirs.length; ++i) {\n      if (!inBound(index.get(dirs[i]), this.get(dirs[i]))) {\n        return false;\n      }\n    }\n    // seems ok!\n    return true;\n  }\n\n  /**\n   * Convert an index to an offset in memory.\n   *\n   * @param {Index} index The index to convert.\n   * @param {number} [start] Optional start dimension to base the offset on.\n   * @returns {number} The offset.\n   */\n  indexToOffset(index, start) {\n    // TODO check for equality\n    if (index.length() < this.length()) {\n      throw new Error('Incompatible index and size length');\n    }\n    if (typeof start === 'undefined') {\n      start = 0;\n    } else {\n      if (start < 0 || start > this.length() - 1) {\n        throw new Error('Invalid start value for indexToOffset');\n      }\n    }\n    let offset = 0;\n    for (let i = start; i < this.length(); ++i) {\n      offset += index.get(i) * this.getDimSize(i, start);\n    }\n    return offset;\n  }\n\n  /**\n   * Convert an offset in memory to an index.\n   *\n   * @param {number} offset The offset to convert.\n   * @returns {Index} The index.\n   */\n  offsetToIndex(offset) {\n    const values = new Array(this.length());\n    let off = offset;\n    let dimSize = 0;\n    for (let i = this.length() - 1; i > 0; --i) {\n      dimSize = this.getDimSize(i);\n      values[i] = Math.floor(off / dimSize);\n      off = off - values[i] * dimSize;\n    }\n    values[0] = off;\n    return new Index(values);\n  }\n\n  /**\n   * Get the 2D base of this size.\n   *\n   * @returns {object} The 2D base [0,1] as {x,y}.\n   */\n  get2D() {\n    return {\n      x: this.get(0),\n      y: this.get(1)\n    };\n  }\n\n} // Size class\n","/**\n * Immutable Spacing class.\n * Warning: the input array is NOT cloned, modifying it will\n *  modify the index values.\n */\nexport class Spacing {\n\n  /**\n   * The spacing values.\n   *\n   * @type {Array}\n   */\n  #values;\n\n  /**\n   * @param {Array} values The spacing values.\n   */\n  constructor(values) {\n    if (!values || typeof values === 'undefined') {\n      throw new Error('Cannot create spacing with no values.');\n    }\n    if (values.length === 0) {\n      throw new Error('Cannot create spacing with empty values.');\n    }\n    const valueCheck = function (val) {\n      return !isNaN(val) && val !== 0;\n    };\n    if (!values.every(valueCheck)) {\n      throw new Error('Cannot create spacing with non number or zero values.');\n    }\n    this.#values = values;\n  }\n\n  /**\n   * Get the spacing value at the given array index.\n   *\n   * @param {number} i The index to get.\n   * @returns {number} The value.\n   */\n  get(i) {\n    return this.#values[i];\n  }\n\n  /**\n   * Get the length of the spacing.\n   *\n   * @returns {number} The length.\n   */\n  length() {\n    return this.#values.length;\n  }\n\n  /**\n   * Get a string representation of the spacing.\n   *\n   * @returns {string} The spacing as a string.\n   */\n  toString() {\n    return '(' + this.#values.toString() + ')';\n  }\n\n  /**\n   * Get the values of this spacing.\n   *\n   * @returns {Array} The array of values.\n   */\n  getValues() {\n    return this.#values.slice();\n  }\n\n  /**\n   * Check for equality.\n   *\n   * @param {Spacing} rhs The object to compare to.\n   * @returns {boolean} True if both objects are equal.\n   */\n  equals(rhs) {\n    // check input\n    if (!rhs) {\n      return false;\n    }\n    // check length\n    const length = this.length();\n    if (length !== rhs.length()) {\n      return false;\n    }\n    // check values\n    for (let i = 0; i < length; ++i) {\n      if (this.get(i) !== rhs.get(i)) {\n        return false;\n      }\n    }\n    // seems ok!\n    return true;\n  }\n\n  /**\n   * Get the 2D base of this size.\n   *\n   * @returns {object} The 2D base [col,row] as {x,y}.\n   */\n  get2D() {\n    return {\n      x: this.get(0),\n      y: this.get(1)\n    };\n  }\n\n} // Spacing class\n","import {\n  BIG_EPSILON,\n  isSimilar,\n  getIdentityMat33\n} from '../math/matrix';\nimport {Point3D, Point} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {Index} from '../math/index';\nimport {logger} from '../utils/logger';\nimport {Size} from './size';\nimport {Spacing} from './spacing';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * 2D/3D Geometry class.\n */\nexport class Geometry {\n\n  /**\n   * Array of origins.\n   *\n   * @type {Array}\n   */\n  #origins;\n\n  /**\n   * Data size.\n   *\n   * @type {Size}\n   */\n  #size;\n\n  /**\n   * Data spacing.\n   *\n   * @type {Spacing}\n   */\n  #spacing;\n\n  /**\n   * Local helper object for time points.\n   *\n   * @type {object}\n   */\n  #timeOrigins = {};\n\n  /**\n   * Initial time index.\n   *\n   * @type {number}\n   */\n  #initialTime;\n\n  /**\n   * Data orientation.\n   *\n   * @type {Matrix33}\n   */\n  #orientation = getIdentityMat33();\n\n  /**\n   * Flag to know if new origins were added.\n   *\n   * @type {boolean}\n   */\n  #newOrigins = false;\n\n  /**\n   * @param {Point3D} origin The object origin (a 3D point).\n   * @param {Size} size The object size.\n   * @param {Spacing} spacing The object spacing.\n   * @param {Matrix33} [orientation] The object orientation (3*3 matrix,\n   *   default to 3*3 identity).\n   * @param {number} [time] Optional time index.\n   */\n  constructor(origin, size, spacing, orientation, time) {\n    this.#origins = [origin];\n    this.#size = size;\n    this.#spacing = spacing;\n    if (typeof time !== 'undefined') {\n      this.#initialTime = time;\n      this.#timeOrigins[time] = [origin];\n    }\n    // check input orientation\n    if (typeof orientation !== 'undefined') {\n      this.#orientation = orientation;\n    }\n  }\n\n  /**\n   * Get the time value that was passed at construction.\n   *\n   * @returns {number} The time value.\n   */\n  getInitialTime() {\n    return this.#initialTime;\n  }\n\n  /**\n   * Get the total number of slices.\n   * Can be different from what is stored in the size object\n   *  during a volume with time points creation process.\n   *\n   * @returns {number} The total count.\n   */\n  getCurrentTotalNumberOfSlices() {\n    const keys = Object.keys(this.#timeOrigins);\n    if (keys.length === 0) {\n      return this.#origins.length;\n    }\n    let count = 0;\n    for (let i = 0; i < keys.length; ++i) {\n      count += this.#timeOrigins[keys[i]].length;\n    }\n    return count;\n  }\n\n  /**\n   * Check if a time point has associated slices.\n   *\n   * @param {number} time The time point to check.\n   * @returns {boolean} True if slices are present.\n   */\n  hasSlicesAtTime(time) {\n    return typeof this.#timeOrigins[time] !== 'undefined';\n  }\n\n  /**\n   * Get the number of slices stored for time points preceding\n   * the input one.\n   *\n   * @param {number} time The time point to check.\n   * @returns {number|undefined} The count.\n   */\n  getCurrentNumberOfSlicesBeforeTime(time) {\n    const keys = Object.keys(this.#timeOrigins);\n    if (keys.length === 0) {\n      return undefined;\n    }\n    let count = 0;\n    for (let i = 0; i < keys.length; ++i) {\n      const key = keys[i];\n      if (parseInt(key, 10) === time) {\n        break;\n      }\n      count += this.#timeOrigins[key].length;\n    }\n    return count;\n  }\n\n  /**\n   * Get the object origin.\n   * This should be the lowest origin to ease calculations (?).\n   *\n   * @returns {Point3D} The object origin.\n   */\n  getOrigin() {\n    return this.#origins[0];\n  }\n\n  /**\n   * Get the object origins.\n   *\n   * @returns {Array} The object origins.\n   */\n  getOrigins() {\n    return this.#origins;\n  }\n\n  /**\n   * Check if a point is in the origin list.\n   *\n   * @param {Point3D} point3D The point to check.\n   * @param {number} tol The comparison tolerance\n   *   default to Number.EPSILON.\n   * @returns {boolean} True if in list.\n   */\n  includesOrigin(point3D, tol) {\n    for (let i = 0; i < this.#origins.length; ++i) {\n      if (this.#origins[i].isSimilar(point3D, tol)) {\n        return true;\n      }\n    }\n    return false;\n  }\n\n  /**\n   * Get the object size.\n   * Warning: the size comes as stored in DICOM, meaning that it could\n   * be oriented.\n   *\n   * @param {Matrix33} [viewOrientation] The view orientation (optional)\n   * @returns {Size} The object size.\n   */\n  getSize(viewOrientation) {\n    let res = this.#size;\n    if (viewOrientation && typeof viewOrientation !== 'undefined') {\n      let values = getOrientedArray3D(\n        [\n          this.#size.get(0),\n          this.#size.get(1),\n          this.#size.get(2)\n        ],\n        viewOrientation);\n      values = values.map(Math.abs);\n      res = new Size(values.concat(this.#size.getValues().slice(3)));\n    }\n    return res;\n  }\n\n  /**\n   * Calculate slice spacing from origins and replace current\n   *   if needed.\n   */\n  #updateSliceSpacing() {\n    const geoSliceSpacing = getSliceGeometrySpacing(\n      this.#origins,\n      this.#orientation\n    );\n    // update local if needed\n    if (typeof geoSliceSpacing !== 'undefined' &&\n      this.#spacing.get(2) !== geoSliceSpacing) {\n      logger.trace('Updating slice spacing.');\n      const values = this.#spacing.getValues();\n      values[2] = geoSliceSpacing;\n      this.#spacing = new Spacing(values);\n    }\n  }\n\n  /**\n   * Get the object spacing.\n   * Warning: the spacing comes as stored in DICOM, meaning that it could\n   * be oriented.\n   *\n   * @param {Matrix33} [viewOrientation] The view orientation (optional)\n   * @returns {Spacing} The object spacing.\n   */\n  getSpacing(viewOrientation) {\n    // update slice spacing after appendSlice\n    if (this.#newOrigins) {\n      this.#updateSliceSpacing();\n      this.#newOrigins = false;\n    }\n    let res = this.#spacing;\n    if (viewOrientation && typeof viewOrientation !== 'undefined') {\n      let orientedValues = getOrientedArray3D(\n        [\n          this.#spacing.get(0),\n          this.#spacing.get(1),\n          this.#spacing.get(2)\n        ],\n        viewOrientation);\n      orientedValues = orientedValues.map(Math.abs);\n      res = new Spacing(orientedValues);\n    }\n    return res;\n  }\n\n  /**\n   * Get the image spacing in real world.\n   *\n   * @returns {Spacing} The object spacing.\n   */\n  getRealSpacing() {\n    // asOneAndZeros to not change spacing values...\n    return this.getSpacing(\n      this.#orientation.getInverse().asOneAndZeros()\n    );\n  }\n\n  /**\n   * Get the object orientation.\n   *\n   * @returns {Matrix33} The object orientation.\n   */\n  getOrientation() {\n    return this.#orientation;\n  }\n\n  /**\n   * Get the slice position of a point in the current slice layout.\n   * Slice indices increase with decreasing origins (high index -> low origin),\n   * this simplified the handling of reconstruction since it means\n   * the displayed data is in the same 'direction' as the extracted data.\n   * As seen in the getOrigin method, the main origin is the lowest one.\n   * This implies that the index to world and reverse method do some flipping\n   * magic...\n   *\n   * @param {Point3D} point The point to evaluate.\n   * @param {number} time Optional time index.\n   * @returns {number} The slice index.\n   */\n  getSliceIndex(point, time) {\n    // cannot use this.worldToIndex(point).getK() since\n    // we cannot guaranty consecutive slices...\n\n    let localOrigins = this.#origins;\n    if (typeof time !== 'undefined') {\n      localOrigins = this.#timeOrigins[time];\n    }\n\n    // find the closest index\n    let closestSliceIndex = 0;\n    let minDist = point.getDistance(localOrigins[0]);\n    let dist = 0;\n    for (let i = 0; i < localOrigins.length; ++i) {\n      dist = point.getDistance(localOrigins[i]);\n      if (dist < minDist) {\n        minDist = dist;\n        closestSliceIndex = i;\n      }\n    }\n    const closestOrigin = localOrigins[closestSliceIndex];\n    // direction between the input point and the closest origin\n    const pointDir = point.minus(closestOrigin);\n    // use third orientation matrix column as base plane vector\n    const normal = new Vector3D(\n      this.#orientation.get(0, 2),\n      this.#orientation.get(1, 2),\n      this.#orientation.get(2, 2)\n    );\n    // a.dot(b) = ||a|| * ||b|| * cos(theta)\n    // (https://en.wikipedia.org/wiki/Dot_product#Geometric_definition)\n    // -> the sign of the dot product depends on the cosinus of\n    //    the angle between the vectors\n    //   -> >0 => vectors are codirectional\n    //   -> <0 => vectors are opposite\n    const dotProd = normal.dotProduct(pointDir);\n    // oposite vectors get higher index\n    const sliceIndex = dotProd > 0 ? closestSliceIndex + 1 : closestSliceIndex;\n    return sliceIndex;\n  }\n\n  /**\n   * Append an origin to the geometry.\n   *\n   * @param {Point3D} origin The origin to append.\n   * @param {number} index The index at which to append.\n   * @param {number} [time] Optional time index.\n   */\n  appendOrigin(origin, index, time) {\n    if (typeof time !== 'undefined') {\n      this.#timeOrigins[time].splice(index, 0, origin);\n    }\n    if (typeof time === 'undefined' || time === this.#initialTime) {\n      this.#newOrigins = true;\n      // add in origin array\n      this.#origins.splice(index, 0, origin);\n      // increment second dimension\n      const values = this.#size.getValues();\n      values[2] += 1;\n      this.#size = new Size(values);\n    }\n  }\n\n  /**\n   * Append a frame to the geometry.\n   *\n   * @param {Point3D} origin The origin to append.\n   * @param {number} time Optional time index.\n   */\n  appendFrame(origin, time) {\n    // add origin to list\n    this.#timeOrigins[time] = [origin];\n    // increment third dimension\n    const sizeValues = this.#size.getValues();\n    const spacingValues = this.#spacing.getValues();\n    if (sizeValues.length === 4) {\n      sizeValues[3] += 1;\n    } else {\n      sizeValues.push(2);\n      spacingValues.push(1);\n    }\n    this.#size = new Size(sizeValues);\n    this.#spacing = new Spacing(spacingValues);\n  }\n\n  /**\n   * Get a string representation of the geometry.\n   *\n   * @returns {string} The geometry as a string.\n   */\n  toString() {\n    return 'Origin: ' + this.getOrigin() +\n      ', Size: ' + this.getSize() +\n      ', Spacing: ' + this.getSpacing() +\n      ', Orientation: ' + this.getOrientation();\n  }\n\n  /**\n   * Check for equality.\n   *\n   * @param {Geometry} rhs The object to compare to.\n   * @returns {boolean} True if both objects are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getOrigin().equals(rhs.getOrigin()) &&\n      this.getSize().equals(rhs.getSize()) &&\n      this.getSpacing().equals(rhs.getSpacing());\n  }\n\n  /**\n   * Check that a point is within bounds.\n   *\n   * @param {Point} point The point to check.\n   * @returns {boolean} True if the given coordinates are within bounds.\n   */\n  isInBounds(point) {\n    return this.isIndexInBounds(this.worldToIndex(point));\n  }\n\n  /**\n   * Check that a index is within bounds.\n   *\n   * @param {Index} index The index to check.\n   * @param {Array} [dirs] Optional list of directions to check.\n   * @returns {boolean} True if the given coordinates are within bounds.\n   */\n  isIndexInBounds(index, dirs) {\n    return this.getSize().isInBounds(index, dirs);\n  }\n\n  /**\n   * Convert an index into world coordinates.\n   *\n   * @param {Index} index The index to convert.\n   * @returns {Point} The corresponding point.\n   */\n  indexToWorld(index) {\n    // apply spacing\n    // (spacing is oriented, apply before orientation)\n    const spacing = this.getSpacing();\n    const orientedPoint3D = new Point3D(\n      index.get(0) * spacing.get(0),\n      index.get(1) * spacing.get(1),\n      index.get(2) * spacing.get(2)\n    );\n    // de-orient\n    const point3D = this.getOrientation().multiplyPoint3D(orientedPoint3D);\n    // keep >3d values\n    const values = index.getValues();\n    const origin = this.getOrigin();\n    values[0] = origin.getX() + point3D.getX();\n    values[1] = origin.getY() + point3D.getY();\n    values[2] = origin.getZ() + point3D.getZ();\n    // return point\n    return new Point(values);\n  }\n\n  /**\n   * Convert a 3D point into world coordinates.\n   *\n   * @param {Point3D} point The 3D point to convert.\n   * @returns {Point3D} The corresponding world 3D point.\n   */\n  pointToWorld(point) {\n    // apply spacing\n    // (spacing is oriented, apply before orientation)\n    const spacing = this.getSpacing();\n    const orientedPoint3D = new Point3D(\n      point.getX() * spacing.get(0),\n      point.getY() * spacing.get(1),\n      point.getZ() * spacing.get(2)\n    );\n    // de-orient\n    const point3D = this.getOrientation().multiplyPoint3D(orientedPoint3D);\n    // return point3D\n    const origin = this.getOrigin();\n    return new Point3D(\n      origin.getX() + point3D.getX(),\n      origin.getY() + point3D.getY(),\n      origin.getZ() + point3D.getZ()\n    );\n  }\n\n  /**\n   * Convert world coordinates into an index.\n   *\n   * @param {Point} point The point to convert.\n   * @returns {Index} The corresponding index.\n   */\n  worldToIndex(point) {\n    // compensate for origin\n    // (origin is not oriented, compensate before orientation)\n    // TODO: use slice origin...\n    const origin = this.getOrigin();\n    const point3D = new Point3D(\n      point.get(0) - origin.getX(),\n      point.get(1) - origin.getY(),\n      point.get(2) - origin.getZ()\n    );\n    // orient\n    const orientedPoint3D =\n      this.getOrientation().getInverse().multiplyPoint3D(point3D);\n    // keep >3d values\n    const values = point.getValues();\n    // apply spacing and round\n    const spacing = this.getSpacing();\n    values[0] = Math.round(orientedPoint3D.getX() / spacing.get(0));\n    values[1] = Math.round(orientedPoint3D.getY() / spacing.get(1));\n    values[2] = Math.round(orientedPoint3D.getZ() / spacing.get(2));\n\n    // return index\n    return new Index(values);\n  }\n\n  /**\n   * Convert world coordinates into an point.\n   *\n   * @param {Point} point The world point to convert.\n   * @returns {Point3D} The corresponding point.\n   */\n  worldToPoint(point) {\n    // compensate for origin\n    // (origin is not oriented, compensate before orientation)\n    const origin = this.getOrigin();\n    const point3D = new Point3D(\n      point.get(0) - origin.getX(),\n      point.get(1) - origin.getY(),\n      point.get(2) - origin.getZ()\n    );\n    // orient\n    const orientedPoint3D =\n      this.getOrientation().getInverse().multiplyPoint3D(point3D);\n    // keep >3d values\n    const values = point.getValues();\n    // apply spacing and round\n    const spacing = this.getSpacing();\n    values[0] = orientedPoint3D.getX() / spacing.get(0);\n    values[1] = orientedPoint3D.getY() / spacing.get(1);\n    values[2] = orientedPoint3D.getZ() / spacing.get(2);\n\n    // return index\n    return new Point3D(values[0], values[1], values[2]);\n  }\n\n} // class Geometry\n\n/**\n * Get the oriented values of an input 3D array.\n *\n * @param {Array} array3D The 3D array.\n * @param {Matrix33} orientation The orientation 3D matrix.\n * @returns {Array} The values reordered according to the orientation.\n */\nexport function getOrientedArray3D(array3D, orientation) {\n  // values = orientation * orientedValues\n  // -> inv(orientation) * values = orientedValues\n  return orientation.getInverse().multiplyArray3D(array3D);\n}\n\n/**\n * Get the raw values of an oriented input 3D array.\n *\n * @param {Array} array3D The 3D array.\n * @param {Matrix33} orientation The orientation 3D matrix.\n * @returns {Array} The values reordered to compensate the orientation.\n */\nexport function getDeOrientedArray3D(array3D, orientation) {\n  // values = orientation * orientedValues\n  return orientation.multiplyArray3D(array3D);\n}\n\n/**\n * Get the slice spacing from the difference in the Z directions\n * of input origins.\n *\n * @param {Array} origins An array of Point3D.\n * @param {Matrix33} orientation The oritentation matrix.\n * @param {boolean} [withCheck] Flag to activate spacing variation check,\n *   default to true.\n * @returns {number|undefined} The spacing.\n */\nexport function getSliceGeometrySpacing(origins, orientation, withCheck) {\n  if (typeof withCheck === 'undefined') {\n    withCheck = true;\n  }\n  // check origins\n  if (origins.length <= 1) {\n    return;\n  }\n  // (x, y, z) = orientationMatrix * (i, j, k)\n  // -> inv(orientationMatrix) * (x, y, z) = (i, j, k)\n  // applied on the patient position, reorders indices\n  // so that Z is the slice direction\n  const invOrientation = orientation.getInverse();\n  let origin1 = invOrientation.multiplyVector3D(origins[0]);\n  let origin2 = invOrientation.multiplyVector3D(origins[1]);\n  let sliceSpacing = Math.abs(origin1.getZ() - origin2.getZ());\n  const deltas = [];\n  for (let i = 0; i < origins.length - 1; ++i) {\n    origin1 = invOrientation.multiplyVector3D(origins[i]);\n    origin2 = invOrientation.multiplyVector3D(origins[i + 1]);\n    const diff = Math.abs(origin1.getZ() - origin2.getZ());\n    if (diff === 0) {\n      throw new Error('Zero slice spacing.' +\n        origin1.toString() + ' ' + origin2.toString());\n    }\n    // keep smallest\n    if (diff < sliceSpacing) {\n      sliceSpacing = diff;\n    }\n    if (withCheck) {\n      if (!isSimilar(sliceSpacing, diff, BIG_EPSILON)) {\n        deltas.push(Math.abs(sliceSpacing - diff));\n      }\n    }\n  }\n  // warn if non constant\n  if (withCheck && deltas.length !== 0) {\n    const sumReducer = function (sum, value) {\n      return sum + value;\n    };\n    const mean = deltas.reduce(sumReducer) / deltas.length;\n    if (mean > 1e-4) {\n      logger.warn('Varying slice spacing, mean delta: ' +\n        mean.toFixed(3) + ' (' + deltas.length + ' case(s))');\n    }\n  }\n\n  return sliceSpacing;\n}\n","import {\n  DicomParser,\n  getTransferSyntaxName\n} from './dicomParser';\nimport {\n  isPixelDataTag,\n  isItemDelimitationItemTag,\n  isSequenceDelimitationItemTag,\n  getItemTag,\n  getItemDelimitationItemTag,\n  getSequenceDelimitationItemTag,\n  getPixelDataTag,\n  getTagFromDictionary,\n  getTagFromKey\n} from './dicomTag';\nimport {isNativeLittleEndian} from './dataReader';\nimport {Spacing} from '../image/spacing';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Tag} from './dicomTag';\nimport {DataElement} from './dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * DicomElements wrapper.\n *\n * Warning: limited support for merged meta data.\n */\nexport class DicomElementsWrapper {\n\n  /**\n   * Wrapped elements.\n   *\n   * @type {Array}\n   */\n  #dicomElements;\n\n  /**\n   * @param {Array} dicomElements The elements to wrap.\n   */\n  constructor(dicomElements) {\n    this.#dicomElements = dicomElements;\n  }\n\n  /**\n   * Get a DICOM Element value from a group/element key.\n   *\n   * @param {string} groupElementKey The key to retrieve.\n   * @param {boolean} [asArray] Get the value as an Array.\n   * @returns {object} The DICOM element value.\n   */\n  getFromKey(groupElementKey, asArray) {\n    // default\n    if (typeof asArray === 'undefined') {\n      asArray = false;\n    }\n    let value = null;\n    const dElement = this.#dicomElements[groupElementKey];\n    if (typeof dElement !== 'undefined') {\n      // raw value if only one\n      if (dElement.value.length === 1 && asArray === false) {\n        value = dElement.value[0];\n      } else {\n        value = dElement.value;\n      }\n    }\n    return value;\n  }\n\n  /**\n   * Dump the DICOM tags to an object.\n   *\n   * @returns {object} The DICOM tags as an object.\n   */\n  dumpToObject() {\n    const keys = Object.keys(this.#dicomElements);\n    const obj = {};\n    let dicomElement = null;\n    for (let i = 0, leni = keys.length; i < leni; ++i) {\n      dicomElement = this.#dicomElements[keys[i]];\n      const tag = getTagFromKey(keys[i]);\n      obj[this.#getTagName(tag)] =\n        this.#getElementAsObject(tag, dicomElement);\n    }\n    return obj;\n  }\n\n  /**\n   * Get a tag string name from the dictionary.\n   *\n   * @param {object} tag The DICOM tag object.\n   * @returns {string} The tag name.\n   */\n  #getTagName(tag) {\n    let name = tag.getNameFromDictionary();\n    if (name === null) {\n      name = tag.getKey();\n    }\n    return name;\n  }\n\n  /**\n   * Get a DICOM element as a simple object.\n   *\n   * @param {Tag} tag The DICOM tag.\n   * @param {object} dicomElement The DICOM element.\n   * @returns {object} The element as a simple object.\n   */\n  #getElementAsObject(tag, dicomElement) {\n    // element value\n    let value = null;\n\n    const isPixel = isPixelDataTag(tag);\n\n    const vr = dicomElement.vr;\n    if (vr === 'SQ' &&\n      typeof dicomElement.value !== 'undefined' &&\n      !isPixel) {\n      value = [];\n      const items = dicomElement.value;\n      let itemValues = null;\n      for (let i = 0; i < items.length; ++i) {\n        itemValues = {};\n        const keys = Object.keys(items[i]);\n        for (let k = 0; k < keys.length; ++k) {\n          const itemElement = items[i][keys[k]];\n          const tag = getTagFromKey(keys[k]);\n          const key = this.#getTagName(tag);\n          // do not inclure Item elements\n          if (key !== 'Item') {\n            itemValues[key] = this.#getElementAsObject(tag, itemElement);\n          }\n        }\n        value.push(itemValues);\n      }\n    } else {\n      value = this.#getElementValueAsString(tag, dicomElement);\n    }\n\n    // return\n    return {\n      value: value,\n      vr: vr\n    };\n  }\n\n  /**\n   * Dump the DICOM tags to a string.\n   *\n   * @returns {string} The dumped file.\n   */\n  dump() {\n    const keys = Object.keys(this.#dicomElements);\n    let result = '\\n';\n    result += '# Dicom-File-Format\\n';\n    result += '\\n';\n    result += '# Dicom-Meta-Information-Header\\n';\n    result += '# Used TransferSyntax: ';\n    if (isNativeLittleEndian()) {\n      result += 'Little Endian Explicit\\n';\n    } else {\n      result += 'NOT Little Endian Explicit\\n';\n    }\n    let dicomElement = null;\n    let tag = null;\n    let checkHeader = true;\n    for (let i = 0, leni = keys.length; i < leni; ++i) {\n      dicomElement = this.#dicomElements[keys[i]];\n      tag = getTagFromKey(keys[i]);\n      if (checkHeader && tag.getGroup() !== '0002') {\n        result += '\\n';\n        result += '# Dicom-Data-Set\\n';\n        result += '# Used TransferSyntax: ';\n        const syntax = this.#dicomElements['00020010'].value[0];\n        result += getTransferSyntaxName(syntax);\n        result += '\\n';\n        checkHeader = false;\n      }\n      result += this.#getElementAsString(tag, dicomElement) + '\\n';\n    }\n    return result;\n  }\n\n  /**\n   * Get a data element value as a string.\n   *\n   * @param {Tag} tag The DICOM tag.\n   * @param {object} dicomElement The DICOM element.\n   * @param {boolean} [pretty] When set to true, returns a 'pretified' content.\n   * @returns {string} A string representation of the DICOM element.\n   */\n  #getElementValueAsString(tag, dicomElement, pretty) {\n    let str = '';\n    const strLenLimit = 65;\n\n    // dafault to pretty output\n    if (typeof pretty === 'undefined') {\n      pretty = true;\n    }\n    // check dicom element input\n    if (typeof dicomElement === 'undefined' || dicomElement === null) {\n      return str;\n    }\n\n    // Polyfill for Number.isInteger.\n    const isInteger = Number.isInteger || function (value) {\n      return typeof value === 'number' &&\n        isFinite(value) &&\n        Math.floor(value) === value;\n    };\n\n    // TODO Support sequences.\n\n    if (dicomElement.vr !== 'SQ' &&\n      dicomElement.value.length === 1 && dicomElement.value[0] === '') {\n      str += '(no value available)';\n    } else if (isPixelDataTag(tag) &&\n      dicomElement.undefinedLength) {\n      str = '(PixelSequence)';\n    } else if (dicomElement.vr === 'DA' && pretty) {\n      const daObj = getDate(dicomElement);\n      const da = new Date(daObj.year, daObj.monthIndex, daObj.day);\n      str = da.toLocaleDateString();\n    } else if (dicomElement.vr === 'TM' && pretty) {\n      const tmObj = getTime(dicomElement);\n      str = tmObj.hours + ':' + tmObj.minutes + ':' + tmObj.seconds;\n    } else {\n      let isOtherVR = false;\n      if (dicomElement.vr.length !== 0) {\n        isOtherVR = (dicomElement.vr[0].toUpperCase() === 'O');\n      }\n      const isFloatNumberVR = (dicomElement.vr === 'FL' ||\n        dicomElement.vr === 'FD' ||\n        dicomElement.vr === 'DS');\n      let valueStr = '';\n      for (let k = 0, lenk = dicomElement.value.length; k < lenk; ++k) {\n        valueStr = '';\n        if (k !== 0) {\n          valueStr += '\\\\';\n        }\n        if (isFloatNumberVR) {\n          const num = Number(dicomElement.value[k]);\n          if (!isInteger(num) && pretty) {\n            valueStr += num.toPrecision(4);\n          } else {\n            valueStr += num.toString();\n          }\n        } else if (isOtherVR) {\n          let tmp = dicomElement.value[k].toString(16);\n          if (dicomElement.vr === 'OB') {\n            tmp = '00'.substring(0, 2 - tmp.length) + tmp;\n          } else {\n            tmp = '0000'.substring(0, 4 - tmp.length) + tmp;\n          }\n          valueStr += tmp;\n        } else {\n          valueStr += dicomElement.value[k];\n        }\n        // check length\n        if (str.length + valueStr.length <= strLenLimit) {\n          str += valueStr;\n        } else {\n          str += '...';\n          break;\n        }\n      }\n    }\n    return str;\n  }\n\n  /**\n   * Get a data element as a string.\n   *\n   * @param {Tag} tag The DICOM tag.\n   * @param {object} dicomElement The DICOM element.\n   * @param {string} [prefix] A string to prepend this one.\n   * @returns {string} The element as a string.\n   */\n  #getElementAsString(tag, dicomElement, prefix) {\n    // default prefix\n    prefix = prefix || '';\n\n    // get tag anme from dictionary\n    const tagName = tag.getNameFromDictionary();\n\n    let deSize = dicomElement.value.length;\n    let isOtherVR = false;\n    if (dicomElement.vr.length !== 0) {\n      isOtherVR = (dicomElement.vr[0].toUpperCase() === 'O');\n    }\n\n    // no size for delimitations\n    if (isItemDelimitationItemTag(tag) ||\n      isSequenceDelimitationItemTag(tag)) {\n      deSize = 0;\n    } else if (isOtherVR) {\n      deSize = 1;\n    }\n\n    const isPixSequence = (isPixelDataTag(tag) &&\n      dicomElement.undefinedLength);\n\n    let line = null;\n\n    // (group,element)\n    line = '(';\n    line += tag.getGroup().toLowerCase();\n    line += ',';\n    line += tag.getElement().toLowerCase();\n    line += ') ';\n    // value representation\n    line += dicomElement.vr;\n    // value\n    if (dicomElement.vr !== 'SQ' &&\n      dicomElement.value.length === 1 &&\n      dicomElement.value[0] === '') {\n      line += ' (no value available)';\n      deSize = 0;\n    } else {\n      // simple number display\n      if (dicomElement.vr === 'na') {\n        line += ' ';\n        line += dicomElement.value[0];\n      } else if (isPixSequence) {\n        // pixel sequence\n        line += ' (PixelSequence #=' + deSize + ')';\n      } else if (dicomElement.vr === 'SQ') {\n        line += ' (Sequence with';\n        if (dicomElement.undefinedLength) {\n          line += ' undefined';\n        } else {\n          line += ' explicit';\n        }\n        line += ' length #=';\n        line += dicomElement.value.length;\n        line += ')';\n      } else if (isOtherVR ||\n          dicomElement.vr === 'pi' ||\n          dicomElement.vr === 'UL' ||\n          dicomElement.vr === 'US' ||\n          dicomElement.vr === 'SL' ||\n          dicomElement.vr === 'SS' ||\n          dicomElement.vr === 'FL' ||\n          dicomElement.vr === 'FD' ||\n          dicomElement.vr === 'AT') {\n        // 'O'ther array, limited display length\n        line += ' ';\n        line += this.#getElementValueAsString(tag, dicomElement, false);\n      } else {\n        // default\n        line += ' [';\n        line += this.#getElementValueAsString(tag, dicomElement, false);\n        line += ']';\n      }\n    }\n\n    // align #\n    const nSpaces = 55 - line.length;\n    if (nSpaces > 0) {\n      for (let s = 0; s < nSpaces; ++s) {\n        line += ' ';\n      }\n    }\n    line += ' # ';\n    if (dicomElement.vl < 100) {\n      line += ' ';\n    }\n    if (dicomElement.vl < 10) {\n      line += ' ';\n    }\n    line += dicomElement.vl;\n    line += ', ';\n    line += deSize; //dictElement[1];\n    line += ' ';\n    if (tagName !== null) {\n      line += tagName;\n    } else {\n      line += 'Unknown Tag & Data';\n    }\n\n    let message = null;\n\n    // continue for sequence\n    if (dicomElement.vr === 'SQ') {\n      let item = null;\n      for (let l = 0, lenl = dicomElement.value.length; l < lenl; ++l) {\n        item = dicomElement.value[l];\n        const itemKeys = Object.keys(item);\n        if (itemKeys.length === 0) {\n          continue;\n        }\n\n        // get the item element\n        const itemTag = getItemTag();\n        const itemElement = item['FFFEE000'];\n        message = '(Item with';\n        if (itemElement.undefinedLength) {\n          message += ' undefined';\n        } else {\n          message += ' explicit';\n        }\n        message += ' length #=' + (itemKeys.length - 1) + ')';\n        itemElement.value = [message];\n        itemElement.vr = 'na';\n\n        line += '\\n';\n        line += this.#getElementAsString(itemTag, itemElement, prefix + '  ');\n\n        for (let m = 0, lenm = itemKeys.length; m < lenm; ++m) {\n          const itemTag = getTagFromKey(itemKeys[m]);\n          if (itemKeys[m] !== 'xFFFEE000') {\n            line += '\\n';\n            line += this.#getElementAsString(itemTag, item[itemKeys[m]],\n              prefix + '    ');\n          }\n        }\n\n        message = '(ItemDelimitationItem';\n        if (!itemElement.undefinedLength) {\n          message += ' for re-encoding';\n        }\n        message += ')';\n        const itemDelimTag = getItemDelimitationItemTag();\n        const itemDelimElement = {\n          vr: 'na',\n          vl: '0',\n          value: [message]\n        };\n        line += '\\n';\n        line += this.#getElementAsString(\n          itemDelimTag, itemDelimElement, prefix + '  ');\n\n      }\n\n      message = '(SequenceDelimitationItem';\n      if (!dicomElement.undefinedLength) {\n        message += ' for re-encod.';\n      }\n      message += ')';\n      const sqDelimTag = getSequenceDelimitationItemTag();\n      const sqDelimElement = {\n        vr: 'na',\n        vl: '0',\n        value: [message]\n      };\n      line += '\\n';\n      line += this.#getElementAsString(sqDelimTag, sqDelimElement, prefix);\n    } else if (isPixSequence) {\n      // pixel sequence\n      let pixItem = null;\n      for (let n = 0, lenn = dicomElement.value.length; n < lenn; ++n) {\n        pixItem = dicomElement.value[n];\n        line += '\\n';\n        pixItem.vr = 'pi';\n        line += this.#getElementAsString(\n          getPixelDataTag(), pixItem, prefix + '  ');\n      }\n\n      const pixDelimTag = getSequenceDelimitationItemTag();\n      const pixDelimElement = {\n        vr: 'na',\n        vl: '0',\n        value: ['(SequenceDelimitationItem)']\n      };\n      line += '\\n';\n      line += this.#getElementAsString(pixDelimTag, pixDelimElement, prefix);\n    }\n\n    return prefix + line;\n  }\n\n  /**\n   * Get a DICOM Element value from a tag name.\n   * Uses the DICOM dictionary.\n   *\n   * @param {string} name The tag name.\n   * @returns {object} The DICOM element value.\n   */\n  getFromName(name) {\n    let value = null;\n    const tag = getTagFromDictionary(name);\n    // check that we are not at the end of the dictionary\n    if (tag !== null) {\n      value = this.getFromKey(tag.getKey());\n    }\n    return value;\n  }\n\n} // class DicomElementsWrapper\n\n/**\n * Extract the 2D size from dicom elements.\n *\n * @param {object} elements The DICOM elements.\n * @returns {object} The size.\n */\nexport function getImage2DSize(elements) {\n  // rows\n  const rows = elements['00280010'];\n  if (typeof rows === 'undefined') {\n    throw new Error('Missing DICOM image number of rows');\n  }\n  if (rows.value.length === 0) {\n    throw new Error('Empty DICOM image number of rows');\n  }\n  // columns\n  const columns = elements['00280011'];\n  if (typeof columns === 'undefined') {\n    throw new Error('Missing DICOM image number of columns');\n  }\n  if (columns.value.length === 0) {\n    throw new Error('Empty DICOM image number of columns');\n  }\n  return [columns.value[0], rows.value[0]];\n}\n\n/**\n * Get the pixel spacing from the different spacing tags.\n *\n * @param {object} elements The DICOM elements.\n * @returns {object} The read spacing or the default [1,1].\n */\nexport function getPixelSpacing(elements) {\n  // default\n  let rowSpacing = 1;\n  let columnSpacing = 1;\n\n  // 1. PixelSpacing\n  // 2. ImagerPixelSpacing\n  // 3. NominalScannedPixelSpacing\n  // 4. PixelAspectRatio\n  const keys = ['00280030', '00181164', '00182010', '00280034'];\n  for (let k = 0; k < keys.length; ++k) {\n    const spacing = elements[keys[k]];\n    if (spacing && spacing.value.length === 2) {\n      rowSpacing = parseFloat(spacing.value[0]);\n      columnSpacing = parseFloat(spacing.value[1]);\n      break;\n    }\n  }\n\n  // check\n  if (columnSpacing === 0) {\n    logger.warn('Zero column spacing.');\n    columnSpacing = 1;\n  }\n  if (rowSpacing === 0) {\n    logger.warn('Zero row spacing.');\n    rowSpacing = 1;\n  }\n\n  // return\n  // (slice spacing will be calculated using the image position patient)\n  return new Spacing([columnSpacing, rowSpacing, 1]);\n}\n\n/**\n * Get the pixel data unit.\n *\n * @param {object} elements The DICOM elements.\n * @returns {string|null} The unit value if available.\n */\nexport function getPixelUnit(elements) {\n  let unit;\n  // 1. RescaleType\n  // 2. Units (for PET)\n  const keys = ['00281054', '00541001'];\n  for (let i = 0; i < keys.length; ++i) {\n    const element = elements[keys[i]];\n    if (typeof element !== 'undefined') {\n      unit = element.value[0];\n    }\n  }\n  // default rescale type for CT\n  if (typeof unit !== 'undefined') {\n    const modality = elements['00080060'].value[0];\n    if (modality === 'CT') {\n      unit = 'HU';\n    }\n  }\n  return unit;\n}\n\n/**\n * Get a 'date' object with {year, monthIndex, day} ready for the\n *   Date constructor from a DICOM element with vr=DA.\n *\n * @param {object} element The DICOM element with date information.\n * @returns {{year, monthIndex, day}|undefined} The 'date' object.\n */\nexport function getDate(element) {\n  if (typeof element === 'undefined') {\n    return undefined;\n  }\n  if (element.value.length !== 1) {\n    return undefined;\n  }\n  const daValue = element.value[0];\n  // Two possible formats:\n  // - standard 'YYYYMMDD'\n  // - non-standard 'YYYY.MM.DD' (previous ACR-NEMA)\n  let monthBeginIndex = 4;\n  let dayBeginIndex = 6;\n  if (daValue.length === 10) {\n    monthBeginIndex = 5;\n    dayBeginIndex = 8;\n  }\n  const daYears = parseInt(daValue.substring(0, 4), 10);\n  // 0-11 range\n  const daMonthIndex = daValue.length >= monthBeginIndex + 2\n    ? parseInt(daValue.substring(\n      monthBeginIndex, monthBeginIndex + 2), 10) - 1 : 0;\n  const daDay = daValue.length === dayBeginIndex + 2\n    ? parseInt(daValue.substring(\n      dayBeginIndex, dayBeginIndex + 2), 10) : 0;\n  return {\n    year: daYears,\n    monthIndex: daMonthIndex,\n    day: daDay\n  };\n}\n\n/**\n * Get a time object with {hours, minutes, seconds} ready for the\n *   Date constructor from a DICOM element with vr=TM.\n *\n * @param {object} element The DICOM element with date information.\n * @returns {{hours, minutes, seconds, milliseconds}|undefined} The time object.\n */\nexport function getTime(element) {\n  if (typeof element === 'undefined') {\n    return undefined;\n  }\n  if (element.value.length !== 1) {\n    return undefined;\n  }\n  // format: HH[MMSS.FFFFFF]\n  const tmValue = element.value[0];\n  const tmHours = parseInt(tmValue.substring(0, 2), 10);\n  const tmMinutes = tmValue.length >= 4\n    ? parseInt(tmValue.substring(2, 4), 10) : 0;\n  const tmSeconds = tmValue.length >= 6\n    ? parseInt(tmValue.substring(4, 6), 10) : 0;\n  const tmFracSecondsStr = tmValue.length >= 8\n    ? tmValue.substring(7, 10) : 0;\n  const tmMilliSeconds = tmFracSecondsStr === 0 ? 0\n    : parseInt(tmFracSecondsStr, 10) *\n      Math.pow(10, 3 - tmFracSecondsStr.length);\n  return {\n    hours: tmHours,\n    minutes: tmMinutes,\n    seconds: tmSeconds,\n    milliseconds: tmMilliSeconds\n  };\n}\n\n/**\n * Get a 'dateTime' object with {date, time} ready for the\n *   Date constructor from a DICOM element with vr=DT.\n *\n * @param {object} element The DICOM element with date-time information.\n * @returns {{date, time}|undefined} The time object.\n */\nexport function getDateTime(element) {\n  if (typeof element === 'undefined') {\n    return undefined;\n  }\n  if (element.value.length !== 1) {\n    return undefined;\n  }\n  // format: YYYYMMDDHHMMSS.FFFFFF&ZZXX\n  const dtFullValue = element.value[0];\n  // remove offset (&ZZXX)\n  const dtValue = dtFullValue.split('&')[0];\n  const dtDate = getDate({value: [dtValue.substring(0, 8)]});\n  const dtTime = dtValue.length >= 9\n    ? getTime({value: [dtValue.substring(8)]}) : undefined;\n  return {\n    date: dtDate,\n    time: dtTime\n  };\n}\n\n/**\n * Get the file list from a DICOMDIR\n *\n * @param {object} data The buffer data of the DICOMDIR\n * @returns {Array|undefined} The file list as an array ordered by\n *   STUDY > SERIES > IMAGES.\n */\nexport function getFileListFromDicomDir(data) {\n  // parse file\n  const parser = new DicomParser();\n  parser.parse(data);\n  const elements = parser.getDicomElements();\n\n  // Directory Record Sequence\n  if (typeof elements['00041220'] === 'undefined' ||\n    typeof elements['00041220'].value === 'undefined') {\n    logger.warn('No Directory Record Sequence found in DICOMDIR.');\n    return undefined;\n  }\n  const dirSeq = elements['00041220'].value;\n\n  if (dirSeq.length === 0) {\n    logger.warn('The Directory Record Sequence of the DICOMDIR is empty.');\n    return undefined;\n  }\n\n  const records = [];\n  let series = null;\n  let study = null;\n  for (let i = 0; i < dirSeq.length; ++i) {\n    // Directory Record Type\n    if (typeof dirSeq[i]['00041430'] === 'undefined' ||\n      typeof dirSeq[i]['00041430'].value === 'undefined') {\n      continue;\n    }\n    const recType = dirSeq[i]['00041430'].value[0];\n\n    // supposed to come in order...\n    if (recType === 'STUDY') {\n      study = [];\n      records.push(study);\n    } else if (recType === 'SERIES') {\n      series = [];\n      study.push(series);\n    } else if (recType === 'IMAGE') {\n      // Referenced File ID\n      if (typeof dirSeq[i]['00041500'] === 'undefined' ||\n        typeof dirSeq[i]['00041500'].value === 'undefined') {\n        continue;\n      }\n      const refFileIds = dirSeq[i]['00041500'].value;\n      // join ids\n      series.push(refFileIds.join('/'));\n    }\n  }\n  return records;\n}\n\n/**\n * Methods used to extract values from DICOM elements.\n *\n * Implemented as class and method to allow for override via its prototype.\n */\nexport class TagValueExtractor {\n  /**\n   * Get the time.\n   *\n   * @param {Object<string, DataElement>} _elements The DICOM elements.\n   * @returns {number|undefined} The time value if available.\n   */\n  getTime(_elements) {\n    // default returns undefined\n    return undefined;\n  }\n}\n","import {Size} from './size';\nimport {Geometry} from './geometry';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {WindowCenterAndWidth} from './windowCenterAndWidth';\nimport {Image} from './image';\nimport {\n  isJpeg2000TransferSyntax,\n  isJpegBaselineTransferSyntax,\n  isJpegLosslessTransferSyntax\n} from '../dicom/dicomParser';\nimport {\n  getImage2DSize,\n  getPixelSpacing,\n  getPixelUnit,\n  TagValueExtractor\n} from '../dicom/dicomElementsWrapper';\nimport {Vector3D} from '../math/vector';\nimport {Matrix33} from '../math/matrix';\nimport {Point3D} from '../math/point';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object<string, DataElement>} DataElements\n */\n\n/**\n * {@link Image} factory.\n */\nexport class ImageFactory {\n\n  /**\n   * Check dicom elements. Throws an error if not suitable.\n   *\n   * @param {DataElements} dataElements The DICOM data elements.\n   * @returns {object|undefined} A possible warning.\n   */\n  checkElements(dataElements) {\n    // will throw if columns or rows is not defined\n    getImage2DSize(dataElements);\n  }\n\n  /**\n   * Get an {@link Image} object from the read DICOM file.\n   *\n   * @param {DataElements} dataElements The DICOM tags.\n   * @param {Uint8Array | Int8Array |\n   *   Uint16Array | Int16Array |\n   *   Uint32Array | Int32Array} pixelBuffer The pixel buffer.\n   * @param {number} numberOfFiles The input number of files.\n   * @returns {Image} A new Image.\n   */\n  create(dataElements, pixelBuffer, numberOfFiles) {\n    const size2D = getImage2DSize(dataElements);\n    const sizeValues = [size2D[0], size2D[1], 1];\n\n    // frames\n    const frames = dataElements['00280008'];\n    if (frames) {\n      sizeValues.push(frames.value[0]);\n    }\n\n    // image size\n    const size = new Size(sizeValues);\n\n    // image spacing\n    const spacing = getPixelSpacing(dataElements);\n\n    // TransferSyntaxUID\n    const syntax = dataElements['00020010'].value[0];\n    const jpeg2000 = isJpeg2000TransferSyntax(syntax);\n    const jpegBase = isJpegBaselineTransferSyntax(syntax);\n    const jpegLoss = isJpegLosslessTransferSyntax(syntax);\n\n    // ImagePositionPatient\n    const imagePositionPatient = dataElements['00200032'];\n    // slice position\n    let slicePosition = new Array(0, 0, 0);\n    if (typeof imagePositionPatient !== 'undefined') {\n      slicePosition = [\n        parseFloat(imagePositionPatient.value[0]),\n        parseFloat(imagePositionPatient.value[1]),\n        parseFloat(imagePositionPatient.value[2])\n      ];\n    }\n\n    // slice orientation (cosines are matrices' columns)\n    // http://dicom.nema.org/medical/dicom/current/output/chtml/part03/sect_C.7.6.2.html#sect_C.7.6.2.1.1\n    const imageOrientationPatient = dataElements['00200037'];\n    let orientationMatrix;\n    if (typeof imageOrientationPatient !== 'undefined') {\n      const rowCosines = new Vector3D(\n        parseFloat(imageOrientationPatient.value[0]),\n        parseFloat(imageOrientationPatient.value[1]),\n        parseFloat(imageOrientationPatient.value[2]));\n      const colCosines = new Vector3D(\n        parseFloat(imageOrientationPatient.value[3]),\n        parseFloat(imageOrientationPatient.value[4]),\n        parseFloat(imageOrientationPatient.value[5]));\n      const normal = rowCosines.crossProduct(colCosines);\n      /* eslint-disable array-element-newline */\n      orientationMatrix = new Matrix33([\n        rowCosines.getX(), colCosines.getX(), normal.getX(),\n        rowCosines.getY(), colCosines.getY(), normal.getY(),\n        rowCosines.getZ(), colCosines.getZ(), normal.getZ()\n      ]);\n      /* eslint-enable array-element-newline */\n    }\n\n    // geometry\n    const origin = new Point3D(\n      slicePosition[0], slicePosition[1], slicePosition[2]);\n    const extractor = new TagValueExtractor();\n    const time = extractor.getTime(dataElements);\n    const geometry = new Geometry(\n      origin, size, spacing, orientationMatrix, time);\n\n    // SOP Instance UID\n    let sopInstanceUid;\n    const siu = dataElements['00080018'];\n    if (typeof siu !== 'undefined') {\n      sopInstanceUid = siu.value[0];\n    }\n\n    // Sample per pixels\n    let samplesPerPixel = 1;\n    const spp = dataElements['00280002'];\n    if (typeof spp !== 'undefined') {\n      samplesPerPixel = spp.value[0];\n    }\n\n    // check buffer size\n    const bufferSize = size.getTotalSize() * samplesPerPixel;\n    if (bufferSize !== pixelBuffer.length) {\n      logger.warn('Badly sized pixel buffer: ' +\n        pixelBuffer.length + ' != ' + bufferSize);\n      if (bufferSize < pixelBuffer.length) {\n        pixelBuffer = pixelBuffer.slice(0, size.getTotalSize());\n      } else {\n        throw new Error('Underestimated buffer size, can\\'t fix it...');\n      }\n    }\n\n    // image\n    const image = new Image(geometry, pixelBuffer, [sopInstanceUid]);\n    // PhotometricInterpretation\n    const photometricInterpretation = dataElements['00280004'];\n    if (typeof photometricInterpretation !== 'undefined') {\n      let photo = photometricInterpretation.value[0].toUpperCase();\n      // jpeg decoders output RGB data\n      if ((jpeg2000 || jpegBase || jpegLoss) &&\n        (photo !== 'MONOCHROME1' && photo !== 'MONOCHROME2')) {\n        photo = 'RGB';\n      }\n      // check samples per pixels\n      if (photo === 'RGB' && samplesPerPixel === 1) {\n        photo = 'PALETTE COLOR';\n      }\n      image.setPhotometricInterpretation(photo);\n    }\n    // PlanarConfiguration\n    const planarConfiguration = dataElements['00280006'];\n    if (typeof planarConfiguration !== 'undefined') {\n      image.setPlanarConfiguration(planarConfiguration.value[0]);\n    }\n\n    // rescale slope and intercept\n    let slope = 1;\n    // RescaleSlope\n    const rescaleSlope = dataElements['00281053'];\n    if (typeof rescaleSlope !== 'undefined') {\n      const value = parseFloat(rescaleSlope.value[0]);\n      if (!isNaN(value)) {\n        slope = value;\n      }\n    }\n    let intercept = 0;\n    // RescaleIntercept\n    const rescaleIntercept = dataElements['00281052'];\n    if (typeof rescaleIntercept !== 'undefined') {\n      const value = parseFloat(rescaleIntercept.value[0]);\n      if (!isNaN(value)) {\n        intercept = value;\n      }\n    }\n    const rsi = new RescaleSlopeAndIntercept(slope, intercept);\n    image.setRescaleSlopeAndIntercept(rsi);\n\n    // meta information\n    const meta = {\n      numberOfFiles: numberOfFiles\n    };\n    const modality = dataElements['00080060'];\n    if (typeof modality !== 'undefined') {\n      meta.Modality = modality.value[0];\n    }\n    const sopClassUID = dataElements['00080016'];\n    if (typeof sopClassUID !== 'undefined') {\n      meta.SOPClassUID = sopClassUID.value[0];\n    }\n    const studyUID = dataElements['0020000D'];\n    if (typeof studyUID !== 'undefined') {\n      meta.StudyInstanceUID = studyUID.value[0];\n    }\n    const seriesUID = dataElements['0020000E'];\n    if (typeof seriesUID !== 'undefined') {\n      meta.SeriesInstanceUID = seriesUID.value[0];\n    }\n    const bits = dataElements['00280101'];\n    if (typeof bits !== 'undefined') {\n      meta.BitsStored = bits.value[0];\n    }\n    const pixelRep = dataElements['00280103'];\n    if (typeof pixelRep !== 'undefined') {\n      meta.PixelRepresentation = pixelRep.value[0];\n    }\n    // PixelRepresentation -> is signed\n    meta.IsSigned = meta.PixelRepresentation === 1;\n    // local pixel unit\n    const pixelUnit = getPixelUnit(dataElements);\n    if (typeof pixelUnit !== 'undefined') {\n      meta.pixelUnit = pixelUnit;\n    }\n    // FrameOfReferenceUID (optional)\n    const frameOfReferenceUID = dataElements['00200052'];\n    if (typeof frameOfReferenceUID !== 'undefined') {\n      meta.FrameOfReferenceUID = frameOfReferenceUID.value[0];\n    }\n    // window level presets\n    const windowPresets = {};\n    const windowCenter = dataElements['00281050'];\n    const windowWidth = dataElements['00281051'];\n    const windowCWExplanation = dataElements['00281055'];\n    if (typeof windowCenter !== 'undefined' &&\n      typeof windowWidth !== 'undefined') {\n      let name;\n      for (let j = 0; j < windowCenter.value.length; ++j) {\n        const center = parseFloat(windowCenter.value[j]);\n        const width = parseFloat(windowWidth.value[j]);\n        if (center && width && width !== 0) {\n          name = '';\n          if (typeof windowCWExplanation !== 'undefined') {\n            name = windowCWExplanation.value[j];\n          }\n          if (name === '') {\n            name = 'Default' + j;\n          }\n          windowPresets[name] = {\n            wl: [new WindowCenterAndWidth(center, width)],\n            name: name\n          };\n        }\n        if (width === 0) {\n          logger.warn('Zero window width found in DICOM.');\n        }\n      }\n    }\n    meta.windowPresets = windowPresets;\n\n    // PALETTE COLOR luts\n    if (image.getPhotometricInterpretation() === 'PALETTE COLOR') {\n      const redLutElement = dataElements['00281201'];\n      const greenLutElement = dataElements['00281202'];\n      const blueLutElement = dataElements['00281203'];\n      let redLut;\n      let greenLut;\n      let blueLut;\n      // check red palette descriptor (should all be equal)\n      const descriptor = dataElements['00281101'];\n      if (typeof descriptor !== 'undefined' &&\n        descriptor.value.length === 3) {\n        if (descriptor.value[2] === 16) {\n          let doScale = false;\n          // (C.7.6.3.1.5 Palette Color Lookup Table Descriptor)\n          // Some implementations have encoded 8 bit entries with 16 bits\n          // allocated, padding the high bits;\n          let descSize = descriptor.value[0];\n          // (C.7.6.3.1.5 Palette Color Lookup Table Descriptor)\n          // The first Palette Color Lookup Table Descriptor value is the\n          // number of entries in the lookup table. When the number of table\n          // entries is equal to 216 then this value shall be 0.\n          if (descSize === 0) {\n            descSize = 65536;\n          }\n          // red palette VL\n          const vlSize = redLutElement.vl;\n          // check double size\n          if (vlSize !== 2 * descSize) {\n            doScale = true;\n            logger.info('16bits lut but size is not double. desc: ' +\n              descSize + ' vl: ' + vlSize);\n          }\n          // (C.7.6.3.1.6 Palette Color Lookup Table Data)\n          // Palette color values must always be scaled across the full\n          // range of available intensities\n          const bitsAllocated = parseInt(\n            dataElements['00280100'].value[0], 10);\n          if (bitsAllocated === 8) {\n            doScale = true;\n            logger.info(\n              'Scaling 16bits color lut since bits allocated is 8.');\n          }\n\n          if (doScale) {\n            const scaleTo8 = function (value) {\n              return value >> 8;\n            };\n\n            redLut = redLutElement.value.map(scaleTo8);\n            greenLut = greenLutElement.value.map(scaleTo8);\n            blueLut = blueLutElement.value.map(scaleTo8);\n          }\n        } else if (descriptor.value[2] === 8) {\n          // lut with vr=OW was read as Uint16, convert it to Uint8\n          logger.info(\n            'Scaling 16bits color lut since the lut descriptor is 8.');\n          let clone = redLutElement.value.slice(0);\n          // @ts-expect-error\n          redLut = new Uint8Array(clone.buffer);\n          clone = greenLutElement.value.slice(0);\n          // @ts-expect-error\n          greenLut = new Uint8Array(clone.buffer);\n          clone = blueLutElement.value.slice(0);\n          // @ts-expect-error\n          blueLut = new Uint8Array(clone.buffer);\n        }\n      }\n      // set the palette\n      meta.paletteLut = {\n        red: redLut,\n        green: greenLut,\n        blue: blueLut\n      };\n    }\n\n    // RecommendedDisplayFrameRate\n    const recommendedDisplayFrameRate = dataElements['00082144'];\n    if (typeof recommendedDisplayFrameRate !== 'undefined') {\n      meta.RecommendedDisplayFrameRate = parseInt(\n        recommendedDisplayFrameRate.value[0], 10);\n    }\n\n    // store the meta data\n    image.setMeta(meta);\n\n    return image;\n  }\n\n}","import {getImage2DSize} from '../dicom/dicomElementsWrapper';\nimport {Spacing} from '../image/spacing';\nimport {Image} from '../image/image';\nimport {Geometry, getSliceGeometrySpacing} from '../image/geometry';\nimport {Point3D} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {Index} from '../math/index';\nimport {Matrix33, REAL_WORLD_EPSILON} from '../math/matrix';\nimport {logger} from '../utils/logger';\nimport {arraySortEquals} from '../utils/array';\nimport {\n  isEqualRgb,\n  cielabToSrgb,\n  uintLabToLab\n} from '../utils/colour';\nimport {Size} from './size';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * @typedef {Object<string, DataElement>} DataElements\n */\n\n/**\n * Check two position patients for equality.\n *\n * @param {*} pos1 The first position patient.\n * @param {*} pos2 The second position patient.\n * @returns {boolean} True is equal.\n */\nfunction equalPosPat(pos1, pos2) {\n  return JSON.stringify(pos1) === JSON.stringify(pos2);\n}\n\n/**\n * @callback compareFn\n * @param {object} a The first object.\n * @param {object} b The first object.\n * @returns {number} >0 to sort a after b, <0 to sort a before b,\n *   0 to not change order.\n */\n\n/**\n * Get a position patient compare function accroding to an\n * input orientation.\n *\n * @param {Matrix33} orientation The orientation matrix.\n * @returns {compareFn} The position compare function.\n */\nfunction getComparePosPat(orientation) {\n  const invOrientation = orientation.getInverse();\n  return function (pos1, pos2) {\n    const p1 = invOrientation.multiplyArray3D(pos1);\n    const p2 = invOrientation.multiplyArray3D(pos2);\n    return p1[2] - p2[2];\n  };\n}\n\n/**\n * Check that a DICOM tag definition is present in a parsed element.\n *\n * @param {DataElements} dataElements The root dicom element.\n * @param {object} tagDefinition The tag definition as {name, tag, type, enum}.\n */\nfunction checkTag(dataElements, tagDefinition) {\n  const element = dataElements[tagDefinition.tag];\n  // check null and undefined\n  if (tagDefinition.type === 1 || tagDefinition.type === 2) {\n    if (typeof element === 'undefined') {\n      throw new Error('Missing or empty ' + tagDefinition.name);\n    }\n  } else {\n    if (typeof element === 'undefined') {\n      // non mandatory value, exit\n      return;\n    }\n  }\n  let includes = false;\n  let tagValue;\n  if (element.value.length === 1) {\n    tagValue = element.value[0];\n  } else {\n    tagValue = element.value;\n  }\n  if (Array.isArray(tagValue)) {\n    for (let i = 0; i < tagDefinition.enum.length; ++i) {\n      if (!Array.isArray(tagDefinition.enum[i])) {\n        throw new Error('Cannot compare array and non array tag value.');\n      }\n      if (arraySortEquals(tagDefinition.enum[i], tagValue)) {\n        includes = true;\n        break;\n      }\n    }\n  } else {\n    includes = tagDefinition.enum.includes(tagValue);\n  }\n  if (!includes) {\n    throw new Error(\n      'Unsupported ' + tagDefinition.name + ' value: ' + tagValue);\n  }\n}\n\n/**\n * List of DICOM Seg required tags.\n */\nconst RequiredDicomSegTags = [\n  {\n    name: 'TransferSyntaxUID',\n    tag: 'x00020010',\n    type: '1',\n    enum: ['1.2.840.10008.1.2.1']\n  },\n  {\n    name: 'MediaStorageSOPClassUID',\n    tag: 'x00020002',\n    type: '1',\n    enum: ['1.2.840.10008.5.1.4.1.1.66.4']\n  },\n  {\n    name: 'SOPClassUID',\n    tag: 'x00020002',\n    type: '1',\n    enum: ['1.2.840.10008.5.1.4.1.1.66.4']\n  },\n  {\n    name: 'Modality',\n    tag: 'x00080060',\n    type: '1',\n    enum: ['SEG']\n  },\n  {\n    name: 'SegmentationType',\n    tag: 'x00620001',\n    type: '1',\n    enum: ['BINARY']\n  },\n  {\n    name: 'DimensionOrganizationType',\n    tag: 'x00209311',\n    type: '3',\n    enum: ['3D']\n  },\n  {\n    name: 'ImageType',\n    tag: 'x00080008',\n    type: '1',\n    enum: [['DERIVED', 'PRIMARY']]\n  },\n  {\n    name: 'SamplesPerPixel',\n    tag: 'x00280002',\n    type: '1',\n    enum: [1]\n  },\n  {\n    name: 'PhotometricInterpretation',\n    tag: 'x00280004',\n    type: '1',\n    enum: ['MONOCHROME2']\n  },\n  {\n    name: 'PixelRepresentation',\n    tag: 'x00280103',\n    type: '1',\n    enum: [0]\n  },\n  {\n    name: 'BitsAllocated',\n    tag: 'x00280100',\n    type: '1',\n    enum: [1]\n  },\n  {\n    name: 'BitsStored',\n    tag: 'x00280101',\n    type: '1',\n    enum: [1]\n  },\n  {\n    name: 'HighBit',\n    tag: 'x00280102',\n    type: '1',\n    enum: [0]\n  },\n];\n\n/**\n * Get the default DICOM seg tags as an object.\n *\n * @returns {object} The default tags.\n */\nfunction getDefaultDicomSegJson() {\n  const tags = {};\n  for (let i = 0; i < RequiredDicomSegTags.length; ++i) {\n    const reqTag = RequiredDicomSegTags[i];\n    tags[reqTag.name] = reqTag.enum[0];\n  }\n  return tags;\n}\n\n/**\n * Check the dimension organization from a dicom element.\n *\n * @param {DataElements} dataElements The root dicom element.\n * @returns {object} The dimension organizations and indices.\n */\nfunction getDimensionOrganization(dataElements) {\n  // Dimension Organization Sequence (required)\n  const orgSq = dataElements['00209221'];\n  if (typeof orgSq === 'undefined' || orgSq.value.length !== 1) {\n    throw new Error('Unsupported dimension organization sequence length');\n  }\n  // Dimension Organization UID\n  const orgUID = orgSq.value[0]['00209164'].value[0];\n\n  // Dimension Index Sequence (conditionally required)\n  const indices = [];\n  const indexSqElem = dataElements['00209222'];\n  if (typeof indexSqElem !== 'undefined') {\n    const indexSq = indexSqElem.value;\n    // expecting 2D index\n    if (indexSq.length !== 2) {\n      throw new Error('Unsupported dimension index sequence length');\n    }\n    let indexPointer;\n    for (let i = 0; i < indexSq.length; ++i) {\n      // Dimension Organization UID (required)\n      const indexOrg = indexSq[i]['00209164'].value[0];\n      if (indexOrg !== orgUID) {\n        throw new Error(\n          'Dimension Index Sequence contains a unknown Dimension Organization');\n      }\n      // Dimension Index Pointer (required)\n      indexPointer = indexSq[i]['00209165'].value[0];\n\n      const index = {\n        DimensionOrganizationUID: indexOrg,\n        DimensionIndexPointer: indexPointer\n      };\n      // Dimension Description Label (optional)\n      if (typeof indexSq[i]['00209421'] !== 'undefined') {\n        index.DimensionDescriptionLabel = indexSq[i]['00209421'].value[0];\n      }\n      // store\n      indices.push(index);\n    }\n    // expecting Image Position at last position\n    if (indexPointer !== '(0020,0032)') {\n      throw new Error('Unsupported non image position as last index');\n    }\n  }\n\n  return {\n    organizations: {\n      value: [\n        {\n          DimensionOrganizationUID: orgUID\n        }\n      ]\n    },\n    indices: {\n      value: indices\n    }\n  };\n}\n\n/**\n * Get a code object from a dicom element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {object} A code object.\n */\nfunction getCode(dataElements) {\n  // meaning -> CodeMeaning (type1)\n  const code = {\n    meaning: dataElements['00080104'].value[0]\n  };\n  // value -> CodeValue (type1C)\n  // longValue -> LongCodeValue (type1C)\n  // urnValue -> URNCodeValue (type1C)\n  if (dataElements['00080100']) {\n    code.value = dataElements['00080100'].value[0];\n  } else if (dataElements['00080119']) {\n    code.longValue = dataElements['00080119'].value[0];\n  } else if (dataElements['00080120']) {\n    code.urnValue = dataElements['00080120'].value[0];\n  } else {\n    throw Error('Invalid code with no value, no long value and no urn value.');\n  }\n  // schemeDesignator -> CodingSchemeDesignator (type1C)\n  if (typeof code.value !== 'undefined' ||\n    typeof code.longValue !== 'undefined') {\n    if (dataElements['00080102']) {\n      code.schemeDesignator = dataElements['00080102'].value[0];\n    } else {\n      throw Error(\n        'No coding sheme designator when code value or long value is present');\n    }\n  }\n  return code;\n}\n\n/**\n * Get a segment object from a dicom element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {object} A segment object.\n */\nfunction getSegment(dataElements) {\n  // number -> SegmentNumber (type1)\n  // label -> SegmentLabel (type1)\n  // algorithmType -> SegmentAlgorithmType (type1)\n  const segment = {\n    number: dataElements['00620004'].value[0],\n    label: dataElements['00620005'].value[0],\n    algorithmType: dataElements['00620008'].value[0]\n  };\n  // algorithmName -> SegmentAlgorithmName (type1C)\n  if (dataElements['00620009']) {\n    segment.algorithmName = dataElements['00620009'].value[0];\n  }\n  // // required if type is not MANUAL\n  // if (segment.algorithmType !== 'MANUAL' &&\n  //   (typeof segment.algorithmName === 'undefined' ||\n  //   segment.algorithmName.length === 0)) {\n  //   throw new Error('Empty algorithm name for non MANUAL algorithm type.');\n  // }\n  // displayValue ->\n  // - RecommendedDisplayGrayscaleValue\n  // - RecommendedDisplayCIELabValue converted to RGB\n  if (typeof dataElements['0062000C'] !== 'undefined') {\n    segment.displayValue = dataElements['006200C'].value;\n  } else if (typeof dataElements['0062000D'] !== 'undefined') {\n    const cielabElement = dataElements['0062000D'].value;\n    const rgb = cielabToSrgb(uintLabToLab({\n      l: cielabElement[0],\n      a: cielabElement[1],\n      b: cielabElement[2]\n    }));\n    segment.displayValue = rgb;\n  }\n  // Segmented Property Category Code Sequence (type1, only one)\n  if (typeof dataElements['00620003'] !== 'undefined') {\n    segment.propertyCategoryCode =\n      getCode(dataElements['00620003'].value[0]);\n  } else {\n    throw Error('Missing Segmented Property Category Code Sequence.');\n  }\n  // Segmented Property Type Code Sequence (type1)\n  if (typeof dataElements['0062000F'] !== 'undefined') {\n    segment.propertyTypeCode =\n      getCode(dataElements['0062000F'].value[0]);\n  } else {\n    throw Error('Missing Segmented Property Type Code Sequence.');\n  }\n  // tracking Id and UID (type1C)\n  if (typeof dataElements['00620020'] !== 'undefined') {\n    segment.trackingId = dataElements['00620020'].value[0];\n    segment.trackingUid = dataElements['00620021'].value[0];\n  }\n\n  return segment;\n}\n\n/**\n * Check if two segment objects are equal.\n *\n * @param {object} seg1 The first segment.\n * @param {object} seg2 The second segment.\n * @returns {boolean} True if both segment are equal.\n */\nexport function isEqualSegment(seg1, seg2) {\n  // basics\n  if (typeof seg1 === 'undefined' ||\n    typeof seg2 === 'undefined' ||\n    seg1 === null ||\n    seg2 === null) {\n    return false;\n  }\n  let isEqual = seg1.number === seg2.number &&\n    seg1.label === seg2.label &&\n    seg1.algorithmType === seg2.algorithmType;\n  // rgb\n  if (typeof seg1.displayValue.r !== 'undefined') {\n    if (typeof seg2.displayValue.r === 'undefined') {\n      isEqual = false;\n    } else {\n      isEqual = isEqual &&\n        isEqualRgb(seg1.displayValue, seg2.displayValue);\n    }\n  } else {\n    isEqual = isEqual &&\n      seg1.displayValue === seg2.displayValue;\n  }\n  // algorithmName\n  if (typeof seg1.algorithmName !== 'undefined') {\n    if (typeof seg2.algorithmName === 'undefined') {\n      isEqual = false;\n    } else {\n      isEqual = isEqual &&\n        seg1.algorithmName === seg2.algorithmName;\n    }\n  }\n\n  return isEqual;\n}\n\n/**\n * Check if two segment objects are similar: either the\n * number or the displayValue are equal.\n *\n * @param {object} seg1 The first segment.\n * @param {object} seg2 The second segment.\n * @returns {boolean} True if both segment are similar.\n */\nexport function isSimilarSegment(seg1, seg2) {\n  // basics\n  if (typeof seg1 === 'undefined' ||\n    typeof seg2 === 'undefined' ||\n    seg1 === null ||\n    seg2 === null) {\n    return false;\n  }\n  let isSimilar = seg1.number === seg2.number;\n  // rgb\n  if (typeof seg1.displayValue.r !== 'undefined') {\n    if (typeof seg2.displayValue.r === 'undefined') {\n      isSimilar = false;\n    } else {\n      isSimilar = isSimilar ||\n        isEqualRgb(seg1.displayValue, seg2.displayValue);\n    }\n  } else {\n    isSimilar = isSimilar ||\n      seg1.displayValue === seg2.displayValue;\n  }\n\n  return isSimilar;\n}\n\n/**\n * Get a spacing object from a dicom measure element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {Spacing} A spacing object.\n */\nfunction getSpacingFromMeasure(dataElements) {\n  // Pixel Spacing\n  if (typeof dataElements['00280030'] === 'undefined') {\n    return null;\n  }\n  const pixelSpacing = dataElements['00280030'];\n  const spacingValues = [\n    parseFloat(pixelSpacing.value[0]),\n    parseFloat(pixelSpacing.value[1])\n  ];\n  // Slice Thickness\n  if (typeof dataElements['00180050'] !== 'undefined') {\n    spacingValues.push(parseFloat(dataElements['00180050'].value[0]));\n  } else if (typeof dataElements['00180088'] !== 'undefined') {\n    // Spacing Between Slices\n    spacingValues.push(parseFloat(dataElements['00180088'].value[0]));\n  }\n  return new Spacing(spacingValues);\n}\n\n/**\n * Get a frame information object from a dicom element.\n *\n * @param {DataElements} dataElements The dicom element.\n * @returns {object} A frame information object.\n */\nfunction getSegmentFrameInfo(dataElements) {\n  // Derivation Image Sequence\n  const derivationImages = [];\n  if (typeof dataElements['00089124'] !== 'undefined') {\n    const derivationImageSq = dataElements['00089124'].value;\n    // Source Image Sequence\n    for (let i = 0; i < derivationImageSq.length; ++i) {\n      const sourceImages = [];\n      if (typeof derivationImageSq[i]['00082112'] !== 'undefined') {\n        const sourceImageSq = derivationImageSq[i]['00082112'].value;\n        for (let j = 0; j < sourceImageSq.length; ++j) {\n          const sourceImage = {};\n          // Referenced SOP Class UID\n          if (typeof sourceImageSq[j]['00081150'] !== 'undefined') {\n            sourceImage.referencedSOPClassUID =\n              sourceImageSq[j]['00081150'].value[0];\n          }\n          // Referenced SOP Instance UID\n          if (typeof sourceImageSq[j]['00081155'] !== 'undefined') {\n            sourceImage.referencedSOPInstanceUID =\n              sourceImageSq[j]['00081155'].value[0];\n          }\n          sourceImages.push(sourceImage);\n        }\n      }\n      derivationImages.push(sourceImages);\n    }\n  }\n  // Frame Content Sequence (required, only one)\n  const frameContentSq = dataElements['00209111'].value;\n  // Dimension Index Value\n  const dimIndex = frameContentSq[0]['00209157'].value;\n  // Segment Identification Sequence (required, only one)\n  const segmentIdSq = dataElements['0062000A'].value;\n  // Referenced Segment Number\n  const refSegmentNumber = segmentIdSq[0]['0062000B'].value[0];\n  // Plane Position Sequence (required, only one)\n  const planePosSq = dataElements['00209113'].value;\n  // Image Position (Patient) (conditionally required)\n  const imagePosPat = planePosSq[0]['00200032'].value;\n  for (let p = 0; p < imagePosPat.length; ++p) {\n    imagePosPat[p] = parseFloat(imagePosPat[p]);\n  }\n  const frameInfo = {\n    dimIndex: dimIndex,\n    imagePosPat: imagePosPat,\n    derivationImages: derivationImages,\n    refSegmentNumber: refSegmentNumber\n  };\n  // Plane Orientation Sequence\n  if (typeof dataElements['00209116'] !== 'undefined') {\n    const framePlaneOrientationSeq = dataElements['00209116'];\n    if (framePlaneOrientationSeq.value.length !== 0) {\n      // should only be one Image Orientation (Patient)\n      const frameImageOrientation =\n        framePlaneOrientationSeq.value[0]['00200037'].value;\n      if (typeof frameImageOrientation !== 'undefined') {\n        frameInfo.imageOrientationPatient = frameImageOrientation;\n      }\n    }\n  }\n  // Pixel Measures Sequence\n  if (typeof dataElements['00289110'] !== 'undefined') {\n    const framePixelMeasuresSeq = dataElements['00289110'];\n    if (framePixelMeasuresSeq.value.length !== 0) {\n      // should only be one\n      const frameSpacing =\n        getSpacingFromMeasure(framePixelMeasuresSeq.value[0]);\n      if (typeof frameSpacing !== 'undefined') {\n        frameInfo.spacing = frameSpacing;\n      }\n    } else {\n      logger.warn(\n        'No shared functional group pixel measure sequence items.');\n    }\n  }\n\n  return frameInfo;\n}\n\n/**\n * Mask {@link Image} factory.\n */\nexport class MaskFactory {\n\n  /*\n   * Check dicom elements. Throws an error if not suitable.\n   *\n   * @param {object} _dicomElements The DICOM tags.\n   * @returns {object|undefined} A possible warning.\n   */\n  checkElements(_dicomElements) {\n    // does nothing\n  }\n\n  /**\n   * Get an {@link Image} object from the read DICOM file.\n   *\n   * @param {DataElements} dataElements The DICOM tags.\n   * @param {Uint8Array | Int8Array |\n   *   Uint16Array | Int16Array |\n   *   Uint32Array | Int32Array} pixelBuffer The pixel buffer.\n   * @returns {Image} A new Image.\n   */\n  create(dataElements, pixelBuffer) {\n    // check required and supported tags\n    for (let d = 0; d < RequiredDicomSegTags.length; ++d) {\n      checkTag(dataElements, RequiredDicomSegTags[d]);\n    }\n\n    // image size\n    const size2D = getImage2DSize(dataElements);\n    const size = new Size([size2D[0], size2D[1], 1]);\n\n    const sliceSize = size.getTotalSize();\n\n    // frames\n    let frames = 1;\n    const framesElem = dataElements['00280008'];\n    if (typeof framesElem !== 'undefined') {\n      frames = parseInt(framesElem.value[0], 10);\n    }\n\n    if (frames !== pixelBuffer.length / sliceSize) {\n      throw new Error(\n        'Buffer and numberOfFrames meta are not equal.' +\n        frames + ' ' + pixelBuffer.length / sliceSize);\n    }\n\n    // Dimension Organization and Index\n    const dimension = getDimensionOrganization(dataElements);\n\n    // Segment Sequence\n    const segSequence = dataElements['00620002'];\n    if (typeof segSequence === 'undefined') {\n      throw new Error('Missing or empty segmentation sequence');\n    }\n    const segments = [];\n    let storeAsRGB = false;\n    for (let i = 0; i < segSequence.value.length; ++i) {\n      const segment = getSegment(segSequence.value[i]);\n      if (typeof segment.displayValue.r !== 'undefined' &&\n        typeof segment.displayValue.g !== 'undefined' &&\n        typeof segment.displayValue.b !== 'undefined') {\n        // create rgb image\n        storeAsRGB = true;\n      }\n      // store\n      segments.push(segment);\n    }\n\n\n    // Shared Functional Groups Sequence\n    let spacing;\n    let imageOrientationPatient;\n    const sharedFunctionalGroupsSeq = dataElements['52009229'];\n    if (typeof sharedFunctionalGroupsSeq !== 'undefined') {\n      // should be only one\n      const funcGroup0 = sharedFunctionalGroupsSeq.value[0];\n      // Plane Orientation Sequence\n      if (typeof funcGroup0['00209116'] !== 'undefined') {\n        const planeOrientationSeq = funcGroup0['00209116'];\n        if (planeOrientationSeq.value.length !== 0) {\n          // should be only one\n          imageOrientationPatient =\n            planeOrientationSeq.value[0]['00200037'].value;\n        } else {\n          logger.warn(\n            'No shared functional group plane orientation sequence items.');\n        }\n      }\n      // Pixel Measures Sequence\n      if (typeof funcGroup0['00289110'] !== 'undefined') {\n        const pixelMeasuresSeq = funcGroup0['00289110'];\n        if (pixelMeasuresSeq.value.length !== 0) {\n          // should be only one\n          spacing = getSpacingFromMeasure(pixelMeasuresSeq.value[0]);\n        } else {\n          logger.warn(\n            'No shared functional group pixel measure sequence items.');\n        }\n      }\n    }\n\n    const includesPosPat = function (arr, val) {\n      return arr.some(function (arrVal) {\n        return equalPosPat(val, arrVal);\n      });\n    };\n\n    const findIndexPosPat = function (arr, val) {\n      return arr.findIndex(function (arrVal) {\n        return equalPosPat(val, arrVal);\n      });\n    };\n\n    // Per-frame Functional Groups Sequence\n    const perFrameFuncGroupSequence = dataElements['52009230'];\n    if (typeof perFrameFuncGroupSequence === 'undefined') {\n      throw new Error('Missing or empty per frame functional sequence');\n    }\n    if (frames !== perFrameFuncGroupSequence.value.length) {\n      throw new Error(\n        'perFrameFuncGroupSequence meta and numberOfFrames are not equal.');\n    }\n    // create frame info object from per frame func\n    const frameInfos = [];\n    for (let j = 0; j < perFrameFuncGroupSequence.value.length; ++j) {\n      frameInfos.push(\n        getSegmentFrameInfo(perFrameFuncGroupSequence.value[j]));\n    }\n\n    // check frame infos\n    const framePosPats = [];\n    for (let ii = 0; ii < frameInfos.length; ++ii) {\n      if (!includesPosPat(framePosPats, frameInfos[ii].imagePosPat)) {\n        framePosPats.push(frameInfos[ii].imagePosPat);\n      }\n      // store orientation if needed, avoid multi\n      if (typeof frameInfos[ii].imageOrientationPatient !== 'undefined') {\n        if (typeof imageOrientationPatient === 'undefined') {\n          imageOrientationPatient = frameInfos[ii].imageOrientationPatient;\n        } else {\n          if (!arraySortEquals(\n            imageOrientationPatient, frameInfos[ii].imageOrientationPatient)) {\n            throw new Error('Unsupported multi orientation dicom seg.');\n          }\n        }\n      }\n      // store spacing if needed, avoid multi\n      if (typeof frameInfos[ii].spacing !== 'undefined') {\n        if (typeof spacing === 'undefined') {\n          spacing = frameInfos[ii].spacing;\n        } else {\n          if (!spacing.equals(frameInfos[ii].spacing)) {\n            throw new Error('Unsupported multi resolution dicom seg.');\n          }\n        }\n      }\n    }\n\n    // check spacing and orientation\n    if (typeof spacing === 'undefined') {\n      throw new Error('No spacing found for DICOM SEG');\n    }\n    if (typeof imageOrientationPatient === 'undefined') {\n      throw new Error('No imageOrientationPatient found for DICOM SEG');\n    }\n\n    // orientation\n    const rowCosines = new Vector3D(\n      parseFloat(imageOrientationPatient[0]),\n      parseFloat(imageOrientationPatient[1]),\n      parseFloat(imageOrientationPatient[2]));\n    const colCosines = new Vector3D(\n      parseFloat(imageOrientationPatient[3]),\n      parseFloat(imageOrientationPatient[4]),\n      parseFloat(imageOrientationPatient[5]));\n    const normal = rowCosines.crossProduct(colCosines);\n    /* eslint-disable array-element-newline */\n    const orientationMatrix = new Matrix33([\n      rowCosines.getX(), colCosines.getX(), normal.getX(),\n      rowCosines.getY(), colCosines.getY(), normal.getY(),\n      rowCosines.getZ(), colCosines.getZ(), normal.getZ()\n    ]);\n\n    // sort positions patient\n    framePosPats.sort(getComparePosPat(orientationMatrix));\n\n    const point3DFromArray = function (arr) {\n      return new Point3D(arr[0], arr[1], arr[2]);\n    };\n\n    // frame origins\n    const frameOrigins = [];\n    for (let n = 0; n < framePosPats.length; ++n) {\n      frameOrigins.push(point3DFromArray(framePosPats[n]));\n    }\n\n    // use calculated spacing\n    let newSpacing = spacing;\n    const geoSliceSpacing = getSliceGeometrySpacing(\n      frameOrigins, orientationMatrix, false);\n    const spacingValues = spacing.getValues();\n    if (typeof geoSliceSpacing !== 'undefined' &&\n      geoSliceSpacing !== spacingValues[2]) {\n      spacingValues[2] = geoSliceSpacing;\n      newSpacing = new Spacing(spacingValues);\n    }\n\n    // tmp geometry with correct spacing but only one slice\n    const tmpGeometry = new Geometry(\n      frameOrigins[0], size, newSpacing, orientationMatrix);\n\n    // origin distance test\n    // TODO: maybe use sliceSpacing / 10\n    const isNotSmall = function (value) {\n      let res = value > REAL_WORLD_EPSILON;\n      if (res) {\n        // try larger epsilon\n        res = value > REAL_WORLD_EPSILON * 10;\n        if (!res) {\n          // warn if epsilon < value < epsilon * 10\n          logger.warn(\n            'Using larger real world epsilon in SEG pos pat adding'\n          );\n        } else {\n          res = value > REAL_WORLD_EPSILON * 100;\n          if (!res) {\n            // warn if epsilon < value < epsilon * 100\n            logger.warn(\n              'Using larger+ real world epsilon in SEG pos pat adding'\n            );\n          }\n        }\n      }\n      return res;\n    };\n\n    // add possibly missing posPats\n    const posPats = [];\n    posPats.push(framePosPats[0]);\n    let sliceIndex = 0;\n    for (let g = 1; g < framePosPats.length; ++g) {\n      ++sliceIndex;\n      let index = new Index([0, 0, sliceIndex]);\n      let point = tmpGeometry.indexToWorld(index).get3D();\n      const frameOrigin = frameOrigins[g];\n      // check if more pos pats are needed\n      let dist = frameOrigin.getDistance(point);\n      const distPrevious = dist;\n      // TODO: good threshold?\n      while (isNotSmall(dist)) {\n        logger.debug('Adding intermediate pos pats for DICOM seg at ' +\n          point.toString());\n        posPats.push([point.getX(), point.getY(), point.getZ()]);\n        ++sliceIndex;\n        index = new Index([0, 0, sliceIndex]);\n        point = tmpGeometry.indexToWorld(index).get3D();\n        dist = frameOrigin.getDistance(point);\n        if (dist > distPrevious) {\n          throw new Error(\n            'Test distance is increasing when adding intermediate pos pats');\n        }\n      }\n      // add frame pos pat\n      posPats.push(framePosPats[g]);\n    }\n\n    // as many slices as posPats\n    const numberOfSlices = posPats.length;\n\n    // final geometry\n    const geometry = new Geometry(\n      frameOrigins[0], size, newSpacing, orientationMatrix);\n    const uids = [0];\n    for (let m = 1; m < numberOfSlices; ++m) {\n      geometry.appendOrigin(point3DFromArray(posPats[m]), m);\n      uids.push(m);\n    }\n\n    const getFindSegmentFunc = function (number) {\n      return function (item) {\n        return item.number === number;\n      };\n    };\n\n    // create output buffer\n    const mul = storeAsRGB ? 3 : 1;\n    const buffer =\n      // @ts-ignore\n      new pixelBuffer.constructor(mul * sliceSize * numberOfSlices);\n    buffer.fill(0);\n    // merge frame buffers\n    let sliceOffset = null;\n    let frameOffset = null;\n    for (let f = 0; f < frameInfos.length; ++f) {\n      // get the slice index from the position in the posPat array\n      sliceIndex = findIndexPosPat(posPats, frameInfos[f].imagePosPat);\n      frameOffset = sliceSize * f;\n      sliceOffset = sliceSize * sliceIndex;\n      // get the frame display value\n      const frameSegment = segments.find(\n        getFindSegmentFunc(frameInfos[f].refSegmentNumber)\n      );\n      const pixelValue = frameSegment.displayValue;\n      for (let l = 0; l < sliceSize; ++l) {\n        if (pixelBuffer[frameOffset + l] !== 0) {\n          const offset = mul * (sliceOffset + l);\n          if (storeAsRGB) {\n            buffer[offset] = pixelValue.r;\n            buffer[offset + 1] = pixelValue.g;\n            buffer[offset + 2] = pixelValue.b;\n          } else {\n            buffer[offset] = pixelValue;\n          }\n        }\n      }\n    }\n\n    // create image\n    const image = new Image(geometry, buffer, uids);\n    if (storeAsRGB) {\n      image.setPhotometricInterpretation('RGB');\n    }\n    // meta information\n    const meta = getDefaultDicomSegJson();\n    // Study\n    meta.StudyDate = dataElements['00080020'].value[0];\n    meta.StudyTime = dataElements['00080030'].value[0];\n    meta.StudyInstanceUID = dataElements['0020000D'].value[0];\n    meta.StudyID = dataElements['00200010'].value[0];\n    // Series\n    meta.SeriesInstanceUID = dataElements['0020000E'].value[0];\n    meta.SeriesNumber = dataElements['00200011'].value[0];\n    // ReferringPhysicianName\n    meta.ReferringPhysicianName = dataElements['00080090'].value[0];\n    // patient info\n    meta.PatientName = dataElements['00100010'].value[0];\n    meta.PatientID = dataElements['00100020'].value[0];\n    meta.PatientBirthDate = dataElements['00100030'].value[0];\n    meta.PatientSex = dataElements['00100040'].value[0];\n    // Enhanced General Equipment Module\n    meta.Manufacturer = dataElements['00080070'].value[0];\n    meta.ManufacturerModelName = dataElements['00081090'].value[0];\n    meta.DeviceSerialNumber = dataElements['00181000'].value[0];\n    meta.SoftwareVersions = dataElements['00181020'].value[0];\n    // dicom seg dimension\n    meta.DimensionOrganizationSequence = dimension.organizations;\n    meta.DimensionIndexSequence = dimension.indices;\n    // custom\n    meta.custom = {\n      segments: segments,\n      frameInfos: frameInfos,\n      SOPInstanceUID: dataElements['00080018'].value[0]\n    };\n\n    // number of files: in this case equal to number slices,\n    //   used to calculate buffer size\n    meta.numberOfFiles = numberOfSlices;\n    // FrameOfReferenceUID (optional)\n    const frameOfReferenceUID = dataElements['00200052'];\n    if (frameOfReferenceUID) {\n      meta.FrameOfReferenceUID = frameOfReferenceUID.value[0];\n    }\n    // LossyImageCompression (optional)\n    const lossyImageCompression = dataElements['00282110'];\n    if (lossyImageCompression) {\n      meta.LossyImageCompression = lossyImageCompression.value[0];\n    }\n\n    image.setMeta(meta);\n\n    return image;\n  }\n\n} // class MaskFactory\n","import {Index} from '../math/index';\nimport {Point3D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {getTypedArray} from '../dicom/dicomParser';\nimport {ListenerHandler} from '../utils/listen';\nimport {colourRange} from './iterator';\nimport {RescaleSlopeAndIntercept} from './rsi';\nimport {ImageFactory} from './imageFactory';\nimport {MaskFactory} from './maskFactory';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Geometry} from './geometry';\nimport {Matrix33} from '../math/matrix';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the slice index of an input slice into a volume geometry.\n *\n * @param {Geometry} volumeGeometry The volume geometry.\n * @param {Geometry} sliceGeometry The slice geometry.\n * @returns {Index} The index of the slice in the volume geomtry.\n */\nfunction getSliceIndex(volumeGeometry, sliceGeometry) {\n  // possible time\n  const timeId = sliceGeometry.getInitialTime();\n  // index values\n  const values = [];\n  // x, y\n  values.push(0);\n  values.push(0);\n  // z\n  values.push(volumeGeometry.getSliceIndex(sliceGeometry.getOrigin(), timeId));\n  // time\n  if (typeof timeId !== 'undefined') {\n    values.push(timeId);\n  }\n  // return index\n  return new Index(values);\n}\n\n/**\n * Create an Image from DICOM elements.\n *\n * @param {object} elements The DICOM elements.\n * @returns {Image} The Image object.\n */\nexport function createImage(elements) {\n  const factory = new ImageFactory();\n  return factory.create(\n    elements,\n    elements['7FE00010'].value[0],\n    1\n  );\n}\n\n/**\n * Create a mask Image from DICOM elements.\n *\n * @param {object} elements The DICOM elements.\n * @returns {Image} The mask Image object.\n */\nexport function createMaskImage(elements) {\n  const factory = new MaskFactory();\n  return factory.create(\n    elements,\n    elements['7FE00010'].value[0]\n  );\n}\n\n/**\n * Image class.\n * Usable once created, optional are:\n * - rescale slope and intercept (default 1:0),\n * - photometric interpretation (default MONOCHROME2),\n * - planar configuration (default RGBRGB...).\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n *   // parse the dicom buffer\n *   const dicomParser = new dwv.DicomParser();\n *   dicomParser.parse(event.target.response);\n *   // create the image object\n *   const image = dwv.createImage(dicomParser.getDicomElements());\n *   // result div\n *   const div = document.getElementById('dwv');\n *   // display the image size\n *   const size = image.getGeometry().getSize();\n *   div.appendChild(document.createTextNode(\n *     'Size: ' + size.toString() +\n *     ' (should be 256,256,1)'));\n *   // break line\n *   div.appendChild(document.createElement('br'));\n *   // display a pixel value\n *   div.appendChild(document.createTextNode(\n *     'Pixel @ [128,40,0]: ' +\n *     image.getRescaledValue(128,40,0) +\n *     ' (should be 101)'));\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class Image {\n\n  /**\n   * Data geometry.\n   *\n   * @type {Geometry}\n   */\n  #geometry;\n\n  /**\n   * List of compatible typed arrays.\n   *\n   * @typedef {(\n   *   Uint8Array | Int8Array |\n   *   Uint16Array | Int16Array |\n   *   Uint32Array | Int32Array\n   * )} TypedArray\n   */\n\n  /**\n   * Data buffer.\n   *\n   * @type {TypedArray}\n   */\n  #buffer;\n\n  /**\n   * Image UIDs.\n   *\n   * @type {Array}\n   */\n  #imageUids;\n\n  /**\n   * Constant rescale slope and intercept (default).\n   *\n   * @type {object}\n   */\n  #rsi = new RescaleSlopeAndIntercept(1, 0);\n\n  /**\n   * Varying rescale slope and intercept.\n   *\n   * @type {Array}\n   */\n  #rsis = null;\n\n  /**\n   * Flag to know if the RSIs are all identity (1,0).\n   *\n   * @type {boolean}\n   */\n  #isIdentityRSI = true;\n\n  /**\n   * Flag to know if the RSIs are all equals.\n   *\n   * @type {boolean}\n   */\n  #isConstantRSI = true;\n\n  /**\n   * Photometric interpretation (MONOCHROME, RGB...).\n   *\n   * @type {string}\n   */\n  #photometricInterpretation = 'MONOCHROME2';\n\n  /**\n   * Planar configuration for RGB data (0:RGBRGBRGBRGB... or\n   *   1:RRR...GGG...BBB...).\n   *\n   * @type {number}\n   */\n  #planarConfiguration = 0;\n\n  /**\n   * Number of components.\n   *\n   * @type {number}\n   */\n  #numberOfComponents;\n\n  /**\n   * Meta information.\n   *\n   * @type {object}\n   */\n  #meta = {};\n\n  /**\n   * Data range.\n   *\n   * @type {object}\n   */\n  #dataRange = null;\n\n  /**\n   * Rescaled data range.\n   *\n   * @type {object}\n   */\n  #rescaledDataRange = null;\n\n  /**\n   * Histogram.\n   *\n   * @type {Array}\n   */\n  #histogram = null;\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * @param {Geometry} geometry The geometry of the image.\n   * @param {TypedArray} buffer The image data as a one dimensional buffer.\n   * @param {Array} [imageUids] An array of Uids indexed to slice number.\n   */\n  constructor(geometry, buffer, imageUids) {\n    this.#geometry = geometry;\n    this.#buffer = buffer;\n    this.#imageUids = imageUids;\n\n    this.#numberOfComponents = this.#buffer.length / (\n      this.#geometry.getSize().getTotalSize());\n  }\n\n  /**\n   * Get the image UID at a given index.\n   *\n   * @param {Index} [index] The index at which to get the id.\n   * @returns {string} The UID.\n   */\n  getImageUid(index) {\n    let uid = this.#imageUids[0];\n    if (this.#imageUids.length !== 1 && typeof index !== 'undefined') {\n      uid = this.#imageUids[this.getSecondaryOffset(index)];\n    }\n    return uid;\n  }\n\n  /**\n   * Get the geometry of the image.\n   *\n   * @returns {Geometry} The geometry.\n   */\n  getGeometry() {\n    return this.#geometry;\n  }\n\n  /**\n   * Get the data buffer of the image.\n   *\n   * @todo dangerous...\n   * @returns {TypedArray} The data buffer of the image.\n   */\n  getBuffer() {\n    return this.#buffer;\n  }\n\n  /**\n   * Can the image values be quantified?\n   *\n   * @returns {boolean} True if only one component.\n   */\n  canQuantify() {\n    return this.getNumberOfComponents() === 1;\n  }\n\n  /**\n   * Can window and level be applied to the data?\n   *\n   * @returns {boolean} True if the data is monochrome.\n   */\n  canWindowLevel() {\n    return this.getPhotometricInterpretation()\n      .match(/MONOCHROME/) !== null;\n  }\n\n  /**\n   * Can the data be scrolled?\n   *\n   * @param {Matrix33} viewOrientation The view orientation.\n   * @returns {boolean} True if the data has a third dimension greater than one\n   *   after applying the view orientation.\n   */\n  canScroll(viewOrientation) {\n    const size = this.getGeometry().getSize();\n    // also check the numberOfFiles in case we are in the middle of a load\n    let nFiles = 1;\n    if (typeof this.#meta.numberOfFiles !== 'undefined') {\n      nFiles = this.#meta.numberOfFiles;\n    }\n    return size.canScroll(viewOrientation) || nFiles !== 1;\n  }\n\n  /**\n   * Get the secondary offset max.\n   *\n   * @returns {number} The maximum offset.\n   */\n  #getSecondaryOffsetMax() {\n    return this.#geometry.getSize().getTotalSize(2);\n  }\n\n  /**\n   * Get the secondary offset: an offset that takes into account\n   *   the slice and above dimension numbers.\n   *\n   * @param {Index} index The index.\n   * @returns {number} The offset.\n   */\n  getSecondaryOffset(index) {\n    return this.#geometry.getSize().indexToOffset(index, 2);\n  }\n\n  /**\n   * Get the rescale slope and intercept.\n   *\n   * @param {Index} [index] The index (only needed for non constant rsi).\n   * @returns {object} The rescale slope and intercept.\n   */\n  getRescaleSlopeAndIntercept(index) {\n    let res = this.#rsi;\n    if (!this.isConstantRSI()) {\n      if (typeof index === 'undefined') {\n        throw new Error('Cannot get non constant RSI with empty slice index.');\n      }\n      const offset = this.getSecondaryOffset(index);\n      if (typeof this.#rsis[offset] !== 'undefined') {\n        res = this.#rsis[offset];\n      } else {\n        logger.warn('undefined non constant rsi at ' + offset);\n      }\n    }\n    return res;\n  }\n\n  /**\n   * Get the rsi at a specified (secondary) offset.\n   *\n   * @param {number} offset The desired (secondary) offset.\n   * @returns {object} The coresponding rsi.\n   */\n  #getRescaleSlopeAndInterceptAtOffset(offset) {\n    return this.#rsis[offset];\n  }\n\n  /**\n   * Set the rescale slope and intercept.\n   *\n   * @param {object} inRsi The input rescale slope and intercept.\n   * @param {number} [offset] The rsi offset (only needed for non constant rsi).\n   */\n  setRescaleSlopeAndIntercept(inRsi, offset) {\n    // update identity flag\n    this.#isIdentityRSI = this.#isIdentityRSI && inRsi.isID();\n    // update constant flag\n    if (!this.#isConstantRSI) {\n      if (typeof offset === 'undefined') {\n        throw new Error(\n          'Cannot store non constant RSI with empty slice index.');\n      }\n      this.#rsis.splice(offset, 0, inRsi);\n    } else {\n      if (!this.#rsi.equals(inRsi)) {\n        if (typeof offset === 'undefined') {\n          // no slice index, replace existing\n          this.#rsi = inRsi;\n        } else {\n          // first non constant rsi\n          this.#isConstantRSI = false;\n          // switch to non constant mode\n          this.#rsis = [];\n          // initialise RSIs\n          for (let i = 0, leni = this.#getSecondaryOffsetMax(); i < leni; ++i) {\n            this.#rsis.push(i);\n          }\n          // store\n          this.#rsi = null;\n          this.#rsis.splice(offset, 0, inRsi);\n        }\n      }\n    }\n  }\n\n  /**\n   * Are all the RSIs identity (1,0).\n   *\n   * @returns {boolean} True if they are.\n   */\n  isIdentityRSI() {\n    return this.#isIdentityRSI;\n  }\n\n  /**\n   * Are all the RSIs equal.\n   *\n   * @returns {boolean} True if they are.\n   */\n  isConstantRSI() {\n    return this.#isConstantRSI;\n  }\n\n  /**\n   * Get the photometricInterpretation of the image.\n   *\n   * @returns {string} The photometricInterpretation of the image.\n   */\n  getPhotometricInterpretation() {\n    return this.#photometricInterpretation;\n  }\n\n  /**\n   * Set the photometricInterpretation of the image.\n   *\n   * @param {string} interp The photometricInterpretation of the image.\n   */\n  setPhotometricInterpretation(interp) {\n    this.#photometricInterpretation = interp;\n  }\n\n  /**\n   * Get the planarConfiguration of the image.\n   *\n   * @returns {number} The planarConfiguration of the image.\n   */\n  getPlanarConfiguration() {\n    return this.#planarConfiguration;\n  }\n\n  /**\n   * Set the planarConfiguration of the image.\n   *\n   * @param {number} config The planarConfiguration of the image.\n   */\n  setPlanarConfiguration(config) {\n    this.#planarConfiguration = config;\n  }\n\n  /**\n   * Get the numberOfComponents of the image.\n   *\n   * @returns {number} The numberOfComponents of the image.\n   */\n  getNumberOfComponents() {\n    return this.#numberOfComponents;\n  }\n\n  /**\n   * Get the meta information of the image.\n   *\n   * @returns {object} The meta information of the image.\n   */\n  getMeta() {\n    return this.#meta;\n  }\n\n  /**\n   * Set the meta information of the image.\n   *\n   * @param {object} rhs The meta information of the image.\n   */\n  setMeta(rhs) {\n    this.#meta = rhs;\n  }\n\n  /**\n   * Get value at offset. Warning: No size check...\n   *\n   * @param {number} offset The desired offset.\n   * @returns {number} The value at offset.\n   */\n  getValueAtOffset(offset) {\n    return this.#buffer[offset];\n  }\n\n  /**\n   * Get the offsets where the buffer equals the input value.\n   * Loops through the whole volume, can get long for big data...\n   *\n   * @param {number|object} value The value to check.\n   * @returns {Array} The list of offsets.\n   */\n  getOffsets(value) {\n    // value to array\n    if (this.#numberOfComponents === 1) {\n      value = [value];\n    } else if (this.#numberOfComponents === 3 &&\n      typeof value.r !== 'undefined') {\n      value = [value.r, value.g, value.b];\n    }\n    // main loop\n    const offsets = [];\n    let equal;\n    for (let i = 0; i < this.#buffer.length; i = i + this.#numberOfComponents) {\n      equal = true;\n      for (let j = 0; j < this.#numberOfComponents; ++j) {\n        if (this.#buffer[i + j] !== value[j]) {\n          equal = false;\n          break;\n        }\n      }\n      if (equal) {\n        offsets.push(i);\n      }\n    }\n    return offsets;\n  }\n\n  /**\n   * Check if the input values are in the buffer.\n   * Could loop through the whole volume, can get long for big data...\n   *\n   * @param {Array} values The values to check.\n   * @returns {Array} A list of booleans for each input value,\n   *   set to true if the value is present in the buffer.\n   */\n  hasValues(values) {\n    // check input\n    if (typeof values === 'undefined' ||\n      values.length === 0) {\n      return [];\n    }\n    // final array value\n    const finalValues = [];\n    for (let v1 = 0; v1 < values.length; ++v1) {\n      if (this.#numberOfComponents === 1) {\n        finalValues.push([values[v1]]);\n      } else if (this.#numberOfComponents === 3) {\n        finalValues.push([\n          values[v1].r,\n          values[v1].g,\n          values[v1].b\n        ]);\n      }\n    }\n    // find callback\n    let equalFunc;\n    if (this.#numberOfComponents === 1) {\n      equalFunc = function (a, b) {\n        return a[0] === b[0];\n      };\n    } else if (this.#numberOfComponents === 3) {\n      equalFunc = function (a, b) {\n        return a[0] === b[0] &&\n          a[1] === b[1] &&\n          a[2] === b[2];\n      };\n    }\n    const getEqualCallback = function (value) {\n      return function (item) {\n        return equalFunc(item, value);\n      };\n    };\n    // main loop\n    const res = new Array(values.length);\n    res.fill(false);\n    const valuesToFind = finalValues.slice();\n    let equal;\n    let indicesToRemove;\n    for (let i = 0, leni = this.#buffer.length;\n      i < leni; i = i + this.#numberOfComponents) {\n      indicesToRemove = [];\n      for (let v = 0; v < valuesToFind.length; ++v) {\n        equal = true;\n        // check value(s)\n        for (let j = 0; j < this.#numberOfComponents; ++j) {\n          if (this.#buffer[i + j] !== valuesToFind[v][j]) {\n            equal = false;\n            break;\n          }\n        }\n        // if found, store answer and add to indices to remove\n        if (equal) {\n          const valIndex = finalValues.findIndex(\n            getEqualCallback(valuesToFind[v]));\n          res[valIndex] = true;\n          indicesToRemove.push(v);\n        }\n      }\n      // remove found values\n      for (let r = 0; r < indicesToRemove.length; ++r) {\n        valuesToFind.splice(indicesToRemove[r], 1);\n      }\n      // exit if no values to find\n      if (valuesToFind.length === 0) {\n        break;\n      }\n    }\n    // return\n    return res;\n  }\n\n  /**\n   * Clone the image.\n   *\n   * @returns {Image} A clone of this image.\n   */\n  clone() {\n    // clone the image buffer\n    const clonedBuffer = this.#buffer.slice(0);\n    // create the image copy\n    const copy = new Image(this.getGeometry(), clonedBuffer, this.#imageUids);\n    // copy the RSI(s)\n    if (this.isConstantRSI()) {\n      copy.setRescaleSlopeAndIntercept(this.getRescaleSlopeAndIntercept());\n    } else {\n      for (let i = 0; i < this.#getSecondaryOffsetMax(); ++i) {\n        copy.setRescaleSlopeAndIntercept(\n          this.#getRescaleSlopeAndInterceptAtOffset(i), i);\n      }\n    }\n    // copy extras\n    copy.setPhotometricInterpretation(this.getPhotometricInterpretation());\n    copy.setPlanarConfiguration(this.getPlanarConfiguration());\n    copy.setMeta(this.getMeta());\n    // return\n    return copy;\n  }\n\n  /**\n   * Re-allocate buffer memory to an input size.\n   *\n   * @param {number} size The new size.\n   */\n  #realloc(size) {\n    // save buffer\n    let tmpBuffer = this.#buffer;\n    // create new\n    this.#buffer = getTypedArray(\n      this.#buffer.BYTES_PER_ELEMENT * 8,\n      this.#meta.IsSigned ? 1 : 0,\n      size);\n    if (this.#buffer === null) {\n      throw new Error('Cannot reallocate data for image.');\n    }\n    // put old in new\n    this.#buffer.set(tmpBuffer);\n    // clean\n    tmpBuffer = null;\n  }\n\n  /**\n   * Append a slice to the image.\n   *\n   * @param {Image} rhs The slice to append.\n   */\n  appendSlice(rhs) {\n    // check input\n    if (rhs === null) {\n      throw new Error('Cannot append null slice');\n    }\n    const rhsSize = rhs.getGeometry().getSize();\n    let size = this.#geometry.getSize();\n    if (rhsSize.get(2) !== 1) {\n      throw new Error('Cannot append more than one slice');\n    }\n    if (size.get(0) !== rhsSize.get(0)) {\n      throw new Error('Cannot append a slice with different number of columns');\n    }\n    if (size.get(1) !== rhsSize.get(1)) {\n      throw new Error('Cannot append a slice with different number of rows');\n    }\n    if (!this.#geometry.getOrientation().equals(\n      rhs.getGeometry().getOrientation(), 0.0001)) {\n      throw new Error('Cannot append a slice with different orientation');\n    }\n    if (this.#photometricInterpretation !==\n      rhs.getPhotometricInterpretation()) {\n      throw new Error(\n        'Cannot append a slice with different photometric interpretation');\n    }\n    // all meta should be equal\n    for (const key in this.#meta) {\n      if (key === 'windowPresets' || key === 'numberOfFiles' ||\n        key === 'custom') {\n        continue;\n      }\n      if (this.#meta[key] !== rhs.getMeta()[key]) {\n        throw new Error('Cannot append a slice with different ' + key);\n      }\n    }\n\n    // possible time\n    const timeId = rhs.getGeometry().getInitialTime();\n\n    // append frame if needed\n    let isNewFrame = false;\n    if (typeof timeId !== 'undefined' &&\n      !this.#geometry.hasSlicesAtTime(timeId)) {\n      // update grometry\n      this.appendFrame(timeId, rhs.getGeometry().getOrigin());\n      // update size\n      size = this.#geometry.getSize();\n      // update flag\n      isNewFrame = true;\n    }\n\n    // get slice index\n    const index = getSliceIndex(this.#geometry, rhs.getGeometry());\n\n    // calculate slice size\n    const sliceSize = this.#numberOfComponents * size.getDimSize(2);\n\n    // create full buffer if not done yet\n    if (typeof this.#meta.numberOfFiles === 'undefined') {\n      throw new Error('Missing number of files for buffer manipulation.');\n    }\n    const fullBufferSize = sliceSize * this.#meta.numberOfFiles;\n    if (this.#buffer.length !== fullBufferSize) {\n      this.#realloc(fullBufferSize);\n    }\n\n    // slice index\n    const sliceIndex = index.get(2);\n\n    // slice index including possible 4D\n    let fullSliceIndex = sliceIndex;\n    if (typeof timeId !== 'undefined') {\n      fullSliceIndex +=\n        this.#geometry.getCurrentNumberOfSlicesBeforeTime(timeId);\n    }\n    // offset of the input slice\n    const indexOffset = fullSliceIndex * sliceSize;\n    const maxOffset =\n      this.#geometry.getCurrentTotalNumberOfSlices() * sliceSize;\n    // move content if needed\n    if (indexOffset < maxOffset) {\n      this.#buffer.set(\n        this.#buffer.subarray(indexOffset, maxOffset),\n        indexOffset + sliceSize\n      );\n    }\n    // add new slice content\n    this.#buffer.set(rhs.getBuffer(), indexOffset);\n\n    // update geometry\n    if (!isNewFrame) {\n      this.#geometry.appendOrigin(\n        rhs.getGeometry().getOrigin(), sliceIndex, timeId);\n    }\n    // update rsi\n    // (rhs should just have one rsi)\n    this.setRescaleSlopeAndIntercept(\n      rhs.getRescaleSlopeAndIntercept(), fullSliceIndex);\n\n    // current number of images\n    const numberOfImages = this.#imageUids.length;\n\n    // insert sop instance UIDs\n    this.#imageUids.splice(fullSliceIndex, 0, rhs.getImageUid());\n\n    // update window presets\n    if (typeof this.#meta.windowPresets !== 'undefined') {\n      const windowPresets = this.#meta.windowPresets;\n      const rhsPresets = rhs.getMeta().windowPresets;\n      const keys = Object.keys(rhsPresets);\n      let pkey = null;\n      for (let i = 0; i < keys.length; ++i) {\n        pkey = keys[i];\n        const rhsPreset = rhsPresets[pkey];\n        const windowPreset = windowPresets[pkey];\n        if (typeof windowPreset !== 'undefined') {\n          // if not set or false, check perslice\n          if (typeof windowPreset.perslice === 'undefined' ||\n            windowPreset.perslice === false) {\n            // if different preset.wl, mark it as perslice\n            if (!windowPreset.wl[0].equals(rhsPreset.wl[0])) {\n              windowPreset.perslice = true;\n              // fill wl array with copy of wl[0]\n              // (loop on number of images minus the existing one)\n              for (let j = 0; j < numberOfImages - 1; ++j) {\n                windowPreset.wl.push(windowPreset.wl[0]);\n              }\n            }\n          }\n          // store (first) rhs preset.wl if needed\n          if (typeof windowPreset.perslice !== 'undefined' &&\n            windowPreset.perslice === true) {\n            windowPresets[pkey].wl.splice(\n              fullSliceIndex, 0, rhsPreset.wl[0]);\n          }\n        } else {\n          // if not defined (it should be), store all\n          windowPresets[pkey] = rhsPresets[pkey];\n        }\n      }\n    }\n  }\n\n  /**\n   * Append a frame buffer to the image.\n   *\n   * @param {object} frameBuffer The frame buffer to append.\n   * @param {number} frameIndex The frame index.\n   */\n  appendFrameBuffer(frameBuffer, frameIndex) {\n    // create full buffer if not done yet\n    const size = this.#geometry.getSize();\n    const frameSize = this.#numberOfComponents * size.getDimSize(2);\n    if (typeof this.#meta.numberOfFiles === 'undefined') {\n      throw new Error('Missing number of files for frame buffer manipulation.');\n    }\n    const fullBufferSize = frameSize * this.#meta.numberOfFiles;\n    if (this.#buffer.length !== fullBufferSize) {\n      this.#realloc(fullBufferSize);\n    }\n    // check index\n    if (frameIndex >= this.#meta.numberOfFiles) {\n      logger.warn('Ignoring frame at index ' + frameIndex +\n        ' (size: ' + this.#meta.numberOfFiles + ')');\n      return;\n    }\n    // append\n    this.#buffer.set(frameBuffer, frameSize * frameIndex);\n    // update geometry\n    this.appendFrame(frameIndex, new Point3D(0, 0, 0));\n  }\n\n  /**\n   * Append a frame to the image.\n   *\n   * @param {number} time The frame time value.\n   * @param {Point3D} origin The origin of the frame.\n   */\n  appendFrame(time, origin) {\n    this.#geometry.appendFrame(origin, time);\n    this.#fireEvent({type: 'appendframe'});\n    // memory will be updated at the first appendSlice or appendFrameBuffer\n  }\n\n  /**\n   * Get the data range.\n   *\n   * @returns {object} The data range.\n   */\n  getDataRange() {\n    if (!this.#dataRange) {\n      this.#dataRange = this.calculateDataRange();\n    }\n    return this.#dataRange;\n  }\n\n  /**\n   * Get the rescaled data range.\n   *\n   * @returns {object} The rescaled data range.\n   */\n  getRescaledDataRange() {\n    if (!this.#rescaledDataRange) {\n      this.#rescaledDataRange = this.calculateRescaledDataRange();\n    }\n    return this.#rescaledDataRange;\n  }\n\n  /**\n   * Get the histogram.\n   *\n   * @returns {Array} The histogram.\n   */\n  getHistogram() {\n    if (!this.#histogram) {\n      const res = this.calculateHistogram();\n      this.#dataRange = res.dataRange;\n      this.#rescaledDataRange = res.rescaledDataRange;\n      this.#histogram = res.histogram;\n    }\n    return this.#histogram;\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  // ****************************************\n  // image data modifiers... carefull...\n  // ****************************************\n\n  /**\n   * Set the inner buffer values at given offsets.\n   *\n   * @param {Array} offsets List of offsets where to set the data.\n   * @param {object} value The value to set at the given offsets.\n   * @fires Image#imagechange\n   */\n  setAtOffsets(offsets, value) {\n    let offset;\n    for (let i = 0, leni = offsets.length; i < leni; ++i) {\n      offset = offsets[i];\n      this.#buffer[offset] = value.r;\n      this.#buffer[offset + 1] = value.g;\n      this.#buffer[offset + 2] = value.b;\n    }\n    // fire imagechange\n    this.#fireEvent({type: 'imagechange'});\n  }\n\n  /**\n   * Set the inner buffer values at given offsets.\n   *\n   * @param {Array} offsetsLists List of offset lists where to set the data.\n   * @param {object} value The value to set at the given offsets.\n   * @returns {Array} A list of objects representing the original values before\n   *  replacing them.\n   * @fires Image#imagechange\n   */\n  setAtOffsetsAndGetOriginals(offsetsLists, value) {\n    const originalColoursLists = [];\n\n    // update and store\n    for (let j = 0; j < offsetsLists.length; ++j) {\n      const offsets = offsetsLists[j];\n      // first colour\n      let offset = offsets[0] * 3;\n      let previousColour = {\n        r: this.#buffer[offset],\n        g: this.#buffer[offset + 1],\n        b: this.#buffer[offset + 2]\n      };\n      // original value storage\n      const originalColours = [];\n      originalColours.push({\n        index: 0,\n        colour: previousColour\n      });\n      for (let i = 0; i < offsets.length; ++i) {\n        offset = offsets[i] * 3;\n        const currentColour = {\n          r: this.#buffer[offset],\n          g: this.#buffer[offset + 1],\n          b: this.#buffer[offset + 2]\n        };\n        // check if new colour\n        if (previousColour.r !== currentColour.r ||\n          previousColour.g !== currentColour.g ||\n          previousColour.b !== currentColour.b) {\n          // store new colour\n          originalColours.push({\n            index: i,\n            colour: currentColour\n          });\n          previousColour = currentColour;\n        }\n        // write update colour\n        this.#buffer[offset] = value.r;\n        this.#buffer[offset + 1] = value.g;\n        this.#buffer[offset + 2] = value.b;\n      }\n      originalColoursLists.push(originalColours);\n    }\n    // fire imagechange\n    this.#fireEvent({type: 'imagechange'});\n    return originalColoursLists;\n  }\n\n  /**\n   * Set the inner buffer values at given offsets.\n   *\n   * @param {Array} offsetsLists List of offset lists where to set the data.\n   * @param {object|Array} value The value to set at the given offsets.\n   * @fires Image#imagechange\n   */\n  setAtOffsetsWithIterator(offsetsLists, value) {\n    for (let j = 0; j < offsetsLists.length; ++j) {\n      const offsets = offsetsLists[j];\n      let iterator;\n      if (typeof value !== 'undefined' &&\n        typeof value.r !== 'undefined') {\n        // input value is a simple color\n        iterator = colourRange(\n          [{index: 0, colour: value}], offsets.length);\n      } else {\n        // input value is a list of iterators\n        // created by setAtOffsetsAndGetOriginals\n        iterator = colourRange(\n          value[j], offsets.length);\n      }\n\n      // set values\n      let ival = iterator.next();\n      while (!ival.done) {\n        const offset = offsets[ival.index] * 3;\n        this.#buffer[offset] = ival.value.r;\n        this.#buffer[offset + 1] = ival.value.g;\n        this.#buffer[offset + 2] = ival.value.b;\n        ival = iterator.next();\n      }\n    }\n    /**\n     * Image change event.\n     *\n     * @event Image#imagechange\n     * @type {object}\n     */\n    this.#fireEvent({type: 'imagechange'});\n  }\n\n  /**\n   * Get the value of the image at a specific coordinate.\n   *\n   * @param {number} i The X index.\n   * @param {number} j The Y index.\n   * @param {number} k The Z index.\n   * @param {number} f The frame number.\n   * @returns {number} The value at the desired position.\n   * Warning: No size check...\n   */\n  getValue(i, j, k, f) {\n    const frame = (f || 0);\n    const index = new Index([i, j, k, frame]);\n    return this.getValueAtOffset(\n      this.getGeometry().getSize().indexToOffset(index));\n  }\n\n  /**\n   * Get the value of the image at a specific index.\n   *\n   * @param {Index} index The index.\n   * @returns {number} The value at the desired position.\n   * Warning: No size check...\n   */\n  getValueAtIndex(index) {\n    return this.getValueAtOffset(\n      this.getGeometry().getSize().indexToOffset(index));\n  }\n\n  /**\n   * Get the rescaled value of the image at a specific position.\n   *\n   * @param {number} i The X index.\n   * @param {number} j The Y index.\n   * @param {number} k The Z index.\n   * @param {number} f The frame number.\n   * @returns {number} The rescaled value at the desired position.\n   * Warning: No size check...\n   */\n  getRescaledValue(i, j, k, f) {\n    if (typeof f === 'undefined') {\n      f = 0;\n    }\n    let val = this.getValue(i, j, k, f);\n    if (!this.isIdentityRSI()) {\n      if (this.isConstantRSI()) {\n        val = this.getRescaleSlopeAndIntercept().apply(val);\n      } else {\n        const values = [i, j, k, f];\n        const index = new Index(values);\n        val = this.getRescaleSlopeAndIntercept(index).apply(val);\n      }\n    }\n    return val;\n  }\n\n  /**\n   * Get the rescaled value of the image at a specific index.\n   *\n   * @param {Index} index The index.\n   * @returns {number} The rescaled value at the desired position.\n   * Warning: No size check...\n   */\n  getRescaledValueAtIndex(index) {\n    return this.getRescaledValueAtOffset(\n      this.getGeometry().getSize().indexToOffset(index)\n    );\n  }\n\n  /**\n   * Get the rescaled value of the image at a specific offset.\n   *\n   * @param {number} offset The desired offset.\n   * @returns {number} The rescaled value at the desired offset.\n   * Warning: No size check...\n   */\n  getRescaledValueAtOffset(offset) {\n    let val = this.getValueAtOffset(offset);\n    if (!this.isIdentityRSI()) {\n      if (this.isConstantRSI()) {\n        val = this.getRescaleSlopeAndIntercept().apply(val);\n      } else {\n        const index = this.getGeometry().getSize().offsetToIndex(offset);\n        val = this.getRescaleSlopeAndIntercept(index).apply(val);\n      }\n    }\n    return val;\n  }\n\n  /**\n   * Calculate the data range of the image.\n   * WARNING: for speed reasons, only calculated on the first frame...\n   *\n   * @returns {object} The range {min, max}.\n   */\n  calculateDataRange() {\n    let min = this.getValueAtOffset(0);\n    let max = min;\n    let value = 0;\n    const size = this.getGeometry().getSize();\n    let leni = size.getTotalSize();\n    // max to 3D\n    if (size.length() >= 3) {\n      leni = size.getDimSize(3);\n    }\n    for (let i = 0; i < leni; ++i) {\n      value = this.getValueAtOffset(i);\n      if (value > max) {\n        max = value;\n      }\n      if (value < min) {\n        min = value;\n      }\n    }\n    // return\n    return {min: min, max: max};\n  }\n\n  /**\n   * Calculate the rescaled data range of the image.\n   * WARNING: for speed reasons, only calculated on the first frame...\n   *\n   * @returns {object} The range {min, max}.\n   */\n  calculateRescaledDataRange() {\n    if (this.isIdentityRSI()) {\n      return this.getDataRange();\n    } else if (this.isConstantRSI()) {\n      const range = this.getDataRange();\n      const resmin = this.getRescaleSlopeAndIntercept().apply(range.min);\n      const resmax = this.getRescaleSlopeAndIntercept().apply(range.max);\n      return {\n        min: ((resmin < resmax) ? resmin : resmax),\n        max: ((resmin > resmax) ? resmin : resmax)\n      };\n    } else {\n      let rmin = this.getRescaledValueAtOffset(0);\n      let rmax = rmin;\n      let rvalue = 0;\n      const size = this.getGeometry().getSize();\n      let leni = size.getTotalSize();\n      // max to 3D\n      if (size.length() === 3) {\n        leni = size.getDimSize(3);\n      }\n      for (let i = 0; i < leni; ++i) {\n        rvalue = this.getRescaledValueAtOffset(i);\n        if (rvalue > rmax) {\n          rmax = rvalue;\n        }\n        if (rvalue < rmin) {\n          rmin = rvalue;\n        }\n      }\n      // return\n      return {min: rmin, max: rmax};\n    }\n  }\n\n  /**\n   * Calculate the histogram of the image.\n   *\n   * @returns {object} The histogram, data range and rescaled data range.\n   */\n  calculateHistogram() {\n    const size = this.getGeometry().getSize();\n    const histo = [];\n    let min = this.getValueAtOffset(0);\n    let max = min;\n    let value = 0;\n    let rmin = this.getRescaledValueAtOffset(0);\n    let rmax = rmin;\n    let rvalue = 0;\n    for (let i = 0, leni = size.getTotalSize(); i < leni; ++i) {\n      value = this.getValueAtOffset(i);\n      if (value > max) {\n        max = value;\n      }\n      if (value < min) {\n        min = value;\n      }\n      rvalue = this.getRescaledValueAtOffset(i);\n      if (rvalue > rmax) {\n        rmax = rvalue;\n      }\n      if (rvalue < rmin) {\n        rmin = rvalue;\n      }\n      histo[rvalue] = (histo[rvalue] || 0) + 1;\n    }\n    // set data range\n    const dataRange = {min: min, max: max};\n    const rescaledDataRange = {min: rmin, max: rmax};\n    // generate data for plotting\n    const histogram = [];\n    for (let b = rmin; b <= rmax; ++b) {\n      histogram.push([b, (histo[b] || 0)]);\n    }\n    // return\n    return {\n      dataRange: dataRange,\n      rescaledDataRange: rescaledDataRange,\n      histogram: histogram\n    };\n  }\n\n  /**\n   * Convolute the image with a given 2D kernel.\n   *\n   * Note: Uses raw buffer values.\n   *\n   * @param {Array} weights The weights of the 2D kernel as a 3x3 matrix.\n   * @returns {Image} The convoluted image.\n   */\n  convolute2D(weights) {\n    if (weights.length !== 9) {\n      throw new Error(\n        'The convolution matrix does not have a length of 9; it has ' +\n        weights.length);\n    }\n\n    const newImage = this.clone();\n    const newBuffer = newImage.getBuffer();\n\n    const imgSize = this.getGeometry().getSize();\n    const dimOffset = imgSize.getDimSize(2) * this.getNumberOfComponents();\n    for (let k = 0; k < imgSize.get(2); ++k) {\n      this.convoluteBuffer(weights, newBuffer, k * dimOffset);\n    }\n\n    return newImage;\n  }\n\n  /**\n   * Convolute an image buffer with a given 2D kernel.\n   *\n   * Note: Uses raw buffer values.\n   *\n   * @param {Array} weights The weights of the 2D kernel as a 3x3 matrix.\n   * @param {TypedArray} buffer The buffer to convolute.\n   * @param {number} startOffset The index to start at.\n   */\n  convoluteBuffer(\n    weights, buffer, startOffset) {\n    const imgSize = this.getGeometry().getSize();\n    const ncols = imgSize.get(0);\n    const nrows = imgSize.get(1);\n    const ncomp = this.getNumberOfComponents();\n\n    // number of component and planar configuration vars\n    let factor = 1;\n    let componentOffset = 1;\n    if (ncomp === 3) {\n      if (this.getPlanarConfiguration() === 0) {\n        factor = 3;\n      } else {\n        componentOffset = imgSize.getDimSize(2);\n      }\n    }\n\n    // allow special indent for matrices\n    /*jshint indent:false */\n\n    // default weight offset matrix\n    const wOff = [];\n    wOff[0] = (-ncols - 1) * factor;\n    wOff[1] = (-ncols) * factor;\n    wOff[2] = (-ncols + 1) * factor;\n    wOff[3] = -factor;\n    wOff[4] = 0;\n    wOff[5] = 1 * factor;\n    wOff[6] = (ncols - 1) * factor;\n    wOff[7] = (ncols) * factor;\n    wOff[8] = (ncols + 1) * factor;\n\n    // border weight offset matrices\n    // borders are extended (see http://en.wikipedia.org/wiki/Kernel_%28image_processing%29)\n\n    // i=0, j=0\n    const wOff00 = [];\n    wOff00[0] = wOff[4]; wOff00[1] = wOff[4]; wOff00[2] = wOff[5];\n    wOff00[3] = wOff[4]; wOff00[4] = wOff[4]; wOff00[5] = wOff[5];\n    wOff00[6] = wOff[7]; wOff00[7] = wOff[7]; wOff00[8] = wOff[8];\n    // i=0, j=*\n    const wOff0x = [];\n    wOff0x[0] = wOff[1]; wOff0x[1] = wOff[1]; wOff0x[2] = wOff[2];\n    wOff0x[3] = wOff[4]; wOff0x[4] = wOff[4]; wOff0x[5] = wOff[5];\n    wOff0x[6] = wOff[7]; wOff0x[7] = wOff[7]; wOff0x[8] = wOff[8];\n    // i=0, j=nrows\n    const wOff0n = [];\n    wOff0n[0] = wOff[1]; wOff0n[1] = wOff[1]; wOff0n[2] = wOff[2];\n    wOff0n[3] = wOff[4]; wOff0n[4] = wOff[4]; wOff0n[5] = wOff[5];\n    wOff0n[6] = wOff[4]; wOff0n[7] = wOff[4]; wOff0n[8] = wOff[5];\n\n    // i=*, j=0\n    const wOffx0 = [];\n    wOffx0[0] = wOff[3]; wOffx0[1] = wOff[4]; wOffx0[2] = wOff[5];\n    wOffx0[3] = wOff[3]; wOffx0[4] = wOff[4]; wOffx0[5] = wOff[5];\n    wOffx0[6] = wOff[6]; wOffx0[7] = wOff[7]; wOffx0[8] = wOff[8];\n    // i=*, j=* -> wOff\n    // i=*, j=nrows\n    const wOffxn = [];\n    wOffxn[0] = wOff[0]; wOffxn[1] = wOff[1]; wOffxn[2] = wOff[2];\n    wOffxn[3] = wOff[3]; wOffxn[4] = wOff[4]; wOffxn[5] = wOff[5];\n    wOffxn[6] = wOff[3]; wOffxn[7] = wOff[4]; wOffxn[8] = wOff[5];\n\n    // i=ncols, j=0\n    const wOffn0 = [];\n    wOffn0[0] = wOff[3]; wOffn0[1] = wOff[4]; wOffn0[2] = wOff[4];\n    wOffn0[3] = wOff[3]; wOffn0[4] = wOff[4]; wOffn0[5] = wOff[4];\n    wOffn0[6] = wOff[6]; wOffn0[7] = wOff[7]; wOffn0[8] = wOff[7];\n    // i=ncols, j=*\n    const wOffnx = [];\n    wOffnx[0] = wOff[0]; wOffnx[1] = wOff[1]; wOffnx[2] = wOff[1];\n    wOffnx[3] = wOff[3]; wOffnx[4] = wOff[4]; wOffnx[5] = wOff[4];\n    wOffnx[6] = wOff[6]; wOffnx[7] = wOff[7]; wOffnx[8] = wOff[7];\n    // i=ncols, j=nrows\n    const wOffnn = [];\n    wOffnn[0] = wOff[0]; wOffnn[1] = wOff[1]; wOffnn[2] = wOff[1];\n    wOffnn[3] = wOff[3]; wOffnn[4] = wOff[4]; wOffnn[5] = wOff[4];\n    wOffnn[6] = wOff[3]; wOffnn[7] = wOff[4]; wOffnn[8] = wOff[4];\n\n    // restore indent for rest of method\n    /*jshint indent:4 */\n\n    // loop vars\n    let pixelOffset = startOffset;\n    let newValue = 0;\n    let wOffFinal = [];\n    for (let c = 0; c < ncomp; ++c) {\n      // component offset\n      pixelOffset += c * componentOffset;\n      for (let j = 0; j < nrows; ++j) {\n        for (let i = 0; i < ncols; ++i) {\n          wOffFinal = wOff;\n          // special border cases\n          if (i === 0 && j === 0) {\n            wOffFinal = wOff00;\n          } else if (i === 0 && j === (nrows - 1)) {\n            wOffFinal = wOff0n;\n          } else if (i === (ncols - 1) && j === 0) {\n            wOffFinal = wOffn0;\n          } else if (i === (ncols - 1) && j === (nrows - 1)) {\n            wOffFinal = wOffnn;\n          } else if (i === 0 && j !== (nrows - 1) && j !== 0) {\n            wOffFinal = wOff0x;\n          } else if (i === (ncols - 1) && j !== (nrows - 1) && j !== 0) {\n            wOffFinal = wOffnx;\n          } else if (i !== 0 && i !== (ncols - 1) && j === 0) {\n            wOffFinal = wOffx0;\n          } else if (i !== 0 && i !== (ncols - 1) && j === (nrows - 1)) {\n            wOffFinal = wOffxn;\n          }\n          // calculate the weighed sum of the source image pixels that\n          // fall under the convolution matrix\n          newValue = 0;\n          for (let wi = 0; wi < 9; ++wi) {\n            newValue += this.getValueAtOffset(\n              pixelOffset + wOffFinal[wi]) * weights[wi];\n          }\n          buffer[pixelOffset] = newValue;\n          // increment pixel offset\n          pixelOffset += factor;\n        }\n      }\n    }\n  }\n\n  /**\n   * Transform an image using a specific operator.\n   * WARNING: no size check!\n   *\n   * @param {Function} operator The operator to use when transforming.\n   * @returns {Image} The transformed image.\n   * Note: Uses the raw buffer values.\n   */\n  transform(operator) {\n    const newImage = this.clone();\n    const newBuffer = newImage.getBuffer();\n    for (let i = 0, leni = newBuffer.length; i < leni; ++i) {\n      newBuffer[i] = operator(newImage.getValueAtOffset(i));\n    }\n    return newImage;\n  }\n\n  /**\n   * Compose this image with another one and using a specific operator.\n   * WARNING: no size check!\n   *\n   * @param {Image} rhs The image to compose with.\n   * @param {Function} operator The operator to use when composing.\n   * @returns {Image} The composed image.\n   * Note: Uses the raw buffer values.\n   */\n  compose(rhs, operator) {\n    const newImage = this.clone();\n    const newBuffer = newImage.getBuffer();\n    for (let i = 0, leni = newBuffer.length; i < leni; ++i) {\n      // using the operator on the local buffer, i.e. the\n      // latest (not original) data\n      newBuffer[i] = Math.floor(\n        operator(this.getValueAtOffset(i), rhs.getValueAtOffset(i))\n      );\n    }\n    return newImage;\n  }\n\n} // class Image\n","import {View} from './view';\nimport {luts} from './luts';\nimport {\n  WindowCenterAndWidth,\n  defaultPresets\n} from './windowCenterAndWidth';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * {@link View} factory.\n */\nexport class ViewFactory {\n\n  /**\n   * Get an View object from the read DICOM file.\n   *\n   * @param {Object<string, DataElement>} dataElements The DICOM tags.\n   * @param {Image} image The associated image.\n   * @returns {View} The new View.\n   */\n  create(dataElements, image) {\n    // view\n    const view = new View(image);\n\n    // default color map\n    if (image.getPhotometricInterpretation() === 'MONOCHROME1') {\n      view.setDefaultColourMap(luts.invPlain);\n    } else if (image.getPhotometricInterpretation() === 'PALETTE COLOR') {\n      const paletteLut = image.getMeta().paletteLut;\n      if (typeof (paletteLut) !== 'undefined') {\n        view.setDefaultColourMap(paletteLut);\n      }\n    }\n\n    // window level presets\n    let windowPresets = {};\n    // image presets\n    if (typeof image.getMeta().windowPresets !== 'undefined') {\n      windowPresets = image.getMeta().windowPresets;\n    }\n    // min/max\n    // Not filled yet since it is stil too costly to calculate min/max\n    // for each slice... It will be filled at first use\n    // (see view.setWindowLevelPreset).\n    // Order is important, if no wl from DICOM, this will be the default.\n    windowPresets.minmax = {name: 'minmax'};\n    // optional modality presets\n    if (typeof defaultPresets !== 'undefined') {\n      const modality = image.getMeta().Modality;\n      for (const key in defaultPresets[modality]) {\n        const preset = defaultPresets[modality][key];\n        windowPresets[key] = {\n          wl: [new WindowCenterAndWidth(preset.center, preset.width)],\n          name: key\n        };\n      }\n    }\n\n    // store\n    view.setWindowPresets(windowPresets);\n\n    // initialise the view\n    view.init();\n\n    return view;\n  }\n\n} // class ViewFactory\n","import {Index} from '../math/index';\nimport {RescaleLut} from './rescaleLut';\nimport {WindowLut} from './windowLut';\nimport {luts} from './luts';\nimport {WindowCenterAndWidth} from './windowCenterAndWidth';\nimport {generateImageDataMonochrome} from './viewMonochrome';\nimport {generateImageDataPaletteColor} from './viewPaletteColor';\nimport {generateImageDataRgb} from './viewRgb';\nimport {generateImageDataYbrFull} from './viewYbrFull';\nimport {ViewFactory} from './viewFactory';\nimport {getSliceIterator} from '../image/iterator';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\nimport {ColourMap} from './luts';\nimport {Matrix33} from '../math/matrix';\nimport {Point} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * List of view event names.\n *\n * @type {Array}\n */\nexport const viewEventNames = [\n  'wlchange',\n  'wlpresetadd',\n  'colourchange',\n  'positionchange',\n  'opacitychange',\n  'alphafuncchange'\n];\n\n/**\n * Create a View from DICOM elements and image.\n *\n * @param {object} elements The DICOM elements.\n * @param {Image} image The associated image.\n * @returns {View} The View object.\n */\nexport function createView(elements, image) {\n  const factory = new ViewFactory();\n  return factory.create(elements, image);\n}\n\n/**\n * View class.\n *\n * Need to set the window lookup table once created\n * (either directly or with helper methods).\n *\n * @example\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n *   // parse the dicom buffer\n *   const dicomParser = new dwv.DicomParser();\n *   dicomParser.parse(event.target.response);\n *   // create the image object\n *   const image = dwv.createImage(dicomParser.getDicomElements());\n *   // create the view\n *   const view = dwv.createView(dicomParser.getDicomElements(), image);\n *   // setup canvas\n *   const canvas = document.createElement('canvas');\n *   canvas.width = 256;\n *   canvas.height = 256;\n *   const ctx = canvas.getContext(\"2d\");\n *   // update the image data\n *   const imageData = ctx.createImageData(256, 256);\n *   view.generateImageData(imageData);\n *   ctx.putImageData(imageData, 0, 0);\n *   // update html\n *   const div = document.getElementById('dwv');\n *   div.appendChild(canvas);;\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class View {\n\n  /**\n   * The associated image.\n   *\n   * @type {Image}\n   */\n  #image;\n\n  /**\n   * Window lookup tables, indexed per Rescale Slope and Intercept (RSI).\n   *\n   * @type {object}\n   */\n  #windowLuts = {};\n\n  /**\n   * Window presets.\n   * Minmax will be filled at first use (see view.setWindowLevelPreset).\n   *\n   * @type {object}\n   */\n  #windowPresets = {minmax: {name: 'minmax'}};\n\n  /**\n   * Current window preset name.\n   *\n   * @type {string}\n   */\n  #currentPresetName = null;\n\n  /**\n   * Current window level.\n   *\n   * @type {object}\n   */\n  #currentWl = null;\n\n  /**\n   * colour map.\n   *\n   * @type {ColourMap}\n   */\n  #colourMap = luts.plain;\n\n  /**\n   * Current position as a Point.\n   * Store position and not index to stay geometry independent.\n   *\n   * @type {Point}\n   */\n  #currentPosition = null;\n\n  /**\n   * View orientation. Undefined will use the original slice ordering.\n   *\n   * @type {object}\n   */\n  #orientation;\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * @param {Image} image The associated image.\n   */\n  constructor(image) {\n    this.#image = image;\n\n    // listen to appendframe event to update the current position\n    //   to add the extra dimension\n    this.#image.addEventListener('appendframe', () => {\n      // update current position if first appendFrame\n      const index = this.getCurrentIndex();\n      if (index.length() === 3) {\n        // add dimension\n        const values = index.getValues();\n        values.push(0);\n        this.setCurrentIndex(new Index(values));\n      }\n    });\n  }\n\n  /**\n   * Get the associated image.\n   *\n   * @returns {Image} The associated image.\n   */\n  getImage() {\n    return this.#image;\n  }\n\n  /**\n   * Set the associated image.\n   *\n   * @param {Image} inImage The associated image.\n   */\n  setImage(inImage) {\n    this.#image = inImage;\n  }\n\n  /**\n   * Get the view orientation.\n   *\n   * @returns {Matrix33} The orientation matrix.\n   */\n  getOrientation() {\n    return this.#orientation;\n  }\n\n  /**\n   * Set the view orientation.\n   *\n   * @param {Matrix33} mat33 The orientation matrix.\n   */\n  setOrientation(mat33) {\n    this.#orientation = mat33;\n  }\n\n  /**\n   * Initialise the view: set initial index.\n   */\n  init() {\n    this.setInitialIndex();\n  }\n\n  /**\n   * Set the initial index to 0.\n   */\n  setInitialIndex() {\n    const geometry = this.#image.getGeometry();\n    const size = geometry.getSize();\n    const values = new Array(size.length());\n    values.fill(0);\n    // middle\n    values[0] = Math.floor(size.get(0) / 2);\n    values[1] = Math.floor(size.get(1) / 2);\n    values[2] = Math.floor(size.get(2) / 2);\n    this.setCurrentIndex(new Index(values), true);\n  }\n\n  /**\n   * Get the milliseconds per frame from frame rate.\n   *\n   * @param {number} recommendedDisplayFrameRate Recommended Display Frame Rate.\n   * @returns {number} The milliseconds per frame.\n   */\n  getPlaybackMilliseconds(recommendedDisplayFrameRate) {\n    if (!recommendedDisplayFrameRate) {\n      // Default to 10 FPS if none is found in the meta\n      recommendedDisplayFrameRate = 10;\n    }\n    // round milliseconds per frame to nearest whole number\n    return Math.round(1000 / recommendedDisplayFrameRate);\n  }\n\n  /**\n   * Per value alpha function.\n   *\n   * @param {*} _value The pixel value. Can be a number for monochrome\n   *  data or an array for RGB data.\n   * @param {number} _index The data index of the value.\n   * @returns {number} The coresponding alpha [0,255].\n   */\n  #alphaFunction = function (_value, _index) {\n    // default always returns fully visible\n    return 0xff;\n  };\n\n  /**\n   * @callback alphaFn\n   * @param {object} value The pixel value.\n   * @param {object} index The values' index.\n   * @returns {number} The value to display.\n   */\n\n  /**\n   * Get the alpha function.\n   *\n   * @returns {alphaFn} The function.\n   */\n  getAlphaFunction() {\n    return this.#alphaFunction;\n  }\n\n  /**\n   * Set alpha function.\n   *\n   * @param {alphaFn} func The function.\n   * @fires View#alphafuncchange\n   */\n  setAlphaFunction(func) {\n    this.#alphaFunction = func;\n    /**\n     * Alpha func change event.\n     *\n     * @event View#alphafuncchange\n     * @type {object}\n     */\n    this.#fireEvent({\n      type: 'alphafuncchange'\n    });\n  }\n\n  /**\n   * Get the window LUT of the image.\n   * Warning: can be undefined in no window/level was set.\n   *\n   * @param {object} [rsi] Optional image rsi, will take the one of the\n   *   current slice otherwise.\n   * @returns {WindowLut} The window LUT of the image.\n   * @fires View#wlchange\n   */\n  getCurrentWindowLut(rsi) {\n    // check position\n    if (!this.getCurrentIndex()) {\n      this.setInitialIndex();\n    }\n    const currentIndex = this.getCurrentIndex();\n    // use current rsi if not provided\n    if (typeof rsi === 'undefined') {\n      rsi = this.#image.getRescaleSlopeAndIntercept(currentIndex);\n    }\n\n    // get the current window level\n    let wl = null;\n    // special case for 'perslice' presets\n    if (this.#currentPresetName &&\n      typeof this.#windowPresets[this.#currentPresetName] !== 'undefined' &&\n      typeof this.#windowPresets[this.#currentPresetName].perslice !==\n        'undefined' &&\n      this.#windowPresets[this.#currentPresetName].perslice === true) {\n      // get the preset for this slice\n      const offset = this.#image.getSecondaryOffset(currentIndex);\n      wl = this.#windowPresets[this.#currentPresetName].wl[offset];\n    }\n    // regular case\n    if (!wl) {\n      // if no current, use first id\n      if (!this.#currentWl) {\n        this.setWindowLevelPresetById(0, true);\n      }\n      wl = this.#currentWl;\n    }\n\n    // get the window lut\n    let wlut = this.#windowLuts[rsi.toString()];\n    if (typeof wlut === 'undefined') {\n      // create the rescale lookup table\n      const rescaleLut = new RescaleLut(\n        this.#image.getRescaleSlopeAndIntercept(),\n        this.#image.getMeta().BitsStored);\n      // create the window lookup table\n      const windowLut = new WindowLut(\n        rescaleLut, this.#image.getMeta().IsSigned);\n      // store\n      this.addWindowLut(windowLut);\n      wlut = windowLut;\n    }\n\n    // update lut window level if not present or different from previous\n    const lutWl = wlut.getWindowLevel();\n    if (!wl.equals(lutWl)) {\n      // set lut window level\n      wlut.setWindowLevel(wl);\n      wlut.update();\n      // fire change event\n      if (!lutWl ||\n        lutWl.getWidth() !== wl.getWidth() ||\n        lutWl.getCenter() !== wl.getCenter()) {\n        this.#fireEvent({\n          type: 'wlchange',\n          value: [wl.getCenter(), wl.getWidth()],\n          wc: wl.getCenter(),\n          ww: wl.getWidth(),\n          skipGenerate: true\n        });\n      }\n    }\n\n    // return\n    return wlut;\n  }\n\n  /**\n   * Add the window LUT to the list.\n   *\n   * @param {WindowLut} wlut The window LUT of the image.\n   */\n  addWindowLut(wlut) {\n    const rsi = wlut.getRescaleLut().getRSI();\n    this.#windowLuts[rsi.toString()] = wlut;\n  }\n\n  /**\n   * Get the window presets.\n   *\n   * @returns {object} The window presets.\n   */\n  getWindowPresets() {\n    return this.#windowPresets;\n  }\n\n  /**\n   * Get the window presets names.\n   *\n   * @returns {object} The list of window presets names.\n   */\n  getWindowPresetsNames() {\n    return Object.keys(this.#windowPresets);\n  }\n\n  /**\n   * Set the window presets.\n   *\n   * @param {object} presets The window presets.\n   */\n  setWindowPresets(presets) {\n    this.#windowPresets = presets;\n  }\n\n  /**\n   * Set the default colour map.\n   *\n   * @param {ColourMap} map The colour map.\n   */\n  setDefaultColourMap(map) {\n    this.#colourMap = map;\n  }\n\n  /**\n   * Add window presets to the existing ones.\n   *\n   * @param {object} presets The window presets.\n   */\n  addWindowPresets(presets) {\n    const keys = Object.keys(presets);\n    let key = null;\n    for (let i = 0; i < keys.length; ++i) {\n      key = keys[i];\n      if (typeof this.#windowPresets[key] !== 'undefined') {\n        if (typeof this.#windowPresets[key].perslice !== 'undefined' &&\n        this.#windowPresets[key].perslice === true) {\n          throw new Error('Cannot add perslice preset');\n        } else {\n          this.#windowPresets[key] = presets[key];\n        }\n      } else {\n        // add new\n        this.#windowPresets[key] = presets[key];\n        // fire event\n        /**\n         * Window/level add preset event.\n         *\n         * @event View#wlpresetadd\n         * @type {object}\n         * @property {string} name The name of the preset.\n         */\n        this.#fireEvent({\n          type: 'wlpresetadd',\n          name: key\n        });\n      }\n    }\n  }\n\n  /**\n   * Get the colour map of the image.\n   *\n   * @returns {ColourMap} The colour map of the image.\n   */\n  getColourMap() {\n    return this.#colourMap;\n  }\n\n  /**\n   * Set the colour map of the image.\n   *\n   * @param {ColourMap} map The colour map of the image.\n   * @fires View#colourchange\n   */\n  setColourMap(map) {\n    this.#colourMap = map;\n    /**\n     * Color change event.\n     *\n     * @event View#colourchange\n     * @type {object}\n     * @property {Array} value The changed value.\n     * @property {number} wc The new window center value.\n     * @property {number} ww The new window wdth value.\n     */\n    this.#fireEvent({\n      type: 'colourchange',\n      wc: this.getCurrentWindowLut().getWindowLevel().getCenter(),\n      ww: this.getCurrentWindowLut().getWindowLevel().getWidth()\n    });\n  }\n\n  /**\n   * Get the current position.\n   *\n   * @returns {Point} The current position.\n   */\n  getCurrentPosition() {\n    return this.#currentPosition;\n  }\n\n  /**\n   * Get the current index.\n   *\n   * @returns {Index} The current index.\n   */\n  getCurrentIndex() {\n    const position = this.getCurrentPosition();\n    if (!position) {\n      return null;\n    }\n    const geometry = this.getImage().getGeometry();\n    return geometry.worldToIndex(position);\n  }\n\n  /**\n   * Check is the provided position can be set.\n   *\n   * @param {Point} position The position.\n   * @returns {boolean} True is the position is in bounds.\n   */\n  canSetPosition(position) {\n    const geometry = this.#image.getGeometry();\n    const index = geometry.worldToIndex(position);\n    const dirs = [this.getScrollIndex()];\n    if (index.length() === 4) {\n      dirs.push(3);\n    }\n    return geometry.isIndexInBounds(index, dirs);\n  }\n\n  /**\n   * Get the origin at a given position.\n   *\n   * @param {Point} position The position.\n   * @returns {Point} The origin.\n   */\n  getOrigin(position) {\n    const geometry = this.#image.getGeometry();\n    let originIndex = 0;\n    if (typeof position !== 'undefined') {\n      const index = geometry.worldToIndex(position);\n      // index is reoriented, 2 is scroll index\n      originIndex = index.get(2);\n    }\n    return geometry.getOrigins()[originIndex];\n  }\n\n  /**\n   * Set the current position.\n   *\n   * @param {Point} position The new position.\n   * @param {boolean} silent Flag to fire event or not.\n   * @returns {boolean} False if not in bounds\n   * @fires View#positionchange\n   */\n  setCurrentPosition(position, silent) {\n    // send invalid event if not in bounds\n    const geometry = this.#image.getGeometry();\n    const index = geometry.worldToIndex(position);\n    const dirs = [this.getScrollIndex()];\n    if (index.length() === 4) {\n      dirs.push(3);\n    }\n    if (!geometry.isIndexInBounds(index, dirs)) {\n      if (!silent) {\n        // fire event with valid: false\n        this.#fireEvent({\n          type: 'positionchange',\n          value: [\n            index.getValues(),\n            position.getValues(),\n          ],\n          valid: false\n        });\n      }\n      return false;\n    }\n    return this.setCurrentIndex(index, silent);\n  }\n\n  /**\n   * Set the current index.\n   *\n   * @param {Index} index The new index.\n   * @param {boolean} [silent] Flag to fire event or not.\n   * @returns {boolean} False if not in bounds.\n   * @fires View#positionchange\n   */\n  setCurrentIndex(index, silent) {\n    // check input\n    if (typeof silent === 'undefined') {\n      silent = false;\n    }\n\n    const geometry = this.#image.getGeometry();\n    const position = geometry.indexToWorld(index);\n\n    // check if possible\n    const dirs = [this.getScrollIndex()];\n    if (index.length() === 4) {\n      dirs.push(3);\n    }\n    if (!geometry.isIndexInBounds(index, dirs)) {\n      // do no send invalid positionchange event: avoid empty repaint\n      return false;\n    }\n\n    // calculate diff dims before updating internal\n    let diffDims = null;\n    let currentIndex = null;\n    if (this.getCurrentPosition()) {\n      currentIndex = this.getCurrentIndex();\n    }\n    if (currentIndex) {\n      if (currentIndex.canCompare(index)) {\n        diffDims = currentIndex.compare(index);\n      } else {\n        diffDims = [];\n        const minLen = Math.min(currentIndex.length(), index.length());\n        for (let i = 0; i < minLen; ++i) {\n          if (currentIndex.get(i) !== index.get(i)) {\n            diffDims.push(i);\n          }\n        }\n        const maxLen = Math.max(currentIndex.length(), index.length());\n        for (let j = minLen; j < maxLen; ++j) {\n          diffDims.push(j);\n        }\n      }\n    } else {\n      diffDims = [];\n      for (let k = 0; k < index.length(); ++k) {\n        diffDims.push(k);\n      }\n    }\n\n    // assign\n    this.#currentPosition = position;\n\n    if (!silent) {\n      /**\n       * Position change event.\n       *\n       * @event View#positionchange\n       * @type {object}\n       * @property {Array} value The changed value as [index, pixelValue].\n       * @property {Array} diffDims An array of modified indices.\n       */\n      const posEvent = {\n        type: 'positionchange',\n        value: [\n          index.getValues(),\n          position.getValues(),\n        ],\n        diffDims: diffDims,\n        data: {\n          imageUid: this.#image.getImageUid(index)\n        }\n      };\n\n      // add value if possible\n      if (this.#image.canQuantify()) {\n        const pixValue = this.#image.getRescaledValueAtIndex(index);\n        posEvent.value.push(pixValue);\n      }\n\n      // fire\n      this.#fireEvent(posEvent);\n    }\n\n    // all good\n    return true;\n  }\n\n  /**\n   * Set the view window/level.\n   *\n   * @param {number} center The window center.\n   * @param {number} width The window width.\n   * @param {string} [name] Associated preset name, defaults to 'manual'.\n   * Warning: uses the latest set rescale LUT or the default linear one.\n   * @param {boolean} [silent] Flag to launch events with skipGenerate.\n   * @fires View#wlchange\n   */\n  setWindowLevel(center, width, name, silent) {\n    // window width shall be >= 1 (see https://www.dabsoft.ch/dicom/3/C.11.2.1.2/)\n    if (width < 1) {\n      return;\n    }\n\n    // check input\n    if (typeof name === 'undefined') {\n      name = 'manual';\n    }\n    if (typeof silent === 'undefined') {\n      silent = false;\n    }\n\n    // new window level\n    const newWl = new WindowCenterAndWidth(center, width);\n\n    // check if new\n    const isNew = !newWl.equals(this.#currentWl);\n\n    // compare to previous if present\n    if (isNew) {\n      const isNewWidth = this.#currentWl\n        ? this.#currentWl.getWidth() !== width : true;\n      const isNewCenter = this.#currentWl\n        ? this.#currentWl.getCenter() !== center : true;\n      // assign\n      this.#currentWl = newWl;\n      this.#currentPresetName = name;\n\n      if (isNewWidth || isNewCenter) {\n        /**\n         * Window/level change event.\n         *\n         * @event View#wlchange\n         * @type {object}\n         * @property {Array} value The changed value.\n         * @property {number} wc The new window center value.\n         * @property {number} ww The new window wdth value.\n         * @property {boolean} skipGenerate Flag to skip view generation.\n         */\n        this.#fireEvent({\n          type: 'wlchange',\n          value: [center, width],\n          wc: center,\n          ww: width,\n          skipGenerate: silent\n        });\n      }\n    }\n  }\n\n  /**\n   * Set the window level to the preset with the input name.\n   *\n   * @param {string} name The name of the preset to activate.\n   * @param {boolean} [silent] Flag to launch events with skipGenerate.\n   */\n  setWindowLevelPreset(name, silent) {\n    const preset = this.getWindowPresets()[name];\n    if (typeof preset === 'undefined') {\n      throw new Error('Unknown window level preset: \\'' + name + '\\'');\n    }\n    // special min/max\n    if (name === 'minmax' && typeof preset.wl === 'undefined') {\n      preset.wl = [this.getWindowLevelMinMax()];\n    }\n    // default to first\n    let wl = preset.wl[0];\n    // check if 'perslice' case\n    if (typeof preset.perslice !== 'undefined' &&\n      preset.perslice === true) {\n      const offset = this.#image.getSecondaryOffset(this.getCurrentIndex());\n      wl = preset.wl[offset];\n    }\n    // set w/l\n    this.setWindowLevel(\n      wl.getCenter(), wl.getWidth(), name, silent);\n  }\n\n  /**\n   * Set the window level to the preset with the input id.\n   *\n   * @param {number} id The id of the preset to activate.\n   * @param {boolean} [silent] Flag to launch events with skipGenerate.\n   */\n  setWindowLevelPresetById(id, silent) {\n    const keys = Object.keys(this.getWindowPresets());\n    this.setWindowLevelPreset(keys[id], silent);\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  /**\n   * Get the image window/level that covers the full data range.\n   * Warning: uses the latest set rescale LUT or the default linear one.\n   *\n   * @returns {WindowCenterAndWidth} A min/max window level.\n   */\n  getWindowLevelMinMax() {\n    const range = this.getImage().getRescaledDataRange();\n    const min = range.min;\n    const max = range.max;\n    let width = max - min;\n    // full black / white images, defaults to 1.\n    if (width < 1) {\n      logger.warn('Zero or negative window width, defaulting to one.');\n      width = 1;\n    }\n    const center = min + width / 2;\n    return new WindowCenterAndWidth(center, width);\n  }\n\n  /**\n   * Set the image window/level to cover the full data range.\n   * Warning: uses the latest set rescale LUT or the default linear one.\n   */\n  setWindowLevelMinMax() {\n    // calculate center and width\n    const wl = this.getWindowLevelMinMax();\n    // set window level\n    this.setWindowLevel(wl.getCenter(), wl.getWidth(), 'minmax');\n  }\n\n  /**\n   * Generate display image data to be given to a canvas.\n   *\n   * @param {ImageData} data The iamge data to fill in.\n   * @param {Index} index Optional index at which to generate,\n   *   otherwise generates at current index.\n   */\n  generateImageData(data, index) {\n    // check index\n    if (typeof index === 'undefined') {\n      if (!this.getCurrentIndex()) {\n        this.setInitialIndex();\n      }\n      index = this.getCurrentIndex();\n    }\n\n    const image = this.getImage();\n    const iterator = getSliceIterator(\n      image, index, false, this.getOrientation());\n\n    const photoInterpretation = image.getPhotometricInterpretation();\n    switch (photoInterpretation) {\n    case 'MONOCHROME1':\n    case 'MONOCHROME2':\n      generateImageDataMonochrome(\n        data,\n        iterator,\n        this.getAlphaFunction(),\n        this.getCurrentWindowLut(),\n        this.getColourMap()\n      );\n      break;\n\n    case 'PALETTE COLOR':\n      generateImageDataPaletteColor(\n        data,\n        iterator,\n        this.getAlphaFunction(),\n        this.getColourMap(),\n        image.getMeta().BitsStored === 16\n      );\n      break;\n\n    case 'RGB':\n      generateImageDataRgb(\n        data,\n        iterator,\n        this.getAlphaFunction()\n      );\n      break;\n\n    case 'YBR_FULL':\n      generateImageDataYbrFull(\n        data,\n        iterator,\n        this.getAlphaFunction()\n      );\n      break;\n\n    default:\n      throw new Error(\n        'Unsupported photometric interpretation: ' + photoInterpretation);\n    }\n  }\n\n  /**\n   * Increment the provided dimension.\n   *\n   * @param {number} dim The dimension to increment.\n   * @param {boolean} silent Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  incrementIndex(dim, silent) {\n    const index = this.getCurrentIndex();\n    const values = new Array(index.length());\n    values.fill(0);\n    if (dim < values.length) {\n      values[dim] = 1;\n    } else {\n      console.warn('Cannot increment given index: ', dim, values.length);\n    }\n    const incr = new Index(values);\n    const newIndex = index.add(incr);\n    return this.setCurrentIndex(newIndex, silent);\n  }\n\n  /**\n   * Decrement the provided dimension.\n   *\n   * @param {number} dim The dimension to increment.\n   * @param {boolean} silent Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  decrementIndex(dim, silent) {\n    const index = this.getCurrentIndex();\n    const values = new Array(index.length());\n    values.fill(0);\n    if (dim < values.length) {\n      values[dim] = -1;\n    } else {\n      console.warn('Cannot decrement given index: ', dim, values.length);\n    }\n    const incr = new Index(values);\n    const newIndex = index.add(incr);\n    return this.setCurrentIndex(newIndex, silent);\n  }\n\n  /**\n   * Get the scroll dimension index.\n   *\n   * @returns {number} The index.\n   */\n  getScrollIndex() {\n    let index = null;\n    const orientation = this.getOrientation();\n    if (typeof orientation !== 'undefined') {\n      index = orientation.getThirdColMajorDirection();\n    } else {\n      index = 2;\n    }\n    return index;\n  }\n\n  /**\n   * Decrement the scroll dimension index.\n   *\n   * @param {boolean} silent Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  decrementScrollIndex(silent) {\n    return this.decrementIndex(this.getScrollIndex(), silent);\n  }\n\n  /**\n   * Increment the scroll dimension index.\n   *\n   * @param {boolean} silent Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  incrementScrollIndex(silent) {\n    return this.incrementIndex(this.getScrollIndex(), silent);\n  }\n\n} // class View\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {WindowLut} from './windowLut';\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Generate image data for 'MONOCHROME*' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n * @param {WindowLut} windowLut The window/level LUT.\n * @param {ColourMap} colourMap The colour map.\n */\nexport function generateImageDataMonochrome(\n  array,\n  iterator,\n  alphaFunc,\n  windowLut,\n  colourMap) {\n  let index = 0;\n  let pxValue = 0;\n  let ival = iterator.next();\n  while (!ival.done) {\n    // pixel value\n    pxValue = windowLut.getValue(ival.value);\n    // store data\n    array.data[index] = colourMap.red[pxValue];\n    array.data[index + 1] = colourMap.green[pxValue];\n    array.data[index + 2] = colourMap.blue[pxValue];\n    array.data[index + 3] = alphaFunc(ival.value, ival.index);\n    // increment\n    index += 4;\n    ival = iterator.next();\n  }\n}\n","import {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {ColourMap} from './luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * Generate image data for 'PALETTE COLOR' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n * @param {ColourMap} colourMap The colour map.\n * @param {boolean} is16BitsStored Flag to know if the data is 16bits.\n */\nexport function generateImageDataPaletteColor(\n  array,\n  iterator,\n  alphaFunc,\n  colourMap,\n  is16BitsStored) {\n  // right shift 8\n  const to8 = function (value) {\n    return value >> 8;\n  };\n\n  if (is16BitsStored) {\n    logger.info('Scaling 16bits data to 8bits.');\n  }\n\n  let index = 0;\n  let pxValue = 0;\n  let ival = iterator.next();\n  while (!ival.done) {\n    // pixel value\n    pxValue = ival.value;\n    // store data\n    // TODO check pxValue fits in lut\n    if (is16BitsStored) {\n      array.data[index] = to8(colourMap.red[pxValue]);\n      array.data[index + 1] = to8(colourMap.green[pxValue]);\n      array.data[index + 2] = to8(colourMap.blue[pxValue]);\n    } else {\n      array.data[index] = colourMap.red[pxValue];\n      array.data[index + 1] = colourMap.green[pxValue];\n      array.data[index + 2] = colourMap.blue[pxValue];\n    }\n    array.data[index + 3] = alphaFunc(pxValue, ival.index);\n    // increment\n    index += 4;\n    ival = iterator.next();\n  }\n}\n","/**\n * Generate image data for 'RGB' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n */\nexport function generateImageDataRgb(\n  array,\n  iterator,\n  alphaFunc) {\n  let index = 0;\n  let ival = iterator.next();\n  while (!ival.done) {\n    // store data\n    array.data[index] = ival.value[0];\n    array.data[index + 1] = ival.value[1];\n    array.data[index + 2] = ival.value[2];\n    array.data[index + 3] = alphaFunc(ival.value, ival.index);\n    // increment\n    index += 4;\n    ival = iterator.next();\n  }\n}\n","import {ybrToRgb} from '../utils/colour';\n\n/**\n * Generate image data for 'YBR_FULL' photometric interpretation.\n *\n * @param {ImageData} array The array to store the outut data\n * @param {object} iterator Position iterator.\n * @param {Function} alphaFunc The alpha function.\n */\nexport function generateImageDataYbrFull(\n  array,\n  iterator,\n  alphaFunc) {\n  let index = 0;\n  let rgb = null;\n  let ival = iterator.next();\n  while (!ival.done) {\n    // convert ybr to rgb\n    rgb = ybrToRgb(ival.value[0], ival.value[1], ival.value[2]);\n    // store data\n    array.data[index] = rgb.r;\n    array.data[index + 1] = rgb.g;\n    array.data[index + 2] = rgb.b;\n    array.data[index + 3] = alphaFunc(ival.value, ival.index);\n    // increment\n    index += 4;\n    ival = iterator.next();\n  }\n}\n","import {Vector3D} from '../math/vector';\nimport {Point3D} from '../math/point';\nimport {getTargetOrientation} from '../gui/layerGroup';\nimport {getOrientedArray3D, getDeOrientedArray3D} from './geometry';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\nimport {Spacing} from './spacing';\n/* eslint-enable no-unused-vars */\n\n/**\n * Plane geometry helper.\n */\nexport class PlaneHelper {\n\n  /**\n   * The associated spacing.\n   *\n   * @type {Spacing}\n   */\n  #spacing;\n\n  /**\n   * The image orientation.\n   *\n   * @type {Matrix33}\n   */\n  #imageOrientation;\n\n  /**\n   * The viewe orientation.\n   *\n   * @type {Matrix33}\n   */\n  #viewOrientation;\n\n  /**\n   * The target orientation.\n   *\n   * @type {Matrix33}\n   */\n  #targetOrientation;\n\n  /**\n   * @param {Spacing} spacing The spacing.\n   * @param {Matrix33} imageOrientation The image oientation.\n   * @param {Matrix33} viewOrientation The view orientation.\n   */\n  constructor(spacing, imageOrientation, viewOrientation) {\n    this.#spacing = spacing;\n    this.#imageOrientation = imageOrientation;\n    this.#viewOrientation = viewOrientation;\n\n    this.#targetOrientation = getTargetOrientation(\n      imageOrientation, viewOrientation);\n  }\n\n  /**\n   * Get a 3D offset from a plane one.\n   *\n   * @param {object} offset2D The plane offset as {x,y}.\n   * @returns {Vector3D} The 3D world offset.\n   */\n  getOffset3DFromPlaneOffset(offset2D) {\n    // make 3D\n    const planeOffset = new Vector3D(\n      offset2D.x, offset2D.y, 0);\n    // de-orient\n    const pixelOffset = this.getTargetDeOrientedVector3D(planeOffset);\n    // ~indexToWorld\n    return new Vector3D(\n      pixelOffset.getX() * this.#spacing.get(0),\n      pixelOffset.getY() * this.#spacing.get(1),\n      pixelOffset.getZ() * this.#spacing.get(2));\n  }\n\n  /**\n   * Get a plane offset from a 3D one.\n   *\n   * @param {object} offset3D The 3D offset as {x,y,z}.\n   * @returns {object} The plane offset as {x,y}.\n   */\n  getPlaneOffsetFromOffset3D(offset3D) {\n    // ~worldToIndex\n    const pixelOffset = new Vector3D(\n      offset3D.x / this.#spacing.get(0),\n      offset3D.y / this.#spacing.get(1),\n      offset3D.z / this.#spacing.get(2));\n    // orient\n    const planeOffset = this.getTargetOrientedVector3D(pixelOffset);\n    // make 2D\n    return {\n      x: planeOffset.getX(),\n      y: planeOffset.getY()\n    };\n  }\n\n  /**\n   * Orient an input vector from real to target space.\n   *\n   * @param {Vector3D} vector The input vector.\n   * @returns {Vector3D} The oriented vector.\n   */\n  getTargetOrientedVector3D(vector) {\n    let planeVector = vector;\n    if (typeof this.#targetOrientation !== 'undefined') {\n      planeVector =\n        this.#targetOrientation.getInverse().multiplyVector3D(vector);\n    }\n    return planeVector;\n  }\n\n  /**\n   * De-orient an input vector from target to real space.\n   *\n   * @param {Vector3D} planeVector The input vector.\n   * @returns {Vector3D} The de-orienteded vector.\n   */\n  getTargetDeOrientedVector3D(planeVector) {\n    let vector = planeVector;\n    if (typeof this.#targetOrientation !== 'undefined') {\n      vector = this.#targetOrientation.multiplyVector3D(planeVector);\n    }\n    return vector;\n  }\n\n  /**\n   * De-orient an input point from target to real space.\n   *\n   * @param {Point3D} planePoint The input point.\n   * @returns {Point3D} The de-orienteded point.\n   */\n  getTargetDeOrientedPoint3D(planePoint) {\n    let point = planePoint;\n    if (typeof this.#targetOrientation !== 'undefined') {\n      point = this.#targetOrientation.multiplyPoint3D(planePoint);\n    }\n    return point;\n  }\n\n  /**\n   * Orient an input vector from target to image space.\n   *\n   * @param {Vector3D} planeVector The input vector.\n   * @returns {Vector3D} The orienteded vector.\n   */\n  getImageOrientedVector3D(planeVector) {\n    let vector = planeVector;\n    if (typeof this.#viewOrientation !== 'undefined') {\n      // image oriented => view de-oriented\n      const values = getDeOrientedArray3D(\n        [\n          planeVector.getX(),\n          planeVector.getY(),\n          planeVector.getZ()\n        ],\n        this.#viewOrientation);\n      vector = new Vector3D(\n        values[0],\n        values[1],\n        values[2]\n      );\n    }\n    return vector;\n  }\n\n  /**\n   * Orient an input point from target to image space.\n   *\n   * @param {Point3D} planePoint The input vector.\n   * @returns {Point3D} The orienteded vector.\n   */\n  getImageOrientedPoint3D(planePoint) {\n    let point = planePoint;\n    if (typeof this.#viewOrientation !== 'undefined') {\n      // image oriented => view de-oriented\n      const values = getDeOrientedArray3D(\n        [\n          planePoint.getX(),\n          planePoint.getY(),\n          planePoint.getZ()\n        ],\n        this.#viewOrientation);\n      point = new Point3D(\n        values[0],\n        values[1],\n        values[2]\n      );\n    }\n    return point;\n  }\n\n  /**\n   * De-orient an input vector from image to target space.\n   *\n   * @param {Vector3D} vector The input vector.\n   * @returns {Vector3D} The de-orienteded vector.\n   */\n  getImageDeOrientedVector3D(vector) {\n    let planeVector = vector;\n    if (typeof this.#viewOrientation !== 'undefined') {\n      // image de-oriented => view oriented\n      const orientedValues = getOrientedArray3D(\n        [\n          vector.getX(),\n          vector.getY(),\n          vector.getZ()\n        ],\n        this.#viewOrientation);\n      planeVector = new Vector3D(\n        orientedValues[0],\n        orientedValues[1],\n        orientedValues[2]\n      );\n    }\n    return planeVector;\n  }\n\n  /**\n   * De-orient an input point from image to target space.\n   *\n   * @param {Point3D} point The input point.\n   * @returns {Point3D} The de-orienteded point.\n   */\n  getImageDeOrientedPoint3D(point) {\n    let planePoint = point;\n    if (typeof this.#viewOrientation !== 'undefined') {\n      // image de-oriented => view oriented\n      const orientedValues = getOrientedArray3D(\n        [\n          point.getX(),\n          point.getY(),\n          point.getZ()\n        ],\n        this.#viewOrientation);\n      planePoint = new Point3D(\n        orientedValues[0],\n        orientedValues[1],\n        orientedValues[2]\n      );\n    }\n    return planePoint;\n  }\n\n  /**\n   * Reorder values to follow target orientation.\n   *\n   * @param {object} values Values as {x,y,z}.\n   * @returns {object} Reoriented values as {x,y,z}.\n   */\n  getTargetOrientedPositiveXYZ(values) {\n    const orientedValues = getOrientedArray3D(\n      [\n        values.x,\n        values.y,\n        values.z\n      ],\n      this.#targetOrientation);\n    return {\n      x: orientedValues[0],\n      y: orientedValues[1],\n      z: orientedValues[2]\n    };\n  }\n\n  /**\n   * Get the (view) scroll dimension index.\n   *\n   * @returns {number} The index.\n   */\n  getScrollIndex() {\n    let index = null;\n    if (typeof this.#viewOrientation !== 'undefined') {\n      index = this.#viewOrientation.getThirdColMajorDirection();\n    } else {\n      index = 2;\n    }\n    return index;\n  }\n\n  /**\n   * Get the native (image) scroll dimension index.\n   *\n   * @returns {number} The index.\n   */\n  getNativeScrollIndex() {\n    let index = null;\n    if (typeof this.#imageOrientation !== 'undefined') {\n      index = this.#imageOrientation.getThirdColMajorDirection();\n    } else {\n      index = 2;\n    }\n    return index;\n  }\n\n} // class PlaneHelper\n","import {getIdentityMat33, getCoronalMat33} from '../math/matrix';\nimport {Index} from '../math/index';\nimport {Point} from '../math/point';\nimport {Vector3D} from '../math/vector';\nimport {viewEventNames} from '../image/view';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\nimport {ViewLayer} from './viewLayer';\nimport {DrawLayer} from './drawLayer';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Matrix33} from '../math/matrix';\nimport {Point3D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the layer div id.\n *\n * @param {string} groupDivId The layer group div id.\n * @param {number} layerId The lyaer id.\n * @returns {string} A string id.\n */\nexport function getLayerDivId(groupDivId, layerId) {\n  return groupDivId + '-layer-' + layerId;\n}\n\n/**\n * Get the layer details from a div id.\n *\n * @param {string} idString The layer div id.\n * @returns {object} The layer details as {groupDivId, layerId}.\n */\nexport function getLayerDetailsFromLayerDivId(idString) {\n  const split = idString.split('-layer-');\n  if (split.length !== 2) {\n    logger.warn('Not the expected layer div id format...');\n  }\n  return {\n    groupDivId: split[0],\n    layerId: split[1]\n  };\n}\n\n/**\n * Get the layer details from a mouse event.\n *\n * @param {object} event The event to get the layer div id from. Expecting\n * an event origininating from a canvas inside a layer HTML div\n * with the 'layer' class and id generated with `getLayerDivId`.\n * @returns {object} The layer details as {groupDivId, layerId}.\n */\nexport function getLayerDetailsFromEvent(event) {\n  let res = null;\n  // get the closest element from the event target and with the 'layer' class\n  const layerDiv = event.target.closest('.layer');\n  if (layerDiv && typeof layerDiv.id !== 'undefined') {\n    res = getLayerDetailsFromLayerDivId(layerDiv.id);\n  }\n  return res;\n}\n\n/**\n * Get the view orientation according to an image and target orientation.\n * The view orientation is used to go from target to image space.\n *\n * @param {Matrix33} imageOrientation The image geometry.\n * @param {Matrix33} targetOrientation The target orientation.\n * @returns {Matrix33} The view orientation.\n */\nexport function getViewOrientation(imageOrientation, targetOrientation) {\n  let viewOrientation = getIdentityMat33();\n  if (typeof targetOrientation !== 'undefined') {\n    // i: image, v: view, t: target, O: orientation, P: point\n    // [Img] -- Oi --> [Real] <-- Ot -- [Target]\n    // Pi = (Oi)-1 * Ot * Pt = Ov * Pt\n    // -> Ov = (Oi)-1 * Ot\n    // TODO: asOneAndZeros simplifies but not nice...\n    viewOrientation =\n      imageOrientation.asOneAndZeros().getInverse().multiply(targetOrientation);\n  }\n  // TODO: why abs???\n  return viewOrientation.getAbs();\n}\n\n/**\n * Get the target orientation according to an image and view orientation.\n * The target orientation is used to go from target to real space.\n *\n * @param {Matrix33} imageOrientation The image geometry.\n * @param {Matrix33} viewOrientation The view orientation.\n * @returns {Matrix33} The target orientation.\n */\nexport function getTargetOrientation(imageOrientation, viewOrientation) {\n  // i: image, v: view, t: target, O: orientation, P: point\n  // [Img] -- Oi --> [Real] <-- Ot -- [Target]\n  // Pi = (Oi)-1 * Ot * Pt = Ov * Pt\n  // -> Ot = Oi * Ov\n  // note: asOneAndZeros as in getViewOrientation...\n  let targetOrientation =\n    imageOrientation.asOneAndZeros().multiply(viewOrientation);\n\n  // TODO: why abs???\n  const simpleImageOrientation = imageOrientation.asOneAndZeros().getAbs();\n  if (simpleImageOrientation.equals(getCoronalMat33().getAbs())) {\n    targetOrientation = targetOrientation.getAbs();\n  }\n\n  return targetOrientation;\n}\n\n/**\n * Get a scaled offset to adapt to new scale and such as the input center\n * stays at the same position.\n *\n * @param {object} offset The previous offset as {x,y}.\n * @param {object} scale The previous scale as {x,y}.\n * @param {object} newScale The new scale as {x,y}.\n * @param {object} center The scale center as {x,y}.\n * @returns {object} The scaled offset as {x,y}.\n */\nexport function getScaledOffset(offset, scale, newScale, center) {\n  // worldPoint = indexPoint / scale + offset\n  //=> indexPoint = (worldPoint - offset ) * scale\n\n  // plane center should stay the same:\n  // indexCenter / newScale + newOffset =\n  //   indexCenter / oldScale + oldOffset\n  //=> newOffset = indexCenter / oldScale + oldOffset -\n  //     indexCenter / newScale\n  //=> newOffset = worldCenter - indexCenter / newScale\n  const indexCenter = {\n    x: (center.x - offset.x) * scale.x,\n    y: (center.y - offset.y) * scale.y\n  };\n  return {\n    x: center.x - (indexCenter.x / newScale.x),\n    y: center.y - (indexCenter.y / newScale.y)\n  };\n}\n\n/**\n * Layer group.\n *\n * Display position: {x,y}\n * Plane position: Index (access: get(i))\n * (world) Position: Point3D (access: getX, getY, getZ)\n *\n * Display -> World:\n * planePos = viewLayer.displayToPlanePos(displayPos)\n * -> compensate for layer scale and offset\n * pos = viewController.getPositionFromPlanePoint(planePos)\n *\n * World -> display\n * planePos = viewController.getOffset3DFromPlaneOffset(pos)\n * no need yet for a planePos to displayPos...\n */\nexport class LayerGroup {\n\n  /**\n   * The container div.\n   *\n   * @type {HTMLElement}\n   */\n  #containerDiv;\n\n  /**\n   * List of layers.\n   *\n   * @type {Array}\n   */\n  #layers = [];\n\n  /**\n   * The layer scale as {x,y}.\n   *\n   * @type {object}\n   */\n  #scale = {x: 1, y: 1, z: 1};\n\n  /**\n   * The base scale as {x,y}: all posterior scale will be on top of this one.\n   *\n   * @type {object}\n   */\n  #baseScale = {x: 1, y: 1, z: 1};\n\n  /**\n   * The layer offset as {x,y}.\n   *\n   * @type {object}\n   */\n  #offset = {x: 0, y: 0, z: 0};\n\n  /**\n   * Active view layer index.\n   *\n   * @type {number}\n   */\n  #activeViewLayerIndex = null;\n\n  /**\n   * Active draw layer index.\n   *\n   * @type {number}\n   */\n  #activeDrawLayerIndex = null;\n\n  /**\n   * Listener handler.\n   *\n   * @type {ListenerHandler}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * The target orientation matrix.\n   *\n   * @type {Matrix33}\n   */\n  #targetOrientation;\n\n  /**\n   * Flag to activate crosshair or not.\n   *\n   * @type {boolean}\n   */\n  #showCrosshair = false;\n\n  /**\n   * The current position used for the crosshair.\n   *\n   * @type {Point}\n   */\n  #currentPosition;\n\n  /**\n   * @param {HTMLElement} containerDiv The associated HTML div.\n   */\n  constructor(containerDiv) {\n    this.#containerDiv = containerDiv;\n  }\n\n  /**\n   * Get the target orientation.\n   *\n   * @returns {Matrix33} The orientation matrix.\n   */\n  getTargetOrientation() {\n    return this.#targetOrientation;\n  }\n\n  /**\n   * Set the target orientation.\n   *\n   * @param {Matrix33} orientation The orientation matrix.\n   */\n  setTargetOrientation(orientation) {\n    this.#targetOrientation = orientation;\n  }\n\n  /**\n   * Get the showCrosshair flag.\n   *\n   * @returns {boolean} True to display the crosshair.\n   */\n  getShowCrosshair() {\n    return this.#showCrosshair;\n  }\n\n  /**\n   * Set the showCrosshair flag.\n   *\n   * @param {boolean} flag True to display the crosshair.\n   */\n  setShowCrosshair(flag) {\n    this.#showCrosshair = flag;\n    if (flag) {\n      // listen to offset and zoom change\n      this.addEventListener('offsetchange', this.#updateCrosshairOnChange);\n      this.addEventListener('zoomchange', this.#updateCrosshairOnChange);\n      // show crosshair div\n      this.#showCrosshairDiv();\n    } else {\n      // listen to offset and zoom change\n      this.removeEventListener('offsetchange', this.#updateCrosshairOnChange);\n      this.removeEventListener('zoomchange', this.#updateCrosshairOnChange);\n      // remove crosshair div\n      this.#removeCrosshairDiv();\n    }\n  }\n\n  /**\n   * Update crosshair on offset or zoom change.\n   *\n   * @param {object} _event The change event.\n   */\n  #updateCrosshairOnChange = (_event) => {\n    this.#showCrosshairDiv();\n  };\n\n  /**\n   * Get the Id of the container div.\n   *\n   * @returns {string} The id of the div.\n   */\n  getDivId() {\n    return this.#containerDiv.id;\n  }\n\n  /**\n   * Get the layer scale.\n   *\n   * @returns {object} The scale as {x,y,z}.\n   */\n  getScale() {\n    return this.#scale;\n  }\n\n  /**\n   * Get the base scale.\n   *\n   * @returns {object} The scale as {x,y,z}.\n   */\n  getBaseScale() {\n    return this.#baseScale;\n  }\n\n  /**\n   * Get the added scale: the scale added to the base scale\n   *\n   * @returns {object} The scale as {x,y,z}.\n   */\n  getAddedScale() {\n    return {\n      x: this.#scale.x / this.#baseScale.x,\n      y: this.#scale.y / this.#baseScale.y,\n      z: this.#scale.z / this.#baseScale.z\n    };\n  }\n\n  /**\n   * Get the layer offset.\n   *\n   * @returns {object} The offset as {x,y,z}.\n   */\n  getOffset() {\n    return this.#offset;\n  }\n\n  /**\n   * Get the number of layers handled by this class.\n   *\n   * @returns {number} The number of layers.\n   */\n  getNumberOfLayers() {\n    return this.#layers.length;\n  }\n\n  /**\n   * Get the active image layer.\n   *\n   * @returns {ViewLayer} The layer.\n   */\n  getActiveViewLayer() {\n    return this.#layers[this.#activeViewLayerIndex];\n  }\n\n  /**\n   * Get the view layers associated to a data index.\n   *\n   * @param {number} index The data index.\n   * @returns {ViewLayer[]} The layers.\n   */\n  getViewLayersByDataIndex(index) {\n    const res = [];\n    for (let i = 0; i < this.#layers.length; ++i) {\n      if (this.#layers[i] instanceof ViewLayer &&\n        this.#layers[i].getDataIndex() === index) {\n        res.push(this.#layers[i]);\n      }\n    }\n    return res;\n  }\n\n  /**\n   * Search view layers for equal imae meta data.\n   *\n   * @param {object} meta The meta data to find.\n   * @returns {ViewLayer[]} The list of view layers that contain matched data.\n   */\n  searchViewLayers(meta) {\n    const res = [];\n    for (let i = 0; i < this.#layers.length; ++i) {\n      if (this.#layers[i] instanceof ViewLayer) {\n        if (this.#layers[i].getViewController().equalImageMeta(meta)) {\n          res.push(this.#layers[i]);\n        }\n      }\n    }\n    return res;\n  }\n\n  /**\n   * Get the view layers data indices.\n   *\n   * @returns {Array} The list of indices.\n   */\n  getViewDataIndices() {\n    const res = [];\n    for (let i = 0; i < this.#layers.length; ++i) {\n      if (this.#layers[i] instanceof ViewLayer) {\n        res.push(this.#layers[i].getDataIndex());\n      }\n    }\n    return res;\n  }\n\n  /**\n   * Get the active draw layer.\n   *\n   * @returns {DrawLayer} The layer.\n   */\n  getActiveDrawLayer() {\n    return this.#layers[this.#activeDrawLayerIndex];\n  }\n\n  /**\n   * Get the draw layers associated to a data index.\n   *\n   * @param {number} index The data index.\n   * @returns {DrawLayer[]} The layers.\n   */\n  getDrawLayersByDataIndex(index) {\n    const res = [];\n    for (let i = 0; i < this.#layers.length; ++i) {\n      if (this.#layers[i] instanceof DrawLayer &&\n        this.#layers[i].getDataIndex() === index) {\n        res.push(this.#layers[i]);\n      }\n    }\n    return res;\n  }\n\n  /**\n   * Set the active view layer.\n   *\n   * @param {number} index The index of the layer to set as active.\n   */\n  setActiveViewLayer(index) {\n    this.#activeViewLayerIndex = index;\n  }\n\n  /**\n   * Set the active view layer with a data index.\n   *\n   * @param {number} index The data index.\n   */\n  setActiveViewLayerByDataIndex(index) {\n    for (let i = 0; i < this.#layers.length; ++i) {\n      if (this.#layers[i] instanceof ViewLayer &&\n        this.#layers[i].getDataIndex() === index) {\n        this.setActiveViewLayer(i);\n        break;\n      }\n    }\n  }\n\n  /**\n   * Set the active draw layer.\n   *\n   * @param {number} index The index of the layer to set as active.\n   */\n  setActiveDrawLayer(index) {\n    this.#activeDrawLayerIndex = index;\n  }\n\n  /**\n   * Set the active draw layer with a data index.\n   *\n   * @param {number} index The data index.\n   */\n  setActiveDrawLayerByDataIndex(index) {\n    for (let i = 0; i < this.#layers.length; ++i) {\n      if (this.#layers[i] instanceof DrawLayer &&\n        this.#layers[i].getDataIndex() === index) {\n        this.setActiveDrawLayer(i);\n        break;\n      }\n    }\n  }\n\n  /**\n   * Add a view layer.\n   *\n   * @returns {ViewLayer} The created layer.\n   */\n  addViewLayer() {\n    // layer index\n    const viewLayerIndex = this.#layers.length;\n    // create div\n    const div = this.#getNextLayerDiv();\n    // prepend to container\n    this.#containerDiv.append(div);\n    // view layer\n    const layer = new ViewLayer(div);\n    // add layer\n    this.#layers.push(layer);\n    // mark it as active\n    this.setActiveViewLayer(viewLayerIndex);\n    // bind view layer events\n    this.#bindViewLayer(layer);\n    // return\n    return layer;\n  }\n\n  /**\n   * Add a draw layer.\n   *\n   * @returns {DrawLayer} The created layer.\n   */\n  addDrawLayer() {\n    // store active index\n    this.#activeDrawLayerIndex = this.#layers.length;\n    // create div\n    const div = this.#getNextLayerDiv();\n    // prepend to container\n    this.#containerDiv.append(div);\n    // draw layer\n    const layer = new DrawLayer(div);\n    // add layer\n    this.#layers.push(layer);\n    // bind draw layer events\n    this.#bindDrawLayer(layer);\n    // return\n    return layer;\n  }\n\n  /**\n   * Bind view layer events to this.\n   *\n   * @param {ViewLayer} viewLayer The view layer to bind.\n   */\n  #bindViewLayer(viewLayer) {\n    // listen to position change to update other group layers\n    viewLayer.addEventListener(\n      'positionchange', this.updateLayersToPositionChange);\n    // propagate view viewLayer-layer events\n    for (let j = 0; j < viewEventNames.length; ++j) {\n      viewLayer.addEventListener(viewEventNames[j], this.#fireEvent);\n    }\n    // propagate viewLayer events\n    viewLayer.addEventListener('renderstart', this.#fireEvent);\n    viewLayer.addEventListener('renderend', this.#fireEvent);\n  }\n\n  /**\n   * Bind draw layer events to this.\n   *\n   * @param {DrawLayer} drawLayer The draw layer to bind.\n   */\n  #bindDrawLayer(drawLayer) {\n    // propagate drawLayer events\n    drawLayer.addEventListener('drawcreate', this.#fireEvent);\n    drawLayer.addEventListener('drawdelete', this.#fireEvent);\n  }\n\n  /**\n   * Get the next layer DOM div.\n   *\n   * @returns {HTMLDivElement} A DOM div.\n   */\n  #getNextLayerDiv() {\n    const div = document.createElement('div');\n    div.id = getLayerDivId(this.getDivId(), this.#layers.length);\n    div.className = 'layer';\n    div.style.pointerEvents = 'none';\n    return div;\n  }\n\n  /**\n   * Empty the layer list.\n   */\n  empty() {\n    this.#layers = [];\n    // reset active indices\n    this.#activeViewLayerIndex = null;\n    this.#activeDrawLayerIndex = null;\n    // clean container div\n    const previous = this.#containerDiv.getElementsByClassName('layer');\n    if (previous) {\n      while (previous.length > 0) {\n        previous[0].remove();\n      }\n    }\n  }\n\n  /**\n   * Show a crosshair at a given position.\n   *\n   * @param {Point} [position] The position where to show the crosshair,\n   *   defaults to current position.\n   */\n  #showCrosshairDiv(position) {\n    if (typeof position === 'undefined') {\n      position = this.#currentPosition;\n    }\n\n    // remove previous\n    this.#removeCrosshairDiv();\n\n    // use first layer as base for calculating position and\n    // line sizes\n    const layer0 = this.#layers[0];\n    const vc = layer0.getViewController();\n    const p2D = vc.getPlanePositionFromPosition(position);\n    const displayPos = layer0.planePosToDisplay(p2D.x, p2D.y);\n\n    const lineH = document.createElement('hr');\n    lineH.id = this.getDivId() + '-scroll-crosshair-horizontal';\n    lineH.className = 'horizontal';\n    lineH.style.width = this.#containerDiv.offsetWidth + 'px';\n    lineH.style.left = '0px';\n    lineH.style.top = displayPos.y + 'px';\n\n    const lineV = document.createElement('hr');\n    lineV.id = this.getDivId() + '-scroll-crosshair-vertical';\n    lineV.className = 'vertical';\n    lineV.style.width = this.#containerDiv.offsetHeight + 'px';\n    lineV.style.left = (displayPos.x) + 'px';\n    lineV.style.top = '0px';\n\n    this.#containerDiv.appendChild(lineH);\n    this.#containerDiv.appendChild(lineV);\n  }\n\n  /**\n   * Remove crosshair divs.\n   */\n  #removeCrosshairDiv() {\n    let div = document.getElementById(\n      this.getDivId() + '-scroll-crosshair-horizontal');\n    if (div) {\n      div.remove();\n    }\n    div = document.getElementById(\n      this.getDivId() + '-scroll-crosshair-vertical');\n    if (div) {\n      div.remove();\n    }\n  }\n\n  /**\n   * Update layers (but not the active view layer) to a position change.\n   *\n   * @param {object} event The position change event.\n   * @function\n   */\n  updateLayersToPositionChange = (event) => {\n    // pause positionchange listeners\n    for (let j = 0; j < this.#layers.length; ++j) {\n      if (this.#layers[j] instanceof ViewLayer) {\n        this.#layers[j].removeEventListener(\n          'positionchange', this.updateLayersToPositionChange);\n        this.#layers[j].removeEventListener('positionchange', this.#fireEvent);\n      }\n    }\n\n    const index = new Index(event.value[0]);\n    const position = new Point(event.value[1]);\n\n    // store current position\n    this.#currentPosition = position;\n\n    if (this.#showCrosshair) {\n      this.#showCrosshairDiv(position);\n    }\n\n    // origin of the first view layer\n    let baseViewLayerOrigin0 = null;\n    let baseViewLayerOrigin = null;\n    // update position for all layers except the source one\n    for (let i = 0; i < this.#layers.length; ++i) {\n\n      // update base offset (does not trigger redraw)\n      // TODO check draw layers update\n      let hasSetOffset = false;\n      if (this.#layers[i] instanceof ViewLayer) {\n        const vc = this.#layers[i].getViewController();\n        // origin0 should always be there\n        const origin0 = vc.getOrigin();\n        // depending on position, origin could be undefined\n        const origin = vc.getOrigin(position);\n\n        if (!baseViewLayerOrigin) {\n          baseViewLayerOrigin0 = origin0;\n          baseViewLayerOrigin = origin;\n        } else {\n          if (vc.canSetPosition(position) &&\n            typeof origin !== 'undefined') {\n            // TODO: compensate for possible different orientation between views\n\n            const scrollDiff = baseViewLayerOrigin0.minus(origin0);\n            const scrollOffset = new Vector3D(\n              scrollDiff.getX(), scrollDiff.getY(), scrollDiff.getZ());\n\n            const planeDiff = baseViewLayerOrigin.minus(origin);\n            const planeOffset = new Vector3D(\n              planeDiff.getX(), planeDiff.getY(), planeDiff.getZ());\n\n            hasSetOffset =\n              this.#layers[i].setBaseOffset(scrollOffset, planeOffset);\n          }\n        }\n      }\n\n      // update position (triggers redraw)\n      let hasSetPos = false;\n      if (this.#layers[i].getId() !== event.srclayerid) {\n        hasSetPos = this.#layers[i].setCurrentPosition(position, index);\n      }\n\n      // force redraw if needed\n      if (!hasSetPos && hasSetOffset) {\n        this.#layers[i].draw();\n      }\n    }\n\n    // re-start positionchange listeners\n    for (let k = 0; k < this.#layers.length; ++k) {\n      if (this.#layers[k] instanceof ViewLayer) {\n        this.#layers[k].addEventListener(\n          'positionchange', this.updateLayersToPositionChange);\n        this.#layers[k].addEventListener('positionchange', this.#fireEvent);\n      }\n    }\n  };\n\n  /**\n   * Calculate the fit scale: the scale that fits the largest data.\n   *\n   * @returns {number|undefined} The fit scale.\n   */\n  calculateFitScale() {\n    // check container\n    if (this.#containerDiv.offsetWidth === 0 &&\n      this.#containerDiv.offsetHeight === 0) {\n      throw new Error('Cannot fit to zero sized container.');\n    }\n    // get max size\n    const maxSize = this.getMaxSize();\n    if (typeof maxSize === 'undefined') {\n      return undefined;\n    }\n    // if the container has a width but no height,\n    // resize it to follow the same ratio to completely\n    // fill the div with the image\n    if (this.#containerDiv.offsetHeight === 0) {\n      const ratioX = this.#containerDiv.offsetWidth / maxSize.x;\n      const height = maxSize.y * ratioX;\n      this.#containerDiv.style.height = height + 'px';\n    }\n    // return best fit\n    return Math.min(\n      this.#containerDiv.offsetWidth / maxSize.x,\n      this.#containerDiv.offsetHeight / maxSize.y\n    );\n  }\n\n  /**\n   * Set the layer group fit scale.\n   *\n   * @param {number} scaleIn The fit scale.\n   */\n  setFitScale(scaleIn) {\n    // get maximum size\n    const maxSize = this.getMaxSize();\n    // exit if none\n    if (typeof maxSize === 'undefined') {\n      return;\n    }\n\n    const containerSize = {\n      x: this.#containerDiv.offsetWidth,\n      y: this.#containerDiv.offsetHeight\n    };\n    // offset to keep data centered\n    const fitOffset = {\n      x: -0.5 * (containerSize.x - Math.floor(maxSize.x * scaleIn)),\n      y: -0.5 * (containerSize.y - Math.floor(maxSize.y * scaleIn))\n    };\n\n    // apply to layers\n    for (let j = 0; j < this.#layers.length; ++j) {\n      this.#layers[j].fitToContainer(scaleIn, containerSize, fitOffset);\n    }\n\n    // update crosshair\n    if (this.#showCrosshair) {\n      this.#showCrosshairDiv();\n    }\n  }\n\n  /**\n   * Get the largest data size.\n   *\n   * @returns {object|undefined} The largest size as {x,y}.\n   */\n  getMaxSize() {\n    let maxSize = {x: 0, y: 0};\n    for (let j = 0; j < this.#layers.length; ++j) {\n      if (this.#layers[j] instanceof ViewLayer) {\n        const size = this.#layers[j].getImageWorldSize();\n        if (size.x > maxSize.x) {\n          maxSize.x = size.x;\n        }\n        if (size.y > maxSize.y) {\n          maxSize.y = size.y;\n        }\n      }\n    }\n    if (maxSize.x === 0 && maxSize.y === 0) {\n      maxSize = undefined;\n    }\n    return maxSize;\n  }\n\n  /**\n   * Flip all layers along the Z axis without offset compensation.\n   */\n  flipScaleZ() {\n    this.#baseScale.z *= -1;\n    this.setScale(this.#baseScale);\n  }\n\n  /**\n   * Add scale to the layers. Scale cannot go lower than 0.1.\n   *\n   * @param {number} scaleStep The scale to add.\n   * @param {Point3D} center The scale center Point3D.\n   */\n  addScale(scaleStep, center) {\n    const newScale = {\n      x: this.#scale.x * (1 + scaleStep),\n      y: this.#scale.y * (1 + scaleStep),\n      z: this.#scale.z * (1 + scaleStep)\n    };\n    this.setScale(newScale, center);\n  }\n\n  /**\n   * Set the layers' scale.\n   *\n   * @param {object} newScale The scale to apply as {x,y,z}.\n   * @param {Point3D} [center] The scale center Point3D.\n   * @fires LayerGroup#zoomchange\n   */\n  setScale(newScale, center) {\n    this.#scale = newScale;\n    // apply to layers\n    for (let i = 0; i < this.#layers.length; ++i) {\n      this.#layers[i].setScale(this.#scale, center);\n    }\n\n    // event value\n    const value = [\n      newScale.x,\n      newScale.y,\n      newScale.z\n    ];\n    if (typeof center !== 'undefined') {\n      value.push(center.getX());\n      value.push(center.getY());\n      value.push(center.getZ());\n    }\n\n    /**\n     * Zoom change event.\n     *\n     * @event LayerGroup#zoomchange\n     * @type {object}\n     * @property {Array} value The changed value.\n     */\n    this.#fireEvent({\n      type: 'zoomchange',\n      value: value\n    });\n  }\n\n  /**\n   * Add translation to the layers.\n   *\n   * @param {object} translation The translation as {x,y,z}.\n   */\n  addTranslation(translation) {\n    this.setOffset({\n      x: this.#offset.x - translation.x,\n      y: this.#offset.y - translation.y,\n      z: this.#offset.z - translation.z\n    });\n  }\n\n  /**\n   * Set the layers' offset.\n   *\n   * @param {object} newOffset The offset as {x,y,z}.\n   * @fires LayerGroup#offsetchange\n   */\n  setOffset(newOffset) {\n    // store\n    this.#offset = newOffset;\n    // apply to layers\n    for (let i = 0; i < this.#layers.length; ++i) {\n      this.#layers[i].setOffset(this.#offset);\n    }\n\n    /**\n     * Offset change event.\n     *\n     * @event LayerGroup#offsetchange\n     * @type {object}\n     * @property {Array} value The changed value.\n     */\n    this.#fireEvent({\n      type: 'offsetchange',\n      value: [\n        this.#offset.x,\n        this.#offset.y,\n        this.#offset.z\n      ]\n    });\n  }\n\n  /**\n   * Reset the stage to its initial scale and no offset.\n   */\n  reset() {\n    this.setScale(this.#baseScale);\n    this.setOffset({x: 0, y: 0, z: 0});\n  }\n\n  /**\n   * Draw the layer.\n   */\n  draw() {\n    for (let i = 0; i < this.#layers.length; ++i) {\n      this.#layers[i].draw();\n    }\n  }\n\n  /**\n   * Display the layer.\n   *\n   * @param {boolean} flag Whether to display the layer or not.\n   */\n  display(flag) {\n    for (let i = 0; i < this.#layers.length; ++i) {\n      this.#layers[i].display(flag);\n    }\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n} // LayerGroup class\n","import {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mask segment helper.\n */\nexport class MaskSegmentHelper {\n\n  /**\n   * The associated mask.\n   *\n   * @type {Image}\n   */\n  #mask;\n\n  /**\n   * The segments: array of segment description.\n   *\n   * @type {Array}\n   */\n  #segments;\n\n  /**\n   * List of ids of hidden segments.\n   *\n   * @type {Array}\n   */\n  #hiddenSegments = [];\n\n  /**\n   * @param {Image} mask The associated mask image.\n   */\n  constructor(mask) {\n    this.#mask = mask;\n    this.#segments = mask.getMeta().custom.segments;\n  }\n\n  /**\n   * Check if a segment is part of the inner segment list.\n   *\n   * @param {number} segmentNumber The segment number.\n   * @returns {boolean} True if the segment is included.\n   */\n  hasSegment(segmentNumber) {\n    return typeof this.getSegment(segmentNumber) !== 'undefined';\n  }\n\n  /**\n   * Check if a segment is present in a mask image.\n   *\n   * @param {Array} numbers Array of segment numbers.\n   * @returns {Array} Array of boolean set to true\n   *   if the segment is present in the mask.\n   */\n  maskHasSegments(numbers) {\n    // create values using displayValue\n    const values = [];\n    const unknowns = [];\n    for (let i = 0; i < numbers.length; ++i) {\n      const segment = this.getSegment(numbers[i]);\n      if (typeof segment !== 'undefined') {\n        values.push(segment.displayValue);\n      } else {\n        logger.warn('Unknown segment in maskHasSegments: ' + numbers[i]);\n        unknowns.push(i);\n      }\n    }\n    const res = this.#mask.hasValues(values);\n    // insert unknowns as false in result\n    for (let j = 0; j < unknowns.length; ++j) {\n      res.splice(unknowns[j], 0, false);\n    }\n    return res;\n  }\n\n  /**\n   * Get a segment from the inner segment list.\n   *\n   * @param {number} segmentNumber The segment number.\n   * @returns {object} The segment.\n   */\n  getSegment(segmentNumber) {\n    return this.#segments.find(function (item) {\n      return item.number === segmentNumber;\n    });\n  }\n\n  /**\n   * Get the inner segment list.\n   *\n   * @returns {Array} The list of segments.\n   */\n  getSegments() {\n    return this.#segments;\n  }\n\n  /**\n   * Set the inner segment list.\n   *\n   * @param {Array} list The segment list.\n   */\n  setSegments(list) {\n    this.#segments = list;\n  }\n\n  /**\n   * Set the hidden segment list.\n   * TODO: not sure if needed...\n   *\n   * @param {Array} list The list of hidden segment numbers.\n   */\n  setHiddenSegments(list) {\n    this.#hiddenSegments = list;\n  }\n\n  /**\n   * Get the index of a segment in the hidden list.\n   *\n   * @param {number} segmentNumber The segment number.\n   * @returns {number|undefined} The index in the array.\n   */\n  #getHiddenIndex(segmentNumber) {\n    return this.#hiddenSegments.findIndex(function (item) {\n      return item === segmentNumber;\n    });\n  }\n\n  /**\n   * Check if a segment is in the hidden list.\n   *\n   * @param {number} segmentNumber The segment number.\n   * @returns {boolean} True if the segment is in the list.\n   */\n  isHidden(segmentNumber) {\n    return this.#getHiddenIndex(segmentNumber) !== -1;\n  }\n\n  /**\n   * Add a segment to the hidden list.\n   *\n   * @param {number} segmentNumber The segment number.\n   */\n  addToHidden(segmentNumber) {\n    if (!this.isHidden(segmentNumber)) {\n      this.#hiddenSegments.push(segmentNumber);\n    } else {\n      logger.warn(\n        'Segment is allready in the hidden list: ' + segmentNumber);\n    }\n  }\n\n  /**\n   * Remove a segment from the hidden list.\n   *\n   * @param {number} segmentNumber The segment number.\n   */\n  removeFromHidden(segmentNumber) {\n    const index = this.#getHiddenIndex(segmentNumber);\n    if (index !== -1) {\n      this.#hiddenSegments.splice(index, 1);\n    } else {\n      logger.warn('Segment is not in the hidden list: ' + segmentNumber);\n    }\n  }\n\n  /**\n   * @callback alphaFn\n   * @param {object} value The pixel value.\n   * @param {object} index The values' index.\n   * @returns {number} The value to display.\n   */\n\n  /**\n   * Get the alpha function to apply hidden colors.\n   *\n   * @returns {alphaFn} The corresponding alpha function.\n   */\n  getAlphaFunc() {\n    // get colours\n    const hiddenColours = [{r: 0, g: 0, b: 0}];\n    for (let i = 0; i < this.#hiddenSegments.length; ++i) {\n      const segment = this.getSegment(this.#hiddenSegments[i]);\n      if (typeof segment !== 'undefined') {\n        hiddenColours.push(segment.displayValue);\n      }\n    }\n\n    // create alpha function\n    return function (value/*, index*/) {\n      for (let i = 0; i < hiddenColours.length; ++i) {\n        if (value[0] === hiddenColours[i].r &&\n          value[1] === hiddenColours[i].g &&\n          value[2] === hiddenColours[i].b) {\n          return 0;\n        }\n      }\n      // default\n      return 255;\n    };\n  }\n\n  /**\n   * @callback eventFn\n   * @param {object} event The event.\n   */\n\n  /**\n   * Delete a segment.\n   *\n   * @param {number} segmentNumber The segment number.\n   * @param {eventFn} cmdCallback The command event callback.\n   * @param {Function} exeCallback The post execution callback.\n   */\n  deleteSegment(segmentNumber, cmdCallback, exeCallback) {\n    const delcmd = new DeleteSegmentCommand(\n      this.#mask, this.getSegment(segmentNumber));\n    delcmd.onExecute = cmdCallback;\n    delcmd.onUndo = cmdCallback;\n    if (delcmd.isValid()) {\n      delcmd.execute();\n      // callback\n      exeCallback(delcmd);\n      // possibly hidden\n      if (this.isHidden(segmentNumber)) {\n        this.removeFromHidden(segmentNumber);\n      }\n    }\n  }\n\n} // class MaskSegmentHelper\n\n/**\n * Delete segment command.\n */\nexport class DeleteSegmentCommand {\n\n  /**\n   * The associated mask.\n   *\n   * @type {Image}\n   */\n  #mask;\n\n  /**\n   * The segment to remove.\n   *\n   * @type {object}\n   */\n  #segment;\n\n  /**\n   * Flag to send creation events.\n   *\n   * @type {boolean}\n   */\n  #isSilent;\n\n  /**\n   * List of offsets.\n   *\n   * @type {Array}\n   */\n  #offsets;\n\n  /**\n   * @param {Image} mask The mask image.\n   * @param {object} segment The segment to remove.\n   * @param {boolean} [silent] Whether to send a creation event or not.\n   */\n  constructor(mask, segment, silent) {\n    this.#mask = mask;\n    this.#segment = segment;\n\n    this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n    // list of offsets with the colour to delete\n    this.#offsets = mask.getOffsets(segment.displayValue);\n  }\n\n  /**\n   * Get the command name.\n   *\n   * @returns {string} The command name.\n   */\n  getName() {\n    return 'Delete-segment';\n  }\n\n  /**\n   * Check if a command is valid and can be executed.\n   *\n   * @returns {boolean} True if the command is valid.\n   */\n  isValid() {\n    return this.#offsets.length !== 0;\n  }\n\n  /**\n   * Execute the command.\n   *\n   * @fires DeleteSegmentCommand#masksegmentdelete\n   */\n  execute() {\n    // remove\n    this.#mask.setAtOffsets(this.#offsets, {r: 0, g: 0, b: 0});\n\n    // callback\n    if (!this.#isSilent) {\n      /**\n       * Segment delete event.\n       *\n       * @event DeleteSegmentCommand#masksegmentdelete\n       * @type {object}\n       * @property {number} segmentnumber The segment number.\n       */\n      this.onExecute({\n        type: 'masksegmentdelete',\n        segmentnumber: this.#segment.number\n      });\n    }\n  }\n\n  /**\n   * Undo the command.\n   *\n   * @fires DeleteSegmentCommand#masksegmentredraw\n   */\n  undo() {\n    // re-draw\n    this.#mask.setAtOffsets(this.#offsets, this.#segment.displayValue);\n\n    // callback\n    /**\n     * Segment redraw event.\n     *\n     * @event DeleteSegmentCommand#masksegmentredraw\n     * @type {object}\n     * @property {number} segmentnumber The segment number.\n     */\n    this.onUndo({\n      type: 'masksegmentredraw',\n      segmentnumber: this.#segment.number\n    });\n  }\n\n  /**\n   * Handle an execute event.\n   *\n   * @param {object} _event The execute event with type and id.\n   */\n  onExecute(_event) {\n    // default does nothing.\n  }\n\n  /**\n   * Handle an undo event.\n   *\n   * @param {object} _event The undo event with type and id.\n   */\n  onUndo(_event) {\n    // default does nothing.\n  }\n\n} // DeleteSegmentCommand class\n","import {Index} from '../math/index';\nimport {Vector3D} from '../math/vector';\nimport {Point3D} from '../math/point';\nimport {isIdentityMat33} from '../math/matrix';\nimport {Size} from '../image/size';\nimport {Spacing} from '../image/spacing';\nimport {Image} from '../image/image';\nimport {Geometry} from '../image/geometry';\nimport {PlaneHelper} from '../image/planeHelper';\nimport {MaskSegmentHelper} from '../image/maskSegmentHelper';\nimport {\n  getSliceIterator,\n  getIteratorValues,\n  getRegionSliceIterator,\n  getVariableRegionSliceIterator\n} from '../image/iterator';\nimport {luts} from '../image/luts';\nimport {ListenerHandler} from '../utils/listen';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {View} from '../image/view';\nimport {ColourMap} from '../image/luts';\nimport {Point, Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * View controller.\n */\nexport class ViewController {\n\n  /**\n   * Associated View.\n   *\n   * @type {View}\n   */\n  #view;\n\n  /**\n   * Associated data index.\n   *\n   * @type {number}\n   */\n  #index;\n\n  /**\n   * Plane helper.\n   *\n   * @type {PlaneHelper}\n   */\n  #planeHelper;\n\n  /**\n   * Mask segment helper.\n   *\n   * @type {MaskSegmentHelper}\n   */\n  #maskSegmentHelper;\n\n  // third dimension player ID (created by setInterval)\n  #playerID = null;\n  // associated data index\n  #dataIndex;\n\n  /**\n   * @param {View} view The associated view.\n   * @param {number} index The associated data index.\n   */\n  constructor(view, index) {\n    // check view\n    if (typeof view.getImage() === 'undefined') {\n      throw new Error('View does not have an image, cannot setup controller');\n    }\n\n    this.#view = view;\n    this.#index = index;\n\n    // setup the plane helper\n    this.#planeHelper = new PlaneHelper(\n      view.getImage().getGeometry().getRealSpacing(),\n      view.getImage().getGeometry().getOrientation(),\n      view.getOrientation()\n    );\n\n    // mask segment helper\n    if (view.getImage().getMeta().Modality === 'SEG') {\n      this.#maskSegmentHelper =\n        new MaskSegmentHelper(view.getImage());\n    }\n  }\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Get the plane helper.\n   *\n   * @returns {object} The helper.\n   */\n  getPlaneHelper() {\n    return this.#planeHelper;\n  }\n\n  /**\n   * Check is the associated image is a mask.\n   *\n   * @returns {boolean} True if the associated image is a mask.\n   */\n  isMask() {\n    return typeof this.#maskSegmentHelper !== 'undefined';\n  }\n\n  /**\n   * Get the mask segment helper.\n   *\n   * @returns {object} The helper.\n   */\n  getMaskSegmentHelper() {\n    return this.#maskSegmentHelper;\n  }\n\n  /**\n   * Apply the hidden segments list by setting\n   * the corresponding alpha function.\n   */\n  applyHiddenSegments() {\n    if (this.isMask) {\n      this.setViewAlphaFunction(this.#maskSegmentHelper.getAlphaFunc());\n    }\n  }\n\n  /**\n   * Delete a segment.\n   *\n   * @param {number} segmentNumber The segment number.\n   * @param {Function} exeCallback The post execution callback.\n   */\n  deleteSegment(segmentNumber, exeCallback) {\n    if (this.isMask) {\n      this.#maskSegmentHelper.deleteSegment(\n        segmentNumber, this.#fireEvent, exeCallback);\n    }\n  }\n\n  /**\n   * Initialise the controller.\n   */\n  initialise() {\n    // set window/level to first preset\n    this.setWindowLevelPresetById(0);\n    // default position\n    this.setCurrentPosition(this.getPositionFromPlanePoint(0, 0));\n  }\n\n  /**\n   * Get the window/level presets names.\n   *\n   * @returns {Array} The presets names.\n   */\n  getWindowLevelPresetsNames() {\n    return this.#view.getWindowPresetsNames();\n  }\n\n  /**\n   * Add window/level presets to the view.\n   *\n   * @param {object} presets A preset object.\n   * @returns {object} The list of presets.\n   */\n  addWindowLevelPresets(presets) {\n    return this.#view.addWindowPresets(presets);\n  }\n\n  /**\n   * Set the window level to the preset with the input name.\n   *\n   * @param {string} name The name of the preset to activate.\n   */\n  setWindowLevelPreset(name) {\n    this.#view.setWindowLevelPreset(name);\n  }\n\n  /**\n   * Set the window level to the preset with the input id.\n   *\n   * @param {number} id The id of the preset to activate.\n   */\n  setWindowLevelPresetById(id) {\n    this.#view.setWindowLevelPresetById(id);\n  }\n\n  /**\n   * Check if the controller is playing.\n   *\n   * @returns {boolean} True if the controler is playing.\n   */\n  isPlaying() {\n    return (this.#playerID !== null);\n  }\n\n  /**\n   * Get the current position.\n   *\n   * @returns {Point} The position.\n   */\n  getCurrentPosition() {\n    return this.#view.getCurrentPosition();\n  }\n\n  /**\n   * Get the current index.\n   *\n   * @returns {Index} The current index.\n   */\n  getCurrentIndex() {\n    return this.#view.getCurrentIndex();\n  }\n\n  /**\n   * Get the current oriented index.\n   *\n   * @returns {Index} The index.\n   */\n  getCurrentOrientedIndex() {\n    let res = this.#view.getCurrentIndex();\n    if (typeof this.#view.getOrientation() !== 'undefined') {\n      // view oriented => image de-oriented\n      const vector = this.#planeHelper.getImageDeOrientedVector3D(\n        new Vector3D(res.get(0), res.get(1), res.get(2))\n      );\n      res = new Index([\n        vector.getX(), vector.getY(), vector.getZ()\n      ]);\n    }\n    return res;\n  }\n\n  /**\n   * Get the scroll index.\n   *\n   * @returns {number} The index.\n   */\n  getScrollIndex() {\n    return this.#view.getScrollIndex();\n  }\n\n  /**\n   * Get the current scroll index value.\n   *\n   * @returns {object} The value.\n   */\n  getCurrentScrollIndexValue() {\n    return this.#view.getCurrentIndex().get(this.#view.getScrollIndex());\n  }\n\n  /**\n   * Get the origin at a given posittion.\n   *\n   * @param {Point} position The input position.\n   * @returns {Point} The origin.\n   */\n  getOrigin(position) {\n    return this.#view.getOrigin(position);\n  }\n\n  /**\n   * Get the current scroll position value.\n   *\n   * @returns {object} The value.\n   */\n  getCurrentScrollPosition() {\n    const scrollIndex = this.#view.getScrollIndex();\n    return this.#view.getCurrentPosition().get(scrollIndex);\n  }\n\n  /**\n   * Generate display image data to be given to a canvas.\n   *\n   * @param {ImageData} array The array to fill in.\n   * @param {Index} index Optional index at which to generate,\n   *   otherwise generates at current index.\n   */\n  generateImageData(array, index) {\n    this.#view.generateImageData(array, index);\n  }\n\n  /**\n   * Set the associated image.\n   *\n   * @param {Image} img The associated image.\n   * @param {number} index The data index of the image.\n   */\n  setImage(img, index) {\n    this.#view.setImage(img);\n    this.#dataIndex = index;\n  }\n\n  /**\n   * Get the current spacing.\n   *\n   * @returns {Array} The 2D spacing.\n   */\n  get2DSpacing() {\n    const spacing = this.#view.getImage().getGeometry().getSpacing();\n    return [spacing.get(0), spacing.get(1)];\n  }\n\n  /**\n   * Get the image rescaled value at the input position.\n   *\n   * @param {Point} position the input position.\n   * @returns {number|undefined} The image value or undefined if out of bounds\n   *   or no quantifiable (for ex RGB).\n   */\n  getRescaledImageValue(position) {\n    const image = this.#view.getImage();\n    if (!image.canQuantify()) {\n      return;\n    }\n    const geometry = image.getGeometry();\n    const index = geometry.worldToIndex(position);\n    let value;\n    if (geometry.isIndexInBounds(index)) {\n      value = image.getRescaledValueAtIndex(index);\n    }\n    return value;\n  }\n\n  /**\n   * Get the image pixel unit.\n   *\n   * @returns {string} The unit\n   */\n  getPixelUnit() {\n    return this.#view.getImage().getMeta().pixelUnit;\n  }\n\n  /**\n   * Get some values from the associated image in a region.\n   *\n   * @param {Point2D} min Minimum point.\n   * @param {Point2D} max Maximum point.\n   * @returns {Array} A list of values.\n   */\n  getImageRegionValues(min, max) {\n    let image = this.#view.getImage();\n    const orientation = this.#view.getOrientation();\n    let position = this.getCurrentIndex();\n    let rescaled = true;\n\n    // created oriented slice if needed\n    if (!isIdentityMat33(orientation)) {\n      // generate slice values\n      const sliceIter = getSliceIterator(\n        image,\n        position,\n        rescaled,\n        orientation\n      );\n      const sliceValues = getIteratorValues(sliceIter);\n      // oriented geometry\n      const orientedSize = image.getGeometry().getSize(orientation);\n      const sizeValues = orientedSize.getValues();\n      sizeValues[2] = 1;\n      const sliceSize = new Size(sizeValues);\n      const orientedSpacing = image.getGeometry().getSpacing(orientation);\n      const spacingValues = orientedSpacing.getValues();\n      spacingValues[2] = 1;\n      const sliceSpacing = new Spacing(spacingValues);\n      const sliceOrigin = new Point3D(0, 0, 0);\n      const sliceGeometry =\n        new Geometry(sliceOrigin, sliceSize, sliceSpacing);\n      // slice image\n      // @ts-ignore\n      image = new Image(sliceGeometry, sliceValues);\n      // update position\n      position = new Index([0, 0, 0]);\n      rescaled = false;\n    }\n\n    // get region values\n    const iter = getRegionSliceIterator(\n      image, position, rescaled, min, max);\n    let values = [];\n    if (iter) {\n      values = getIteratorValues(iter);\n    }\n    return values;\n  }\n\n  /**\n   * Get some values from the associated image in variable regions.\n   *\n   * @param {Array} regions A list of regions.\n   * @returns {Array} A list of values.\n   */\n  getImageVariableRegionValues(regions) {\n    const iter = getVariableRegionSliceIterator(\n      this.#view.getImage(),\n      this.getCurrentIndex(),\n      true, regions\n    );\n    let values = [];\n    if (iter) {\n      values = getIteratorValues(iter);\n    }\n    return values;\n  }\n\n  /**\n   * Can the image values be quantified?\n   *\n   * @returns {boolean} True if possible.\n   */\n  canQuantifyImage() {\n    return this.#view.getImage().canQuantify();\n  }\n\n  /**\n   * Can window and level be applied to the data?\n   *\n   * @returns {boolean} True if possible.\n   */\n  canWindowLevel() {\n    return this.#view.getImage().canWindowLevel();\n  }\n\n  /**\n   * Can the data be scrolled?\n   *\n   * @returns {boolean} True if the data has either the third dimension\n   * or above greater than one.\n   */\n  canScroll() {\n    return this.#view.getImage().canScroll(this.#view.getOrientation());\n  }\n\n  /**\n   * Get the image size.\n   *\n   * @returns {Size} The size.\n   */\n  getImageSize() {\n    return this.#view.getImage().getGeometry().getSize(\n      this.#view.getOrientation());\n  }\n\n  /**\n   * Get the image world (mm) 2D size.\n   *\n   * @returns {object} The 2D size as {x,y}.\n   */\n  getImageWorldSize() {\n    const geometry = this.#view.getImage().getGeometry();\n    const size = geometry.getSize(this.#view.getOrientation()).get2D();\n    const spacing = geometry.getSpacing(this.#view.getOrientation()).get2D();\n    return {\n      x: size.x * spacing.x,\n      y: size.y * spacing.y\n    };\n  }\n\n  /**\n   * Get the image rescaled data range.\n   *\n   * @returns {object} The range as {min, max}.\n   */\n  getImageRescaledDataRange() {\n    return this.#view.getImage().getRescaledDataRange();\n  }\n\n  /**\n   * Compare the input meta data to the associated image one.\n   *\n   * @param {object} meta The meta data.\n   * @returns {boolean} True if the associated image has equal meta data.\n   */\n  equalImageMeta(meta) {\n    const imageMeta = this.#view.getImage().getMeta();\n    // loop through input meta keys\n    const metaKeys = Object.keys(meta);\n    for (let i = 0; i < metaKeys.length; ++i) {\n      const metaKey = metaKeys[i];\n      if (typeof imageMeta[metaKey] === 'undefined') {\n        return false;\n      }\n      if (imageMeta[metaKey] !== meta[metaKey]) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  /**\n   * Check is the provided position can be set.\n   *\n   * @param {Point} position The position.\n   * @returns {boolean} True is the position is in bounds.\n   */\n  canSetPosition(position) {\n    return this.#view.canSetPosition(position);\n  }\n\n  /**\n   * Set the current position.\n   *\n   * @param {Point} pos The position.\n   * @param {boolean} [silent] If true, does not fire a\n   *   positionchange event.\n   * @returns {boolean} False if not in bounds.\n   */\n  setCurrentPosition(pos, silent) {\n    return this.#view.setCurrentPosition(pos, silent);\n  }\n\n  /**\n   * Get a position from a 2D (x,y) position.\n   *\n   * @param {number} x The column position.\n   * @param {number} y The row position.\n   * @returns {Point} The associated position.\n   */\n  getPositionFromPlanePoint(x, y) {\n    // keep third direction\n    const k = this.getCurrentScrollIndexValue();\n    const planePoint = new Point3D(x, y, k);\n    // de-orient\n    const point = this.#planeHelper.getImageOrientedPoint3D(planePoint);\n    // ~indexToWorld to not loose precision\n    const geometry = this.#view.getImage().getGeometry();\n    const point3D = geometry.pointToWorld(point);\n    // merge with current position to keep extra dimensions\n    return this.getCurrentPosition().mergeWith3D(point3D);\n  }\n\n  /**\n   * Get a 2D (x,y) position from a position.\n   *\n   * @param {Point} point The 3D position.\n   * @returns {object} The 2D position.\n   */\n  getPlanePositionFromPosition(point) {\n    // orient\n    const geometry = this.#view.getImage().getGeometry();\n    // ~worldToIndex to not loose precision\n    const point3D = geometry.worldToPoint(point);\n    const planePoint = this.#planeHelper.getImageDeOrientedPoint3D(point3D);\n    // return\n    return {\n      x: planePoint.getX(),\n      y: planePoint.getY(),\n    };\n  }\n\n  /**\n   * Set the current index.\n   *\n   * @param {Index} index The index.\n   * @param {boolean} [silent] If true, does not fire a positionchange event.\n   * @returns {boolean} False if not in bounds.\n   */\n  setCurrentIndex(index, silent) {\n    return this.#view.setCurrentIndex(index, silent);\n  }\n\n  /**\n   * Get a plane 3D position from a plane 2D position: does not compensate\n   *   for the image origin. Needed for setting the scale center...\n   *\n   * @param {object} point2D The 2D position as {x,y}.\n   * @returns {Point3D} The 3D point.\n   */\n  getPlanePositionFromPlanePoint(point2D) {\n    // keep third direction\n    const k = this.getCurrentScrollIndexValue();\n    const planePoint = new Point3D(point2D.x, point2D.y, k);\n    // de-orient\n    const point = this.#planeHelper.getTargetDeOrientedPoint3D(planePoint);\n    // ~indexToWorld to not loose precision\n    const geometry = this.#view.getImage().getGeometry();\n    const spacing = geometry.getRealSpacing();\n    return new Point3D(\n      point.getX() * spacing.get(0),\n      point.getY() * spacing.get(1),\n      point.getZ() * spacing.get(2));\n  }\n\n  /**\n   * Get a 3D offset from a plane one.\n   *\n   * @param {object} offset2D The plane offset as {x,y}.\n   * @returns {Vector3D} The 3D world offset.\n   */\n  getOffset3DFromPlaneOffset(offset2D) {\n    return this.#planeHelper.getOffset3DFromPlaneOffset(offset2D);\n  }\n\n  /**\n   * Increment the provided dimension.\n   *\n   * @param {number} dim The dimension to increment.\n   * @param {boolean} [silent] Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  incrementIndex(dim, silent) {\n    return this.#view.incrementIndex(dim, silent);\n  }\n\n  /**\n   * Decrement the provided dimension.\n   *\n   * @param {number} dim The dimension to increment.\n   * @param {boolean} [silent] Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  decrementIndex(dim, silent) {\n    return this.#view.decrementIndex(dim, silent);\n  }\n\n  /**\n   * Decrement the scroll dimension index.\n   *\n   * @param {boolean} [silent] Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  decrementScrollIndex(silent) {\n    return this.#view.decrementScrollIndex(silent);\n  }\n\n  /**\n   * Increment the scroll dimension index.\n   *\n   * @param {boolean} [silent] Do not send event.\n   * @returns {boolean} False if not in bounds.\n   */\n  incrementScrollIndex(silent) {\n    return this.#view.incrementScrollIndex(silent);\n  }\n\n  /**\n   * Scroll play: loop through all slices.\n   */\n  play() {\n    // ensure data is scrollable: dim >= 3\n    if (!this.canScroll()) {\n      return;\n    }\n    if (this.#playerID === null) {\n      const image = this.#view.getImage();\n      const recommendedDisplayFrameRate =\n        image.getMeta().RecommendedDisplayFrameRate;\n      const milliseconds = this.#view.getPlaybackMilliseconds(\n        recommendedDisplayFrameRate);\n      const size = image.getGeometry().getSize();\n      const canScroll3D = size.canScroll3D();\n\n      this.#playerID = setInterval(() => {\n        let canDoMore = false;\n        if (canScroll3D) {\n          canDoMore = this.incrementScrollIndex();\n        } else {\n          canDoMore = this.incrementIndex(3);\n        }\n        // end of scroll, loop back\n        if (!canDoMore) {\n          const pos1 = this.getCurrentIndex();\n          const values = pos1.getValues();\n          const orientation = this.#view.getOrientation();\n          if (canScroll3D) {\n            values[orientation.getThirdColMajorDirection()] = 0;\n          } else {\n            values[3] = 0;\n          }\n          const index = new Index(values);\n          const geometry = this.#view.getImage().getGeometry();\n          this.setCurrentPosition(geometry.indexToWorld(index));\n        }\n      }, milliseconds);\n    } else {\n      this.stop();\n    }\n  }\n\n  /**\n   * Stop scroll playing.\n   */\n  stop() {\n    if (this.#playerID !== null) {\n      clearInterval(this.#playerID);\n      this.#playerID = null;\n    }\n  }\n\n  /**\n   * Get the window/level.\n   *\n   * @returns {object} The window center and width.\n   */\n  getWindowLevel() {\n    return {\n      width: this.#view.getCurrentWindowLut().getWindowLevel().getWidth(),\n      center: this.#view.getCurrentWindowLut().getWindowLevel().getCenter()\n    };\n  }\n\n  /**\n   * Set the window/level.\n   *\n   * @param {number} wc The window center.\n   * @param {number} ww The window width.\n   */\n  setWindowLevel(wc, ww) {\n    this.#view.setWindowLevel(wc, ww);\n  }\n\n  /**\n   * Get the colour map.\n   *\n   * @returns {ColourMap} The colour map.\n   */\n  getColourMap() {\n    return this.#view.getColourMap();\n  }\n\n  /**\n   * Set the colour map.\n   *\n   * @param {ColourMap} colourMap The colour map.\n   */\n  setColourMap(colourMap) {\n    this.#view.setColourMap(colourMap);\n  }\n\n  /**\n   * @callback alphaFn\n   * @param {object} value The pixel value.\n   * @param {object} index The values' index.\n   * @returns {number} The value to display.\n   */\n\n  /**\n   * Set the view per value alpha function.\n   *\n   * @param {alphaFn} func The function.\n   */\n  setViewAlphaFunction(func) {\n    this.#view.setAlphaFunction(func);\n  }\n\n  /**\n   * Set the colour map from a name.\n   *\n   * @param {string} name The name of the colour map to set.\n   */\n  setColourMapFromName(name) {\n    // check if we have it\n    if (!luts[name]) {\n      throw new Error('Unknown colour map: \\'' + name + '\\'');\n    }\n    // enable it\n    this.setColourMap(luts[name]);\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    event.dataid = this.#dataIndex;\n    this.#listenerHandler.fireEvent(event);\n  };\n\n} // class ViewController\n","import {logger} from '../utils/logger';\n\n/**\n * List of interaction event names.\n */\nexport const InteractionEventNames = [\n  'mousedown',\n  'mousemove',\n  'mouseup',\n  'mouseout',\n  'wheel',\n  'dblclick',\n  'touchstart',\n  'touchmove',\n  'touchend'\n];\n\n/**\n * Get a HTML element associated to a container div.\n *\n * @param {string} containerDivId The id of the container div.\n * @param {string} name The name or id to find.\n * @returns {object} The found element or null.\n * @deprecated\n */\nexport function getElement(containerDivId, name) {\n  // get by class in the container div\n  const parent = document.getElementById(containerDivId);\n  if (!parent) {\n    return null;\n  }\n  const elements = parent.getElementsByClassName(name);\n  // getting the last element since some libraries (ie jquery-mobile) create\n  // span in front of regular tags (such as select)...\n  let element = elements[elements.length - 1];\n  // if not found get by id with 'containerDivId-className'\n  if (typeof element === 'undefined') {\n    element = document.getElementById(containerDivId + '-' + name);\n  }\n  return element;\n}\n\n/**\n * Overridalbe custom UI object for client defined UI.\n */\nexport const customUI = {\n  /**\n   * Open a dialogue to edit roi data. Defaults to window.prompt.\n   *\n   * @param {object} data The roi data.\n   * @param {Function} callback The callback to launch on dialogue exit.\n   */\n  openRoiDialog(data, callback) {\n    const textExpr = prompt('Label', data.textExpr);\n    if (textExpr !== null) {\n      data.textExpr = textExpr;\n      callback(data);\n    }\n  }\n};\n\n/**\n * Get the positions (without the parent offset) of a list of touch events.\n *\n * @param {Array} touches The list of touch events.\n * @returns {Array} The list of positions of the touch events.\n */\nfunction getTouchesPositions(touches) {\n  // get the touch offset from all its parents\n  let offsetLeft = 0;\n  let offsetTop = 0;\n  if (touches.length !== 0 &&\n    typeof touches[0].target !== 'undefined') {\n    let offsetParent = touches[0].target.offsetParent;\n    while (offsetParent) {\n      if (!isNaN(offsetParent.offsetLeft)) {\n        offsetLeft += offsetParent.offsetLeft;\n      }\n      if (!isNaN(offsetParent.offsetTop)) {\n        offsetTop += offsetParent.offsetTop;\n      }\n      offsetParent = offsetParent.offsetParent;\n    }\n  } else {\n    logger.debug('No touch target offset parent.');\n  }\n  // set its position\n  const positions = [];\n  for (let i = 0; i < touches.length; ++i) {\n    positions.push({\n      x: touches[i].pageX - offsetLeft,\n      y: touches[i].pageY - offsetTop\n    });\n  }\n  return positions;\n}\n\n/**\n * Get the offset of an input event.\n *\n * @param {object} event The event to get the offset from.\n * @returns {Array} The array of offsets.\n */\nexport function getEventOffset(event) {\n  let positions = [];\n  if (typeof event.targetTouches !== 'undefined' &&\n    event.targetTouches.length !== 0) {\n    // see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/targetTouches\n    positions = getTouchesPositions(event.targetTouches);\n  } else if (typeof event.changedTouches !== 'undefined' &&\n    event.changedTouches.length !== 0) {\n    // see https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/changedTouches\n    positions = getTouchesPositions(event.changedTouches);\n  } else {\n    // offsetX/Y: the offset in the X coordinate of the mouse pointer\n    // between that event and the padding edge of the target node\n    // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/offsetX\n    // https://caniuse.com/mdn-api_mouseevent_offsetx\n    positions.push({\n      x: event.offsetX,\n      y: event.offsetY\n    });\n  }\n  return positions;\n}\n\n/**\n * Test if a canvas with the input size can be created.\n *\n * @see https://github.com/ivmartel/dwv/issues/902\n * @see https://github.com/jhildenbiddle/canvas-size/blob/v1.2.4/src/canvas-test.js\n * @param {number} width The canvas width.\n * @param {number} height The canvas height.\n * @returns {boolean} True is the canvas can be created.\n */\nexport function canCreateCanvas(width, height) {\n  // test canvas with input size\n  const testCvs = document.createElement('canvas');\n  testCvs.width = width;\n  testCvs.height = height;\n  // crop canvas to speed up test\n  const cropCvs = document.createElement('canvas');\n  cropCvs.width = 1;\n  cropCvs.height = 1;\n  // contexts\n  const testCtx = testCvs.getContext('2d');\n  const cropCtx = cropCvs.getContext('2d');\n  // set data\n  if (testCtx) {\n    testCtx.fillRect(width - 1, height - 1, 1, 1);\n    // Render the test pixel in the bottom-right corner of the\n    // test canvas in the top-left of the 1x1 crop canvas. This\n    // dramatically reducing the time for getImageData to complete.\n    cropCtx.drawImage(testCvs, width - 1, height - 1, 1, 1, 0, 0, 1, 1);\n  }\n  // Verify image data (alpha component, Pass = 255, Fail = 0)\n  return cropCtx && cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0;\n}\n","import {Index} from '../math/index';\nimport {ListenerHandler} from '../utils/listen';\nimport {viewEventNames} from '../image/view';\nimport {ViewController} from '../app/viewController';\nimport {\n  canCreateCanvas,\n  InteractionEventNames\n} from './generic';\nimport {getScaledOffset} from './layerGroup';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Vector3D} from '../math/vector';\nimport {Point, Point3D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * View layer.\n */\nexport class ViewLayer {\n\n  /**\n   * Container div.\n   *\n   * @type {HTMLElement}\n   */\n  #containerDiv;\n\n  /**\n   * The view controller.\n   *\n   * @type {object}\n   */\n  #viewController = null;\n\n  /**\n   * The main display canvas.\n   *\n   * @type {object}\n   */\n  #canvas = null;\n\n  /**\n   * The offscreen canvas: used to store the raw, unscaled pixel data.\n   *\n   * @type {object}\n   */\n  #offscreenCanvas = null;\n\n  /**\n   * The associated CanvasRenderingContext2D.\n   *\n   * @type {object}\n   */\n  #context = null;\n\n  /**\n   * Flag to know if the current position is valid.\n   *\n   * @type {boolean}\n   */\n  #isValidPosition = true;\n\n  /**\n   * The image data array.\n   *\n   * @type {ImageData}\n   */\n  #imageData = null;\n\n  /**\n   * The layer base size as {x,y}.\n   *\n   * @type {object}\n   */\n  #baseSize;\n\n  /**\n   * The layer base spacing as {x,y}.\n   *\n   * @type {object}\n   */\n  #baseSpacing;\n\n  /**\n   * The layer opacity.\n   *\n   * @type {number}\n   */\n  #opacity = 1;\n\n  /**\n   * The layer scale.\n   *\n   * @type {object}\n   */\n  #scale = {x: 1, y: 1};\n\n  /**\n   * The layer fit scale.\n   *\n   * @type {object}\n   */\n  #fitScale = {x: 1, y: 1};\n\n  /**\n   * The layer offset.\n   *\n   * @type {object}\n   */\n  #offset = {x: 0, y: 0};\n\n  /**\n   * The base layer offset.\n   *\n   * @type {object}\n   */\n  #baseOffset = {x: 0, y: 0};\n\n  /**\n   * The view offset.\n   *\n   * @type {object}\n   */\n  #viewOffset = {x: 0, y: 0};\n\n  /**\n   * The zoom offset.\n   *\n   * @type {object}\n   */\n  #zoomOffset = {x: 0, y: 0};\n\n  /**\n   * The flip offset.\n   *\n   * @type {object}\n   */\n  #flipOffset = {x: 0, y: 0};\n\n  /**\n   * Data update flag.\n   *\n   * @type {boolean}\n   */\n  #needsDataUpdate = null;\n\n  /**\n   * The associated data index.\n   *\n   * @type {number}\n   */\n  #dataIndex = null;\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Image smoothing flag.\n   * see: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled\n   *\n   * @type {boolean}\n   */\n  #imageSmoothingEnabled = false;\n\n  /**\n   * @param {HTMLElement} containerDiv The layer div, its id will be used\n   *   as this layer id.\n   */\n  constructor(containerDiv) {\n    this.#containerDiv = containerDiv;\n    // specific css class name\n    this.#containerDiv.className += ' viewLayer';\n  }\n\n  /**\n   * Get the associated data index.\n   *\n   * @returns {number} The index.\n   */\n  getDataIndex() {\n    return this.#dataIndex;\n  }\n\n  /**\n   * Set the imageSmoothingEnabled flag value.\n   *\n   * @param {boolean} flag True to enable smoothing.\n   */\n  enableImageSmoothing(flag) {\n    this.#imageSmoothingEnabled = flag;\n  }\n\n  /**\n   * Set the associated view.\n   *\n   * @param {object} view The view.\n   * @param {number} index The associated data index.\n   */\n  setView(view, index) {\n    this.#dataIndex = index;\n    // local listeners\n    view.addEventListener('wlchange', this.#onWLChange);\n    view.addEventListener('colourchange', this.#onColourChange);\n    view.addEventListener('positionchange', this.#onPositionChange);\n    view.addEventListener('alphafuncchange', this.#onAlphaFuncChange);\n    // view events\n    for (let j = 0; j < viewEventNames.length; ++j) {\n      view.addEventListener(viewEventNames[j], this.#fireEvent);\n    }\n    // create view controller\n    this.#viewController = new ViewController(view, index);\n  }\n\n  /**\n   * Get the view controller.\n   *\n   * @returns {ViewController} The controller.\n   */\n  getViewController() {\n    return this.#viewController;\n  }\n\n  /**\n   * Get the canvas image data.\n   *\n   * @returns {object} The image data.\n   */\n  getImageData() {\n    return this.#imageData;\n  }\n\n  /**\n   * Handle an image set event.\n   *\n   * @param {object} event The event.\n   * @function\n   */\n  onimageset = (event) => {\n    // event.value = [index, image]\n    if (this.#dataIndex === event.dataid) {\n      this.#viewController.setImage(event.value[0], this.#dataIndex);\n      this.#setBaseSize(this.#viewController.getImageSize().get2D());\n      this.#needsDataUpdate = true;\n    }\n  };\n\n  /**\n   * Handle an image change event.\n   *\n   * @param {object} event The event.\n   * @function\n   */\n  onimagechange = (event) => {\n    // event.value = [index]\n    if (this.#dataIndex === event.dataid) {\n      this.#needsDataUpdate = true;\n    }\n  };\n\n  // common layer methods [start] ---------------\n\n  /**\n   * Get the id of the layer.\n   *\n   * @returns {string} The string id.\n   */\n  getId() {\n    return this.#containerDiv.id;\n  }\n\n  /**\n   * Get the layer base size (without scale).\n   *\n   * @returns {object} The size as {x,y}.\n   */\n  getBaseSize() {\n    return this.#baseSize;\n  }\n\n  /**\n   * Get the image world (mm) 2D size.\n   *\n   * @returns {object} The 2D size as {x,y}.\n   */\n  getImageWorldSize() {\n    return this.#viewController.getImageWorldSize();\n  }\n\n  /**\n   * Get the layer opacity.\n   *\n   * @returns {number} The opacity ([0:1] range).\n   */\n  getOpacity() {\n    return this.#opacity;\n  }\n\n  /**\n   * Set the layer opacity.\n   *\n   * @param {number} alpha The opacity ([0:1] range).\n   */\n  setOpacity(alpha) {\n    if (alpha === this.#opacity) {\n      return;\n    }\n\n    this.#opacity = Math.min(Math.max(alpha, 0), 1);\n\n    /**\n     * Opacity change event.\n     *\n     * @event App#opacitychange\n     * @type {object}\n     * @property {string} type The event type.\n     */\n    const event = {\n      type: 'opacitychange',\n      value: [this.#opacity]\n    };\n    this.#fireEvent(event);\n  }\n\n  /**\n   * Add a flip offset along the layer X axis.\n   */\n  addFlipOffsetX() {\n    // flip scale is handled by layer group\n    // flip offset\n    this.#flipOffset.x += this.#canvas.width / this.#scale.x;\n    this.#offset.x += this.#flipOffset.x;\n  }\n\n  /**\n   * Add a flip offset along the layer Y axis.\n   */\n  addFlipOffsetY() {\n    // flip scale is handled by layer group\n    // flip offset\n    this.#flipOffset.y += this.#canvas.height / this.#scale.y;\n    this.#offset.y += this.#flipOffset.y;\n  }\n\n  /**\n   * Set the layer scale.\n   *\n   * @param {object} newScale The scale as {x,y}.\n   * @param {Point3D} [center] The scale center.\n   */\n  setScale(newScale, center) {\n    const helper = this.#viewController.getPlaneHelper();\n    const orientedNewScale = helper.getTargetOrientedPositiveXYZ(newScale);\n    const finalNewScale = {\n      x: this.#fitScale.x * orientedNewScale.x,\n      y: this.#fitScale.y * orientedNewScale.y\n    };\n\n    if (Math.abs(newScale.x) === 1 &&\n      Math.abs(newScale.y) === 1 &&\n      Math.abs(newScale.z) === 1) {\n      // reset zoom offset for scale=1\n      const resetOffset = {\n        x: this.#offset.x - this.#zoomOffset.x,\n        y: this.#offset.y - this.#zoomOffset.y\n      };\n      // store new offset\n      this.#zoomOffset = {x: 0, y: 0};\n      this.#offset = resetOffset;\n    } else {\n      if (typeof center !== 'undefined') {\n        let worldCenter = helper.getPlaneOffsetFromOffset3D({\n          x: center.getX(),\n          y: center.getY(),\n          z: center.getZ()\n        });\n        // center was obtained with viewLayer.displayToMainPlanePos\n        // compensated for baseOffset\n        // TODO: justify...\n        worldCenter = {\n          x: worldCenter.x + this.#baseOffset.x,\n          y: worldCenter.y + this.#baseOffset.y\n        };\n\n        const newOffset = getScaledOffset(\n          this.#offset, this.#scale, finalNewScale, worldCenter);\n\n        const newZoomOffset = {\n          x: this.#zoomOffset.x + newOffset.x - this.#offset.x,\n          y: this.#zoomOffset.y + newOffset.y - this.#offset.y\n        };\n        // store new offset\n        this.#zoomOffset = newZoomOffset;\n        this.#offset = newOffset;\n      }\n    }\n\n    // store new scale\n    this.#scale = finalNewScale;\n  }\n\n  /**\n   * Set the base layer offset. Updates the layer offset.\n   *\n   * @param {Vector3D} scrollOffset The scroll offset vector.\n   * @param {Vector3D} planeOffset The plane offset vector.\n   * @returns {boolean} True if the offset was updated.\n   */\n  setBaseOffset(scrollOffset, planeOffset) {\n    const helper = this.#viewController.getPlaneHelper();\n    const scrollIndex = helper.getNativeScrollIndex();\n    const newOffset = helper.getPlaneOffsetFromOffset3D({\n      x: scrollIndex === 0 ? scrollOffset.getX() : planeOffset.getX(),\n      y: scrollIndex === 1 ? scrollOffset.getY() : planeOffset.getY(),\n      z: scrollIndex === 2 ? scrollOffset.getZ() : planeOffset.getZ(),\n    });\n    const needsUpdate = this.#baseOffset.x !== newOffset.x ||\n    this.#baseOffset.y !== newOffset.y;\n    // reset offset if needed\n    if (needsUpdate) {\n      this.#offset = {\n        x: this.#offset.x - this.#baseOffset.x + newOffset.x,\n        y: this.#offset.y - this.#baseOffset.y + newOffset.y\n      };\n      this.#baseOffset = newOffset;\n    }\n    return needsUpdate;\n  }\n\n  /**\n   * Set the layer offset.\n   *\n   * @param {object} newOffset The offset as {x,y}.\n   */\n  setOffset(newOffset) {\n    const helper = this.#viewController.getPlaneHelper();\n    const planeNewOffset = helper.getPlaneOffsetFromOffset3D(newOffset);\n    this.#offset = {\n      x: planeNewOffset.x +\n        this.#viewOffset.x +\n        this.#baseOffset.x +\n        this.#zoomOffset.x +\n        this.#flipOffset.x,\n      y: planeNewOffset.y +\n        this.#viewOffset.y +\n        this.#baseOffset.y +\n        this.#zoomOffset.y +\n        this.#flipOffset.y\n    };\n  }\n\n  /**\n   * Transform a display position to an index.\n   *\n   * @param {number} x The X position.\n   * @param {number} y The Y position.\n   * @returns {Index} The equivalent index.\n   */\n  displayToPlaneIndex(x, y) {\n    const planePos = this.displayToPlanePos(x, y);\n    return new Index([\n      Math.floor(planePos.x),\n      Math.floor(planePos.y)\n    ]);\n  }\n\n  /**\n   * Remove scale from a display position.\n   *\n   * @param {number} x The X position.\n   * @param {number} y The Y position.\n   * @returns {object} The de-scaled position as {x,y}.\n   */\n  displayToPlaneScale(x, y) {\n    return {\n      x: x / this.#scale.x,\n      y: y / this.#scale.y\n    };\n  }\n\n  /**\n   * Get a plane position from a display position.\n   *\n   * @param {number} x The X position.\n   * @param {number} y The Y position.\n   * @returns {object} The plane position as {x,y}.\n   */\n  displayToPlanePos(x, y) {\n    const deScaled = this.displayToPlaneScale(x, y);\n    return {\n      x: deScaled.x + this.#offset.x,\n      y: deScaled.y + this.#offset.y\n    };\n  }\n\n  /**\n   * Get a display position from a plane position.\n   *\n   * @param {number} x The X position.\n   * @param {number} y The Y position.\n   * @returns {object} The display position as {x,y}.\n   */\n  planePosToDisplay(x, y) {\n    return {\n      x: (x - this.#offset.x + this.#baseOffset.x) * this.#scale.x,\n      y: (y - this.#offset.y + this.#baseOffset.y) * this.#scale.y\n    };\n  }\n\n  /**\n   * Get a main plane position from a display position.\n   *\n   * @param {number} x The X position.\n   * @param {number} y The Y position.\n   * @returns {object} The main plane position as {x,y}.\n   */\n  displayToMainPlanePos(x, y) {\n    const planePos = this.displayToPlanePos(x, y);\n    return {\n      x: planePos.x - this.#baseOffset.x,\n      y: planePos.y - this.#baseOffset.y\n    };\n  }\n\n  /**\n   * Display the layer.\n   *\n   * @param {boolean} flag Whether to display the layer or not.\n   */\n  display(flag) {\n    this.#containerDiv.style.display = flag ? '' : 'none';\n  }\n\n  /**\n   * Check if the layer is visible.\n   *\n   * @returns {boolean} True if the layer is visible.\n   */\n  isVisible() {\n    return this.#containerDiv.style.display === '';\n  }\n\n  /**\n   * Draw the content (imageData) of the layer.\n   * The imageData variable needs to be set\n   *\n   * @fires App#renderstart\n   * @fires App#renderend\n   */\n  draw() {\n    // skip for non valid position\n    if (!this.#isValidPosition) {\n      return;\n    }\n\n    /**\n     * Render start event.\n     *\n     * @event App#renderstart\n     * @type {object}\n     * @property {string} type The event type.\n     */\n    let event = {\n      type: 'renderstart',\n      layerid: this.getId(),\n      dataid: this.getDataIndex()\n    };\n    this.#fireEvent(event);\n\n    // update data if needed\n    if (this.#needsDataUpdate) {\n      this.#updateImageData();\n    }\n\n    // context opacity\n    this.#context.globalAlpha = this.#opacity;\n\n    // clear context\n    this.clear();\n\n    // draw the cached canvas on the context\n    // transform takes as input a, b, c, d, e, f to create\n    // the transform matrix (column-major order):\n    // [ a c e ]\n    // [ b d f ]\n    // [ 0 0 1 ]\n    this.#context.setTransform(\n      this.#scale.x,\n      0,\n      0,\n      this.#scale.y,\n      -1 * this.#offset.x * this.#scale.x,\n      -1 * this.#offset.y * this.#scale.y\n    );\n\n    // disable smoothing (set just before draw, could be reset by resize)\n    this.#context.imageSmoothingEnabled = this.#imageSmoothingEnabled;\n    // draw image\n    this.#context.drawImage(this.#offscreenCanvas, 0, 0);\n\n    /**\n     * Render end event.\n     *\n     * @event App#renderend\n     * @type {object}\n     * @property {string} type The event type.\n     */\n    event = {\n      type: 'renderend',\n      layerid: this.getId(),\n      dataid: this.getDataIndex()\n    };\n    this.#fireEvent(event);\n  }\n\n  /**\n   * Initialise the layer: set the canvas and context\n   *\n   * @param {object} size The image size as {x,y}.\n   * @param {object} spacing The image spacing as {x,y}.\n   * @param {number} alpha The initial data opacity.\n   */\n  initialise(size, spacing, alpha) {\n    // set locals\n    this.#baseSpacing = spacing;\n    this.#opacity = Math.min(Math.max(alpha, 0), 1);\n\n    // create canvas\n    // (canvas size is set in fitToContainer)\n    this.#canvas = document.createElement('canvas');\n    this.#containerDiv.appendChild(this.#canvas);\n\n    // check that the getContext method exists\n    if (!this.#canvas.getContext) {\n      alert('Error: no canvas.getContext method.');\n      return;\n    }\n    // get the 2D context\n    this.#context = this.#canvas.getContext('2d');\n    if (!this.#context) {\n      alert('Error: failed to get the 2D context.');\n      return;\n    }\n\n    // off screen canvas\n    this.#offscreenCanvas = document.createElement('canvas');\n\n    // set base size: needs an existing context and off screen canvas\n    this.#setBaseSize(size);\n\n    // update data on first draw\n    this.#needsDataUpdate = true;\n  }\n\n  /**\n   * Set the base size of the layer.\n   *\n   * @param {object} size The size as {x,y}.\n   */\n  #setBaseSize(size) {\n    // check canvas creation\n    if (!canCreateCanvas(size.x, size.y)) {\n      throw new Error('Cannot create canvas with size ' +\n        size.x + ', ' + size.y);\n    }\n\n    // set local\n    this.#baseSize = size;\n\n    // off screen canvas\n    this.#offscreenCanvas.width = this.#baseSize.x;\n    this.#offscreenCanvas.height = this.#baseSize.y;\n    // original empty image data array\n    this.#context.clearRect(0, 0, this.#baseSize.x, this.#baseSize.y);\n    this.#imageData = this.#context.createImageData(\n      this.#baseSize.x, this.#baseSize.y);\n  }\n\n  /**\n   * Fit the layer to its parent container.\n   *\n   * @param {number} fitScale1D The 1D fit scale.\n   * @param {object} fitSize The fit size as {x,y}.\n   * @param {object} fitOffset The fit offset as {x,y}.\n   */\n  fitToContainer(fitScale1D, fitSize, fitOffset) {\n    let needsDraw = false;\n\n    // update canvas size if needed (triggers canvas reset)\n    if (this.#canvas.width !== fitSize.x || this.#canvas.height !== fitSize.y) {\n      if (!canCreateCanvas(fitSize.x, fitSize.y)) {\n        throw new Error('Cannot resize canvas ' + fitSize.x + ', ' + fitSize.y);\n      }\n      // canvas size  change triggers canvas reset\n      this.#canvas.width = fitSize.x;\n      this.#canvas.height = fitSize.y;\n      // update draw flag\n      needsDraw = true;\n    }\n    // previous fit scale\n    const previousFitScale = this.#fitScale;\n    // previous scale without fit\n    const previousScale = {\n      x: this.#scale.x / this.#fitScale.x,\n      y: this.#scale.y / this.#fitScale.y\n    };\n    // fit scale\n    const newFitScale = {\n      x: fitScale1D * this.#baseSpacing.x,\n      y: fitScale1D * this.#baseSpacing.y\n    };\n    // scale\n    const newScale = {\n      x: previousScale.x * newFitScale.x,\n      y: previousScale.y * newFitScale.y\n    };\n    // check if different\n    if (previousScale.x !== newScale.x || previousScale.y !== newScale.y) {\n      this.#fitScale = newFitScale;\n      this.#scale = newScale;\n      // update draw flag\n      needsDraw = true;\n    }\n\n    // view offset\n    const newViewOffset = {\n      x: fitOffset.x / newFitScale.x,\n      y: fitOffset.y / newFitScale.y\n    };\n    const newFlipOffset = {\n      x: this.#flipOffset.x * previousFitScale.x / newFitScale.x,\n      y: this.#flipOffset.y * previousFitScale.y / newFitScale.y\n    };\n    // check if different\n    if (this.#viewOffset.x !== newViewOffset.x ||\n      this.#viewOffset.y !== newViewOffset.y ||\n      this.#flipOffset.x !== newFlipOffset.x ||\n      this.#flipOffset.y !== newFlipOffset.y) {\n      // update private local offsets\n      this.#flipOffset = newFlipOffset;\n      this.#viewOffset = newViewOffset;\n      // update global offset\n      this.#offset = {\n        x: this.#viewOffset.x +\n          this.#baseOffset.x +\n          this.#zoomOffset.x +\n          this.#flipOffset.x,\n        y: this.#viewOffset.y +\n          this.#baseOffset.y +\n          this.#zoomOffset.y +\n          this.#flipOffset.y\n      };\n      // update draw flag\n      needsDraw = true;\n    }\n\n    // draw if needed\n    if (needsDraw) {\n      this.draw();\n    }\n  }\n\n  /**\n   * Enable and listen to container interaction events.\n   */\n  bindInteraction() {\n    // allow pointer events\n    this.#containerDiv.style.pointerEvents = 'auto';\n    // interaction events\n    const names = InteractionEventNames;\n    for (let i = 0; i < names.length; ++i) {\n      const eventName = names[i];\n      const passive = eventName !== 'wheel';\n      this.#containerDiv.addEventListener(\n        names[i], this.#fireEvent, {passive: passive});\n    }\n  }\n\n  /**\n   * Disable and stop listening to container interaction events.\n   */\n  unbindInteraction() {\n    // disable pointer events\n    this.#containerDiv.style.pointerEvents = 'none';\n    // interaction events\n    const names = InteractionEventNames;\n    for (let i = 0; i < names.length; ++i) {\n      this.#containerDiv.removeEventListener(names[i], this.#fireEvent);\n    }\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    event.srclayerid = this.getId();\n    event.dataid = this.#dataIndex;\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  // common layer methods [end] ---------------\n\n  /**\n   * Update the canvas image data.\n   */\n  #updateImageData() {\n    // generate image data\n    this.#viewController.generateImageData(this.#imageData);\n    // pass the data to the off screen canvas\n    this.#offscreenCanvas.getContext('2d').putImageData(this.#imageData, 0, 0);\n    // update data flag\n    this.#needsDataUpdate = false;\n  }\n\n  /**\n   * Handle window/level change.\n   *\n   * @param {object} event The event fired when changing the window/level.\n   */\n  #onWLChange = (event) => {\n    // generate and draw if no skip flag\n    const skip = typeof event.skipGenerate !== 'undefined' &&\n      event.skipGenerate === true;\n    if (!skip) {\n      this.#needsDataUpdate = true;\n      this.draw();\n    }\n  };\n\n  /**\n   * Handle colour map change.\n   *\n   * @param {object} event The event fired when changing the colour map.\n   */\n  #onColourChange = (event) => {\n    const skip = typeof event.skipGenerate !== 'undefined' &&\n      event.skipGenerate === true;\n    if (!skip) {\n      this.#needsDataUpdate = true;\n      this.draw();\n    }\n  };\n\n  /**\n   * Handle position change.\n   *\n   * @param {object} event The event fired when changing the position.\n   */\n  #onPositionChange = (event) => {\n    const skip = typeof event.skipGenerate !== 'undefined' &&\n      event.skipGenerate === true;\n    if (!skip) {\n      let valid = true;\n      if (typeof event.valid !== 'undefined') {\n        valid = event.valid;\n      }\n      // clear for non valid events\n      if (!valid) {\n        // clear only once\n        if (this.#isValidPosition) {\n          this.#isValidPosition = false;\n          this.clear();\n        }\n      } else {\n        // 3D dimensions\n        const dims3D = [0, 1, 2];\n        // remove scroll index\n        const indexScrollIndex =\n          dims3D.indexOf(this.#viewController.getScrollIndex());\n        dims3D.splice(indexScrollIndex, 1);\n        // remove non scroll index from diff dims\n        const diffDims = event.diffDims.filter(function (item) {\n          return dims3D.indexOf(item) === -1;\n        });\n        // update if we have something left\n        if (diffDims.length !== 0 || !this.#isValidPosition) {\n          // reset valid flag\n          this.#isValidPosition = true;\n          // reset update flag\n          this.#needsDataUpdate = true;\n          this.draw();\n        }\n      }\n    }\n  };\n\n  /**\n   * Handle alpha function change.\n   *\n   * @param {object} event The event fired when changing the function.\n   */\n  #onAlphaFuncChange = (event) => {\n    const skip = typeof event.skipGenerate !== 'undefined' &&\n      event.skipGenerate === true;\n    if (!skip) {\n      this.#needsDataUpdate = true;\n      this.draw();\n    }\n  };\n\n  /**\n   * Set the current position.\n   *\n   * @param {Point} position The new position.\n   * @param {Index} _index The new index.\n   * @returns {boolean} True if the position was updated.\n   */\n  setCurrentPosition(position, _index) {\n    return this.#viewController.setCurrentPosition(position);\n  }\n\n  /**\n   * Clear the context.\n   */\n  clear() {\n    // clear the context: reset the transform first\n    // store the current transformation matrix\n    this.#context.save();\n    // use the identity matrix while clearing the canvas\n    this.#context.setTransform(1, 0, 0, 1, 0, 0);\n    this.#context.clearRect(0, 0, this.#canvas.width, this.#canvas.height);\n    // restore the transform\n    this.#context.restore();\n  }\n\n} // ViewLayer class\n","import {getShadowColour} from '../utils/colour';\n\n/**\n * Style class.\n */\nexport class Style {\n  /**\n   * Font size.\n   *\n   * @type {number}\n   */\n  #fontSize = 10;\n\n  /**\n   * Font family.\n   *\n   * @type {string}\n   */\n  #fontFamily = 'Verdana';\n\n  /**\n   * Text colour.\n   *\n   * @type {string}\n   */\n  #textColour = '#fff';\n\n  /**\n   * Line colour.\n   *\n   * @type {string}\n   */\n  #lineColour = '#ffff80';\n\n  /**\n   * Base scale.\n   *\n   * @type {object}\n   */\n  #baseScale = {x: 1, y: 1};\n\n  /**\n   * Zoom scale.\n   *\n   * @type {object}\n   */\n  #zoomScale = {x: 1, y: 1};\n\n  /**\n   * Stroke width.\n   *\n   * @type {number}\n   */\n  #strokeWidth = 2;\n\n  /**\n   * Shadow offset.\n   *\n   * @type {object}\n   */\n  #shadowOffset = {x: 0.25, y: 0.25};\n\n  /**\n   * Tag opacity.\n   *\n   * @type {number}\n   */\n  #tagOpacity = 0.2;\n\n  /**\n   * Text padding.\n   *\n   * @type {number}\n   */\n  #textPadding = 3;\n\n  /**\n   * Get the font family.\n   *\n   * @returns {string} The font family.\n   */\n  getFontFamily() {\n    return this.#fontFamily;\n  }\n\n  /**\n   * Get the font size.\n   *\n   * @returns {number} The font size.\n   */\n  getFontSize() {\n    return this.#fontSize;\n  }\n\n  /**\n   * Get the stroke width.\n   *\n   * @returns {number} The stroke width.\n   */\n  getStrokeWidth() {\n    return this.#strokeWidth;\n  }\n\n  /**\n   * Get the text colour.\n   *\n   * @returns {string} The text colour.\n   */\n  getTextColour() {\n    return this.#textColour;\n  }\n\n  /**\n   * Get the line colour.\n   *\n   * @returns {string} The line colour.\n   */\n  getLineColour() {\n    return this.#lineColour;\n  }\n\n  /**\n   * Set the line colour.\n   *\n   * @param {string} colour The line colour.\n   */\n  setLineColour(colour) {\n    this.#lineColour = colour;\n  }\n\n  /**\n   * Set the base scale.\n   *\n   * @param {number} scale The scale as {x,y}.\n   */\n  setBaseScale(scale) {\n    this.#baseScale = scale;\n  }\n\n  /**\n   * Set the zoom scale.\n   *\n   * @param {object} scale The scale as {x,y}.\n   */\n  setZoomScale(scale) {\n    this.#zoomScale = scale;\n  }\n\n  /**\n   * Get the base scale.\n   *\n   * @returns {number} The scale as {x,y}.\n   */\n  getBaseScale() {\n    return this.#baseScale;\n  }\n\n  /**\n   * Get the zoom scale.\n   *\n   * @returns {object} The scale as {x,y}.\n   */\n  getZoomScale() {\n    return this.#zoomScale;\n  }\n\n  /**\n   * Scale an input value using the base scale.\n   *\n   * @param {number} value The value to scale.\n   * @returns {number} The scaled value.\n   */\n  scale(value) {\n    // TODO: 2D?\n    return value / this.#baseScale.x;\n  }\n\n  /**\n   * Apply zoom scale on an input value.\n   *\n   * @param {number} value The value to scale.\n   * @returns {object} The scaled value as {x,y}.\n   */\n  applyZoomScale(value) {\n    // times 2 so that the font size 10 looks like a 10...\n    // (same logic as in the DrawController::updateLabelScale)\n    return {\n      x: 2 * value / this.#zoomScale.x,\n      y: 2 * value / this.#zoomScale.y\n    };\n  }\n\n  /**\n   * Get the shadow offset.\n   *\n   * @returns {object} The offset as {x,y}.\n   */\n  getShadowOffset() {\n    return this.#shadowOffset;\n  }\n\n  /**\n   * Get the tag opacity.\n   *\n   * @returns {number} The opacity.\n   */\n  getTagOpacity() {\n    return this.#tagOpacity;\n  }\n\n  /**\n   * Get the text padding.\n   *\n   * @returns {number} The padding.\n   */\n  getTextPadding() {\n    return this.#textPadding;\n  }\n\n  /**\n   * Get the font definition string.\n   *\n   * @returns {string} The font definition string.\n   */\n  getFontStr() {\n    return ('normal ' + this.getFontSize() + 'px sans-serif');\n  }\n\n  /**\n   * Get the line height.\n   *\n   * @returns {number} The line height.\n   */\n  getLineHeight() {\n    return (this.getFontSize() + this.getFontSize() / 5);\n  }\n\n  /**\n   * Get the font size scaled to the display.\n   *\n   * @returns {number} The scaled font size.\n   */\n  getScaledFontSize() {\n    return this.scale(this.getFontSize());\n  }\n\n  /**\n   * Get the stroke width scaled to the display.\n   *\n   * @returns {number} The scaled stroke width.\n   */\n  getScaledStrokeWidth() {\n    return this.scale(this.getStrokeWidth());\n  }\n\n  /**\n   * Get the shadow line colour.\n   *\n   * @returns {string} The shadow line colour.\n   */\n  getShadowLineColour() {\n    return getShadowColour(this.getLineColour());\n  }\n\n} // class Style\n","// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Style} from '../gui/style';\nimport {ViewController} from '../app/viewController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the display name of the input shape.\n *\n * @param {object} shape The Konva shape.\n * @returns {string} The display name.\n */\nexport function getShapeDisplayName(shape) {\n  let displayName = 'shape';\n  if (shape instanceof Konva.Line) {\n    if (shape.points().length === 4) {\n      displayName = 'line';\n    } else if (shape.points().length === 6) {\n      displayName = 'protractor';\n    } else {\n      displayName = 'roi';\n    }\n  } else if (shape instanceof Konva.Rect) {\n    displayName = 'rectangle';\n  } else if (shape instanceof Konva.Ellipse) {\n    displayName = 'ellipse';\n  }\n  // return\n  return displayName;\n}\n\n/**\n * Draw group command.\n */\nexport class DrawGroupCommand {\n\n  /**\n   * The group to draw.\n   *\n   * @type {Konva.Group}\n   */\n  #group;\n\n  /**\n   * The shape display name.\n   *\n   * @type {string}\n   */\n  #name;\n\n  /**\n   * The Konva layer.\n   *\n   * @type {Konva.Layer}\n   */\n  #layer;\n\n  /**\n   * Flag to send events.\n   *\n   * @type {boolean}\n   */\n  #isSilent;\n\n  /**\n   * The group parent.\n   *\n   * @type {object}\n   */\n  #parent;\n\n  /**\n   * @param {Konva.Group} group The group draw.\n   * @param {string} name The shape display name.\n   * @param {Konva.Layer} layer The layer where to draw the group.\n   * @param {boolean} [silent] Whether to send a creation event or not.\n   */\n  constructor(group, name, layer, silent) {\n    this.#group = group;\n    this.#name = name;\n    this.#layer = layer;\n    this.#isSilent = (typeof silent === 'undefined') ? false : silent;\n    this.#parent = group.getParent();\n  }\n\n  /**\n   * Get the command name.\n   *\n   * @returns {string} The command name.\n   */\n  getName() {\n    return 'Draw-' + this.#name;\n  }\n\n  /**\n   * Execute the command.\n   *\n   * @fires DrawGroupCommand#drawcreate\n   */\n  execute() {\n    // add the group to the parent (in case of undo/redo)\n    this.#parent.add(this.#group);\n    // draw\n    this.#layer.draw();\n    // callback\n    if (!this.#isSilent) {\n      /**\n       * Draw create event.\n       *\n       * @event DrawGroupCommand#drawcreate\n       * @type {object}\n       * @property {number} id The id of the create draw.\n       */\n      this.onExecute({\n        type: 'drawcreate',\n        id: this.#group.id()\n      });\n    }\n  }\n\n  /**\n   * Undo the command.\n   *\n   * @fires DeleteGroupCommand#drawdelete\n   */\n  undo() {\n    // remove the group from the parent layer\n    this.#group.remove();\n    // draw\n    this.#layer.draw();\n    // callback\n    this.onUndo({\n      type: 'drawdelete',\n      id: this.#group.id()\n    });\n  }\n\n  /**\n   * Handle an execute event.\n   *\n   * @param {object} _event The execute event with type and id.\n   */\n  onExecute(_event) {\n    // default does nothing.\n  }\n\n  /**\n   * Handle an undo event.\n   *\n   * @param {object} _event The undo event with type and id.\n   */\n  onUndo(_event) {\n    // default does nothing.\n  }\n\n} // DrawGroupCommand class\n\n\n/**\n * Move group command.\n */\nexport class MoveGroupCommand {\n\n  /**\n   * The group to move.\n   *\n   * @type {Konva.Group}\n   */\n  #group;\n\n  /**\n   * The shape display name.\n   *\n   * @type {string}\n   */\n  #name;\n\n  /**\n   * The 2D translation as {x,y}.\n   *\n   * @type {object}\n   */\n  #translation;\n\n  /**\n   * The Konva layer.\n   *\n   * @type {Konva.Layer}\n   */\n  #layer;\n\n  /**\n   * @param {Konva.Group} group The group draw.\n   * @param {string} name The shape display name.\n   * @param {object} translation A 2D translation to move the group by.\n   * @param {Konva.Layer} layer The layer where to move the group.\n   */\n  constructor(group, name, translation, layer) {\n    this.#group = group;\n    this.#name = name;\n    this.#translation = translation;\n    this.#layer = layer;\n  }\n\n  /**\n   * Get the command name.\n   *\n   * @returns {string} The command name.\n   */\n  getName() {\n    return 'Move-' + this.#name;\n  }\n\n  /**\n   * Execute the command.\n   *\n   * @fires MoveGroupCommand#drawmove\n   */\n  execute() {\n    // translate group\n    this.#group.move(this.#translation);\n    // draw\n    this.#layer.draw();\n    // callback\n    /**\n     * Draw move event.\n     *\n     * @event MoveGroupCommand#drawmove\n     * @type {object}\n     * @property {number} id The id of the create draw.\n     */\n    this.onExecute({\n      type: 'drawmove',\n      id: this.#group.id()\n    });\n  }\n\n  /**\n   * Undo the command.\n   *\n   * @fires MoveGroupCommand#drawmove\n   */\n  undo() {\n    // invert translate group\n    const minusTrans = {\n      x: -this.#translation.x,\n      y: -this.#translation.y\n    };\n    this.#group.move(minusTrans);\n    // draw\n    this.#layer.draw();\n    // callback\n    this.onUndo({\n      type: 'drawmove',\n      id: this.#group.id()\n    });\n  }\n\n  /**\n   * Handle an execute event.\n   *\n   * @param {object} _event The execute event with type and id.\n   */\n  onExecute(_event) {\n    // default does nothing.\n  }\n\n  /**\n   * Handle an undo event.\n   *\n   * @param {object} _event The undo event with type and id.\n   */\n  onUndo(_event) {\n    // default does nothing.\n  }\n\n} // MoveGroupCommand class\n\n\n/**\n * Change group command.\n */\nexport class ChangeGroupCommand {\n\n  /**\n   * The shape display name.\n   *\n   * @type {string}\n   */\n  #name;\n\n  /**\n   * The shape factory.\n   *\n   * @type {object}\n   */\n  #factory;\n\n  /**\n   * The start anchor.\n   *\n   * @type {object}\n   */\n  #startAnchor;\n\n  /**\n   * The end anchor.\n   *\n   * @type {object}\n   */\n  #endAnchor;\n\n  /**\n   * The Konva layer.\n   *\n   * @type {Konva.Layer}\n   */\n  #layer;\n\n  /**\n   * The associated view controller.\n   *\n   * @type {ViewController}\n   */\n  #viewController;\n\n  /**\n   * The app style.\n   *\n   * @type {Style}\n   */\n  #style;\n\n  /**\n   * @param {string} name The shape display name.\n   * @param {object} factory The shape factory.\n   * @param {object} startAnchor The anchor that starts the change.\n   * @param {object} endAnchor The anchor that ends the change.\n   * @param {Konva.Layer} layer The layer where to change the group.\n   * @param {ViewController} viewController The associated viewController.\n   * @param {Style} style The app style.\n   */\n  constructor(\n    name, factory, startAnchor, endAnchor, layer, viewController, style) {\n    this.#name = name;\n    this.#factory = factory;\n    this.#startAnchor = startAnchor;\n    this.#endAnchor = endAnchor;\n    this.#layer = layer;\n    this.#viewController = viewController;\n    this.#style = style;\n  }\n\n  /**\n   * Get the command name.\n   *\n   * @returns {string} The command name.\n   */\n  getName() {\n    return 'Change-' + this.#name;\n  }\n\n  /**\n   * Execute the command.\n   *\n   * @fires ChangeGroupCommand#drawchange\n   */\n  execute() {\n    // change shape\n    this.#factory.update(\n      this.#endAnchor,\n      this.#style,\n      this.#viewController\n    );\n    // draw\n    this.#layer.draw();\n    // callback\n    /**\n     * Draw change event.\n     *\n     * @event ChangeGroupCommand#drawchange\n     * @type {object}\n     */\n    this.onExecute({\n      type: 'drawchange',\n      id: this.#endAnchor.getParent().id()\n    });\n  }\n\n  /**\n   * Undo the command.\n   *\n   * @fires ChangeGroupCommand#drawchange\n   */\n  undo() {\n    // invert change shape\n    this.#factory.update(\n      this.#startAnchor,\n      this.#style,\n      this.#viewController\n    );\n    // draw\n    this.#layer.draw();\n    // callback\n    this.onUndo({\n      type: 'drawchange',\n      id: this.#startAnchor.getParent().id()\n    });\n  }\n\n  /**\n   * Handle an execute event.\n   *\n   * @param {object} _event The execute event with type and id.\n   */\n  onExecute(_event) {\n    // default does nothing.\n  }\n\n  /**\n   * Handle an undo event.\n   *\n   * @param {object} _event The undo event with type and id.\n   */\n  onUndo(_event) {\n    // default does nothing.\n  }\n\n} // ChangeGroupCommand class\n\n/**\n * Delete group command.\n */\nexport class DeleteGroupCommand {\n\n  /**\n   * The group to draw.\n   *\n   * @type {Konva.Group}\n   */\n  #group;\n\n  /**\n   * The shape display name.\n   *\n   * @type {string}\n   */\n  #name;\n\n  /**\n   * The Konva layer.\n   *\n   * @type {Konva.Layer}\n   */\n  #layer;\n\n  /**\n   * The group parent.\n   *\n   * @type {object}\n   */\n  #parent;\n\n  /**\n   * @param {object} group The group draw.\n   * @param {string} name The shape display name.\n   * @param {object} layer The layer where to delete the group.\n   */\n  constructor(group, name, layer) {\n    this.#group = group;\n    this.#name = name;\n    this.#layer = layer;\n    this.#parent = group.getParent();\n  }\n\n  /**\n   * Get the command name.\n   *\n   * @returns {string} The command name.\n   */\n  getName() {\n    return 'Delete-' + this.#name;\n  }\n\n  /**\n   * Execute the command.\n   *\n   * @fires DeleteGroupCommand#drawdelete\n   */\n  execute() {\n    // remove the group from its parent\n    this.#group.remove();\n    // draw\n    this.#layer.draw();\n    // callback\n    /**\n     * Draw delete event.\n     *\n     * @event DeleteGroupCommand#drawdelete\n     * @type {object}\n     * @property {number} id The id of the create draw.\n     */\n    this.onExecute({\n      type: 'drawdelete',\n      id: this.#group.id()\n    });\n  }\n\n  /**\n   * Undo the command.\n   *\n   * @fires DrawGroupCommand#drawcreate\n   */\n  undo() {\n    // add the group to its parent\n    this.#parent.add(this.#group);\n    // draw\n    this.#layer.draw();\n    // callback\n    this.onUndo({\n      type: 'drawcreate',\n      id: this.#group.id()\n    });\n  }\n\n  /**\n   * Handle an execute event.\n   *\n   * @param {object} _event The execute event with type and id.\n   */\n  onExecute(_event) {\n    // default does nothing.\n  }\n\n  /**\n   * Handle an undo event.\n   *\n   * @param {object} _event The undo event with type and id.\n   */\n  onUndo(_event) {\n    // default does nothing.\n  }\n\n} // DeleteGroupCommand class\n","import {getIndexFromStringId} from '../math/index';\nimport {logger} from '../utils/logger';\nimport {replaceFlags} from '../utils/string';\nimport {getShadowColour} from '../utils/colour';\nimport {\n  getShapeDisplayName,\n  DrawGroupCommand,\n  DeleteGroupCommand\n} from '../tools/drawCommands';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Index} from '../math/index';\n/* eslint-enable no-unused-vars */\n\n/**\n * Konva.\n *\n * @external Konva\n * @see https://konvajs.org/\n */\nimport Konva from 'konva';\n\n/**\n * Is an input node's name 'shape'.\n *\n * @param {object} node A Konva node.\n * @returns {boolean} True if the node's name is 'shape'.\n */\nexport function isNodeNameShape(node) {\n  return node.name() === 'shape';\n}\n\n/**\n * Is a node an extra shape associated with a main one.\n *\n * @param {object} node A Konva node.\n * @returns {boolean} True if the node's name starts with 'shape-'.\n */\nexport function isNodeNameShapeExtra(node) {\n  return node.name().startsWith('shape-');\n}\n\n/**\n * Is an input node's name 'label'.\n *\n * @param {object} node A Konva node.\n * @returns {boolean} True if the node's name is 'label'.\n */\nexport function isNodeNameLabel(node) {\n  return node.name() === 'label';\n}\n\n/**\n * Is an input node a position node.\n *\n * @param {object} node A Konva node.\n * @returns {boolean} True if the node's name is 'position-group'.\n */\nexport function isPositionNode(node) {\n  return node.name() === 'position-group';\n}\n\n/**\n * @callback testFn\n * @param {object} node The node.\n * @returns {boolean} True if the node passes the test.\n */\n\n/**\n * Get a lambda to check a node's id.\n *\n * @param {string} id The id to check.\n * @returns {testFn} A function to check a node's id.\n */\nexport function isNodeWithId(id) {\n  return function (node) {\n    return node.id() === id;\n  };\n}\n\n/**\n * Is the input node a node that has the 'stroke' method.\n *\n * @param {object} node A Konva node.\n * @returns {boolean} True if the node's name is 'anchor' and 'label'.\n */\nexport function canNodeChangeColour(node) {\n  return node.name() !== 'anchor' && node.name() !== 'label';\n}\n\n/**\n * Debug function to output the layer hierarchy as text.\n *\n * @param {object} layer The Konva layer.\n * @param {string} prefix A display prefix (used in recursion).\n * @returns {string} A text representation of the hierarchy.\n */\nexport function getHierarchyLog(layer, prefix) {\n  if (typeof prefix === 'undefined') {\n    prefix = '';\n  }\n  const kids = layer.getChildren();\n  let log = prefix + '|__ ' + layer.name() + ': ' + layer.id() + '\\n';\n  for (let i = 0; i < kids.length; ++i) {\n    log += getHierarchyLog(kids[i], prefix + '    ');\n  }\n  return log;\n}\n\n/**\n * Draw controller.\n */\nexport class DrawController {\n\n  /**\n   * The Konva layer.\n   *\n   * @type {Konva.Layer}\n   */\n  #konvaLayer;\n\n  /**\n   * Current position group id.\n   *\n   * @type {string}\n   */\n  #currentPosGroupId = null;\n\n  /**\n   * @param {Konva.Layer} konvaLayer The draw layer.\n   */\n  constructor(konvaLayer) {\n    this.#konvaLayer = konvaLayer;\n  }\n\n  /**\n   * Get the current position group.\n   *\n   * @returns {object} The Konva.Group.\n   */\n  getCurrentPosGroup() {\n    // get position groups\n    const posGroups = this.#konvaLayer.getChildren((node) => {\n      return node.id() === this.#currentPosGroupId;\n    });\n    // if one group, use it\n    // if no group, create one\n    let posGroup = null;\n    if (posGroups.length === 1) {\n      posGroup = posGroups[0];\n    } else if (posGroups.length === 0) {\n      posGroup = new Konva.Group();\n      posGroup.name('position-group');\n      posGroup.id(this.#currentPosGroupId);\n      posGroup.visible(true); // dont inherit\n      // add new group to layer\n      this.#konvaLayer.add(posGroup);\n    } else {\n      logger.warn('Unexpected number of draw position groups.');\n    }\n    // return\n    return posGroup;\n  }\n\n  /**\n   * Reset: clear the layers array.\n   */\n  reset() {\n    this.#konvaLayer = null;\n  }\n\n  /**\n   * Get a Konva group using its id.\n   *\n   * @param {string} id The group id.\n   * @returns {object|undefined} The Konva group.\n   */\n  getGroup(id) {\n    const group = this.#konvaLayer.findOne('#' + id);\n    if (typeof group === 'undefined') {\n      logger.warn('Cannot find node with id: ' + id\n      );\n    }\n    return group;\n  }\n\n  /**\n   * Activate the current draw layer.\n   *\n   * @param {Index} index The current position.\n   * @param {number} scrollIndex The scroll index.\n   */\n  activateDrawLayer(index, scrollIndex) {\n    // TODO: add layer info\n    // get and store the position group id\n    const dims = [scrollIndex];\n    for (let j = 3; j < index.length(); ++j) {\n      dims.push(j);\n    }\n    this.#currentPosGroupId = index.toStringId(dims);\n\n    // get all position groups\n    const posGroups = this.#konvaLayer.getChildren(isPositionNode);\n    // reset or set the visible property\n    let visible;\n    for (let i = 0, leni = posGroups.length; i < leni; ++i) {\n      visible = false;\n      if (posGroups[i].id() === this.#currentPosGroupId) {\n        visible = true;\n      }\n      // group members inherit the visible property\n      posGroups[i].visible(visible);\n    }\n\n    // show current draw layer\n    this.#konvaLayer.draw();\n  }\n\n  /**\n   * Get a list of drawing display details.\n   *\n   * @returns {Array} A list of draw details as\n   *   {id, position, type, color, meta}\n   */\n  getDrawDisplayDetails() {\n    const list = [];\n    const groups = this.#konvaLayer.getChildren();\n    for (let j = 0, lenj = groups.length; j < lenj; ++j) {\n      const position = getIndexFromStringId(groups[j].id());\n      // @ts-ignore\n      const collec = groups[j].getChildren();\n      for (let i = 0, leni = collec.length; i < leni; ++i) {\n        const shape = collec[i].getChildren(isNodeNameShape)[0];\n        const label = collec[i].getChildren(isNodeNameLabel)[0];\n        const text = label.getChildren()[0];\n        let type = shape.className;\n        if (type === 'Line') {\n          const shapeExtrakids = collec[i].getChildren(\n            isNodeNameShapeExtra);\n          if (shape.closed()) {\n            type = 'Roi';\n          } else if (shapeExtrakids.length !== 0) {\n            const extraName0 = shapeExtrakids[0].name();\n            if (extraName0.indexOf('triangle') !== -1) {\n              type = 'Arrow';\n            } else if (extraName0.indexOf('arc') !== -1) {\n              type = 'Protractor';\n            } else {\n              type = 'Ruler';\n            }\n          }\n        }\n        if (type === 'Rect') {\n          type = 'Rectangle';\n        }\n        list.push({\n          id: collec[i].id(),\n          position: position.toString(),\n          type: type,\n          color: shape.stroke(),\n          meta: text.meta\n        });\n      }\n    }\n    return list;\n  }\n\n  /**\n   * Get a list of drawing store details. Used in state.\n   *\n   * @returns {object} A list of draw details including id, text, quant...\n   * TODO Unify with getDrawDisplayDetails?\n   */\n  getDrawStoreDetails() {\n    const drawingsDetails = {};\n\n    // get all position groups\n    const posGroups = this.#konvaLayer.getChildren(isPositionNode);\n\n    let posKids;\n    let group;\n    for (let i = 0, leni = posGroups.length; i < leni; ++i) {\n      // @ts-ignore\n      posKids = posGroups[i].getChildren();\n      for (let j = 0, lenj = posKids.length; j < lenj; ++j) {\n        group = posKids[j];\n        // remove anchors\n        const anchors = group.find('.anchor');\n        for (let a = 0; a < anchors.length; ++a) {\n          anchors[a].remove();\n        }\n        // get text\n        const texts = group.find('.text');\n        if (texts.length !== 1) {\n          logger.warn('There should not be more than one text per shape.');\n        }\n        // get meta (non konva vars)\n        drawingsDetails[group.id()] = {\n          meta: texts[0].meta\n        };\n      }\n    }\n    return drawingsDetails;\n  }\n\n  /**\n   * Set the drawings on the current stage.\n   *\n   * @param {Array} drawings An array of drawings.\n   * @param {Array} drawingsDetails An array of drawings details.\n   * @param {object} cmdCallback The DrawCommand callback.\n   * @param {object} exeCallback The callback to call once the\n   *   DrawCommand has been executed.\n   */\n  setDrawings(\n    drawings, drawingsDetails, cmdCallback, exeCallback) {\n    // regular Konva deserialize\n    const stateLayer = Konva.Node.create(drawings);\n\n    // get all position groups\n    const statePosGroups = stateLayer.getChildren(isPositionNode);\n\n    for (let i = 0, leni = statePosGroups.length; i < leni; ++i) {\n      const statePosGroup = statePosGroups[i];\n\n      // Get or create position-group if it does not exist and\n      // append it to konvaLayer\n      let posGroup = this.#konvaLayer.getChildren(\n        isNodeWithId(statePosGroup.id()))[0];\n      if (typeof posGroup === 'undefined') {\n        posGroup = new Konva.Group({\n          id: statePosGroup.id(),\n          name: 'position-group',\n          visible: false\n        });\n        this.#konvaLayer.add(posGroup);\n      }\n\n      const statePosKids = statePosGroup.getChildren();\n      for (let j = 0, lenj = statePosKids.length; j < lenj; ++j) {\n        // shape group (use first one since it will be removed from\n        // the group when we change it)\n        const stateGroup = statePosKids[0];\n        // add group to posGroup (switches its parent)\n        // @ts-ignore\n        posGroup.add(stateGroup);\n        // shape\n        const shape = stateGroup.getChildren(isNodeNameShape)[0];\n        // create the draw command\n        const cmd = new DrawGroupCommand(\n          stateGroup, shape.className, this.#konvaLayer);\n        // draw command callbacks\n        cmd.onExecute = cmdCallback;\n        cmd.onUndo = cmdCallback;\n        // details\n        if (drawingsDetails) {\n          const details = drawingsDetails[stateGroup.id()];\n          const label = stateGroup.getChildren(isNodeNameLabel)[0];\n          const text = label.getText();\n          // store details\n          text.meta = details.meta;\n          // reset text (it was not encoded)\n          text.setText(replaceFlags(\n            text.meta.textExpr, text.meta.quantification\n          ));\n        }\n        // execute\n        cmd.execute();\n        exeCallback(cmd);\n      }\n    }\n  }\n\n  /**\n   * Update a drawing from its details.\n   *\n   * @param {object} drawDetails Details of the drawing to update.\n   */\n  updateDraw(drawDetails) {\n    // get the group\n    const group = this.#konvaLayer.findOne('#' + drawDetails.id);\n    if (typeof group === 'undefined') {\n      logger.warn(\n        '[updateDraw] Cannot find group with id: ' + drawDetails.id\n      );\n      return;\n    }\n    // shape\n    // @ts-ignore\n    const shapes = group.getChildren(isNodeNameShape);\n    for (let i = 0; i < shapes.length; ++i) {\n      shapes[i].stroke(drawDetails.color);\n    }\n    // shape extra\n    // @ts-ignore\n    const shapesExtra = group.getChildren(isNodeNameShapeExtra);\n    for (let j = 0; j < shapesExtra.length; ++j) {\n      if (typeof shapesExtra[j].stroke() !== 'undefined') {\n        shapesExtra[j].stroke(drawDetails.color);\n      } else if (typeof shapesExtra[j].fill() !== 'undefined') {\n        // for example text\n        shapesExtra[j].fill(drawDetails.color);\n      }\n    }\n    // label\n    // @ts-ignore\n    const label = group.getChildren(isNodeNameLabel)[0];\n    const shadowColor = getShadowColour(drawDetails.color);\n    const kids = label.getChildren();\n    for (let k = 0; k < kids.length; ++k) {\n      const kid = kids[k];\n      kid.fill(drawDetails.color);\n      if (kids[k].className === 'Text') {\n        const text = kids[k];\n        text.shadowColor(shadowColor);\n        if (typeof drawDetails.meta !== 'undefined') {\n          text.meta = drawDetails.meta;\n          text.setText(replaceFlags(\n            text.meta.textExpr, text.meta.quantification\n          ));\n          label.setVisible(text.meta.textExpr.length !== 0);\n        }\n      }\n    }\n\n    // udpate current layer\n    this.#konvaLayer.draw();\n  }\n\n  /**\n   * Delete a Draw from the stage.\n   *\n   * @param {object} group The group to delete.\n   * @param {object} cmdCallback The DeleteCommand callback.\n   * @param {object} exeCallback The callback to call once the\n   *  DeleteCommand has been executed.\n   */\n  deleteDrawGroup(group, cmdCallback, exeCallback) {\n    const shape = group.getChildren(isNodeNameShape)[0];\n    const shapeDisplayName = getShapeDisplayName(shape);\n    const delcmd = new DeleteGroupCommand(\n      group, shapeDisplayName, this.#konvaLayer);\n    delcmd.onExecute = cmdCallback;\n    delcmd.onUndo = cmdCallback;\n    delcmd.execute();\n    // callback\n    exeCallback(delcmd);\n  }\n\n  /**\n   * Delete a Draw from the stage.\n   *\n   * @param {string} id The id of the group to delete.\n   * @param {Function} cmdCallback The DeleteCommand callback.\n   * @param {Function} exeCallback The callback to call once the\n   *  DeleteCommand has been executed.\n   * @returns {boolean} False if the group cannot be found.\n   */\n  deleteDraw(id, cmdCallback, exeCallback) {\n    // get the group\n    const group = this.getGroup(id);\n    if (typeof group === 'undefined') {\n      return false;\n    }\n    // delete\n    this.deleteDrawGroup(group, cmdCallback, exeCallback);\n\n    return true;\n  }\n\n  /**\n   * Delete all Draws from the stage.\n   *\n   * @param {Function} cmdCallback The DeleteCommand callback.\n   * @param {Function} exeCallback The callback to call once the\n   *  DeleteCommand has been executed.\n   */\n  deleteDraws(cmdCallback, exeCallback) {\n    const groups = this.#konvaLayer.getChildren();\n    while (groups.length) {\n      this.deleteDrawGroup(groups[0], cmdCallback, exeCallback);\n    }\n  }\n\n} // class DrawController\n","import {ListenerHandler} from '../utils/listen';\nimport {DrawController} from '../app/drawController';\nimport {getScaledOffset} from './layerGroup';\nimport {InteractionEventNames} from './generic';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point, Point3D} from '../math/point';\nimport {Index} from '../math/index';\nimport {Vector3D} from '../math/vector';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw layer.\n */\nexport class DrawLayer {\n\n  /**\n   * The container div.\n   *\n   * @type {HTMLDivElement}\n   */\n  #containerDiv;\n\n  /**\n   * Konva stage.\n   *\n   * @type {Konva.Stage}\n   */\n  #konvaStage = null;\n\n  /**\n   * The layer base size as {x,y}.\n   *\n   * @type {object}\n   */\n  #baseSize;\n\n  /**\n   * The layer base spacing as {x,y}.\n   *\n   * @type {object}\n   */\n  #baseSpacing;\n\n  /**\n   * The layer fit scale.\n   *\n   * @type {object}\n   */\n  #fitScale = {x: 1, y: 1};\n\n  /**\n   * The base layer offset.\n   *\n   * @type {object}\n   */\n  #baseOffset = {x: 0, y: 0};\n\n  /**\n   * The view offset.\n   *\n   * @type {object}\n   */\n  #viewOffset = {x: 0, y: 0};\n\n  /**\n   * The zoom offset.\n   *\n   * @type {object}\n   */\n  #zoomOffset = {x: 0, y: 0};\n\n  /**\n   * The flip offset.\n   *\n   * @type {object}\n   */\n  #flipOffset = {x: 0, y: 0};\n\n  /**\n   * The draw controller.\n   *\n   * @type {object}\n   */\n  #drawController = null;\n\n  /**\n   * The plane helper.\n   *\n   * @type {object}\n   */\n  #planeHelper;\n\n  /**\n   * The associated data index.\n   *\n   * @type {number}\n   */\n  #dataIndex = null;\n\n  /**\n   * @param {HTMLDivElement} containerDiv The layer div, its id will be used\n   *   as this layer id.\n   */\n  constructor(containerDiv) {\n    this.#containerDiv = containerDiv;\n    // specific css class name\n    this.#containerDiv.className += ' drawLayer';\n  }\n\n  /**\n   * Get the associated data index.\n   *\n   * @returns {number} The index.\n   */\n  getDataIndex() {\n    return this.#dataIndex;\n  }\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Get the Konva stage.\n   *\n   * @returns {object} The stage.\n   */\n  getKonvaStage() {\n    return this.#konvaStage;\n  }\n\n  /**\n   * Get the Konva layer.\n   *\n   * @returns {object} The layer.\n   */\n  getKonvaLayer() {\n    // there should only be one layer\n    return this.#konvaStage.getLayers()[0];\n  }\n\n  /**\n   * Get the draw controller.\n   *\n   * @returns {object} The controller.\n   */\n  getDrawController() {\n    return this.#drawController;\n  }\n\n  /**\n   * Set the plane helper.\n   *\n   * @param {object} helper The helper.\n   */\n  setPlaneHelper(helper) {\n    this.#planeHelper = helper;\n  }\n\n  // common layer methods [start] ---------------\n\n  /**\n   * Get the id of the layer.\n   *\n   * @returns {string} The string id.\n   */\n  getId() {\n    return this.#containerDiv.id;\n  }\n\n  /**\n   * Get the layer base size (without scale).\n   *\n   * @returns {object} The size as {x,y}.\n   */\n  getBaseSize() {\n    return this.#baseSize;\n  }\n\n  /**\n   * Get the layer opacity.\n   *\n   * @returns {number} The opacity ([0:1] range).\n   */\n  getOpacity() {\n    return this.#konvaStage.opacity();\n  }\n\n  /**\n   * Set the layer opacity.\n   *\n   * @param {number} alpha The opacity ([0:1] range).\n   */\n  setOpacity(alpha) {\n    this.#konvaStage.opacity(Math.min(Math.max(alpha, 0), 1));\n  }\n\n  /**\n   * Add a flip offset along the layer X axis.\n   */\n  addFlipOffsetX() {\n    // flip scale is handled by layer group\n    // flip offset\n    const scale = this.#konvaStage.scale();\n    const size = this.#konvaStage.size();\n    this.#flipOffset.x += size.width / scale.x;\n    // apply\n    const offset = this.#konvaStage.offset();\n    offset.x += this.#flipOffset.x;\n    this.#konvaStage.offset(offset);\n  }\n\n  /**\n   * Add a flip offset along the layer Y axis.\n   */\n  addFlipOffsetY() {\n    // flip scale is handled by layer group\n    // flip offset\n    const scale = this.#konvaStage.scale();\n    const size = this.#konvaStage.size();\n    this.#flipOffset.y += size.height / scale.y;\n    // apply\n    const offset = this.#konvaStage.offset();\n    offset.y += this.#flipOffset.y;\n    this.#konvaStage.offset(offset);\n  }\n\n  /**\n   * Set the layer scale.\n   *\n   * @param {object} newScale The scale as {x,y}.\n   * @param {Point3D} [center] The scale center.\n   */\n  setScale(newScale, center) {\n    const orientedNewScale =\n      this.#planeHelper.getTargetOrientedPositiveXYZ(newScale);\n    const finalNewScale = {\n      x: this.#fitScale.x * orientedNewScale.x,\n      y: this.#fitScale.y * orientedNewScale.y\n    };\n\n    const offset = this.#konvaStage.offset();\n\n    if (Math.abs(newScale.x) === 1 &&\n      Math.abs(newScale.y) === 1 &&\n      Math.abs(newScale.z) === 1) {\n      // reset zoom offset for scale=1\n      const resetOffset = {\n        x: offset.x - this.#zoomOffset.x,\n        y: offset.y - this.#zoomOffset.y\n      };\n      // store new offset\n      this.#zoomOffset = {x: 0, y: 0};\n      this.#konvaStage.offset(resetOffset);\n    } else {\n      if (typeof center !== 'undefined') {\n        let worldCenter = this.#planeHelper.getPlaneOffsetFromOffset3D({\n          x: center.getX(),\n          y: center.getY(),\n          z: center.getZ()\n        });\n        // center was obtained with viewLayer.displayToMainPlanePos\n        // compensated for baseOffset\n        // TODO: justify...\n        worldCenter = {\n          x: worldCenter.x + this.#baseOffset.x,\n          y: worldCenter.y + this.#baseOffset.y\n        };\n\n        const newOffset = getScaledOffset(\n          offset, this.#konvaStage.scale(), finalNewScale, worldCenter);\n\n        const newZoomOffset = {\n          x: this.#zoomOffset.x + newOffset.x - offset.x,\n          y: this.#zoomOffset.y + newOffset.y - offset.y\n        };\n        // store new offset\n        this.#zoomOffset = newZoomOffset;\n        this.#konvaStage.offset(newOffset);\n      }\n    }\n\n    this.#konvaStage.scale(finalNewScale);\n    // update labels\n    this.#updateLabelScale(finalNewScale);\n  }\n\n  /**\n   * Set the layer offset.\n   *\n   * @param {object} newOffset The offset as {x,y}.\n   */\n  setOffset(newOffset) {\n    const planeNewOffset =\n      this.#planeHelper.getPlaneOffsetFromOffset3D(newOffset);\n    this.#konvaStage.offset({\n      x: planeNewOffset.x +\n        this.#viewOffset.x +\n        this.#baseOffset.x +\n        this.#zoomOffset.x +\n        this.#flipOffset.x,\n      y: planeNewOffset.y +\n        this.#viewOffset.y +\n        this.#baseOffset.y +\n        this.#zoomOffset.y +\n        this.#flipOffset.y\n    });\n  }\n\n  /**\n   * Set the base layer offset. Updates the layer offset.\n   *\n   * @param {Vector3D} scrollOffset The scroll offset vector.\n   * @param {Vector3D} planeOffset The plane offset vector.\n   * @returns {boolean} True if the offset was updated.\n   */\n  setBaseOffset(scrollOffset, planeOffset) {\n    const scrollIndex = this.#planeHelper.getNativeScrollIndex();\n    const newOffset = this.#planeHelper.getPlaneOffsetFromOffset3D({\n      x: scrollIndex === 0 ? scrollOffset.getX() : planeOffset.getX(),\n      y: scrollIndex === 1 ? scrollOffset.getY() : planeOffset.getY(),\n      z: scrollIndex === 2 ? scrollOffset.getZ() : planeOffset.getZ(),\n    });\n    const needsUpdate = this.#baseOffset.x !== newOffset.x ||\n      this.#baseOffset.y !== newOffset.y;\n    // reset offset if needed\n    if (needsUpdate) {\n      const offset = this.#konvaStage.offset();\n      this.#konvaStage.offset({\n        x: offset.x - this.#baseOffset.x + newOffset.x,\n        y: offset.y - this.#baseOffset.y + newOffset.y\n      });\n      this.#baseOffset = newOffset;\n    }\n    return needsUpdate;\n  }\n\n  /**\n   * Display the layer.\n   *\n   * @param {boolean} flag Whether to display the layer or not.\n   */\n  display(flag) {\n    this.#containerDiv.style.display = flag ? '' : 'none';\n  }\n\n  /**\n   * Check if the layer is visible.\n   *\n   * @returns {boolean} True if the layer is visible.\n   */\n  isVisible() {\n    return this.#containerDiv.style.display === '';\n  }\n\n  /**\n   * Draw the content (imageData) of the layer.\n   * The imageData variable needs to be set\n   */\n  draw() {\n    this.#konvaStage.draw();\n  }\n\n  /**\n   * Initialise the layer: set the canvas and context\n   *\n   * @param {object} size The image size as {x,y}.\n   * @param {object} spacing The image spacing as {x,y}.\n   * @param {number} index The associated data index.\n   */\n  initialise(size, spacing, index) {\n    // set locals\n    this.#baseSize = size;\n    this.#baseSpacing = spacing;\n    this.#dataIndex = index;\n\n    // create stage\n    this.#konvaStage = new Konva.Stage({\n      container: this.#containerDiv,\n      width: this.#baseSize.x,\n      height: this.#baseSize.y,\n      listening: false\n    });\n    // reset style\n    // (avoids a not needed vertical scrollbar)\n    this.#konvaStage.getContent().setAttribute('style', '');\n\n    // create layer\n    const konvaLayer = new Konva.Layer({\n      listening: false,\n      visible: true\n    });\n    this.#konvaStage.add(konvaLayer);\n\n    // create draw controller\n    this.#drawController = new DrawController(konvaLayer);\n  }\n\n  /**\n   * Fit the layer to its parent container.\n   *\n   * @param {number} fitScale1D The 1D fit scale.\n   * @param {object} fitSize The fit size as {x,y}.\n   * @param {object} fitOffset The fit offset as {x,y}.\n   */\n  fitToContainer(fitScale1D, fitSize, fitOffset) {\n    // update konva\n    this.#konvaStage.width(fitSize.x);\n    this.#konvaStage.height(fitSize.y);\n\n    // previous scale without fit\n    const previousScale = {\n      x: this.#konvaStage.scale().x / this.#fitScale.x,\n      y: this.#konvaStage.scale().y / this.#fitScale.y\n    };\n    // update fit scale\n    this.#fitScale = {\n      x: fitScale1D * this.#baseSpacing.x,\n      y: fitScale1D * this.#baseSpacing.y\n    };\n    // update scale\n    this.#konvaStage.scale({\n      x: previousScale.x * this.#fitScale.x,\n      y: previousScale.y * this.#fitScale.y\n    });\n\n    // update offsets\n    this.#viewOffset = {\n      x: fitOffset.x / this.#fitScale.x,\n      y: fitOffset.y / this.#fitScale.y\n    };\n    this.#konvaStage.offset({\n      x: this.#viewOffset.x +\n        this.#baseOffset.x +\n        this.#zoomOffset.x +\n        this.#flipOffset.x,\n      y: this.#viewOffset.y +\n        this.#baseOffset.y +\n        this.#zoomOffset.y +\n        this.#flipOffset.y\n    });\n  }\n\n  /**\n   * Check the visibility of a given group.\n   *\n   * @param {string} id The id of the group.\n   * @returns {boolean} True if the group is visible.\n   */\n  isGroupVisible(id) {\n    // get the group\n    const group = this.#drawController.getGroup(id);\n    if (typeof group === 'undefined') {\n      return false;\n    }\n    // get visibility\n    return group.isVisible();\n  }\n\n  /**\n   * Toggle the visibility of a given group.\n   *\n   * @param {string} id The id of the group.\n   * @returns {boolean} False if the group cannot be found.\n   */\n  toggleGroupVisibility(id) {\n    // get the group\n    const group = this.#drawController.getGroup(id);\n    if (typeof group === 'undefined') {\n      return false;\n    }\n    // toggle visible\n    group.visible(!group.isVisible());\n\n    // udpate\n    this.draw();\n\n    return true;\n  }\n\n  /**\n   * Delete a Draw from the stage.\n   *\n   * @param {string} id The id of the group to delete.\n   * @param {object} exeCallback The callback to call once the\n   *  DeleteCommand has been executed.\n   */\n  deleteDraw(id, exeCallback) {\n    this.#drawController.deleteDraw(id, this.#fireEvent, exeCallback);\n  }\n\n  /**\n   * Delete all Draws from the stage.\n   *\n   * @param {object} exeCallback The callback to call once the\n   *  DeleteCommand has been executed.\n   */\n  deleteDraws(exeCallback) {\n    this.#drawController.deleteDraws(this.#fireEvent, exeCallback);\n  }\n\n  /**\n   * Enable and listen to container interaction events.\n   */\n  bindInteraction() {\n    this.#konvaStage.listening(true);\n    // allow pointer events\n    this.#containerDiv.style.pointerEvents = 'auto';\n    // interaction events\n    const names = InteractionEventNames;\n    for (let i = 0; i < names.length; ++i) {\n      this.#containerDiv.addEventListener(names[i], this.#fireEvent);\n    }\n  }\n\n  /**\n   * Disable and stop listening to container interaction events.\n   */\n  unbindInteraction() {\n    this.#konvaStage.listening(false);\n    // disable pointer events\n    this.#containerDiv.style.pointerEvents = 'none';\n    // interaction events\n    const names = InteractionEventNames;\n    for (let i = 0; i < names.length; ++i) {\n      this.#containerDiv.removeEventListener(names[i], this.#fireEvent);\n    }\n  }\n\n  /**\n   * Set the current position.\n   *\n   * @param {Point} position The new position.\n   * @param {Index} index The new index.\n   * @returns {boolean} True if the position was updated.\n   */\n  setCurrentPosition(position, index) {\n    this.getDrawController().activateDrawLayer(\n      index, this.#planeHelper.getScrollIndex());\n    // TODO: add check\n    return true;\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    event.srclayerid = this.getId();\n    event.dataid = this.#dataIndex;\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  // common layer methods [end] ---------------\n\n  /**\n   * Update label scale: compensate for it so\n   *   that label size stays visually the same.\n   *\n   * @param {object} scale The scale to compensate for as {x,y}.\n   */\n  #updateLabelScale(scale) {\n    // same formula as in style::applyZoomScale:\n    // compensate for scale and times 2 so that font 10 looks like a 10\n    const ratioX = 2 / scale.x;\n    const ratioY = 2 / scale.y;\n    // compensate scale for labels\n    const labels = this.#konvaStage.find('Label');\n    for (let i = 0; i < labels.length; ++i) {\n      labels[i].scale({x: ratioX, y: ratioY});\n    }\n  }\n\n} // DrawLayer class\n","import {Point, Point3D} from '../math/point';\nimport {LayerGroup} from './layerGroup';\n\n/**\n * Window/level binder.\n */\nexport class WindowLevelBinder {\n  getEventType = function () {\n    return 'wlchange';\n  };\n  getCallback = function (layerGroup) {\n    return function (event) {\n      const viewLayers = layerGroup.getViewLayersByDataIndex(event.dataid);\n      if (viewLayers.length !== 0) {\n        const vc = viewLayers[0].getViewController();\n        vc.setWindowLevel(event.value[0], event.value[1]);\n      }\n    };\n  };\n}\n\n/**\n * Position binder.\n */\nexport class PositionBinder {\n  getEventType = function () {\n    return 'positionchange';\n  };\n  getCallback = function (layerGroup) {\n    return function (event) {\n      const pointValues = event.value[1];\n      const vc = layerGroup.getActiveViewLayer().getViewController();\n      // handle different number of dimensions\n      const currentPos = vc.getCurrentPosition();\n      const currentDims = currentPos.length();\n      const inputDims = pointValues.length;\n      if (inputDims !== currentDims) {\n        if (inputDims === currentDims - 1) {\n          // add missing dim, for ex: input 3D -> current 4D\n          pointValues.push(currentPos.get(currentDims - 1));\n        } else if (inputDims === currentDims + 1) {\n          // remove extra dim, for ex: input 4D -> current 3D\n          pointValues.pop();\n        }\n      }\n      vc.setCurrentPosition(new Point(pointValues));\n    };\n  };\n}\n\n/**\n * Zoom binder.\n */\nexport class ZoomBinder {\n  getEventType = function () {\n    return 'zoomchange';\n  };\n  getCallback = function (layerGroup) {\n    return function (event) {\n      const scale = {\n        x: event.value[0],\n        y: event.value[1],\n        z: event.value[2]\n      };\n      let center;\n      if (event.value.length === 6) {\n        center = new Point3D(\n          event.value[3],\n          event.value[4],\n          event.value[5]\n        );\n      }\n      layerGroup.setScale(scale, center);\n      layerGroup.draw();\n    };\n  };\n}\n\n/**\n * Offset binder.\n */\nexport class OffsetBinder {\n  getEventType = function () {\n    return 'offsetchange';\n  };\n  getCallback = function (layerGroup) {\n    return function (event) {\n      layerGroup.setOffset({\n        x: event.value[0],\n        y: event.value[1],\n        z: event.value[2]\n      });\n      layerGroup.draw();\n    };\n  };\n}\n\n/**\n * Opacity binder. Only propagates to view layers of the same data.\n */\nexport class OpacityBinder {\n  getEventType = function () {\n    return 'opacitychange';\n  };\n  getCallback = function (layerGroup) {\n    return function (event) {\n      // exit if no data index\n      if (typeof event.dataid === 'undefined') {\n        return;\n      }\n      // propagate to first view layer\n      const viewLayers = layerGroup.getViewLayersByDataIndex(event.dataid);\n      if (viewLayers.length !== 0) {\n        viewLayers[0].setOpacity(event.value);\n        viewLayers[0].draw();\n      }\n    };\n  };\n}\n\n/**\n * List of binders.\n */\nexport const binderList = {\n  WindowLevelBinder,\n  PositionBinder,\n  ZoomBinder,\n  OffsetBinder,\n  OpacityBinder\n};\n\n/**\n * Stage: controls a list of layer groups and their\n * synchronisation.\n */\nexport class Stage {\n\n  // associated layer groups\n  #layerGroups = [];\n  // active layer group index\n  #activeLayerGroupIndex = null;\n\n  // layer group binders\n  #binders = [];\n  // binder callbacks\n  #callbackStore = null;\n\n  /**\n   * Get the layer group at the given index.\n   *\n   * @param {number} index The index.\n   * @returns {LayerGroup} The layer group.\n   */\n  getLayerGroup(index) {\n    return this.#layerGroups[index];\n  }\n\n  /**\n   * Get the number of layer groups that form the stage.\n   *\n   * @returns {number} The number of layer groups.\n   */\n  getNumberOfLayerGroups() {\n    return this.#layerGroups.length;\n  }\n\n  /**\n   * Get the active layer group.\n   *\n   * @returns {LayerGroup} The layer group.\n   */\n  getActiveLayerGroup() {\n    return this.getLayerGroup(this.#activeLayerGroupIndex);\n  }\n\n  /**\n   * Get the view layers associated to a data index.\n   *\n   * @param {number} index The data index.\n   * @returns {Array} The layers.\n   */\n  getViewLayersByDataIndex(index) {\n    let res = [];\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      res = res.concat(this.#layerGroups[i].getViewLayersByDataIndex(index));\n    }\n    return res;\n  }\n\n  /**\n   * Get the draw layers associated to a data index.\n   *\n   * @param {number} index The data index.\n   * @returns {Array} The layers.\n   */\n  getDrawLayersByDataIndex(index) {\n    let res = [];\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      res = res.concat(this.#layerGroups[i].getDrawLayersByDataIndex(index));\n    }\n    return res;\n  }\n\n  /**\n   * Add a layer group to the list.\n   *\n   * @param {object} htmlElement The HTML element of the layer group.\n   * @returns {LayerGroup} The newly created layer group.\n   */\n  addLayerGroup(htmlElement) {\n    this.#activeLayerGroupIndex = this.#layerGroups.length;\n    const layerGroup = new LayerGroup(htmlElement);\n    // add to storage\n    const isBound = this.#callbackStore && this.#callbackStore.length !== 0;\n    if (isBound) {\n      this.unbindLayerGroups();\n    }\n    this.#layerGroups.push(layerGroup);\n    if (isBound) {\n      this.bindLayerGroups();\n    }\n    // return created group\n    return layerGroup;\n  }\n\n  /**\n   * Get a layer group from an HTML element id.\n   *\n   * @param {string} id The element id to find.\n   * @returns {LayerGroup} The layer group.\n   */\n  getLayerGroupByDivId(id) {\n    return this.#layerGroups.find(function (item) {\n      return item.getDivId() === id;\n    });\n  }\n\n  /**\n   * Set the layer groups binders.\n   *\n   * @param {Array} list The list of binder objects.\n   */\n  setBinders(list) {\n    if (typeof list === 'undefined' || list === null) {\n      throw new Error('Cannot set null or undefined binders');\n    }\n    if (this.#binders.length !== 0) {\n      this.unbindLayerGroups();\n    }\n    this.#binders = list.slice();\n    this.bindLayerGroups();\n  }\n\n  /**\n   * Empty the layer group list.\n   */\n  empty() {\n    this.unbindLayerGroups();\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      this.#layerGroups[i].empty();\n    }\n    this.#layerGroups = [];\n    this.#activeLayerGroupIndex = null;\n  }\n\n  /**\n   * Reset the stage: calls reset on all layer groups.\n   */\n  reset() {\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      this.#layerGroups[i].reset();\n    }\n  }\n\n  /**\n   * Draw the stage: calls draw on all layer groups.\n   */\n  draw() {\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      this.#layerGroups[i].draw();\n    }\n  }\n\n  /**\n   * Synchronise the fit scale of the group layers.\n   */\n  syncLayerGroupScale() {\n    let minScale;\n    const hasScale = [];\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      const scale = this.#layerGroups[i].calculateFitScale();\n      if (typeof scale !== 'undefined') {\n        hasScale.push(i);\n        if (typeof minScale === 'undefined' || scale < minScale) {\n          minScale = scale;\n        }\n      }\n    }\n    // exit if no scale\n    if (typeof minScale === 'undefined') {\n      return;\n    }\n    // apply min scale to layers\n    for (let j = 0; j < this.#layerGroups.length; ++j) {\n      if (hasScale.includes(j)) {\n        this.#layerGroups[j].setFitScale(minScale);\n      }\n    }\n  }\n\n  /**\n   * Bind the layer groups of the stage.\n   */\n  bindLayerGroups() {\n    if (this.#layerGroups.length === 0 ||\n      this.#layerGroups.length === 1 ||\n      this.#binders.length === 0) {\n      return;\n    }\n    // create callback store\n    this.#callbackStore = new Array(this.#layerGroups.length);\n    // add listeners\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      for (let j = 0; j < this.#binders.length; ++j) {\n        this.#addEventListeners(i, this.#binders[j]);\n      }\n    }\n  }\n\n  /**\n   * Unbind the layer groups of the stage.\n   */\n  unbindLayerGroups() {\n    if (this.#layerGroups.length === 0 ||\n      this.#layerGroups.length === 1 ||\n      this.#binders.length === 0 ||\n      !this.#callbackStore) {\n      return;\n    }\n    // remove listeners\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      for (let j = 0; j < this.#binders.length; ++j) {\n        this.#removeEventListeners(i, this.#binders[j]);\n      }\n    }\n    // clear callback store\n    this.#callbackStore = null;\n  }\n\n  /**\n   * Get the binder callback function for a given layer group index.\n   * The function is created if not yet stored.\n   *\n   * @param {object} binder The layer binder.\n   * @param {number} index The index of the associated layer group.\n   * @returns {Function} The binder function.\n   */\n  #getBinderCallback(binder, index) {\n    if (typeof this.#callbackStore[index] === 'undefined') {\n      this.#callbackStore[index] = [];\n    }\n    const store = this.#callbackStore[index];\n    let binderObj = store.find(function (elem) {\n      return elem.binder === binder;\n    });\n    if (typeof binderObj === 'undefined') {\n      // create new callback object\n      binderObj = {\n        binder: binder,\n        callback: (event) => {\n          // stop listeners\n          this.#removeEventListeners(index, binder);\n          // apply binder\n          binder.getCallback(this.#layerGroups[index])(event);\n          // re-start listeners\n          this.#addEventListeners(index, binder);\n        }\n      };\n      this.#callbackStore[index].push(binderObj);\n    }\n    return binderObj.callback;\n  }\n\n  /**\n   * Add event listeners for a given layer group index and binder.\n   *\n   * @param {number} index The index of the associated layer group.\n   * @param {object} binder The layer binder.\n   */\n  #addEventListeners(index, binder) {\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      if (i !== index) {\n        this.#layerGroups[index].addEventListener(\n          binder.getEventType(),\n          this.#getBinderCallback(binder, i)\n        );\n      }\n    }\n  }\n\n  /**\n   * Remove event listeners for a given layer group index and binder.\n   *\n   * @param {number} index The index of the associated layer group.\n   * @param {object} binder The layer binder.\n   */\n  #removeEventListeners(index, binder) {\n    for (let i = 0; i < this.#layerGroups.length; ++i) {\n      if (i !== index) {\n        this.#layerGroups[index].removeEventListener(\n          binder.getEventType(),\n          this.#getBinderCallback(binder, i)\n        );\n      }\n    }\n  }\n\n} // class Stage\n","import {Index} from '../math/index';\nimport {colourNameToHex} from '../utils/colour';\n\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * State class.\n * Saves: data url/path, display info.\n *\n * History:\n * - v0.5 (dwv 0.30.0, 12/2021)\n *   - store position as array\n *   - new draw position group key\n * - v0.4 (dwv 0.29.0, 06/2021)\n *   - move drawing details into meta property\n *   - remove scale center and translation, add offset\n * - v0.3 (dwv v0.23.0, 03/2018)\n *   - new drawing structure, drawings are now the full layer object and\n *     using toObject to avoid saving a string representation\n *   - new details structure: simple array of objects referenced by draw ids\n * - v0.2 (dwv v0.17.0, 12/2016)\n *   - adds draw details: array [nslices][nframes] of detail objects\n * - v0.1 (dwv v0.15.0, 07/2016)\n *   - adds version\n *   - drawings: array [nslices][nframes] with all groups\n * - initial release (dwv v0.10.0, 05/2015), no version number...\n *   - content: window-center, window-width, position, scale,\n *       scaleCenter, translation, drawings\n *   - drawings: array [nslices] with all groups\n */\nexport class State {\n  /**\n   * Save the application state as JSON.\n   *\n   * @param {App} app The associated application.\n   * @returns {string} The state as a JSON string.\n   */\n  toJSON(app) {\n    const layerGroup = app.getActiveLayerGroup();\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n    const position = viewController.getCurrentIndex();\n    const drawLayer = layerGroup.getActiveDrawLayer();\n    const drawController = drawLayer.getDrawController();\n    // return a JSON string\n    return JSON.stringify({\n      version: '0.5',\n      'window-center': viewController.getWindowLevel().center,\n      'window-width': viewController.getWindowLevel().width,\n      position: position.getValues(),\n      scale: app.getAddedScale(),\n      offset: app.getOffset(),\n      drawings: drawLayer.getKonvaLayer().toObject(),\n      drawingsDetails: drawController.getDrawStoreDetails()\n    });\n  }\n\n  /**\n   * Load an application state from JSON.\n   *\n   * @param {string} json The state as a JSON string.\n   * @returns {object} The state object.\n   */\n  fromJSON(json) {\n    const data = JSON.parse(json);\n    let res = null;\n    if (data.version === '0.1') {\n      res = this.#readV01(data);\n    } else if (data.version === '0.2') {\n      res = this.#readV02(data);\n    } else if (data.version === '0.3') {\n      res = this.#readV03(data);\n    } else if (data.version === '0.4') {\n      res = this.#readV04(data);\n    } else if (data.version === '0.5') {\n      res = this.#readV05(data);\n    } else {\n      throw new Error('Unknown state file format version: \\'' +\n        data.version + '\\'.');\n    }\n    return res;\n  }\n\n  /**\n   * Load an application state from JSON.\n   *\n   * @param {App} app The app to apply the state to.\n   * @param {object} data The state data.\n   */\n  apply(app, data) {\n    const layerGroup = app.getActiveLayerGroup();\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n    // display\n    viewController.setWindowLevel(\n      data['window-center'], data['window-width']);\n    // position is index...\n    viewController.setCurrentIndex(new Index(data.position));\n    // apply saved scale on top of current base one\n    const baseScale = app.getActiveLayerGroup().getBaseScale();\n    let scale = null;\n    let offset = null;\n    if (typeof data.scaleCenter !== 'undefined') {\n      scale = {\n        x: data.scale * baseScale.x,\n        y: data.scale * baseScale.y,\n        z: 1\n      };\n      // ---- transform translation (now) ----\n      // Tx = -offset.x * scale.x\n      // => offset.x = -Tx / scale.x\n      // ---- transform translation (before) ----\n      // origin.x = centerX - (centerX - origin.x) * (newZoomX / zoom.x);\n      // (zoom.x -> initial zoom = base scale, origin.x = 0)\n      // Tx = origin.x + (trans.x * zoom.x)\n      const originX = data.scaleCenter.x - data.scaleCenter.x * data.scale;\n      const originY = data.scaleCenter.y - data.scaleCenter.y * data.scale;\n      const oldTx = originX + data.translation.x * scale.x;\n      const oldTy = originY + data.translation.y * scale.y;\n      offset = {\n        x: -oldTx / scale.x,\n        y: -oldTy / scale.y,\n        z: 0\n      };\n    } else {\n      scale = {\n        x: data.scale.x * baseScale.x,\n        y: data.scale.y * baseScale.y,\n        z: baseScale.z\n      };\n      offset = {\n        x: data.offset.x,\n        y: data.offset.y,\n        z: 0\n      };\n    }\n    app.getActiveLayerGroup().setScale(scale);\n    app.getActiveLayerGroup().setOffset(offset);\n    // render to draw the view layer\n    app.render(0); //todo: fix\n    // drawings (will draw the draw layer)\n    app.setDrawings(data.drawings, data.drawingsDetails);\n  }\n\n  /**\n   * Read an application state from an Object in v0.1 format.\n   *\n   * @param {object} data The Object representation of the state.\n   * @returns {object} The state object.\n   */\n  #readV01(data) {\n    // v0.1 -> v0.2\n    const v02DAndD = v01Tov02DrawingsAndDetails(data.drawings);\n    // v0.2 -> v0.3, v0.4\n    data.drawings = v02Tov03Drawings(v02DAndD.drawings).toObject();\n    data.drawingsDetails = v03Tov04DrawingsDetails(\n      v02DAndD.drawingsDetails);\n    // v0.4 -> v0.5\n    data = v04Tov05Data(data);\n    data.drawings = v04Tov05Drawings(data.drawings);\n    return data;\n  }\n\n  /**\n   * Read an application state from an Object in v0.2 format.\n   *\n   * @param {object} data The Object representation of the state.\n   * @returns {object} The state object.\n   */\n  #readV02(data) {\n    // v0.2 -> v0.3, v0.4\n    data.drawings = v02Tov03Drawings(data.drawings).toObject();\n    data.drawingsDetails = v03Tov04DrawingsDetails(\n      v02Tov03DrawingsDetails(data.drawingsDetails));\n    // v0.4 -> v0.5\n    data = v04Tov05Data(data);\n    data.drawings = v04Tov05Drawings(data.drawings);\n    return data;\n  }\n\n  /**\n   * Read an application state from an Object in v0.3 format.\n   *\n   * @param {object} data The Object representation of the state.\n   * @returns {object} The state object.\n   */\n  #readV03(data) {\n    // v0.3 -> v0.4\n    data.drawingsDetails = v03Tov04DrawingsDetails(data.drawingsDetails);\n    // v0.4 -> v0.5\n    data = v04Tov05Data(data);\n    data.drawings = v04Tov05Drawings(data.drawings);\n    return data;\n  }\n\n  /**\n   * Read an application state from an Object in v0.4 format.\n   *\n   * @param {object} data The Object representation of the state.\n   * @returns {object} The state object.\n   */\n  #readV04(data) {\n    // v0.4 -> v0.5\n    data = v04Tov05Data(data);\n    data.drawings = v04Tov05Drawings(data.drawings);\n    return data;\n  }\n  /**\n   * Read an application state from an Object in v0.5 format.\n   *\n   * @param {object} data The Object representation of the state.\n   * @returns {object} The state object.\n   */\n  #readV05(data) {\n    return data;\n  }\n\n} // State class\n\n/**\n * Convert drawings from v0.2 to v0.3.\n * v0.2: one layer per slice/frame\n * v0.3: one layer, one group per slice. setDrawing expects the full stage\n *\n * @param {Array} drawings An array of drawings.\n * @returns {object} The layer with the converted drawings.\n */\nfunction v02Tov03Drawings(drawings) {\n  // Auxiliar variables\n  let group, groupShapes, parentGroup;\n  // Avoid errors when dropping multiple states\n  //drawLayer.getChildren().each(function(node){\n  //    node.visible(false);\n  //});\n\n  /**\n   * Get the draw group id for a given position.\n   *\n   * @param {Index} currentPosition The current position.\n   * @returns {string} The group id.\n   */\n  function getDrawPositionGroupId(currentPosition) {\n    const sliceNumber = currentPosition.get(2);\n    const frameNumber = currentPosition.length() === 4\n      ? currentPosition.get(3) : 0;\n    return 'slice-' + sliceNumber + '_frame-' + frameNumber;\n  }\n\n  const drawLayer = new Konva.Layer({\n    listening: false,\n    visible: true\n  });\n\n  // Get the positions-groups data\n  const groupDrawings = typeof drawings === 'string'\n    ? JSON.parse(drawings) : drawings;\n  // Iterate over each position-groups\n  for (let k = 0, lenk = groupDrawings.length; k < lenk; ++k) {\n    // Iterate over each frame\n    for (let f = 0, lenf = groupDrawings[k].length; f < lenf; ++f) {\n      groupShapes = groupDrawings[k][f];\n      if (groupShapes.length !== 0) {\n        // Create position-group set as visible and append it to drawLayer\n        parentGroup = new Konva.Group({\n          id: getDrawPositionGroupId(new Index([1, 1, k, f])),\n          name: 'position-group',\n          visible: false\n        });\n\n        // Iterate over shapes-group\n        for (let g = 0, leng = groupShapes.length; g < leng; ++g) {\n          // create the konva group\n          group = Konva.Node.create(groupShapes[g]);\n          // enforce draggable: only the shape was draggable in v0.2,\n          // now the whole group is.\n          group.draggable(true);\n          group.getChildren().forEach(function (gnode) {\n            gnode.draggable(false);\n          });\n          // add to position group\n          parentGroup.add(group);\n        }\n        // add to layer\n        drawLayer.add(parentGroup);\n      }\n    }\n  }\n\n  return drawLayer;\n}\n\n/**\n * Convert drawings from v0.1 to v0.2.\n * v0.1: text on its own\n * v0.2: text as part of label\n *\n * @param {Array} inputDrawings An array of drawings.\n * @returns {object} The converted drawings.\n */\nfunction v01Tov02DrawingsAndDetails(inputDrawings) {\n  const newDrawings = [];\n  const drawingsDetails = {};\n\n  let drawGroups;\n  let drawGroup;\n  // loop over each slice\n  for (let k = 0, lenk = inputDrawings.length; k < lenk; ++k) {\n    // loop over each frame\n    newDrawings[k] = [];\n    for (let f = 0, lenf = inputDrawings[k].length; f < lenf; ++f) {\n      // draw group\n      drawGroups = inputDrawings[k][f];\n      const newFrameDrawings = [];\n      // Iterate over shapes-group\n      for (let g = 0, leng = drawGroups.length; g < leng; ++g) {\n        // create konva group from input\n        drawGroup = Konva.Node.create(drawGroups[g]);\n        // force visible (not set in state)\n        drawGroup.visible(true);\n        // label position\n        let pos = {x: 0, y: 0};\n        // update shape colour\n        const kshape = drawGroup.getChildren(function (node) {\n          return node.name() === 'shape';\n        })[0];\n        kshape.stroke(colourNameToHex(kshape.stroke()));\n        // special line case\n        if (drawGroup.name() === 'line-group') {\n          // update name\n          drawGroup.name('ruler-group');\n          // add ticks\n          const ktick0 = new Konva.Line({\n            points: [kshape.points()[0],\n              kshape.points()[1],\n              kshape.points()[0],\n              kshape.points()[1]],\n            name: 'shape-tick0'\n          });\n          drawGroup.add(ktick0);\n          const ktick1 = new Konva.Line({\n            points: [kshape.points()[2],\n              kshape.points()[3],\n              kshape.points()[2],\n              kshape.points()[3]],\n            name: 'shape-tick1'\n          });\n          drawGroup.add(ktick1);\n        }\n        // special protractor case: update arc name\n        const karcs = drawGroup.getChildren(function (node) {\n          return node.name() === 'arc';\n        });\n        if (karcs.length === 1) {\n          karcs[0].name('shape-arc');\n        }\n        // get its text\n        const ktexts = drawGroup.getChildren(function (node) {\n          return node.name() === 'text';\n        });\n        // update text: move it into a label\n        let ktext = new Konva.Text({\n          name: 'text',\n          text: ''\n        });\n        if (ktexts.length === 1) {\n          pos.x = ktexts[0].x();\n          pos.y = ktexts[0].y();\n          // remove it from the group\n          ktexts[0].remove();\n          // use it\n          ktext = ktexts[0];\n        } else {\n          // use shape position if no text\n          if (kshape.points().length !== 0) {\n            pos = {x: kshape.points()[0],\n              y: kshape.points()[1]};\n          }\n        }\n        // create new label with text and tag\n        const klabel = new Konva.Label({\n          x: pos.x,\n          y: pos.y,\n          name: 'label'\n        });\n        klabel.add(ktext);\n        klabel.add(new Konva.Tag());\n        // add label to group\n        drawGroup.add(klabel);\n        // add group to list\n        newFrameDrawings.push(JSON.stringify(drawGroup.toObject()));\n\n        // create details (v0.3 format)\n        let textExpr = ktext.text();\n        const txtLen = textExpr.length;\n        let quant = null;\n        // adapt to text with flag\n        if (drawGroup.name() === 'ruler-group') {\n          quant = {\n            length: {\n              value: parseFloat(textExpr.substring(0, txtLen - 2)),\n              unit: textExpr.substring(-2)\n            }\n          };\n          textExpr = '{length}';\n        } else if (drawGroup.name() === 'ellipse-group' ||\n                    drawGroup.name() === 'rectangle-group') {\n          quant = {\n            surface: {\n              value: parseFloat(textExpr.substring(0, txtLen - 3)),\n              unit: textExpr.substring(-3)\n            }\n          };\n          textExpr = '{surface}';\n        } else if (drawGroup.name() === 'protractor-group' ||\n                    drawGroup.name() === 'rectangle-group') {\n          quant = {\n            angle: {\n              value: parseFloat(textExpr.substring(0, txtLen - 1)),\n              unit: textExpr.substring(-1)\n            }\n          };\n          textExpr = '{angle}';\n        }\n        // set details\n        drawingsDetails[drawGroup.id()] = {\n          textExpr: textExpr,\n          longText: '',\n          quant: quant\n        };\n\n      }\n      newDrawings[k].push(newFrameDrawings);\n    }\n  }\n\n  return {drawings: newDrawings, drawingsDetails: drawingsDetails};\n}\n\n/**\n * Convert drawing details from v0.2 to v0.3.\n * - v0.2: array [nslices][nframes] with all\n * - v0.3: simple array of objects referenced by draw ids\n *\n * @param {Array} details An array of drawing details.\n * @returns {object} The converted drawings.\n */\nfunction v02Tov03DrawingsDetails(details) {\n  const res = {};\n  // Get the positions-groups data\n  const groupDetails = typeof details === 'string'\n    ? JSON.parse(details) : details;\n  // Iterate over each position-groups\n  for (let k = 0, lenk = groupDetails.length; k < lenk; ++k) {\n    // Iterate over each frame\n    for (let f = 0, lenf = groupDetails[k].length; f < lenf; ++f) {\n      // Iterate over shapes-group\n      for (let g = 0, leng = groupDetails[k][f].length; g < leng; ++g) {\n        const group = groupDetails[k][f][g];\n        res[group.id] = {\n          textExpr: group.textExpr,\n          longText: group.longText,\n          quant: group.quant\n        };\n      }\n    }\n  }\n  return res;\n}\n\n/**\n * Convert drawing details from v0.3 to v0.4.\n * - v0.3: properties at group root\n * - v0.4: properties in group meta object\n *\n * @param {Array} details An array of drawing details.\n * @returns {object} The converted drawings.\n */\nfunction v03Tov04DrawingsDetails(details) {\n  const res = {};\n  const keys = Object.keys(details);\n  // Iterate over each position-groups\n  for (let k = 0, lenk = keys.length; k < lenk; ++k) {\n    const detail = details[keys[k]];\n    res[keys[k]] = {\n      meta: {\n        textExpr: detail.textExpr,\n        longText: detail.longText,\n        quantification: detail.quant\n      }\n    };\n  }\n  return res;\n}\n\n/**\n * Convert drawing from v0.4 to v0.5.\n * - v0.4: position as object\n * - v0.5: position as array\n *\n * @param {object} data An array of drawing.\n * @returns {object} The converted drawings.\n */\nfunction v04Tov05Data(data) {\n  const pos = data.position;\n  data.position = [pos.i, pos.j, pos.k];\n  return data;\n}\n\n/**\n * Convert drawing from v0.4 to v0.5.\n * - v0.4: draw id as 'slice-0_frame-1'\n * - v0.5: draw id as '#2-0_#3-1''\n *\n * @param {object} inputDrawings An array of drawing.\n * @returns {object} The converted drawings.\n */\nfunction v04Tov05Drawings(inputDrawings) {\n  // Iterate over each position-groups\n  const posGroups = inputDrawings.children;\n  for (let k = 0, lenk = posGroups.length; k < lenk; ++k) {\n    const posGroup = posGroups[k];\n    const id = posGroup.attrs.id;\n    const ids = id.split('_');\n    const sliceNumber = parseInt(ids[0].substring(6), 10); // 'slice-0'\n    const frameNumber = parseInt(ids[1].substring(6), 10); // 'frame-0'\n    let newId = '#2-';\n    if (sliceNumber === 0 && frameNumber !== 0) {\n      newId += frameNumber;\n    } else {\n      newId += sliceNumber;\n    }\n    posGroup.attrs.id = newId;\n  }\n  return inputDrawings;\n}\n","import {logger} from './logger';\nimport {splitKeyValueString} from './string';\n\n/**\n * Get an full object URL from a string uri.\n *\n * @param {string} uri A string representing the url.\n * @returns {URL} A URL object.\n */\nexport function getUrlFromUri(uri) {\n  // add base to allow for relative urls\n  // (base is not used for absolute urls)\n  return new URL(uri, window.location.origin);\n}\n\n/**\n * Split an input URI:\n * 'root?key0=val00&key0=val01&key1=val10' returns\n * { base : root, query : [ key0 : [val00, val01], key1 : val1 ] }\n * Returns an empty object if the input string is not correct (null, empty...)\n * or if it is not a query string (no question mark).\n *\n * @param {string} uri The string to split.\n * @returns {object} The split string.\n */\nexport function splitUri(uri) {\n  // result\n  const result = {};\n  // check if query string\n  let sepIndex = null;\n  if (uri && (sepIndex = uri.indexOf('?')) !== -1) {\n    // base: before the '?'\n    result.base = uri.substring(0, sepIndex);\n    // query : after the '?' and until possible '#'\n    let hashIndex = uri.indexOf('#');\n    if (hashIndex === -1) {\n      hashIndex = uri.length;\n    }\n    const query = uri.substring(sepIndex + 1, hashIndex);\n    // split key/value pairs of the query\n    result.query = splitKeyValueString(query);\n  }\n  // return\n  return result;\n}\n\n/**\n * Get the query part, split into an array, of an input URI.\n * The URI scheme is: 'base?query#fragment'\n *\n * @param {string} uri The input URI.\n * @returns {object} The query part, split into an array, of the input URI.\n */\nexport function getUriQuery(uri) {\n  // split\n  const parts = splitUri(uri);\n  // check not empty\n  if (Object.keys(parts).length === 0) {\n    return null;\n  }\n  // return query\n  return parts.query;\n}\n\n/**\n * Generic URI query decoder.\n * Supports manifest:\n *   [dwv root]?input=encodeURIComponent('[manifest file]')&type=manifest\n * or encoded URI with base and key value/pairs:\n *   [dwv root]?input=encodeURIComponent([root]?key0=value0&key1=value1)\n *\n * @param {object} query The query part to the input URI.\n * @param {Function} callback The function to call with the decoded file urls.\n * @param {object} options Optional url request options.\n */\nexport function decodeQuery(query, callback, options) {\n  // manifest\n  if (query.type && query.type === 'manifest') {\n    decodeManifestQuery(query, callback);\n  } else {\n    // default case: encoded URI with base and key/value pairs\n    callback(\n      decodeKeyValueUri(query.input, query.dwvReplaceMode),\n      options);\n  }\n}\n\n/**\n * Decode a Key/Value pair URI. If a key is repeated, the result\n * be an array of base + each key.\n *\n * @param {string} uri The URI to decode.\n * @param {string} replaceMode The key replace mode.\n *   replaceMode can be:\n *   - key (default): keep the key\n *   - other than key: do not use the key\n *   'file' is a special case where the '?' of the query is not kept.\n * @returns {Array} The list of input file urls.\n */\nexport function decodeKeyValueUri(uri, replaceMode) {\n  const result = [];\n\n  // repeat key replace mode (default to keep key)\n  let repeatKeyReplaceMode = 'key';\n  if (replaceMode) {\n    repeatKeyReplaceMode = replaceMode;\n  }\n\n  // decode input URI\n  const queryUri = decodeURIComponent(uri);\n  // get key/value pairs from input URI\n  const inputQueryPairs = splitUri(queryUri);\n  if (Object.keys(inputQueryPairs).length === 0) {\n    result.push(queryUri);\n  } else {\n    const keys = Object.keys(inputQueryPairs.query);\n    // find repeat key\n    let repeatKey = null;\n    for (let i = 0; i < keys.length; ++i) {\n      if (inputQueryPairs.query[keys[i]] instanceof Array) {\n        repeatKey = keys[i];\n        break;\n      }\n    }\n\n    if (!repeatKey) {\n      result.push(queryUri);\n    } else {\n      const repeatList = inputQueryPairs.query[repeatKey];\n      // build base uri\n      let baseUrl = inputQueryPairs.base;\n      // add '?' when:\n      // - base is not empty\n      // - the repeatKey is not 'file'\n      // root/path/to/?file=0.jpg&file=1.jpg\n      if (baseUrl !== '' && repeatKey !== 'file') {\n        baseUrl += '?';\n      }\n      let gotOneArg = false;\n      for (let j = 0; j < keys.length; ++j) {\n        if (keys[j] !== repeatKey) {\n          if (gotOneArg) {\n            baseUrl += '&';\n          }\n          baseUrl += keys[j] + '=' + inputQueryPairs.query[keys[j]];\n          gotOneArg = true;\n        }\n      }\n      // append built urls to result\n      let url;\n      for (let k = 0; k < repeatList.length; ++k) {\n        url = baseUrl;\n        if (gotOneArg) {\n          url += '&';\n        }\n        if (repeatKeyReplaceMode === 'key') {\n          url += repeatKey + '=';\n        }\n        // other than 'key' mode: do nothing\n        url += repeatList[k];\n        result.push(url);\n      }\n    }\n  }\n  // return\n  return result;\n}\n\n/**\n * Decode a manifest query.\n *\n * @external XMLHttpRequest\n * @param {object} query The manifest query: {input, nslices},\n * with input the input URI and nslices the number of slices.\n * @param {Function} callback The function to call with the decoded urls.\n */\nfunction decodeManifestQuery(query, callback) {\n  let uri = '';\n  if (query.input[0] === '/') {\n    uri = window.location.protocol + '//' + window.location.host;\n  }\n  // TODO: needs to be decoded (decodeURIComponent?\n  uri += query.input;\n\n  /**\n   * Handle error.\n   *\n   * @param {object} event The error event.\n   */\n  function onError(event) {\n    logger.warn('RequestError while receiving manifest: ' +\n      event.target.status);\n  }\n\n  /**\n   * Handle load.\n   *\n   * @param {object} event The load event.\n   */\n  function onLoad(event) {\n    callback(decodeManifest(event.target.responseXML, query.nslices));\n  }\n\n  const request = new XMLHttpRequest();\n  request.open('GET', decodeURIComponent(uri), true);\n  request.responseType = 'document';\n  request.onload = onLoad;\n  request.onerror = onError;\n  request.send(null);\n}\n\n/**\n * Decode an XML manifest.\n *\n * @param {object} manifest The manifest to decode.\n * @param {number} nslices The number of slices to load.\n * @returns {Array} The decoded manifest.\n */\nexport function decodeManifest(manifest, nslices) {\n  const result = [];\n  // wado url\n  const wadoElement = manifest.getElementsByTagName('wado_query');\n  const wadoURL = wadoElement[0].getAttribute('wadoURL');\n  const rootURL = wadoURL + '?requestType=WADO&contentType=application/dicom&';\n  // patient list\n  const patientList = manifest.getElementsByTagName('Patient');\n  if (patientList.length > 1) {\n    logger.warn('More than one patient, loading first one.');\n  }\n  // study list\n  const studyList = patientList[0].getElementsByTagName('Study');\n  if (studyList.length > 1) {\n    logger.warn('More than one study, loading first one.');\n  }\n  const studyUID = studyList[0].getAttribute('StudyInstanceUID');\n  // series list\n  const seriesList = studyList[0].getElementsByTagName('Series');\n  if (seriesList.length > 1) {\n    logger.warn('More than one series, loading first one.');\n  }\n  const seriesUID = seriesList[0].getAttribute('SeriesInstanceUID');\n  // instance list\n  const instanceList = seriesList[0].getElementsByTagName('Instance');\n  // loop on instances and push links\n  let max = instanceList.length;\n  if (nslices < max) {\n    max = nslices;\n  }\n  for (let i = 0; i < max; ++i) {\n    const sopInstanceUID = instanceList[i].getAttribute('SOPInstanceUID');\n    const link = rootURL +\n        '&studyUID=' + studyUID +\n        '&seriesUID=' + seriesUID +\n        '&objectUID=' + sopInstanceUID;\n    result.push(link);\n  }\n  // return\n  return result;\n}\n","import {ListenerHandler} from '../utils/listen';\n\n/**\n * UndoStack class.\n */\nexport class UndoStack {\n  /**\n   * Array of commands.\n   *\n   * @type {Array}\n   */\n  #stack = [];\n\n  /**\n   * Current command index.\n   *\n   * @type {number}\n   */\n  #curCmdIndex = 0;\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Get the stack size.\n   *\n   * @returns {number} The size of the stack.\n   */\n  getStackSize() {\n    return this.#stack.length;\n  }\n\n  /**\n   * Get the current stack index.\n   *\n   * @returns {number} The stack index.\n   */\n  getCurrentStackIndex() {\n    return this.#curCmdIndex;\n  }\n\n  /**\n   * Add a command to the stack.\n   *\n   * @param {object} cmd The command to add.\n   * @fires UndoStack#undoadd\n   */\n  add(cmd) {\n    // clear commands after current index\n    this.#stack = this.#stack.slice(0, this.#curCmdIndex);\n    // store command\n    this.#stack.push(cmd);\n    // increment index\n    ++this.#curCmdIndex;\n    /**\n     * Command add to undo stack event.\n     *\n     * @event UndoStack#undoadd\n     * @type {object}\n     * @property {string} command The name of the command added to the\n     *   undo stack.\n     */\n    this.#fireEvent({\n      type: 'undoadd',\n      command: cmd.getName()\n    });\n  }\n\n  /**\n   * Undo the last command.\n   *\n   * @fires UndoStack#undo\n   */\n  undo() {\n    // a bit inefficient...\n    if (this.#curCmdIndex > 0) {\n      // decrement command index\n      --this.#curCmdIndex;\n      // undo last command\n      this.#stack[this.#curCmdIndex].undo();\n      /**\n       * Command undo event.\n       *\n       * @event UndoStack#undo\n       * @type {object}\n       * @property {string} command The name of the undone command.\n       */\n      this.#fireEvent({\n        type: 'undo',\n        command: this.#stack[this.#curCmdIndex].getName()\n      });\n    }\n  }\n\n  /**\n   * Redo the last command.\n   *\n   * @fires UndoStack#redo\n   */\n  redo() {\n    if (this.#curCmdIndex < this.#stack.length) {\n      // run last command\n      this.#stack[this.#curCmdIndex].execute();\n      /**\n       * Command redo event.\n       *\n       * @event UndoStack#redo\n       * @type {object}\n       * @property {string} command The name of the redone command.\n       */\n      this.#fireEvent({\n        type: 'redo',\n        command: this.#stack[this.#curCmdIndex].getName()\n      });\n      // increment command index\n      ++this.#curCmdIndex;\n    }\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *    event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n} // UndoStack class\n","import {InteractionEventNames, getEventOffset} from '../gui/generic';\n\n/**\n * Toolbox controller.\n */\nexport class ToolboxController {\n\n  /**\n   * List of tools to control.\n   *\n   * @type {object}\n   */\n  #toolList;\n\n  /**\n   * Selected tool.\n   *\n   * @type {object}\n   */\n  #selectedTool = null;\n\n  /**\n   * Callback store to allow attach/detach.\n   *\n   * @type {Array}\n   */\n  #callbackStore = [];\n\n  /**\n   * Current layers bound to tool.\n   *\n   * @type {object}\n   */\n  #boundLayers = {};\n\n  /**\n   * @param {object} toolList The list of tool objects.\n   */\n  constructor(toolList) {\n    this.#toolList = toolList;\n  }\n\n  /**\n   * Initialise.\n   */\n  init() {\n    for (const key in this.#toolList) {\n      this.#toolList[key].init();\n    }\n    // keydown listener\n    window.addEventListener('keydown',\n      this.#getOnMouch('window', 'keydown'), true);\n  }\n\n  /**\n   * Get the tool list.\n   *\n   * @returns {Array} The list of tool objects.\n   */\n  getToolList() {\n    return this.#toolList;\n  }\n\n  /**\n   * Check if a tool is in the tool list.\n   *\n   * @param {string} name The name to check.\n   * @returns {boolean} The tool list element for the given name.\n   */\n  hasTool(name) {\n    return typeof this.getToolList()[name] !== 'undefined';\n  }\n\n  /**\n   * Get the selected tool.\n   *\n   * @returns {object} The selected tool.\n   */\n  getSelectedTool() {\n    return this.#selectedTool;\n  }\n\n  /**\n   * Get the selected tool event handler.\n   *\n   * @param {string} eventType The event type, for example\n   *   mousedown, touchstart...\n   * @returns {Function} The event handler.\n   */\n  getSelectedToolEventHandler(eventType) {\n    return this.getSelectedTool()[eventType];\n  }\n\n  /**\n   * Set the selected tool.\n   *\n   * @param {string} name The name of the tool.\n   */\n  setSelectedTool(name) {\n    // check if we have it\n    if (!this.hasTool(name)) {\n      throw new Error('Unknown tool: \\'' + name + '\\'');\n    }\n    // de-activate previous\n    if (this.#selectedTool) {\n      this.#selectedTool.activate(false);\n    }\n    // set internal var\n    this.#selectedTool = this.#toolList[name];\n    // activate new tool\n    this.#selectedTool.activate(true);\n  }\n\n  /**\n   * Set the selected tool live features.\n   *\n   * @param {object} list The list of features.\n   */\n  setToolFeatures(list) {\n    if (this.getSelectedTool()) {\n      this.getSelectedTool().setFeatures(list);\n    }\n  }\n\n  /**\n   * Listen to layer interaction events.\n   *\n   * @param {object} layer The layer to listen to.\n   * @param {string} layerGroupDivId The associated layer group div id.\n   */\n  bindLayer(layer, layerGroupDivId) {\n    if (typeof this.#boundLayers[layerGroupDivId] !== 'undefined') {\n      this.#unbindLayer(this.#boundLayers[layerGroupDivId]);\n    }\n    layer.bindInteraction();\n    // interaction events\n    const names = InteractionEventNames;\n    for (let i = 0; i < names.length; ++i) {\n      layer.addEventListener(names[i],\n        this.#getOnMouch(layer.getId(), names[i]));\n    }\n    // update class var\n    this.#boundLayers[layerGroupDivId] = layer;\n  }\n\n  /**\n   * Remove canvas mouse and touch listeners.\n   *\n   * @param {object} layer The layer to stop listening to.\n   */\n  #unbindLayer(layer) {\n    layer.unbindInteraction();\n    // interaction events\n    const names = InteractionEventNames;\n    for (let i = 0; i < names.length; ++i) {\n      layer.removeEventListener(names[i],\n        this.#getOnMouch(layer.getId(), names[i]));\n    }\n  }\n\n  /**\n   * Mou(se) and (T)ouch event handler. This function just determines\n   * the mouse/touch position relative to the canvas element.\n   * It then passes it to the current tool.\n   *\n   * @param {string} layerId The layer id.\n   * @param {string} eventType The event type.\n   * @returns {object} A callback for the provided layer and event.\n   */\n  #getOnMouch(layerId, eventType) {\n    // augment event with converted offsets\n    const augmentEventOffsets = function (event) {\n      // event offset(s)\n      const offsets = getEventOffset(event);\n      // should have at least one offset\n      event._x = offsets[0].x;\n      event._y = offsets[0].y;\n      // possible second\n      if (offsets.length === 2) {\n        event._x1 = offsets[1].x;\n        event._y1 = offsets[1].y;\n      }\n    };\n\n    const applySelectedTool = (event) => {\n      // make sure we have a tool\n      if (this.#selectedTool) {\n        const func = this.#selectedTool[event.type];\n        if (func) {\n          func(event);\n        }\n      }\n    };\n\n    if (typeof this.#callbackStore[layerId] === 'undefined') {\n      this.#callbackStore[layerId] = [];\n    }\n\n    if (typeof this.#callbackStore[layerId][eventType] === 'undefined') {\n      let callback = null;\n      if (eventType === 'keydown') {\n        callback = function (event) {\n          applySelectedTool(event);\n        };\n      } else if (eventType === 'touchend') {\n        callback = function (event) {\n          applySelectedTool(event);\n        };\n      } else {\n        // mouse or touch events\n        callback = function (event) {\n          augmentEventOffsets(event);\n          applySelectedTool(event);\n        };\n      }\n      // store callback\n      this.#callbackStore[layerId][eventType] = callback;\n    }\n\n    return this.#callbackStore[layerId][eventType];\n  }\n\n} // class ToolboxController\n","/**\n * Multiple progresses handler.\n * Stores a multi dimensional list of progresses to allow to\n * calculate a global progress.\n *\n */\nexport class MultiProgressHandler {\n\n  /**\n   * List of progresses.\n   * First dimension is a list of item for which the progress is recorded,\n   *   for example file names.\n   * Second dimension is a list of possible progresses, for example\n   *   the progress of the download and the progress of the decoding.\n   *\n   * @type {Array}\n   */\n  #progresses = [];\n\n  /**\n   * Number of dimensions.\n   *\n   * @type {number}\n   */\n  #numberOfDimensions = 2;\n\n  /**\n   * Progress callback.\n   *\n   * @type {Function}\n   */\n  #callback;\n\n  /**\n   * @param {Function} callback The function to pass the global progress to.\n   */\n  constructor(callback) {\n    this.#callback = callback;\n  }\n\n  /**\n   * Set the number of dimensions.\n   *\n   * @param {number} num The number.\n   */\n  setNumberOfDimensions(num) {\n    this.#numberOfDimensions = num;\n  }\n\n  /**\n   * Set the number of data to load.\n   *\n   * @param {number} n The number of data to load.\n   */\n  setNToLoad(n) {\n    for (let i = 0; i < n; ++i) {\n      this.#progresses[i] = [];\n      for (let j = 0; j < this.#numberOfDimensions; ++j) {\n        this.#progresses[i][j] = 0;\n      }\n    }\n  }\n\n  /**\n   * Handle a load progress.\n   * Call the member callback with a global event.\n   *\n   * @param {object} event The progress event.\n   */\n  onprogress = (event) => {\n    // check event\n    if (!event.lengthComputable) {\n      return;\n    }\n    if (typeof event.subindex === 'undefined') {\n      return;\n    }\n    if (typeof event.index === 'undefined') {\n      return;\n    }\n    // calculate percent\n    const percent = (event.loaded * 100) / event.total;\n    // set percent for index\n    this.#progresses[event.index][event.subindex] = percent;\n\n    // item progress\n    let item = null;\n    if (typeof event.item !== 'undefined') {\n      item = event.item;\n    } else {\n      item = {\n        loaded: this.#getItemProgress(event.index),\n        total: 100,\n        source: event.source\n      };\n    }\n\n    // call callback with a global event\n    this.#callback({\n      lengthComputable: true,\n      loaded: this.#getGlobalPercent(),\n      total: 100,\n      item: item\n    });\n  };\n\n  /**\n   * Get the item load percent.\n   *\n   * @param {number} index The index of the item.\n   * @returns {number} The load percentage.\n   */\n  #getItemProgress(index) {\n    let sum = 0;\n    for (let j = 0; j < this.#numberOfDimensions; ++j) {\n      sum += this.#progresses[index][j];\n    }\n    return sum / this.#numberOfDimensions;\n  }\n\n  /**\n   * Get the global load percent including the provided one.\n   *\n   * @returns {number} The accumulated percentage.\n   */\n  #getGlobalPercent() {\n    let sum = 0;\n    const lenprog = this.#progresses.length;\n    for (let i = 0; i < lenprog; ++i) {\n      sum += this.#getItemProgress(i);\n    }\n    return Math.round(sum / lenprog);\n  }\n\n\n  /**\n   * @callback eventFn\n   * @param {object} event The event.\n   */\n\n  /**\n   * Create a mono progress event handler.\n   *\n   * @param {number} index The index of the data.\n   * @param {number} subindex The sub-index of the data.\n   * @returns {eventFn} A progress handler function.\n   */\n  getMonoProgressHandler(index, subindex) {\n    return (event) => {\n      event.index = index;\n      event.subindex = subindex;\n      this.onprogress(event);\n    };\n  }\n\n  /**\n   * Create a mono progress event handler with an undefined index.\n   * Warning: The caller handles the progress index.\n   *\n   * @param {number} subindex The sub-index of the data.\n   * @returns {eventFn} A progress handler function.\n   */\n  getUndefinedMonoProgressHandler(subindex) {\n    return (event) => {\n      event.subindex = subindex;\n      this.onprogress(event);\n    };\n  }\n}\n","import {endsWith, getRootPath} from '../utils/string';\nimport {MultiProgressHandler} from '../utils/progress';\nimport {getFileListFromDicomDir} from '../dicom/dicomElementsWrapper';\nimport {loaderList} from './loaderList';\n\n// url content types\nexport const urlContentTypes = {\n  Text: 0,\n  ArrayBuffer: 1\n};\n\n/**\n * Urls loader.\n */\nexport class UrlsLoader {\n\n  /**\n   * Input data.\n   *\n   * @type {Array}\n   */\n  #inputData = null;\n\n  /**\n   * Array of launched requests.\n   *\n   * @type {Array}\n   */\n  #requests = [];\n\n  /**\n   * Data loader.\n   *\n   * @type {object}\n   */\n  #runningLoader = null;\n\n  /**\n   * Number of loaded data.\n   *\n   * @type {number}\n   */\n  #nLoad = 0;\n\n  /**\n   * Number of load end events.\n   *\n   * @type {number}\n   */\n  #nLoadend = 0;\n\n  /**\n   * Flag to know if the load is aborting.\n   *\n   * @type {boolean}\n   */\n  #aborting;\n\n  /**\n   * The default character set (optional).\n   *\n   * @type {string}\n   */\n  #defaultCharacterSet;\n\n  /**\n   * Get the default character set.\n   *\n   * @returns {string} The default character set.\n   */\n  getDefaultCharacterSet() {\n    return this.#defaultCharacterSet;\n  }\n\n  /**\n   * Set the default character set.\n   *\n   * @param {string} characterSet The character set.\n   */\n  setDefaultCharacterSet(characterSet) {\n    this.#defaultCharacterSet = characterSet;\n  }\n\n  /**\n   * Store the current input.\n   *\n   * @param {object} data The input data.\n   */\n  #storeInputData(data) {\n    this.#inputData = data;\n    // reset counters\n    this.#nLoad = 0;\n    this.#nLoadend = 0;\n    // reset flag\n    this.#aborting = false;\n    // clear storage\n    this.#clearStoredRequests();\n    this.#clearStoredLoader();\n  }\n\n  /**\n   * Store a launched request.\n   *\n   * @param {object} request The launched request.\n   */\n  #storeRequest(request) {\n    this.#requests.push(request);\n  }\n\n  /**\n   * Clear the stored requests.\n   *\n   */\n  #clearStoredRequests() {\n    this.#requests = [];\n  }\n\n  /**\n   * Store the launched loader.\n   *\n   * @param {object} loader The launched loader.\n   */\n  #storeLoader(loader) {\n    this.#runningLoader = loader;\n  }\n\n  /**\n   * Clear the stored loader.\n   *\n   */\n  #clearStoredLoader() {\n    this.#runningLoader = null;\n  }\n\n  /**\n   * Increment the number of loaded data\n   *   and call onload if loaded all data.\n   *\n   * @param {object} _event The load data event.\n   */\n  #addLoad = (_event) => {\n    this.#nLoad++;\n    // call onload when all is loaded\n    // (not using the input event since it is not the\n    //   general load)\n    if (this.#nLoad === this.#inputData.length) {\n      this.onload({\n        source: this.#inputData\n      });\n    }\n  };\n\n  /**\n   * Increment the counter of load end events\n   *   and run callbacks when all done, erroneus or not.\n   *\n   * @param {object} _event The load end event.\n   */\n  #addLoadend = (_event) => {\n    this.#nLoadend++;\n    // call onloadend when all is run\n    // (not using the input event since it is not the\n    //   general load end)\n    // x2 to count for request + load\n    if (this.#nLoadend === 2 * this.#inputData.length) {\n      this.onloadend({\n        source: this.#inputData\n      });\n    }\n  };\n\n  /**\n   * @callback eventFn\n   * @param {object} event The event.\n   */\n\n  /**\n   * Augment a callback event with a srouce.\n   *\n   * @param {object} callback The callback to augment its event.\n   * @param {object} source The source to add to the event.\n   * @returns {eventFn} The augmented callback.\n   */\n  #augmentCallbackEvent(callback, source) {\n    return (event) => {\n      event.source = source;\n      callback(event);\n    };\n  }\n\n  /**\n   * Load a list of URLs or a DICOMDIR.\n   *\n   * @param {Array} data The list of urls to load.\n   * @param {object} [options] Load options.\n   */\n  load(data, options) {\n    // send start event\n    this.onloadstart({\n      source: data\n    });\n\n    // check if DICOMDIR case\n    if (data.length === 1 &&\n      (endsWith(data[0], 'DICOMDIR') ||\n      endsWith(data[0], '.dcmdir'))) {\n      this.#loadDicomDir(data[0], options);\n    } else {\n      this.#loadUrls(data, options);\n    }\n  }\n\n  /**\n   * Get a load handler for a data element.\n   *\n   * @param {object} loader The associated loader.\n   * @param {object} dataElement The data element.\n   * @param {number} i The index of the element.\n   * @returns {eventFn} A load handler.\n   */\n  #getLoadHandler(loader, dataElement, i) {\n    return (event) => {\n      // check response status\n      // https://developer.mozilla.org/en-US/docs/Web/HTTP/Response_codes\n      // status 200: \"OK\"; status 0: \"debug\"\n      const status = event.target.status;\n      if (status !== 200 && status !== 0) {\n        this.onerror({\n          source: dataElement,\n          error: 'GET ' + event.target.responseURL +\n            ' ' + event.target.status +\n            ' (' + event.target.statusText + ')',\n          target: event.target\n        });\n        this.#addLoadend();\n      } else {\n        loader.load(event.target.response, dataElement, i);\n      }\n    };\n  }\n\n  /**\n   * Load a list of urls.\n   *\n   * @param {Array} data The list of urls to load.\n   * @param {object} [options] The options object, can contain:\n   *  - requestHeaders: an array of {name, value} to use as request headers\n   *  - withCredentials: boolean xhr.withCredentials flag to pass\n   *    to the request\n   *  - batchSize: the size of the request url batch\n   */\n  #loadUrls(data, options) {\n    // check input\n    if (typeof data === 'undefined' || data.length === 0) {\n      return;\n    }\n    this.#storeInputData(data);\n\n    // create prgress handler\n    const mproghandler = new MultiProgressHandler(this.onprogress);\n    mproghandler.setNToLoad(data.length);\n\n    // create loaders\n    const loaders = [];\n    for (let m = 0; m < loaderList.length; ++m) {\n      loaders.push(new loaderList[m]());\n    }\n\n    // find an appropriate loader\n    let dataElement = data[0];\n    let loader = null;\n    let foundLoader = false;\n    for (let l = 0; l < loaders.length; ++l) {\n      loader = loaders[l];\n      if (loader.canLoadUrl(dataElement, options)) {\n        foundLoader = true;\n        // load options\n        loader.setOptions({\n          numberOfFiles: data.length,\n          defaultCharacterSet: this.getDefaultCharacterSet()\n        });\n        // set loader callbacks\n        // loader.onloadstart: nothing to do\n        loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(1);\n        loader.onloaditem = this.onloaditem;\n        loader.onload = this.#addLoad;\n        loader.onloadend = this.#addLoadend;\n        loader.onerror = this.onerror;\n        loader.onabort = this.onabort;\n\n        // store loader\n        this.#storeLoader(loader);\n        // exit\n        break;\n      }\n    }\n    if (!foundLoader) {\n      throw new Error('No loader found for url: ' + dataElement);\n    }\n\n    // store last run request index\n    let lastRunRequestIndex = 0;\n    const requestOnLoadEnd = () => {\n      this.#addLoadend();\n      // launch next in queue\n      if (lastRunRequestIndex < this.#requests.length - 1 && !this.#aborting) {\n        ++lastRunRequestIndex;\n        this.#requests[lastRunRequestIndex].send(null);\n      }\n    };\n\n    // loop on I/O elements\n    for (let i = 0; i < data.length; ++i) {\n      dataElement = data[i];\n\n      // check loader\n      if (!loader.canLoadUrl(dataElement, options)) {\n        throw new Error('Input url of different type: ' + dataElement);\n      }\n      /**\n       * The http request.\n       *\n       * @external XMLHttpRequest\n       * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest\n       */\n      const request = new XMLHttpRequest();\n      request.open('GET', dataElement, true);\n\n      // request options\n      if (typeof options !== 'undefined') {\n        // optional request headers\n        if (typeof options.requestHeaders !== 'undefined') {\n          const requestHeaders = options.requestHeaders;\n          for (let j = 0; j < requestHeaders.length; ++j) {\n            if (typeof requestHeaders[j].name !== 'undefined' &&\n              typeof requestHeaders[j].value !== 'undefined') {\n              request.setRequestHeader(\n                requestHeaders[j].name, requestHeaders[j].value);\n            }\n          }\n        }\n        // optional withCredentials\n        // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials\n        if (typeof options.withCredentials !== 'undefined') {\n          request.withCredentials = options.withCredentials;\n        }\n      }\n\n      // set request callbacks\n      // request.onloadstart: nothing to do\n      request.onprogress = this.#augmentCallbackEvent(\n        mproghandler.getMonoProgressHandler(i, 0), dataElement);\n      request.onload = this.#getLoadHandler(loader, dataElement, i);\n      request.onloadend = requestOnLoadEnd;\n      request.onerror = this.#augmentCallbackEvent(this.onerror, dataElement);\n      request.onabort = this.#augmentCallbackEvent(this.onabort, dataElement);\n      // response type (default is 'text')\n      if (loader.loadUrlAs() === urlContentTypes.ArrayBuffer) {\n        request.responseType = 'arraybuffer';\n      }\n\n      // store request\n      this.#storeRequest(request);\n    }\n\n    // launch requests in batch\n    let batchSize = this.#requests.length;\n    if (typeof options !== 'undefined') {\n      // optional request batch size\n      if (typeof options.batchSize !== 'undefined' && batchSize !== 0) {\n        batchSize = Math.min(options.batchSize, this.#requests.length);\n      }\n    }\n    for (let r = 0; r < batchSize; ++r) {\n      if (!this.#aborting) {\n        lastRunRequestIndex = r;\n        this.#requests[lastRunRequestIndex].send(null);\n      }\n    }\n  }\n\n  /**\n   * Load a DICOMDIR.\n   *\n   * @param {string} dicomDirUrl The DICOMDIR url.\n   * @param {object} [options] Load options.\n   */\n  #loadDicomDir(dicomDirUrl, options) {\n    // read DICOMDIR\n    const request = new XMLHttpRequest();\n    request.open('GET', dicomDirUrl, true);\n    request.responseType = 'arraybuffer';\n    // request.onloadstart: nothing to do\n    /**\n     * @param {object} event The load event.\n     */\n    request.onload = (event) => {\n      // check status\n      const status = event.target.status;\n      if (status !== 200 && status !== 0) {\n        this.onerror({\n          source: dicomDirUrl,\n          error: 'GET ' + event.target.responseURL +\n            ' ' + event.target.status +\n            ' (' + event.target.statusText + ')',\n          target: event.target\n        });\n        this.onloadend({});\n      } else {\n        // get the file list\n        const list = getFileListFromDicomDir(event.target.response);\n        // use the first list\n        const urls = list[0][0];\n        // append root url\n        const rootUrl = getRootPath(dicomDirUrl);\n        const fullUrls = [];\n        for (let i = 0; i < urls.length; ++i) {\n          fullUrls.push(rootUrl + '/' + urls[i]);\n        }\n        // load urls\n        this.#loadUrls(fullUrls, options);\n      }\n    };\n    request.onerror = (event) => {\n      this.#augmentCallbackEvent(this.onerror, dicomDirUrl)(event);\n      this.onloadend({});\n    };\n    request.onabort = (event) => {\n      this.#augmentCallbackEvent(this.onabort, dicomDirUrl)(event);\n      this.onloadend({});\n    };\n    // request.onloadend: nothing to do\n    // send request\n    request.send(null);\n  }\n\n  /**\n   * Abort a load.\n   */\n  abort() {\n    this.#aborting = true;\n    // abort non finished requests\n    for (let i = 0; i < this.#requests.length; ++i) {\n      // 0: UNSENT, 1: OPENED, 2: HEADERS_RECEIVED (send()), 3: LOADING, 4: DONE\n      if (this.#requests[i].readyState !== 4) {\n        this.#requests[i].abort();\n      }\n    }\n    // abort loader\n    if (this.#runningLoader && this.#runningLoader.isLoading()) {\n      this.#runningLoader.abort();\n    }\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a load progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle a load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class UrlsLoader\n","/**\n * Thread Pool.\n * Highly inspired from {@link http://www.smartjava.org/content/html5-easily-parallelize-jobs-using-web-workers-and-threadpool}.\n */\nexport class ThreadPool {\n\n  /**\n   * @param {number} poolSize The size of the pool.\n   */\n  constructor(poolSize) {\n    this.poolSize = poolSize;\n    // task queue\n    this.taskQueue = [];\n    // lsit of available threads\n    this.freeThreads = [];\n    // create 'poolSize' number of worker threads\n    for (let i = 0; i < poolSize; ++i) {\n      this.freeThreads.push(new WorkerThread(this));\n    }\n    // list of running threads (unsed in abort)\n    this.runningThreads = [];\n  }\n\n  /**\n   * Add a worker task to the queue.\n   * Will be run when a thread is made available.\n   *\n   * @param {object} workerTask The task to add to the queue.\n   */\n  addWorkerTask(workerTask) {\n    // send work start if first task\n    if (this.freeThreads.length === this.poolSize) {\n      this.onworkstart({type: 'work-start'});\n    }\n    // launch task or queue\n    if (this.freeThreads.length > 0) {\n      // get the first free worker thread\n      const workerThread = this.freeThreads.shift();\n      // add the thread to the runnning list\n      this.runningThreads.push(workerThread);\n      // run the input task\n      workerThread.run(workerTask);\n    } else {\n      // no free thread, add task to queue\n      this.taskQueue.push(workerTask);\n    }\n  }\n\n  /**\n   * Abort all threads.\n   */\n  abort() {\n    // stop all threads\n    this.#stop();\n    // callback\n    this.onabort({type: 'work-abort'});\n    this.onworkend({type: 'work-end'});\n  }\n\n  /**\n   * Handle a task end.\n   *\n   * @param {object} workerThread The thread to free.\n   */\n  onTaskEnd(workerThread) {\n    // launch next task in queue or finish\n    if (this.taskQueue.length > 0) {\n      // get waiting task\n      const workerTask = this.taskQueue.shift();\n      // use input thread to run the waiting task\n      workerThread.run(workerTask);\n    } else {\n      // stop the worker\n      workerThread.stop();\n      // no task to run, add to free list\n      this.freeThreads.push(workerThread);\n      // remove from running list\n      for (let i = 0; i < this.runningThreads.length; ++i) {\n        if (this.runningThreads[i].getId() === workerThread.getId()) {\n          this.runningThreads.splice(i, 1);\n        }\n      }\n      // the work is done when the queue is back to its initial size\n      if (this.freeThreads.length === this.poolSize) {\n        this.onwork({type: 'work'});\n        this.onworkend({type: 'work-end'});\n      }\n    }\n  }\n\n  /**\n   * Handle an error message from a worker.\n   *\n   * @param {object} event The error event.\n   */\n  handleWorkerError = (event) => {\n    // stop all threads\n    this.#stop();\n    // callback\n    this.onerror({error: event});\n    this.onworkend({type: 'work-end'});\n  };\n\n  // private ----------------------------------------------------------------\n\n  /**\n   * Stop the pool: stop all running threads.\n   *\n   */\n  #stop() {\n    // clear tasks\n    this.taskQueue = [];\n    // cancel running workers\n    for (let i = 0; i < this.runningThreads.length; ++i) {\n      this.runningThreads[i].stop();\n    }\n    this.runningThreads = [];\n  }\n\n\n  /**\n   * Handle a work start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The work start event.\n   */\n  onworkstart(_event) {}\n\n  /**\n   * Handle a work item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The work item event fired\n   *   when a work item ended successfully.\n   */\n  onworkitem(_event) {}\n\n  /**\n   * Handle a work event.\n   * Default does nothing.\n   *\n   * @param {object} _event The work event fired\n   *   when a work ended successfully.\n   */\n  onwork(_event) {}\n\n  /**\n   * Handle a work end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The work end event fired\n   *  when a work has completed, successfully or not.\n   */\n  onworkend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // ThreadPool\n\n/**\n * Worker background task.\n *\n * @external Worker\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Worker\n */\n\n/**\n * Worker thread.\n */\nclass WorkerThread {\n\n  /**\n   * @param {object} parentPool The parent pool.\n   */\n  constructor(parentPool) {\n    this.parentPool = parentPool;\n    // thread ID\n    this.id = Math.random().toString(36).substring(2, 15);\n    // running task\n    this.runningTask = null;\n    // worker used to run task\n    this.worker;\n  }\n\n  /**\n   * Get the thread ID.\n   *\n   * @returns {string} The thread ID (alphanumeric).\n   */\n  getId() {\n    return this.id;\n  }\n\n  /**\n   * Run a worker task\n   *\n   * @param {object} workerTask The task to run.\n   */\n  run(workerTask) {\n    // store task\n    this.runningTask = workerTask;\n    // create a new web worker if not done yet\n    if (typeof this.worker === 'undefined') {\n      this.worker = new Worker(this.runningTask.script);\n      // set callbacks\n      this.worker.onmessage = this.onmessage;\n      this.worker.onerror = this.onerror;\n    }\n    // launch the worker\n    this.worker.postMessage(this.runningTask.startMessage);\n  }\n\n  /**\n   * Finish a task and tell the parent.\n   */\n  stop() {\n    // stop the worker\n    if (typeof this.worker !== 'undefined') {\n      this.worker.terminate();\n      // force create at next run\n      this.worker = undefined;\n    }\n  }\n\n  /**\n   * Message event handler.\n   * For now assume we only get a single callback from a worker\n   * which also indicates the end of this worker.\n   *\n   * @param {object} event The message event.\n   */\n  onmessage = (event) => {\n    // augment event\n    event.itemNumber = this.runningTask.info.itemNumber;\n    event.numberOfItems = this.runningTask.info.numberOfItems;\n    event.dataIndex = this.runningTask.info.dataIndex;\n    // send event\n    this.parentPool.onworkitem(event);\n    // tell the parent pool the task is done\n    this.parentPool.onTaskEnd(this);\n  };\n\n  /**\n   * Error event handler.\n   *\n   * @param {object} event The error event.\n   */\n  onerror = (event) => {\n    // augment event\n    event.itemNumber = this.runningTask.info.itemNumber;\n    event.numberOfItems = this.runningTask.info.numberOfItems;\n    event.dataIndex = this.runningTask.info.dataIndex;\n    // pass to parent\n    this.parentPool.handleWorkerError(event);\n    // stop the worker and free the thread\n    this.stop();\n  };\n} // class WorkerThread\n\n/**\n * Worker task.\n */\nexport class WorkerTask {\n  /**\n   * @param {string} script The worker script.\n   * @param {object} message The data to pass to the worker.\n   * @param {object} info Information object about the input data.\n   */\n  constructor(script, message, info) {\n    // worker script\n    this.script = script;\n    // worker start message\n    this.startMessage = message;\n    // information about the work data\n    this.info = info;\n  }\n}\n","import {ThreadPool, WorkerTask} from '../utils/thread';\n\n/**\n * The JPEG baseline decoder.\n *\n * @external JpegImage\n * @see https://github.com/mozilla/pdf.js/blob/master/src/core/jpg.js\n */\n/* global JpegImage */\n// @ts-ignore\nconst hasJpegBaselineDecoder = (typeof JpegImage !== 'undefined');\n\n/**\n * The JPEG decoder namespace.\n *\n * @external jpeg\n * @see https://github.com/rii-mango/JPEGLosslessDecoderJS\n */\n/* global jpeg */\nconst hasJpegLosslessDecoder =\n  // @ts-ignore\n  (typeof jpeg !== 'undefined') && (typeof jpeg.lossless !== 'undefined');\n\n/**\n * The JPEG 2000 decoder.\n *\n * @external JpxImage\n * @see https://github.com/jpambrun/jpx-medical/blob/master/jpx.js\n */\n/* global JpxImage */\n// @ts-ignore\nconst hasJpeg2000Decoder = (typeof JpxImage !== 'undefined');\n\n/* global dwvdecoder */\n\n/**\n * Decoder scripts to be passed to web workers for image decoding.\n */\nexport const decoderScripts = {\n  jpeg2000: '',\n  'jpeg-lossless': '',\n  'jpeg-baseline': '',\n  rle: ''\n};\n\n/**\n * Asynchronous pixel buffer decoder.\n */\nclass AsynchPixelBufferDecoder {\n\n  /**\n   * The associated worker script.\n   *\n   * @type {string}\n   */\n  #script;\n\n  /**\n   * Associated thread pool.\n   *\n   * @type {ThreadPool}\n   */\n  #pool = new ThreadPool(10);\n\n  /**\n   * Flag to know if callbacks are set.\n   *\n   * @type {boolean}\n   */\n  #areCallbacksSet = false;\n\n  /**\n   * @param {string} script The path to the decoder script to be used\n   *   by the web worker.\n   * @param {number} _numberOfData The anticipated number of data to decode.\n   */\n  constructor(script, _numberOfData) {\n    this.#script = script;\n  }\n\n  /**\n   * Decode a pixel buffer.\n   *\n   * @param {Array} pixelBuffer The pixel buffer.\n   * @param {object} pixelMeta The input meta data.\n   * @param {object} info Information object about the input data.\n   */\n  decode(pixelBuffer, pixelMeta, info) {\n    if (!this.#areCallbacksSet) {\n      this.#areCallbacksSet = true;\n      // set event handlers\n      this.#pool.onworkstart = this.ondecodestart;\n      this.#pool.onworkitem = this.ondecodeditem;\n      this.#pool.onwork = this.ondecoded;\n      this.#pool.onworkend = this.ondecodeend;\n      this.#pool.onerror = this.onerror;\n      this.#pool.onabort = this.onabort;\n    }\n    // create worker task\n    const workerTask = new WorkerTask(\n      this.#script,\n      {\n        buffer: pixelBuffer,\n        meta: pixelMeta\n      },\n      info\n    );\n    // add it the queue and run it\n    this.#pool.addWorkerTask(workerTask);\n  }\n\n  /**\n   * Abort decoding.\n   */\n  abort() {\n    // abort the thread pool, will trigger pool.onabort\n    this.#pool.abort();\n  }\n\n  /**\n   * Handle a decode start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode start event.\n   */\n  ondecodestart(_event) {}\n\n  /**\n   * Handle a decode item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode item event fired\n   *   when a decode item ended successfully.\n   */\n  ondecodeditem(_event) {}\n\n  /**\n   * Handle a decode event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode event fired\n   *   when a file has been decoded successfully.\n   */\n  ondecoded(_event) {}\n\n  /**\n   * Handle a decode end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode end event fired\n   *  when a file decoding has completed, successfully or not.\n   */\n  ondecodeend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class AsynchPixelBufferDecoder\n\n/**\n * Synchronous pixel buffer decoder.\n */\nclass SynchPixelBufferDecoder {\n\n  /**\n   * Name of the compression algorithm.\n   *\n   * @type {string}\n   */\n  #algoName;\n\n  /**\n   * Number of data.\n   *\n   * @type {number}\n   */\n  #numberOfData;\n\n  /**\n   * @param {string} algoName The decompression algorithm name.\n   * @param {number} numberOfData The anticipated number of data to decode.\n   */\n  constructor(algoName, numberOfData) {\n    this.#algoName = algoName;\n    this.#numberOfData = numberOfData;\n  }\n\n  // decode count\n  #decodeCount = 0;\n\n  /**\n   * Decode a pixel buffer.\n   *\n   * @param {Array} pixelBuffer The pixel buffer.\n   * @param {object} pixelMeta The input meta data.\n   * @param {object} info Information object about the input data.\n   * @external jpeg\n   * @external JpegImage\n   * @external JpxImage\n   */\n  decode(pixelBuffer, pixelMeta, info) {\n    ++this.#decodeCount;\n\n    let decoder = null;\n    let decodedBuffer = null;\n    if (this.#algoName === 'jpeg-lossless') {\n      if (!hasJpegLosslessDecoder) {\n        throw new Error('No JPEG Lossless decoder provided');\n      }\n      // bytes per element\n      const bpe = pixelMeta.bitsAllocated / 8;\n      const buf = new Uint8Array(pixelBuffer);\n      // @ts-ignore\n      decoder = new jpeg.lossless.Decoder();\n      const decoded = decoder.decode(buf.buffer, 0, buf.buffer.byteLength, bpe);\n      if (pixelMeta.bitsAllocated === 8) {\n        if (pixelMeta.isSigned) {\n          decodedBuffer = new Int8Array(decoded.buffer);\n        } else {\n          decodedBuffer = new Uint8Array(decoded.buffer);\n        }\n      } else if (pixelMeta.bitsAllocated === 16) {\n        if (pixelMeta.isSigned) {\n          decodedBuffer = new Int16Array(decoded.buffer);\n        } else {\n          decodedBuffer = new Uint16Array(decoded.buffer);\n        }\n      }\n    } else if (this.#algoName === 'jpeg-baseline') {\n      if (!hasJpegBaselineDecoder) {\n        throw new Error('No JPEG Baseline decoder provided');\n      }\n      // @ts-ignore\n      decoder = new JpegImage();\n      decoder.parse(pixelBuffer);\n      decodedBuffer = decoder.getData(decoder.width, decoder.height);\n    } else if (this.#algoName === 'jpeg2000') {\n      if (!hasJpeg2000Decoder) {\n        throw new Error('No JPEG 2000 decoder provided');\n      }\n      // decompress pixel buffer into Int16 image\n      // @ts-ignore\n      decoder = new JpxImage();\n      decoder.parse(pixelBuffer);\n      // set the pixel buffer\n      decodedBuffer = decoder.tiles[0].items;\n    } else if (this.#algoName === 'rle') {\n      // decode DICOM buffer\n      // @ts-ignore\n      decoder = new dwvdecoder.RleDecoder();\n      // set the pixel buffer\n      decodedBuffer = decoder.decode(\n        pixelBuffer,\n        pixelMeta.bitsAllocated,\n        pixelMeta.isSigned,\n        pixelMeta.sliceSize,\n        pixelMeta.samplesPerPixel,\n        pixelMeta.planarConfiguration);\n    }\n    // send decode events\n    this.ondecodeditem({\n      data: [decodedBuffer],\n      dataIndex: info.dataIndex,\n      numberOfItems: info.numberOfItems,\n      itemNumber: info.itemNumber\n    });\n    // decode end?\n    if (this.#decodeCount === this.#numberOfData) {\n      this.ondecoded({});\n      this.ondecodeend({});\n    }\n  }\n\n  /**\n   * Abort decoding.\n   */\n  abort() {\n    // nothing to do in the synchronous case.\n    // callback\n    this.onabort({});\n    this.ondecodeend({});\n  }\n\n  /**\n   * Handle a decode start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode start event.\n   */\n  ondecodestart(_event) {}\n\n  /**\n   * Handle a decode item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode item event fired\n   *   when a decode item ended successfully.\n   */\n  ondecodeditem(_event) {}\n\n  /**\n   * Handle a decode event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode event fired\n   *   when a file has been decoded successfully.\n   */\n  ondecoded(_event) {}\n\n  /**\n   * Handle a decode end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode end event fired\n   *  when a file decoding has completed, successfully or not.\n   */\n  ondecodeend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class SynchPixelBufferDecoder\n\n/**\n * Decode a pixel buffer.\n *\n * If the 'decoderScripts' variable does not contain the desired,\n * algorythm the decoder will switch to the synchronous mode.\n */\nexport class PixelBufferDecoder {\n\n  /**\n   * Flag to know if callbacks are set.\n   *\n   * @type {boolean}\n   */\n  #areCallbacksSet = false;\n\n  /**\n   * Pixel decoder.\n   * Defined only once.\n   *\n   * @type {object}\n   */\n  #pixelDecoder = null;\n\n  /**\n   * @param {string} algoName The decompression algorithm name.\n   * @param {number} numberOfData The anticipated number of data to decode.\n   */\n  constructor(algoName, numberOfData) {\n    // initialise the asynch decoder (if possible)\n    if (typeof decoderScripts !== 'undefined' &&\n      typeof decoderScripts[algoName] !== 'undefined') {\n      this.#pixelDecoder = new AsynchPixelBufferDecoder(\n        decoderScripts[algoName], numberOfData);\n    } else {\n      this.#pixelDecoder = new SynchPixelBufferDecoder(\n        algoName, numberOfData);\n    }\n  }\n\n  /**\n   * Get data from an input buffer using a DICOM parser.\n   *\n   * @param {Array} pixelBuffer The input data buffer.\n   * @param {object} pixelMeta The input meta data.\n   * @param {object} info Information object about the input data.\n   */\n  decode(pixelBuffer, pixelMeta, info) {\n    if (!this.#areCallbacksSet) {\n      this.#areCallbacksSet = true;\n      // set callbacks\n      this.#pixelDecoder.ondecodestart = this.ondecodestart;\n      this.#pixelDecoder.ondecodeditem = this.ondecodeditem;\n      this.#pixelDecoder.ondecoded = this.ondecoded;\n      this.#pixelDecoder.ondecodeend = this.ondecodeend;\n      this.#pixelDecoder.onerror = this.onerror;\n      this.#pixelDecoder.onabort = this.onabort;\n    }\n    // decode and call the callback\n    this.#pixelDecoder.decode(pixelBuffer, pixelMeta, info);\n  }\n\n  /**\n   * Abort decoding.\n   */\n  abort() {\n    // decoder classes should define an abort\n    this.#pixelDecoder.abort();\n  }\n\n  /**\n   * Handle a decode start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode start event.\n   */\n  ondecodestart(_event) {}\n\n  /**\n   * Handle a decode item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode item event fired\n   *   when a decode item ended successfully.\n   */\n  ondecodeditem(_event) {}\n\n  /**\n   * Handle a decode event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode event fired\n   *   when a file has been decoded successfully.\n   */\n  ondecoded(_event) {}\n\n  /**\n   * Handle a decode end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The decode end event fired\n   *  when a file decoding has completed, successfully or not.\n   */\n  ondecodeend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class PixelBufferDecoder\n","import {logger} from '../utils/logger';\nimport {\n  DicomParser,\n  getSyntaxDecompressionName\n} from '../dicom/dicomParser';\nimport {ImageFactory} from './imageFactory';\nimport {MaskFactory} from './maskFactory';\nimport {PixelBufferDecoder} from './decoder';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {DataElement} from '../dicom/dataElement';\n/* eslint-enable no-unused-vars */\n\n/**\n * Create a View from a DICOM buffer.\n */\nexport class DicomBufferToView {\n\n  /**\n   * Converter options.\n   *\n   * @type {object}\n   */\n  #options;\n\n  /**\n   * Set the converter options.\n   *\n   * @param {object} opt The input options.\n   */\n  setOptions(opt) {\n    this.#options = opt;\n  }\n\n  /**\n   * Pixel buffer decoder.\n   * Define only once to allow optional asynchronous mode.\n   *\n   * @type {object}\n   */\n  #pixelDecoder = null;\n\n  // local tmp storage\n  #dicomParserStore = [];\n  #finalBufferStore = [];\n  #decompressedSizes = [];\n  #factoryWarnings = [];\n\n  /**\n   * Get the factory associated to input DICOM elements.\n   *\n   * @param {Object<string, DataElement>} elements The DICOM elements.\n   * @returns {ImageFactory|MaskFactory} The associated factory.\n   */\n  #getFactory(elements) {\n    let factory;\n    // mask factory for DICOM SEG\n    const element = elements['00080060'];\n    if (typeof element !== 'undefined') {\n      const modality = element.value[0];\n      if (modality === 'SEG') {\n        factory = new MaskFactory();\n      }\n    }\n    // default image factory\n    if (typeof factory === 'undefined') {\n      factory = new ImageFactory();\n    }\n    return factory;\n  }\n\n  /**\n   * Generate the image object.\n   *\n   * @param {number} index The data index.\n   * @param {string} origin The data origin.\n   */\n  #generateImage(index, origin) {\n    const dataElements = this.#dicomParserStore[index].getDicomElements();\n    const factory = this.#getFactory(dataElements);\n    // create the image\n    try {\n      const image = factory.create(\n        dataElements,\n        this.#finalBufferStore[index],\n        this.#options.numberOfFiles);\n      // call onloaditem\n      this.onloaditem({\n        data: {\n          image: image,\n          info: dataElements\n        },\n        source: origin,\n        warn: this.#factoryWarnings[index]\n      });\n    } catch (error) {\n      this.onerror({\n        error: error,\n        source: origin\n      });\n      this.onloadend({\n        source: origin\n      });\n    }\n  }\n\n  /**\n   * Handle a decoded item event.\n   *\n   * @param {object} event The decoded item event.\n   */\n  #onDecodedItem(event) {\n    // send progress\n    this.onprogress({\n      lengthComputable: true,\n      loaded: event.itemNumber + 1,\n      total: event.numberOfItems,\n      index: event.dataIndex,\n      source: origin\n    });\n\n    const dataIndex = event.dataIndex;\n\n    // store decoded data\n    const decodedData = event.data[0];\n    if (event.numberOfItems !== 1) {\n      // allocate buffer if not done yet\n      if (typeof this.#decompressedSizes[dataIndex] === 'undefined') {\n        this.#decompressedSizes[dataIndex] = decodedData.length;\n        const fullSize = event.numberOfItems *\n          this.#decompressedSizes[dataIndex];\n        try {\n          this.#finalBufferStore[dataIndex] =\n            new decodedData.constructor(fullSize);\n        } catch (error) {\n          if (error instanceof RangeError) {\n            const powerOf2 = Math.floor(Math.log(fullSize) / Math.log(2));\n            logger.error('Cannot allocate ' +\n              decodedData.constructor.name +\n              ' of size: ' +\n              fullSize + ' (>2^' + powerOf2 + ') for decompressed data.');\n          }\n          // abort\n          this.#pixelDecoder.abort();\n          // send events\n          this.onerror({\n            error: error,\n            source: origin\n          });\n          this.onloadend({\n            source: origin\n          });\n          // exit\n          return;\n        }\n      }\n      // hoping for all items to have the same size...\n      if (decodedData.length !== this.#decompressedSizes[dataIndex]) {\n        logger.warn('Unsupported varying decompressed data size: ' +\n          decodedData.length + ' != ' + this.#decompressedSizes[dataIndex]);\n      }\n      // set buffer item data\n      this.#finalBufferStore[dataIndex].set(\n        decodedData, this.#decompressedSizes[dataIndex] * event.itemNumber);\n    } else {\n      this.#finalBufferStore[dataIndex] = decodedData;\n    }\n\n    // create image for the first item\n    if (event.itemNumber === 0) {\n      this.#generateImage(dataIndex, origin);\n    }\n  }\n\n  /**\n   * Get data from an input buffer using a DICOM parser.\n   *\n   * @param {ArrayBuffer} buffer The input data buffer.\n   * @param {string} origin The data origin.\n   * @param {number} dataIndex The data index.\n   */\n  convert(buffer, origin, dataIndex) {\n\n    this.onloadstart({\n      source: origin,\n      dataIndex: dataIndex\n    });\n\n    // DICOM parser\n    const dicomParser = new DicomParser();\n\n    if (typeof this.#options.defaultCharacterSet !== 'undefined') {\n      dicomParser.setDefaultCharacterSet(this.#options.defaultCharacterSet);\n    }\n    // parse the buffer\n    let warning;\n    try {\n      dicomParser.parse(buffer);\n      // check elements\n      const factory = this.#getFactory(dicomParser.getDicomElements());\n      warning = factory.checkElements(dicomParser.getDicomElements());\n    } catch (error) {\n      this.onerror({\n        error: error,\n        source: origin\n      });\n      this.onloadend({\n        source: origin\n      });\n      return;\n    }\n\n\n    const pixelBuffer = dicomParser.getDicomElements()['7FE00010'].value;\n    // help GC: discard pixel buffer from elements\n    dicomParser.getDicomElements()['7FE00010'].value = [];\n    const syntax = dicomParser.getDicomElements()['00020010'].value[0];\n    const algoName = getSyntaxDecompressionName(syntax);\n    const needDecompression = (algoName !== null);\n\n    // store\n    this.#dicomParserStore[dataIndex] = dicomParser;\n    this.#finalBufferStore[dataIndex] = pixelBuffer[0];\n    this.#factoryWarnings[dataIndex] = warning;\n\n    if (needDecompression) {\n      // gather pixel buffer meta data\n      const bitsAllocated =\n        dicomParser.getDicomElements()['00280100'].value[0];\n      const pixelRepresentation =\n        dicomParser.getDicomElements()['00280103'].value[0];\n      const pixelMeta = {\n        bitsAllocated: bitsAllocated,\n        isSigned: (pixelRepresentation === 1)\n      };\n      const columnsElement = dicomParser.getDicomElements()['00280011'];\n      const rowsElement = dicomParser.getDicomElements()['00280010'];\n      if (typeof columnsElement !== 'undefined' &&\n        typeof rowsElement !== 'undefined') {\n        pixelMeta.sliceSize = columnsElement.value[0] * rowsElement.value[0];\n      }\n      const samplesPerPixelElement =\n        dicomParser.getDicomElements()['00280002'];\n      if (typeof samplesPerPixelElement !== 'undefined') {\n        pixelMeta.samplesPerPixel = samplesPerPixelElement.value[0];\n      }\n      const planarConfigurationElement =\n        dicomParser.getDicomElements()['00280006'];\n      if (typeof planarConfigurationElement !== 'undefined') {\n        pixelMeta.planarConfiguration = planarConfigurationElement.value[0];\n      }\n\n      // number of items\n      const numberOfItems = pixelBuffer.length;\n\n      // setup the decoder (one decoder per all converts)\n      if (this.#pixelDecoder === null) {\n        this.#pixelDecoder = new PixelBufferDecoder(\n          algoName, numberOfItems);\n        // callbacks\n        // pixelDecoder.ondecodestart: nothing to do\n        this.#pixelDecoder.ondecodeditem = (event) => {\n          this.#onDecodedItem(event);\n          // send onload and onloadend when all items have been decoded\n          if (event.itemNumber + 1 === event.numberOfItems) {\n            this.onload(event);\n            this.onloadend(event);\n          }\n        };\n        // pixelDecoder.ondecoded: nothing to do\n        // pixelDecoder.ondecodeend: nothing to do\n        this.#pixelDecoder.onerror = this.onerror;\n        this.#pixelDecoder.onabort = this.onabort;\n      }\n\n      // launch decode\n      for (let i = 0; i < numberOfItems; ++i) {\n        this.#pixelDecoder.decode(pixelBuffer[i], pixelMeta,\n          {\n            itemNumber: i,\n            numberOfItems: numberOfItems,\n            dataIndex: dataIndex\n          }\n        );\n      }\n    } else {\n      // no decompression\n      // send progress\n      this.onprogress({\n        lengthComputable: true,\n        loaded: 100,\n        total: 100,\n        index: dataIndex,\n        source: origin\n      });\n      // generate image\n      this.#generateImage(dataIndex, origin);\n      // send load events\n      this.onload({\n        source: origin\n      });\n      this.onloadend({\n        source: origin\n      });\n    }\n  }\n\n  /**\n   * Abort a conversion.\n   */\n  abort() {\n    // abort decoding, will trigger pixelDecoder.onabort\n    if (this.#pixelDecoder) {\n      this.#pixelDecoder.abort();\n    }\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n  /**\n   * Handle a load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class DicomBufferToView\n","import {MultiProgressHandler} from '../utils/progress';\nimport {loaderList} from './loaderList';\n\n/**\n * Memory loader.\n */\nexport class MemoryLoader {\n\n  /**\n   * Input data.\n   *\n   * @type {Array}\n   */\n  #inputData = null;\n\n  /**\n   * Data loader.\n   *\n   * @type {object}\n   */\n  #runningLoader = null;\n\n  /**\n   * Number of loaded data.\n   *\n   * @type {number}\n   */\n  #nLoad = 0;\n\n  /**\n   * Number of load end events.\n   *\n   * @type {number}\n   */\n  #nLoadend = 0;\n\n  /**\n   * The default character set (optional).\n   *\n   * @type {string}\n   */\n  #defaultCharacterSet;\n\n  /**\n   * Get the default character set.\n   *\n   * @returns {string} The default character set.\n   */\n  getDefaultCharacterSet() {\n    return this.#defaultCharacterSet;\n  }\n\n  /**\n   * Set the default character set.\n   *\n   * @param {string} characterSet The character set.\n   */\n  setDefaultCharacterSet(characterSet) {\n    this.#defaultCharacterSet = characterSet;\n  }\n\n  /**\n   * Store the current input.\n   *\n   * @param {object} data The input data.\n   */\n  #storeInputData(data) {\n    this.#inputData = data;\n    // reset counters\n    this.#nLoad = 0;\n    this.#nLoadend = 0;\n    // clear storage\n    this.#clearStoredLoader();\n  }\n\n  /**\n   * Store the launched loader.\n   *\n   * @param {object} loader The launched loader.\n   */\n  #storeLoader(loader) {\n    this.#runningLoader = loader;\n  }\n\n  /**\n   * Clear the stored loader.\n   *\n   */\n  #clearStoredLoader() {\n    this.#runningLoader = null;\n  }\n\n  /**\n   * Increment the number of loaded data\n   *   and call onload if loaded all data.\n   *\n   * @param {object} _event The load data event.\n   */\n  #addLoad = (_event) => {\n    this.#nLoad++;\n    // call onload when all is loaded\n    // (not using the input event since it is not the\n    //   general load)\n    if (this.#nLoad === this.#inputData.length) {\n      this.onload({\n        source: this.#inputData\n      });\n    }\n  };\n\n  /**\n   * Increment the counter of load end events\n   *   and run callbacks when all done, erroneus or not.\n   *\n   * @param {object} _event The load end event.\n   */\n  #addLoadend = (_event) => {\n    this.#nLoadend++;\n    // call onloadend when all is run\n    // (not using the input event since it is not the\n    //   general load end)\n    if (this.#nLoadend === this.#inputData.length) {\n      this.onloadend({\n        source: this.#inputData\n      });\n    }\n  };\n\n  /**\n   * Load a list of buffers.\n   *\n   * @param {Array} data The list of buffers to load.\n   */\n  load(data) {\n    // check input\n    if (typeof data === 'undefined' || data.length === 0) {\n      return;\n    }\n    this.#storeInputData(data);\n\n    // send start event\n    this.onloadstart({\n      source: data\n    });\n\n    // create prgress handler\n    const mproghandler = new MultiProgressHandler(this.onprogress);\n    mproghandler.setNToLoad(data.length);\n    mproghandler.setNumberOfDimensions(1);\n\n    // create loaders\n    const loaders = [];\n    for (let m = 0; m < loaderList.length; ++m) {\n      loaders.push(new loaderList[m]());\n    }\n\n    // find an appropriate loader\n    let dataElement = data[0];\n    let loader = null;\n    let foundLoader = false;\n    for (let l = 0; l < loaders.length; ++l) {\n      loader = loaders[l];\n      if (loader.canLoadMemory(dataElement)) {\n        foundLoader = true;\n        // load options\n        loader.setOptions({\n          numberOfFiles: data.length,\n          defaultCharacterSet: this.getDefaultCharacterSet()\n        });\n        // set loader callbacks\n        // loader.onloadstart: nothing to do\n        loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(0);\n        loader.onloaditem = this.onloaditem;\n        loader.onload = this.#addLoad;\n        loader.onloadend = this.#addLoadend;\n        loader.onerror = this.onerror;\n        loader.onabort = this.onabort;\n\n        // store loader\n        this.#storeLoader(loader);\n        // exit\n        break;\n      }\n    }\n    if (!foundLoader) {\n      throw new Error('No loader found for data: ' + dataElement.filename);\n    }\n\n    // loop on I/O elements\n    for (let i = 0; i < data.length; ++i) {\n      dataElement = data[i];\n      // check loader\n      if (!loader.canLoadMemory(dataElement)) {\n        throw new Error('Input data of different type: ' +\n          dataElement.filename);\n      }\n      // read\n      loader.load(dataElement.data, dataElement.filename, i);\n    }\n  }\n\n  /**\n   * Abort a load.\n   */\n  abort() {\n    // abort loader\n    if (this.#runningLoader && this.#runningLoader.isLoading()) {\n      this.#runningLoader.abort();\n    }\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a load progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle a load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class MemoryLoader\n","import {Size} from '../image/size';\nimport {Spacing} from '../image/spacing';\nimport {Geometry} from '../image/geometry';\nimport {Image} from '../image/image';\nimport {Point3D} from '../math/point';\n\n/**\n * Create a simple array buffer from an ImageData buffer.\n *\n * @param {object} imageData The ImageData taken from a context.\n * @returns {Uint8Array} The image buffer.\n */\nfunction imageDataToBuffer(imageData) {\n  // remove alpha\n  // TODO support passing the full image data\n  const dataLen = imageData.data.length;\n  const buffer = new Uint8Array((dataLen / 4) * 3);\n  let j = 0;\n  for (let i = 0; i < dataLen; i += 4) {\n    buffer[j] = imageData.data[i];\n    buffer[j + 1] = imageData.data[i + 1];\n    buffer[j + 2] = imageData.data[i + 2];\n    j += 3;\n  }\n  return buffer;\n}\n\n/**\n * Get an image from an input context imageData.\n *\n * @param {number} width The width of the coresponding image.\n * @param {number} height The height of the coresponding image.\n * @param {number} sliceIndex The slice index of the imageData.\n * @param {object} imageBuffer The image buffer.\n * @param {number} numberOfFrames The final number of frames.\n * @param {string} imageUid The image UID.\n * @returns {object} The corresponding view.\n */\nfunction getDefaultImage(\n  width, height, sliceIndex,\n  imageBuffer, numberOfFrames,\n  imageUid) {\n  // image size\n  const imageSize = new Size([width, height, 1]);\n  // default spacing\n  // TODO: misleading...\n  const imageSpacing = new Spacing([1, 1, 1]);\n  // default origin\n  const origin = new Point3D(0, 0, sliceIndex);\n  // create image\n  const geometry = new Geometry(origin, imageSize, imageSpacing);\n  const image = new Image(geometry, imageBuffer, [imageUid]);\n  image.setPhotometricInterpretation('RGB');\n  // meta information\n  const meta = {};\n  meta.BitsStored = 8;\n  if (typeof numberOfFrames !== 'undefined') {\n    meta.numberOfFiles = numberOfFrames;\n  }\n  image.setMeta(meta);\n  // return\n  return image;\n}\n\n/**\n * Get data from an input image using a canvas.\n *\n * @param {HTMLImageElement} domImage The DOM Image,\n *   an HTMLImageElement with extra info.\n * @param {string|File} origin The data origin.\n * @param {number} index The data index.\n * @returns {object} A load data event.\n */\nexport function getViewFromDOMImage(domImage, origin, index) {\n  // image size\n  const width = domImage.width;\n  const height = domImage.height;\n\n  // draw the image in the canvas in order to get its data\n  const canvas = document.createElement('canvas');\n  canvas.width = width;\n  canvas.height = height;\n  const ctx = canvas.getContext('2d');\n  ctx.drawImage(domImage, 0, 0);\n  // get the image data\n  const imageData = ctx.getImageData(0, 0, width, height);\n\n  // image properties\n  const info = {};\n  if (typeof origin === 'string') {\n    info['origin'] = {value: origin};\n  } else {\n    info['fileName'] = {value: origin.name};\n    info['fileType'] = {value: origin.type};\n    info['fileLastModifiedDate'] = {value: origin.lastModified};\n  }\n  info['imageWidth'] = {value: width};\n  info['imageHeight'] = {value: height};\n\n  const sliceIndex = index ? index : 0;\n  info['imageUid'] = {value: sliceIndex};\n\n  // create view\n  const imageBuffer = imageDataToBuffer(imageData);\n  const image = getDefaultImage(\n    width, height, sliceIndex, imageBuffer, 1, sliceIndex.toString());\n\n  // return\n  return {\n    data: {\n      image: image,\n      info: info\n    },\n    source: origin\n  };\n}\n\n/**\n * Get data from an input image using a canvas.\n *\n * @param {object} video The DOM Video, an HTMLVideoElement with extra info.\n * @param {Function} onloaditem On load callback.\n * @param {object} onload The function to call once the data is loaded.\n * @param {object} onprogress The function to call to report progress.\n * @param {object} onloadend The function to call to report load end.\n * @param {string|File} origin The data origin.\n * @param {number} dataIndex The data index.\n */\nexport function getViewFromDOMVideo(\n  video, onloaditem, onload, onprogress, onloadend,\n  origin, dataIndex) {\n  // video size\n  const width = video.videoWidth;\n  const height = video.videoHeight;\n\n  // default frame rate...\n  const frameRate = 30;\n  // number of frames\n  const numberOfFrames = Math.ceil(video.duration * frameRate);\n\n  // video properties\n  const info = {};\n  if (typeof origin === 'string') {\n    info['origin'] = {value: origin};\n  } else {\n    info['fileName'] = {value: origin.name};\n    info['fileType'] = {value: origin.type};\n    info['fileLastModifiedDate'] = {value: origin.lastModified};\n  }\n  info['imageWidth'] = {value: width};\n  info['imageHeight'] = {value: height};\n  info['numberOfFrames'] = {value: numberOfFrames};\n  info['imageUid'] = {value: 0};\n\n  // draw the image in the canvas in order to get its data\n  const canvas = document.createElement('canvas');\n  canvas.width = width;\n  canvas.height = height;\n  const ctx = canvas.getContext('2d');\n\n  // using seeked to loop through all video frames\n  video.addEventListener('seeked', onseeked, false);\n\n  // current frame index\n  let frameIndex = 0;\n  // video image\n  let image = null;\n\n  /**\n   * Draw the context and store it as a frame\n   */\n  function storeFrame() {\n    // send progress\n    onprogress({\n      lengthComputable: true,\n      loaded: frameIndex,\n      total: numberOfFrames,\n      index: dataIndex,\n      source: origin\n    });\n    // draw image\n    ctx.drawImage(video, 0, 0);\n    // context to image buffer\n    const imgBuffer = imageDataToBuffer(\n      ctx.getImageData(0, 0, width, height));\n    if (frameIndex === 0) {\n      // create view\n      image = getDefaultImage(\n        width, height, 1, imgBuffer, numberOfFrames, dataIndex.toString());\n      // call callback\n      onloaditem({\n        data: {\n          image: image,\n          info: info\n        },\n        source: origin\n      });\n    } else {\n      image.appendFrameBuffer(imgBuffer, frameIndex);\n    }\n    // increment index\n    ++frameIndex;\n  }\n\n  let nextTime = 0;\n\n  /**\n   * Handle seeked event\n   *\n   * @param {object} event The seeked event.\n   */\n  function onseeked(event) {\n    // store\n    storeFrame();\n    // set the next time\n    // (not using currentTime, it seems to get offseted)\n    nextTime += 1 / frameRate;\n    if (nextTime <= event.target.duration) {\n      this.currentTime = nextTime;\n    } else {\n      onload({\n        source: origin\n      });\n      onloadend({\n        source: origin\n      });\n      // stop listening\n      video.removeEventListener('seeked', onseeked);\n    }\n  }\n\n  // trigger the first seek\n  video.currentTime = nextTime;\n}\n","import {DicomDataLoader} from './dicomDataLoader';\nimport {JSONTextLoader} from './jsonTextLoader';\nimport {MultipartLoader} from './multipartLoader';\nimport {RawImageLoader} from './rawImageLoader';\nimport {RawVideoLoader} from './rawVideoLoader';\nimport {ZipLoader} from './zipLoader';\n\nexport const loaderList = [\n  DicomDataLoader,\n  JSONTextLoader,\n  MultipartLoader,\n  RawImageLoader,\n  RawVideoLoader,\n  ZipLoader\n];\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\nimport {DicomBufferToView} from '../image/dicomBufferToView';\n\n/**\n * DICOM data loader.\n */\nexport class DicomDataLoader {\n\n  /**\n   * Loader options.\n   *\n   * @type {object}\n   */\n  #options = {};\n\n  /**\n   * Loading flag.\n   *\n   * @type {boolean}\n   */\n  #isLoading = false;\n\n  /**\n   * Set the loader options.\n   *\n   * @param {object} opt The input options.\n   */\n  setOptions(opt) {\n    this.#options = opt;\n  }\n\n  /**\n   * Is the load ongoing?\n   *\n   * @returns {boolean} True if loading.\n   */\n  isLoading() {\n    return this.#isLoading;\n  }\n\n  /**\n   * DICOM buffer to View (asynchronous)\n   *\n   */\n  #db2v = new DicomBufferToView();\n\n  /**\n   * Load data.\n   *\n   * @param {object} buffer The DICOM buffer.\n   * @param {string} origin The data origin.\n   * @param {number} index The data index.\n   */\n  load(buffer, origin, index) {\n    // setup db2v ony once\n    if (!this.#isLoading) {\n      // pass options\n      this.#db2v.setOptions(this.#options);\n      // connect handlers\n      this.#db2v.onloadstart = this.onloadstart;\n      this.#db2v.onprogress = this.onprogress;\n      this.#db2v.onloaditem = this.onloaditem;\n      this.#db2v.onload = this.onload;\n      this.#db2v.onloadend = (event) => {\n        // reset loading flag\n        this.#isLoading = false;\n        // call listeners\n        this.onloadend(event);\n      };\n      this.#db2v.onerror = (event) => {\n        event.source = origin;\n        this.onerror(event);\n      };\n      this.#db2v.onabort = this.onabort;\n    }\n\n    // set loading flag\n    this.#isLoading = true;\n    // convert\n    this.#db2v.convert(buffer, origin, index);\n  }\n\n  /**\n   * Abort load.\n   */\n  abort() {\n    // reset loading flag\n    this.#isLoading = false;\n    // abort conversion, will trigger db2v.onabort\n    this.#db2v.abort();\n  }\n\n  /**\n   * Check if the loader can load the provided file.\n   *\n   * @param {object} file The file to check.\n   * @returns {boolean} True if the file can be loaded.\n   */\n  canLoadFile(file) {\n    const ext = getFileExtension(file.name);\n    const hasNoExt = (ext === null);\n    const hasDcmExt = (ext === 'dcm');\n    return hasNoExt || hasDcmExt;\n  }\n\n  /**\n   * Check if the loader can load the provided url.\n   * True if:\n   *  - the url has a 'contentType' and it is 'application/dicom'\n   *    (as in wado urls)\n   *  - the url has no 'contentType' and no extension or the extension is 'dcm'\n   *\n   * @param {string} url The url to check.\n   * @param {object} [options] Optional url request options.\n   * @returns {boolean} True if the url can be loaded.\n   */\n  canLoadUrl(url, options) {\n    // if there are options.requestHeaders, just base check on them\n    if (typeof options !== 'undefined' &&\n      typeof options.requestHeaders !== 'undefined') {\n      // starts with 'application/dicom'\n      const isDicom = function (element) {\n        return element.name === 'Accept' &&\n          startsWith(element.value, 'application/dicom') &&\n          element.value[18] !== '+';\n      };\n      return typeof options.requestHeaders.find(isDicom) !== 'undefined';\n    }\n\n    const urlObjext = getUrlFromUri(url);\n    // extension\n    const ext = getFileExtension(urlObjext.pathname);\n    const hasNoExt = (ext === null);\n    const hasDcmExt = (ext === 'dcm');\n    // content type (for wado url)\n    const contentType = urlObjext.searchParams.get('contentType');\n    const hasContentType = contentType !== null &&\n      typeof contentType !== 'undefined';\n    const hasDicomContentType = (contentType === 'application/dicom');\n\n    return hasContentType ? hasDicomContentType : (hasNoExt || hasDcmExt);\n  }\n\n  /**\n   * Check if the loader can load the provided memory object.\n   *\n   * @param {object} mem The memory object.\n   * @returns {boolean} True if the object can be loaded.\n   */\n  canLoadMemory(mem) {\n    if (typeof mem['Content-Type'] !== 'undefined' &&\n      mem['Content-Type'] === 'application/dicom') {\n      return true;\n    }\n    if (typeof mem.filename !== 'undefined') {\n      return this.canLoadFile({name: mem.filename});\n    }\n    return false;\n  }\n\n  /**\n   * Get the file content type needed by the loader.\n   *\n   * @returns {number} One of the 'fileContentTypes'.\n   */\n  loadFileAs() {\n    return fileContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Get the url content type needed by the loader.\n   *\n   * @returns {number} One of the 'urlContentTypes'.\n   */\n  loadUrlAs() {\n    return urlContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle an load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class DicomDataLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * JSON text loader.\n */\nexport class JSONTextLoader {\n\n  /**\n   * Loading flag.\n   *\n   * @type {boolean}\n   */\n  #isLoading = false;\n\n  /**\n   * Set the loader options.\n   *\n   * @param {object} _opt The input options.\n   */\n  setOptions(_opt) {\n    // does nothing\n  }\n\n  /**\n   * Is the load ongoing?\n   *\n   * @returns {boolean} True if loading.\n   */\n  isLoading() {\n    return this.#isLoading;\n  }\n\n  /**\n   * Load data.\n   *\n   * @param {object} text The input text.\n   * @param {string} origin The data origin.\n   * @param {number} index The data index.\n   */\n  load(text, origin, index) {\n    // set loading flag\n    this.#isLoading = true;\n    this.onloadstart({\n      source: origin\n    });\n\n    try {\n      this.onprogress({\n        lengthComputable: true,\n        loaded: 100,\n        total: 100,\n        index: index,\n        source: origin\n      });\n      const data = {\n        data: text,\n        source: origin\n      };\n      // only expecting one item\n      this.onloaditem(data);\n      this.onload(data);\n    } catch (error) {\n      this.onerror({\n        error: error,\n        source: origin\n      });\n    } finally {\n      // reset loading flag\n      this.#isLoading = false;\n      this.onloadend({\n        source: origin\n      });\n    }\n  }\n\n  /**\n   * Abort load: pass to listeners.\n   */\n  abort() {\n    // reset loading flag\n    this.#isLoading = false;\n    // call listeners\n    this.onabort({});\n    this.onloadend({});\n  }\n\n  /**\n   * Check if the loader can load the provided file.\n   *\n   * @param {object} file The file to check.\n   * @returns {boolean} True if the file can be loaded.\n   */\n  canLoadFile(file) {\n    const ext = getFileExtension(file.name);\n    return (ext === 'json');\n  }\n\n  /**\n   * Check if the loader can load the provided url.\n   *\n   * @param {string} url The url to check.\n   * @param {object} [options] Optional url request options.\n   * @returns {boolean} True if the url can be loaded.\n   */\n  canLoadUrl(url, options) {\n    // if there are options.requestHeader, just base check on them\n    if (typeof options !== 'undefined' &&\n      typeof options.requestHeaders !== 'undefined') {\n      // starts with 'application/json' or 'application/dicom+json\n      const isJson = function (element) {\n        return element.name === 'Accept' &&\n          startsWith(element.value, 'application/json') &&\n          startsWith(element.value, 'application/dicom+json');\n      };\n      return typeof options.requestHeaders.find(isJson) !== 'undefined';\n    }\n\n    const urlObjext = getUrlFromUri(url);\n    const ext = getFileExtension(urlObjext.pathname);\n    return (ext === 'json');\n  }\n\n  /**\n   * Check if the loader can load the provided memory object.\n   *\n   * @param {object} mem The memory object.\n   * @returns {boolean} True if the object can be loaded.\n   */\n  canLoadMemory(mem) {\n    if (typeof mem['Content-Type'] !== 'undefined') {\n      if (mem['Content-Type'].includes('json')) {\n        return true;\n      }\n    }\n    if (typeof mem.filename !== 'undefined') {\n      return this.canLoadFile({name: mem.filename});\n    }\n    return false;\n  }\n\n  /**\n   * Get the file content type needed by the loader.\n   *\n   * @returns {number} One of the 'fileContentTypes'.\n   */\n  loadFileAs() {\n    return fileContentTypes.Text;\n  }\n\n  /**\n   * Get the url content type needed by the loader.\n   *\n   * @returns {number} One of the 'urlContentTypes'.\n   */\n  loadUrlAs() {\n    return urlContentTypes.Text;\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle an load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class JSONTextLoader\n","import {startsWith} from '../utils/string';\nimport {parseMultipart} from '../utils/array';\nimport {MemoryLoader} from './memoryLoader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Multipart data loader.\n */\nexport class MultipartLoader {\n\n  /**\n   * Loading flag.\n   *\n   * @type {boolean}\n   */\n  #isLoading = false;\n\n  /**\n   * Set the loader options.\n   *\n   * @param {object} _opt The input options.\n   */\n  setOptions(_opt) {\n    // does nothing\n  }\n\n  /**\n   * Is the load ongoing?\n   *\n   * @returns {boolean} True if loading.\n   */\n  isLoading() {\n    return this.#isLoading;\n  }\n\n  /**\n   * Load data.\n   *\n   * @param {object} buffer The DICOM buffer.\n   * @param {string} origin The data origin.\n   * @param {number} index The data index.\n   */\n  load(buffer, origin, index) {\n    // send start event\n    this.onloadstart({\n      source: origin\n    });\n    // set loading flag\n    this.#isLoading = true;\n\n    const memoryIO = new MemoryLoader();\n    // memoryIO.onloadstart: nothing to do\n    memoryIO.onprogress = (progress) => {\n      // add 50% to take into account the un-Multipartping\n      progress.loaded = 50 + progress.loaded / 2;\n      // set data index\n      progress.index = index;\n      this.onprogress(progress);\n    };\n    memoryIO.onloaditem = this.onloaditem;\n    memoryIO.onload = this.onload;\n    memoryIO.onloadend = (event) => {\n      // reset loading flag\n      this.#isLoading = false;\n      // call listeners\n      this.onloadend(event);\n    };\n    memoryIO.onerror = this.onerror;\n    memoryIO.onabort = this.onabort;\n    // launch\n    memoryIO.load(parseMultipart(buffer));\n  }\n\n  /**\n   * Abort load: pass to listeners.\n   */\n  abort() {\n    // reset loading flag\n    this.#isLoading = false;\n    // call listeners\n    this.onabort({});\n    this.onloadend({});\n  }\n\n  /**\n   * Check if the loader can load the provided file.\n   *\n   * @param {object} _file The file to check.\n   * @returns {boolean} True if the file can be loaded.\n   */\n  canLoadFile(_file) {\n    return false;\n  }\n\n  /**\n   * Check if the loader can load the provided url.\n   *\n   * @param {string} url The url to check.\n   * @param {object} [options] The url request options.\n   * @returns {boolean} True if the url can be loaded.\n   */\n  canLoadUrl(url, options) {\n    // if there are options.requestHeaders, just base check on them\n    if (typeof options !== 'undefined' &&\n      typeof options.requestHeaders !== 'undefined') {\n      const isMultipart = function (element) {\n        return element.name === 'Accept' &&\n          startsWith(element.value, 'multipart/related');\n      };\n      return typeof options.requestHeaders.find(isMultipart) !== 'undefined';\n    }\n\n    return false;\n  }\n\n  /**\n   * Check if the loader can load the provided memory object.\n   *\n   * @param {object} _mem The memory object.\n   * @returns {boolean} True if the url can be loaded.\n   */\n  canLoadMemory(_mem) {\n    return false;\n  }\n\n  /**\n   * Get the file content type needed by the loader.\n   *\n   * @returns {number} One of the 'fileContentTypes'.\n   */\n  loadFileAs() {\n    return fileContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Get the url content type needed by the loader.\n   *\n   * @returns {number} One of the 'urlContentTypes'.\n   */\n  loadUrlAs() {\n    return urlContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a load progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle an load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class MultipartLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {getViewFromDOMImage} from '../image/domReader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Raw image loader.\n */\nexport class RawImageLoader {\n\n  /**\n   * if abort is triggered, all image.onload callbacks have to be cancelled\n   *\n   * @type {boolean}\n   */\n  #aborted = false;\n\n  /**\n   * Set the loader options.\n   *\n   * @param {object} _opt The input options.\n   */\n  setOptions(_opt) {\n    // does nothing\n  }\n\n  /**\n   * Is the load ongoing? TODO...\n   *\n   * @returns {boolean} True if loading.\n   */\n  isLoading() {\n    return true;\n  }\n\n  /**\n   * Create a Data URI from an HTTP request response.\n   *\n   * @param {ArrayBuffer} response The HTTP request response.\n   * @param {string} dataType The data type.\n   * @returns {string} The data URI.\n   */\n  #createDataUri(response, dataType) {\n    // image type\n    let imageType = dataType;\n    if (!imageType || imageType === 'jpg') {\n      imageType = 'jpeg';\n    }\n    // create uri\n    const file = new Blob([response], {type: 'image/' + imageType});\n    return window.URL.createObjectURL(file);\n  }\n\n  /**\n   * Load data.\n   *\n   * @param {ArrayBuffer|string} buffer The read data.\n   * @param {string|File} origin The data origin.\n   * @param {number} index The data index.\n   */\n  load(buffer, origin, index) {\n    this.#aborted = false;\n    // create a DOM image\n    const image = new Image();\n    // triggered by ctx.drawImage\n    image.onload = (/*event*/) => {\n      try {\n        if (!this.#aborted) {\n          this.onprogress({\n            lengthComputable: true,\n            loaded: 100,\n            total: 100,\n            index: index,\n            source: origin\n          });\n          const data = getViewFromDOMImage(image, origin, index);\n          // only expecting one item\n          this.onloaditem(data);\n          this.onload(data);\n        }\n      } catch (error) {\n        this.onerror({\n          error: error,\n          source: origin\n        });\n      } finally {\n        this.onloadend({\n          source: origin\n        });\n      }\n    };\n    // storing values to pass them on\n    if (typeof buffer === 'string') {\n      // file case\n      image.src = buffer;\n    } else if (typeof origin === 'string') {\n      // url case\n      const ext = origin.split('.').pop().toLowerCase();\n      image.src = this.#createDataUri(buffer, ext);\n    }\n  }\n\n  /**\n   * Abort load.\n   */\n  abort() {\n    this.#aborted = true;\n    this.onabort({});\n    this.onloadend({});\n  }\n\n  /**\n   * Check if the loader can load the provided file.\n   *\n   * @param {object} file The file to check.\n   * @returns {boolean} True if the file can be loaded.\n   */\n  canLoadFile(file) {\n    return (typeof file.type !== 'undefined' &&\n      file.type.match('image.*'));\n  }\n\n  /**\n   * Check if the loader can load the provided url.\n   *\n   * @param {string} url The url to check.\n   * @param {object} [options] Optional url request options.\n   * @returns {boolean} True if the url can be loaded.\n   */\n  canLoadUrl(url, options) {\n    // if there are options.requestHeaders, just base check on them\n    if (typeof options !== 'undefined' &&\n      typeof options.requestHeaders !== 'undefined') {\n      // starts with 'image/'\n      const isImage = function (element) {\n        return element.name === 'Accept' &&\n          startsWith(element.value, 'image/');\n      };\n      return typeof options.requestHeaders.find(isImage) !== 'undefined';\n    }\n\n    const urlObjext = getUrlFromUri(url);\n    // extension\n    const ext = getFileExtension(urlObjext.pathname);\n    const hasImageExt = (ext === 'jpeg') || (ext === 'jpg') ||\n      (ext === 'png') || (ext === 'gif');\n    // content type (for wado url)\n    const contentType = urlObjext.searchParams.get('contentType');\n    const hasContentType = contentType !== null &&\n      typeof contentType !== 'undefined';\n    const hasImageContentType = (contentType === 'image/jpeg') ||\n      (contentType === 'image/png') ||\n      (contentType === 'image/gif');\n\n    return hasContentType ? hasImageContentType : hasImageExt;\n  }\n\n  /**\n   * Check if the loader can load the provided memory object.\n   *\n   * @param {object} mem The memory object.\n   * @returns {boolean} True if the object can be loaded.\n   */\n  canLoadMemory(mem) {\n    if (typeof mem.filename !== 'undefined') {\n      return this.canLoadFile({name: mem.filename});\n    }\n    return false;\n  }\n\n  /**\n   * Get the file content type needed by the loader.\n   *\n   * @returns {number} One of the 'fileContentTypes'.\n   */\n  loadFileAs() {\n    return fileContentTypes.DataURL;\n  }\n\n  /**\n   * Get the url content type needed by the loader.\n   *\n   * @returns {number} One of the 'urlContentTypes'.\n   */\n  loadUrlAs() {\n    return urlContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle an load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class RawImageLoader","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {getViewFromDOMVideo} from '../image/domReader';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\n\n/**\n * Raw video loader.\n * url example (cors enabled):\n *   https://raw.githubusercontent.com/clappr/clappr/master/test/fixtures/SampleVideo_360x240_1mb.mp4\n */\nexport class RawVideoLoader {\n\n  /**\n   * Set the loader options.\n   *\n   * @param {object} _opt The input options.\n   */\n  setOptions(_opt) {\n    // does nothing\n  }\n\n  /**\n   * Is the load ongoing? TODO...\n   *\n   * @returns {boolean} True if loading.\n   */\n  isLoading() {\n    return true;\n  }\n\n  /**\n   * Create a Data URI from an HTTP request response.\n   *\n   * @param {object} response The HTTP request response.\n   * @param {string} dataType The data type.\n   * @returns {string} The data URI.\n   */\n  #createDataUri(response, dataType) {\n    // image data as string\n    const bytes = new Uint8Array(response);\n    let videoDataStr = '';\n    for (let i = 0; i < bytes.byteLength; ++i) {\n      videoDataStr += String.fromCharCode(bytes[i]);\n    }\n    // create uri\n    const uri = 'data:video/' + dataType +\n      ';base64,' + window.btoa(videoDataStr);\n    return uri;\n  }\n\n  /**\n   * Internal Data URI load.\n   *\n   * @param {object} buffer The read data.\n   * @param {string} origin The data origin.\n   * @param {number} index The data index.\n   */\n  load(buffer, origin, index) {\n    // create a DOM video\n    const video = document.createElement('video');\n    if (typeof origin === 'string') {\n      // url case\n      const ext = origin.split('.').pop().toLowerCase();\n      video.src = this.#createDataUri(buffer, ext);\n    } else {\n      video.src = buffer;\n    }\n    // onload handler\n    video.onloadedmetadata = (event) => {\n      try {\n        getViewFromDOMVideo(event.target,\n          this.onloaditem, this.onload,\n          this.onprogress, this.onloadend,\n          origin, index);\n      } catch (error) {\n        this.onerror({\n          error: error,\n          source: origin\n        });\n        this.onloadend({\n          source: origin\n        });\n      }\n    };\n  }\n\n  /**\n   * Abort load.\n   */\n  abort() {\n    this.onabort({});\n    this.onloadend({});\n  }\n\n  /**\n   * Check if the loader can load the provided file.\n   *\n   * @param {object} file The file to check.\n   * @returns {boolean} True if the file can be loaded.\n   */\n  canLoadFile(file) {\n    return (typeof file.type !== 'undefined' &&\n      file.type.match('video.*'));\n  }\n\n  /**\n   * Check if the loader can load the provided url.\n   *\n   * @param {string} url The url to check.\n   * @param {object} [options] Optional url request options.\n   * @returns {boolean} True if the url can be loaded.\n   */\n  canLoadUrl(url, options) {\n    // if there are options.requestHeaders, just base check on them\n    if (typeof options !== 'undefined' &&\n      typeof options.requestHeaders !== 'undefined') {\n      // starts with 'video/'\n      const isVideo = function (element) {\n        return element.name === 'Accept' &&\n          startsWith(element.value, 'video/');\n      };\n      return typeof options.requestHeaders.find(isVideo) !== 'undefined';\n    }\n\n    const urlObjext = getUrlFromUri(url);\n    const ext = getFileExtension(urlObjext.pathname);\n    return (ext === 'mp4') ||\n      (ext === 'ogg') ||\n      (ext === 'webm');\n  }\n\n  /**\n   * Check if the loader can load the provided memory object.\n   *\n   * @param {object} mem The memory object.\n   * @returns {boolean} True if the object can be loaded.\n   */\n  canLoadMemory(mem) {\n    if (typeof mem.filename !== 'undefined') {\n      return this.canLoadFile({name: mem.filename});\n    }\n    return false;\n  }\n\n  /**\n   * Get the file content type needed by the loader.\n   *\n   * @returns {number} One of the 'fileContentTypes'.\n   */\n  loadFileAs() {\n    return fileContentTypes.DataURL;\n  }\n\n  /**\n   * Get the url content type needed by the loader.\n   *\n   * @returns {number} One of the 'urlContentTypes'.\n   */\n  loadUrlAs() {\n    return urlContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   * when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   * when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle an load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class RawVideoLoader\n","import {startsWith, getFileExtension} from '../utils/string';\nimport {getUrlFromUri} from '../utils/uri';\nimport {fileContentTypes} from './filesLoader';\nimport {urlContentTypes} from './urlsLoader';\nimport {MemoryLoader} from './memoryLoader';\n\n/**\n * The zip library.\n *\n * @external JSZip\n * @see https://github.com/Stuk/jszip\n */\nimport JSZip from 'jszip';\n\n/**\n * ZIP data loader.\n */\nexport class ZipLoader {\n\n  /**\n   * Loading flag.\n   *\n   * @type {boolean}\n   */\n  #isLoading = false;\n\n  /**\n   * Set the loader options.\n   *\n   * @param {object} _opt The input options.\n   */\n  setOptions(_opt) {\n    // does nothing\n  }\n\n  /**\n   * Is the load ongoing?\n   *\n   * @returns {boolean} True if loading.\n   */\n  isLoading() {\n    return this.#isLoading;\n  }\n\n  #filename = '';\n  #files = [];\n  #zobjs = null;\n\n  /**\n   * JSZip.async callback\n   *\n   * @param {ArrayBuffer} content unzipped file image\n   * @param {object} origin The origin of the file.\n   * @param {number} index The data index.\n   */\n  #zipAsyncCallback(content, origin, index) {\n    this.#files.push({filename: this.#filename, data: content});\n\n    // sent un-ziped progress with the data index\n    // (max 50% to take into account the memory loading)\n    const unzipPercent = this.#files.length * 100 / this.#zobjs.length;\n    this.onprogress({\n      lengthComputable: true,\n      loaded: (unzipPercent / 2),\n      total: 100,\n      index: index,\n      item: {\n        loaded: unzipPercent,\n        total: 100,\n        source: origin\n      }\n    });\n\n    // recursively call until we have all the files\n    if (this.#files.length < this.#zobjs.length) {\n      const num = this.#files.length;\n      this.#filename = this.#zobjs[num].name;\n      this.#zobjs[num].async('arrayBuffer').then((content) => {\n        this.#zipAsyncCallback(content, origin, index);\n      });\n    } else {\n      const memoryIO = new MemoryLoader();\n      // memoryIO.onloadstart: nothing to do\n      memoryIO.onprogress = (progress) => {\n        // add 50% to take into account the un-zipping\n        progress.loaded = 50 + progress.loaded / 2;\n        // set data index\n        progress.index = index;\n        this.onprogress(progress);\n      };\n      memoryIO.onloaditem = this.onloaditem;\n      memoryIO.onload = this.onload;\n      memoryIO.onloadend = (event) => {\n        // reset loading flag\n        this.#isLoading = false;\n        // call listeners\n        this.onloadend(event);\n      };\n      memoryIO.onerror = this.onerror;\n      memoryIO.onabort = this.onabort;\n      // launch\n      memoryIO.load(this.#files);\n    }\n  }\n\n  /**\n   * Load data.\n   *\n   * @param {object} buffer The DICOM buffer.\n   * @param {string} origin The data origin.\n   * @param {number} index The data index.\n   */\n  load(buffer, origin, index) {\n    // send start event\n    this.onloadstart({\n      source: origin\n    });\n    // set loading flag\n    this.#isLoading = true;\n\n    JSZip.loadAsync(buffer).then((zip) => {\n      this.#files = [];\n      this.#zobjs = zip.file(/.*\\.dcm/);\n      // recursively load zip files into the files array\n      const num = this.#files.length;\n      this.#filename = this.#zobjs[num].name;\n      this.#zobjs[num].async('arrayBuffer').then((content) => {\n        this.#zipAsyncCallback(content, origin, index);\n      });\n    });\n  }\n\n  /**\n   * Abort load: pass to listeners.\n   */\n  abort() {\n    // reset loading flag\n    this.#isLoading = false;\n    // call listeners\n    this.onabort({});\n    this.onloadend({});\n  }\n\n  /**\n   * Check if the loader can load the provided file.\n   *\n   * @param {object} file The file to check.\n   * @returns {boolean} True if the file can be loaded.\n   */\n  canLoadFile(file) {\n    const ext = getFileExtension(file.name);\n    return (ext === 'zip');\n  }\n\n  /**\n   * Check if the loader can load the provided url.\n   *\n   * @param {string} url The url to check.\n   * @param {object} [options] Optional url request options.\n   * @returns {boolean} True if the url can be loaded.\n   */\n  canLoadUrl(url, options) {\n    // if there are options.requestHeaders, just base check on them\n    if (typeof options !== 'undefined' &&\n      typeof options.requestHeaders !== 'undefined') {\n      // starts with 'application/zip'\n      const isZip = function (element) {\n        return element.name === 'Accept' &&\n          startsWith(element.value, 'application/zip');\n      };\n      return typeof options.requestHeaders.find(isZip) !== 'undefined';\n    }\n\n    const urlObjext = getUrlFromUri(url);\n    const ext = getFileExtension(urlObjext.pathname);\n    return (ext === 'zip');\n  }\n\n  /**\n   * Check if the loader can load the provided memory object.\n   *\n   * @param {object} mem The memory object.\n   * @returns {boolean} True if the object can be loaded.\n   */\n  canLoadMemory(mem) {\n    if (typeof mem['Content-Type'] !== 'undefined') {\n      if (mem['Content-Type'].includes('zip')) {\n        return true;\n      }\n    }\n    if (typeof mem.filename !== 'undefined') {\n      return this.canLoadFile({name: mem.filename});\n    }\n    return false;\n  }\n\n  /**\n   * Get the file content type needed by the loader.\n   *\n   * @returns {number} One of the 'fileContentTypes'.\n   */\n  loadFileAs() {\n    return fileContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Get the url content type needed by the loader.\n   *\n   * @returns {number} One of the 'urlContentTypes'.\n   */\n  loadUrlAs() {\n    return urlContentTypes.ArrayBuffer;\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a load progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle an load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class DicomDataLoader\n","import {MultiProgressHandler} from '../utils/progress';\nimport {loaderList} from './loaderList';\n\n// file content types\nexport const fileContentTypes = {\n  Text: 0,\n  ArrayBuffer: 1,\n  DataURL: 2\n};\n\n/**\n * Files loader.\n */\nexport class FilesLoader {\n\n  /**\n   * Input data.\n   *\n   * @type {Array}\n   */\n  #inputData = null;\n\n  /**\n   * Array of launched file readers.\n   *\n   * @type {Array}\n   */\n  #readers = [];\n\n  /**\n   * Data loader.\n   *\n   * @type {object}\n   */\n  #runningLoader = null;\n\n  /**\n   * Number of loaded data.\n   *\n   * @type {number}\n   */\n  #nLoad = 0;\n\n  /**\n   * Number of load end events.\n   *\n   * @type {number}\n   */\n  #nLoadend = 0;\n\n  /**\n   * The default character set (optional).\n   *\n   * @type {string}\n   */\n  #defaultCharacterSet;\n\n  /**\n   * Get the default character set.\n   *\n   * @returns {string} The default character set.\n   */\n  getDefaultCharacterSet() {\n    return this.#defaultCharacterSet;\n  }\n\n  /**\n   * Set the default character set.\n   *\n   * @param {string} characterSet The character set.\n   */\n  setDefaultCharacterSet(characterSet) {\n    this.#defaultCharacterSet = characterSet;\n  }\n\n  /**\n   * Store the current input.\n   *\n   * @param {object} data The input data.\n   */\n  #storeInputData(data) {\n    this.#inputData = data;\n    // reset counters\n    this.#nLoad = 0;\n    this.#nLoadend = 0;\n    // clear storage\n    this.#clearStoredReaders();\n    this.#clearStoredLoader();\n  }\n\n  /**\n   * Store a launched reader.\n   *\n   * @param {object} reader The launched reader.\n   */\n  #storeReader(reader) {\n    this.#readers.push(reader);\n  }\n\n  /**\n   * Clear the stored readers.\n   *\n   */\n  #clearStoredReaders() {\n    this.#readers = [];\n  }\n\n  /**\n   * Store the launched loader.\n   *\n   * @param {object} loader The launched loader.\n   */\n  #storeLoader(loader) {\n    this.#runningLoader = loader;\n  }\n\n  /**\n   * Clear the stored loader.\n   *\n   */\n  #clearStoredLoader() {\n    this.#runningLoader = null;\n  }\n\n  /**\n   * Increment the number of loaded data\n   *   and call onload if loaded all data.\n   *\n   * @param {object} _event The load data event.\n   */\n  #addLoad = (_event) => {\n    this.#nLoad++;\n    // call onload when all is loaded\n    // (not using the input event since it is not the\n    //   general load)\n    if (this.#nLoad === this.#inputData.length) {\n      this.onload({\n        source: this.#inputData\n      });\n    }\n  };\n\n  /**\n   * Increment the counter of load end events\n   *   and run callbacks when all done, erroneus or not.\n   *\n   * @param {object} _event The load end event.\n   */\n  #addLoadend = (_event) => {\n    this.#nLoadend++;\n    // call onloadend when all is run\n    // (not using the input event since it is not the\n    //   general load end)\n    // x2 to count for reader + load\n    if (this.#nLoadend === 2 * this.#inputData.length) {\n      this.onloadend({\n        source: this.#inputData\n      });\n    }\n  };\n\n  /**\n   * @callback eventFn\n   * @param {object} event The event.\n   */\n\n  /**\n   * Augment a callback event with a srouce.\n   *\n   * @param {object} callback The callback to augment its event.\n   * @param {object} source The source to add to the event.\n   * @returns {eventFn} The augmented callback.\n   */\n  #augmentCallbackEvent(callback, source) {\n    return (event) => {\n      event.source = source;\n      callback(event);\n    };\n  }\n\n  /**\n   * Get a load handler for a data element.\n   *\n   * @param {object} loader The associated loader.\n   * @param {object} dataElement The data element.\n   * @param {number} i The index of the element.\n   * @returns {eventFn} A load handler.\n   */\n  #getLoadHandler(loader, dataElement, i) {\n    return (event) => {\n      loader.load(event.target.result, dataElement, i);\n    };\n  }\n\n\n  /**\n   * Load a list of files.\n   *\n   * @param {Array} data The list of files to load.\n   */\n  load(data) {\n    // check input\n    if (typeof data === 'undefined' || data.length === 0) {\n      return;\n    }\n    this.#storeInputData(data);\n\n    // send start event\n    this.onloadstart({\n      source: data\n    });\n\n    // create prgress handler\n    const mproghandler = new MultiProgressHandler(this.onprogress);\n    mproghandler.setNToLoad(data.length);\n\n    // create loaders\n    const loaders = [];\n    for (let m = 0; m < loaderList.length; ++m) {\n      loaders.push(new loaderList[m]());\n    }\n\n    // find an appropriate loader\n    let dataElement = data[0];\n    let loader = null;\n    let foundLoader = false;\n    for (let l = 0; l < loaders.length; ++l) {\n      loader = loaders[l];\n      if (loader.canLoadFile(dataElement)) {\n        foundLoader = true;\n        // load options\n        loader.setOptions({\n          numberOfFiles: data.length,\n          defaultCharacterSet: this.getDefaultCharacterSet()\n        });\n        // set loader callbacks\n        // loader.onloadstart: nothing to do\n        loader.onprogress = mproghandler.getUndefinedMonoProgressHandler(1);\n        loader.onloaditem = this.onloaditem;\n        loader.onload = this.#addLoad;\n        loader.onloadend = this.#addLoadend;\n        loader.onerror = this.onerror;\n        loader.onabort = this.onabort;\n\n        // store loader\n        this.#storeLoader(loader);\n        // exit\n        break;\n      }\n    }\n    if (!foundLoader) {\n      throw new Error('No loader found for file: ' + dataElement.name);\n    }\n\n    // loop on I/O elements\n    for (let i = 0; i < data.length; ++i) {\n      dataElement = data[i];\n\n      // check loader\n      if (!loader.canLoadFile(dataElement)) {\n        throw new Error('Input file of different type: ' + dataElement);\n      }\n\n      /**\n       * The file reader.\n       *\n       * @external FileReader\n       * @see https://developer.mozilla.org/en-US/docs/Web/API/FileReader\n       */\n      const reader = new FileReader();\n      // store reader\n      this.#storeReader(reader);\n\n      // set reader callbacks\n      // reader.onloadstart: nothing to do\n      reader.onprogress = this.#augmentCallbackEvent(\n        mproghandler.getMonoProgressHandler(i, 0), dataElement);\n      reader.onload = this.#getLoadHandler(loader, dataElement, i);\n      reader.onloadend = this.#addLoadend;\n      reader.onerror = this.#augmentCallbackEvent(this.onerror, dataElement);\n      reader.onabort = this.#augmentCallbackEvent(this.onabort, dataElement);\n      // read\n      if (loader.loadFileAs() === fileContentTypes.Text) {\n        reader.readAsText(dataElement);\n      } else if (loader.loadFileAs() === fileContentTypes.DataURL) {\n        reader.readAsDataURL(dataElement);\n      } else if (loader.loadFileAs() === fileContentTypes.ArrayBuffer) {\n        reader.readAsArrayBuffer(dataElement);\n      }\n    }\n  }\n\n  /**\n   * Abort a load.\n   */\n  abort() {\n    // abort readers\n    for (let i = 0; i < this.#readers.length; ++i) {\n      // 0: EMPTY, 1: LOADING, 2: DONE\n      if (this.#readers[i].readyState === 1) {\n        this.#readers[i].abort();\n      }\n    }\n    // abort loader\n    if (this.#runningLoader && this.#runningLoader.isLoading()) {\n      this.#runningLoader.abort();\n    }\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a load progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load item event fired\n   *   when a file item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle a load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class FilesLoader\n","import {FilesLoader} from '../io/filesLoader';\nimport {MemoryLoader} from '../io/memoryLoader';\nimport {UrlsLoader} from '../io/urlsLoader';\n\n/**\n * Load controller.\n */\nexport class LoadController {\n\n  /**\n   * The default character set.\n   *\n   * @type {string}\n   */\n  #defaultCharacterSet;\n\n  /**\n   * List of current loaders.\n   *\n   * @type {object}\n   */\n  #currentLoaders = {};\n\n  /**\n   * load counter.\n   *\n   * @type {number}\n   */\n  #counter = -1;\n\n  /**\n   * @param {string} defaultCharacterSet The default character set.\n   */\n  constructor(defaultCharacterSet) {\n    this.#defaultCharacterSet = defaultCharacterSet;\n  }\n\n  /**\n   * Get the next load id.\n   *\n   * @returns {number} The next id.\n   */\n  #getNextLoadId() {\n    ++this.#counter;\n    return this.#counter;\n  }\n\n  /**\n   * Load a list of files. Can be image files or a state file.\n   *\n   * @param {File[]} files The list of files to load.\n   */\n  loadFiles(files) {\n    // has been checked for emptiness.\n    const ext = files[0].name.split('.').pop().toLowerCase();\n    if (ext === 'json') {\n      this.#loadStateFile(files[0]);\n    } else {\n      this.#loadImageFiles(files);\n    }\n  }\n\n  /**\n   * Load a list of URLs. Can be image files or a state file.\n   *\n   * @param {string[]} urls The list of urls to load.\n   * @param {object} [options] The load options:\n   * - requestHeaders: an array of {name, value} to use as request headers.\n   * - withCredentials: credentials flag to pass to the request.\n   */\n  loadURLs(urls, options) {\n    // has been checked for emptiness.\n    const ext = urls[0].split('.').pop().toLowerCase();\n    if (ext === 'json') {\n      this.#loadStateUrl(urls[0], options);\n    } else {\n      this.#loadImageUrls(urls, options);\n    }\n  }\n\n  /**\n   * Load a list of ArrayBuffers.\n   *\n   * @param {Array} data The list of ArrayBuffers to load\n   *   in the form of [{name: \"\", filename: \"\", data: data}].\n   */\n  loadImageObject(data) {\n    // create IO\n    const memoryIO = new MemoryLoader();\n    // load data\n    this.#loadData(data, memoryIO, 'image');\n  }\n\n  /**\n   * Abort the current loaders.\n   */\n  abort() {\n    const keys = Object.keys(this.#currentLoaders);\n    for (let i = 0; i < keys.length; ++i) {\n      this.#currentLoaders[i].loader.abort();\n      delete this.#currentLoaders[i];\n    }\n  }\n\n  // private ----------------------------------------------------------------\n\n  /**\n   * Load a list of image files.\n   *\n   * @param {File[]} files The list of image files to load.\n   */\n  #loadImageFiles(files) {\n    // create IO\n    const fileIO = new FilesLoader();\n    fileIO.setDefaultCharacterSet(this.#defaultCharacterSet);\n    // load data\n    this.#loadData(files, fileIO, 'image');\n  }\n\n  /**\n   * Load a list of image URLs.\n   *\n   * @param {string[]} urls The list of urls to load.\n   * @param {object} [options] The load options:\n   * - requestHeaders: an array of {name, value} to use as request headers.\n   * - withCredentials: credentials flag to pass to the request.\n   */\n  #loadImageUrls(urls, options) {\n    // create IO\n    const urlIO = new UrlsLoader();\n    urlIO.setDefaultCharacterSet(this.#defaultCharacterSet);\n    // load data\n    this.#loadData(urls, urlIO, 'image', options);\n  }\n\n  /**\n   * Load a State file.\n   *\n   * @param {File} file The state file to load.\n   */\n  #loadStateFile(file) {\n    // create IO\n    const fileIO = new FilesLoader();\n    // load data\n    this.#loadData([file], fileIO, 'state');\n  }\n\n  /**\n   * Load a State url.\n   *\n   * @param {string} url The state url to load.\n   * @param {object} [options] The load options:\n   * - requestHeaders: an array of {name, value} to use as request headers.\n   * - withCredentials: credentials flag to pass to the request.\n   */\n  #loadStateUrl(url, options) {\n    // create IO\n    const urlIO = new UrlsLoader();\n    // load data\n    this.#loadData([url], urlIO, 'state', options);\n  }\n\n  /**\n   * Load a list of data.\n   *\n   * @param {string[]|File[]|Array} data Array of data to load.\n   * @param {object} loader The data loader.\n   * @param {string} loadType The data load type: 'image' or 'state'.\n   * @param {object} [options] Options passed to the final loader.\n   */\n  #loadData(data, loader, loadType, options) {\n    const eventInfo = {\n      loadtype: loadType,\n    };\n\n    // load id\n    const loadId = this.#getNextLoadId();\n    eventInfo.loadid = loadId;\n\n    // set callbacks\n    loader.onloadstart = (event) => {\n      // store loader to allow abort\n      this.#currentLoaders[loadId] = {\n        loader: loader,\n        isFirstItem: true\n      };\n      // callback\n      this.#augmentCallbackEvent(this.onloadstart, eventInfo)(event);\n    };\n    loader.onprogress = this.#augmentCallbackEvent(this.onprogress, eventInfo);\n    loader.onloaditem = (event) => {\n      const eventInfoItem = {\n        loadtype: loadType,\n        loadid: loadId\n      };\n      if (typeof this.#currentLoaders[loadId] !== 'undefined') {\n        eventInfoItem.isfirstitem = this.#currentLoaders[loadId].isFirstItem;\n      }\n      // callback\n      this.#augmentCallbackEvent(this.onloaditem, eventInfoItem)(event);\n      // update loader\n      if (typeof this.#currentLoaders[loadId] !== 'undefined' &&\n        this.#currentLoaders[loadId].isFirstItem) {\n        this.#currentLoaders[loadId].isFirstItem = false;\n      }\n    };\n    loader.onload = this.#augmentCallbackEvent(this.onload, eventInfo);\n    loader.onloadend = (event) => {\n      // reset current loader\n      delete this.#currentLoaders[loadId];\n      // callback\n      this.#augmentCallbackEvent(this.onloadend, eventInfo)(event);\n    };\n    loader.onerror = this.#augmentCallbackEvent(this.onerror, eventInfo);\n    loader.onabort = this.#augmentCallbackEvent(this.onabort, eventInfo);\n    // launch load\n    try {\n      loader.load(data, options);\n    } catch (error) {\n      this.onerror({\n        error: error,\n        loadid: loadId\n      });\n      this.onloadend({\n        loadid: loadId\n      });\n      return;\n    }\n  }\n\n  /**\n   * Augment a callback event: adds loadtype to the event\n   *  passed to a callback.\n   *\n   * @param {object} callback The callback to update.\n   * @param {object} info Info object to append to the event.\n   * @returns {object} A function representing the modified callback.\n   */\n  #augmentCallbackEvent(callback, info) {\n    return function (event) {\n      const keys = Object.keys(info);\n      for (let i = 0; i < keys.length; ++i) {\n        const key = keys[i];\n        event[key] = info[key];\n      }\n      callback(event);\n    };\n  }\n\n  /**\n   * Handle a load start event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load start event.\n   */\n  onloadstart(_event) {}\n\n  /**\n   * Handle a load progress event.\n   * Default does nothing.\n   *\n   * @param {object} _event The progress event.\n   */\n  onprogress(_event) {}\n\n  /**\n   * Handle a load event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when a file has been loaded successfully.\n   */\n  onload(_event) {}\n\n  /**\n   * Handle a load item event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load event fired\n   *   when an item has been loaded successfully.\n   */\n  onloaditem(_event) {}\n\n  /**\n   * Handle a load end event.\n   * Default does nothing.\n   *\n   * @param {object} _event The load end event fired\n   *  when a file load has completed, successfully or not.\n   */\n  onloadend(_event) {}\n\n  /**\n   * Handle an error event.\n   * Default does nothing.\n   *\n   * @param {object} _event The error event.\n   */\n  onerror(_event) {}\n\n  /**\n   * Handle an abort event.\n   * Default does nothing.\n   *\n   * @param {object} _event The abort event.\n   */\n  onabort(_event) {}\n\n} // class LoadController\n","import {ListenerHandler} from '../utils/listen';\nimport {mergeObjects} from '../utils/operator';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from '../image/image';\n/* eslint-enable no-unused-vars */\n\n/*\n * Data (list of {image, meta}) controller.\n */\nexport class DataController {\n\n  /**\n   * List of {image, meta}.\n   *\n   * @type {object}\n   */\n  #data = {};\n\n  /**\n   * Listener handler.\n   *\n   * @type {ListenerHandler}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Get the length of the data storage.\n   *\n   * @returns {number} The length.\n   */\n  length() {\n    return Object.keys(this.#data).length;\n  }\n\n  /**\n   * Reset the class: empty the data storage.\n   */\n  reset() {\n    this.#data = [];\n  }\n\n  /**\n   * Get a data at a given index.\n   *\n   * @param {number} index The index of the data.\n   * @returns {object} The data.\n   */\n  get(index) {\n    return this.#data[index];\n  }\n\n  /**\n   * Set the image at a given index.\n   *\n   * @param {number} index The index of the data.\n   * @param {Image} image The image to set.\n   */\n  setImage(index, image) {\n    this.#data[index].image = image;\n    // fire image set\n    this.#fireEvent({\n      type: 'imageset',\n      value: [image],\n      dataid: index\n    });\n    // listen to image change\n    image.addEventListener('imagechange', this.#getFireEvent(index));\n  }\n\n  /**\n   * Add a new data.\n   *\n   * @param {number} index The index of the data.\n   * @param {Image} image The image.\n   * @param {object} meta The image meta.\n   */\n  addNew(index, image, meta) {\n    if (typeof this.#data[index] !== 'undefined') {\n      throw new Error('Index already used in storage: ' + index);\n    }\n    // store the new image\n    this.#data[index] = {\n      image: image,\n      meta: meta\n    };\n    // listen to image change\n    image.addEventListener('imagechange', this.#getFireEvent(index));\n  }\n\n  /**\n   * Update the current data.\n   *\n   * @param {number} index The index of the data.\n   * @param {Image} image The image.\n   * @param {object} meta The image meta.\n   */\n  update(index, image, meta) {\n    const dataToUpdate = this.#data[index];\n\n    // add slice to current image\n    dataToUpdate.image.appendSlice(image);\n\n    // update meta data\n    // TODO add time support\n    let idKey = '';\n    if (typeof meta['00020010'] !== 'undefined') {\n      // dicom case, use 'InstanceNumber'\n      idKey = '00200013';\n    } else {\n      idKey = 'imageUid';\n    }\n    dataToUpdate.meta = mergeObjects(\n      dataToUpdate.meta,\n      meta,\n      idKey,\n      'value');\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  /**\n   * Get a fireEvent function that adds the input index\n   * to the event value.\n   *\n   * @param {number} index The data index.\n   * @returns {Function} A fireEvent function.\n   */\n  #getFireEvent(index) {\n    return (event) => {\n      event.dataid = index;\n      this.#fireEvent(event);\n    };\n  }\n\n} // ImageController class\n","import {arrayEquals} from './array';\n\n/**\n * Merge two similar objects.\n * Objects need to be in the form of:\n * <code>\n * {\n *   idKey: {valueKey: [0]},\n *   key0: {valueKey: [\"abc\"]},\n *   key1: {valueKey: [33]}\n * }\n * </code>\n * Merged objects will be in the form of:\n * <code>\n * {\n *   idKey: {valueKey: [0,1,2], merged: true},\n *   key0: {valueKey: {\n *     0: [\"abc\"],\n *     1: [\"def\"],\n *     2: [\"ghi\"]\n *   }},\n *   key1: {valueKey: {\n *     0: [33],\n *     1: [44],\n *     2: [55]\n *   }}\n * }\n * </code>\n *\n * @param {object} obj1 The first object, can be the result of a previous merge.\n * @param {object} obj2 The second object.\n * @param {string} idKey The key to use as index for duplicate values.\n * @param {string} valueKey The key to use to access object values.\n * @returns {object} The merged object.\n */\nexport function mergeObjects(obj1, obj2, idKey, valueKey) {\n  const res = {};\n  // check id key\n  if (!idKey) {\n    throw new Error('Cannot merge object with an undefined id key: ' + idKey);\n  } else {\n    if (!Object.prototype.hasOwnProperty.call(obj1, idKey)) {\n      throw new Error('Id key not found in first object while merging: ' +\n        idKey + ', obj: ' + obj1);\n    }\n    if (!Object.prototype.hasOwnProperty.call(obj2, idKey)) {\n      throw new Error('Id key not found in second object while merging: ' +\n        idKey + ', obj: ' + obj2);\n    }\n  }\n  // check value key\n  if (!valueKey) {\n    throw new Error('Cannot merge object with an undefined value key: ' +\n      valueKey);\n  }\n\n  // check if merged object\n  let mergedObj1 = false;\n  if (Object.prototype.hasOwnProperty.call(obj1[idKey], 'merged') &&\n    obj1[idKey].merged) {\n    mergedObj1 = true;\n  }\n  // handle the id part\n  if (!Object.prototype.hasOwnProperty.call(obj1[idKey], valueKey)) {\n    throw new Error('Id value not found in first object while merging: ' +\n      idKey + ', valueKey: ' + valueKey + ', ojb: ' + obj1);\n  }\n  if (!Object.prototype.hasOwnProperty.call(obj2[idKey], valueKey)) {\n    throw new Error('Id value not found in second object while merging: ' +\n      idKey + ', valueKey: ' + valueKey + ', ojb: ' + obj2);\n  }\n  let id1 = obj1[idKey][valueKey];\n  const id2 = obj2[idKey][valueKey][0];\n  // update id key\n  res[idKey] = obj1[idKey];\n  if (mergedObj1) {\n    // check if array does not include id2\n    for (let k = 0; k < id1.length; ++k) {\n      if (id1[k] === id2) {\n        throw new Error('The first object already contains id2: ' +\n          id2 + ', id1: ' + id1);\n      }\n    }\n    res[idKey][valueKey].push(id2);\n  } else {\n    id1 = id1[0];\n    if (id1 === id2) {\n      throw new Error('Cannot merge object with same ids: ' +\n        id1 + ', id2: ' + id2);\n    }\n    // update merge object\n    res[idKey][valueKey].push(id2);\n    res[idKey].merged = true;\n  }\n\n  // get keys\n  const keys1 = Object.keys(obj1);\n  // keys2 without duplicates of keys1\n  const keys2 = Object.keys(obj2).filter(function (item) {\n    return keys1.indexOf(item) < 0;\n  });\n  const keys = keys1.concat(keys2);\n\n  // loop through keys\n  for (let i = 0; i < keys.length; ++i) {\n    const key = keys[i];\n    if (key !== idKey) {\n      // first\n      let value1;\n      let subValue1;\n      if (Object.prototype.hasOwnProperty.call(obj1, key)) {\n        value1 = obj1[key];\n        if (Object.prototype.hasOwnProperty.call(value1, valueKey)) {\n          subValue1 = value1[valueKey];\n        }\n      }\n      // second\n      let value2;\n      let subValue2;\n      if (Object.prototype.hasOwnProperty.call(obj2, key)) {\n        value2 = obj2[key];\n        if (Object.prototype.hasOwnProperty.call(value2, valueKey)) {\n          subValue2 = value2[valueKey];\n        }\n      }\n      // result value\n      let value;\n      // use existing to copy properties\n      if (typeof value1 !== 'undefined') {\n        value = value1;\n      } else if (typeof value2 !== 'undefined') {\n        value = value2;\n      }\n      // create merge object if different values\n      if (!arrayEquals(subValue1, subValue2)) {\n        // add to merged object or create new\n        if (mergedObj1) {\n          if (Array.isArray(subValue1)) {\n            // merged object with repeated value\n            // copy it with the index list\n            value[valueKey] = {};\n            for (let j = 0; j < id1.length; ++j) {\n              value[valueKey][id1[j]] = subValue1;\n            }\n          } else {\n            value[valueKey] = subValue1;\n          }\n          // add obj2 value\n          value[valueKey][id2] = subValue2;\n        } else {\n          // create merge object\n          const newValue = {};\n          newValue[id1] = subValue1;\n          newValue[id2] = subValue2;\n          value[valueKey] = newValue;\n        }\n      }\n      // store value in result object\n      res[key] = value;\n    }\n  }\n  return res;\n}\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Scroll wheel class: provides a wheel event handler\n *   that scroll the corresponding data.\n */\nexport class ScrollWheel {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * Accumulated wheel event deltaY.\n   *\n   * @type {number}\n   */\n  #wheelDeltaY = 0;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Handle mouse wheel event.\n   *\n   * @param {object} event The mouse wheel event.\n   */\n  wheel(event) {\n    // deltaMode (deltaY values on my machine...):\n    // - 0 (DOM_DELTA_PIXEL): chrome, deltaY mouse scroll = 53\n    // - 1 (DOM_DELTA_LINE): firefox, deltaY mouse scroll = 6\n    // - 2 (DOM_DELTA_PAGE): ??\n    // TODO: check scroll event\n    let scrollMin = 52;\n    if (event.deltaMode === 1) {\n      scrollMin = 5.99;\n    }\n    this.#wheelDeltaY += event.deltaY;\n    if (Math.abs(this.#wheelDeltaY) < scrollMin) {\n      return;\n    } else {\n      this.#wheelDeltaY = 0;\n    }\n\n    // prevent default page scroll\n    event.preventDefault();\n\n    const up = event.deltaY < 0 ? true : false;\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n    const imageSize = viewController.getImageSize();\n    if (imageSize.canScroll3D()) {\n      if (up) {\n        viewController.incrementScrollIndex();\n      } else {\n        viewController.decrementScrollIndex();\n      }\n    } else if (imageSize.moreThanOne(3)) {\n      if (up) {\n        viewController.incrementIndex(3);\n      } else {\n        viewController.decrementIndex(3);\n      }\n    }\n  }\n\n} // ScrollWheel class\n","/**\n * Namespace for translation function.\n * (in a namespace to allow for override from client)\n */\nexport const i18n = {\n\n  /**\n   * Get the translated text.\n   *\n   * @param {string} key The key to the text entry.\n   * @returns {string|undefined} The translated text.\n   */\n  t(key) {\n    // defaut expects something like 'unit.cm2'\n    const unit = {\n      mm: 'mm',\n      cm2: 'cm²',\n      degree: '°'\n    };\n    const props = key.split('.');\n    if (props.length !== 2) {\n      throw new Error('Unexpected translation key length.');\n    }\n    if (props[0] !== 'unit') {\n      throw new Error('Unexpected translation key prefix.');\n    }\n    return unit[props[1]];\n  }\n\n};\n","import {Point2D} from './point';\nimport {i18n} from '../utils/i18n';\n\n/**\n * Line shape.\n */\nexport class Line {\n\n  /**\n   * Line begin point.\n   *\n   * @type {Point2D}\n   */\n  #begin;\n\n  /**\n   * Line end point.\n   *\n   * @type {Point2D}\n   */\n  #end;\n\n  /**\n   * @param {Point2D} begin A Point2D representing the beginning\n   *   of the line.\n   * @param {Point2D} end A Point2D representing the end of the line.\n   */\n  constructor(begin, end) {\n    this.#begin = begin;\n    this.#end = end;\n  }\n\n  /**\n   * Get the begin point of the line.\n   *\n   * @returns {Point2D} The beginning point of the line.\n   */\n  getBegin() {\n    return this.#begin;\n  }\n\n  /**\n   * Get the end point of the line.\n   *\n   * @returns {Point2D} The ending point of the line.\n   */\n  getEnd() {\n    return this.#end;\n  }\n\n  /**\n   * Check for equality.\n   *\n   * @param {Line} rhs The object to compare to.\n   * @returns {boolean} True if both objects are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getBegin().equals(rhs.getBegin()) &&\n      this.getEnd().equals(rhs.getEnd());\n  }\n\n  /**\n   * Get the line delta in the X direction.\n   *\n   * @returns {number} The delta in the X direction.\n   */\n  getDeltaX() {\n    return this.getEnd().getX() - this.getBegin().getX();\n  }\n\n  /**\n   * Get the line delta in the Y direction.\n   *\n   * @returns {number} The delta in the Y direction.\n   */\n  getDeltaY() {\n    return this.getEnd().getY() - this.getBegin().getY();\n  }\n\n  /**\n   * Get the length of the line.\n   *\n   * @returns {number} The length of the line.\n   */\n  getLength() {\n    return Math.sqrt(\n      this.getDeltaX() * this.getDeltaX() +\n      this.getDeltaY() * this.getDeltaY()\n    );\n  }\n\n  /**\n   * Get the length of the line according to a  spacing.\n   *\n   * @param {number} spacingX The X spacing.\n   * @param {number} spacingY The Y spacing.\n   * @returns {number} The length of the line with spacing\n   *  or null for null spacings.\n   */\n  getWorldLength(spacingX, spacingY) {\n    let wlen = null;\n    if (spacingX !== null && spacingY !== null) {\n      const dxs = this.getDeltaX() * spacingX;\n      const dys = this.getDeltaY() * spacingY;\n      wlen = Math.sqrt(dxs * dxs + dys * dys);\n    }\n    return wlen;\n  }\n\n  /**\n   * Get the mid point of the line.\n   *\n   * @returns {Point2D} The mid point of the line.\n   */\n  getMidpoint() {\n    return new Point2D(\n      (this.getBegin().getX() + this.getEnd().getX()) / 2,\n      (this.getBegin().getY() + this.getEnd().getY()) / 2\n    );\n  }\n\n  /**\n   * Get the slope of the line.\n   *\n   * @returns {number} The slope of the line.\n   */\n  getSlope() {\n    return this.getDeltaY() / this.getDeltaX();\n  }\n\n  /**\n   * Get the intercept of the line.\n   *\n   * @returns {number} The slope of the line.\n   */\n  getIntercept() {\n    return (\n      this.getEnd().getX() * this.getBegin().getY() -\n      this.getBegin().getX() * this.getEnd().getY()\n    ) / this.getDeltaX();\n  }\n\n  /**\n   * Get the inclination of the line.\n   *\n   * @returns {number} The inclination of the line.\n   */\n  getInclination() {\n    // tan(theta) = slope\n    const angle =\n      Math.atan2(this.getDeltaY(), this.getDeltaX()) * 180 / Math.PI;\n    // shift?\n    return 180 - angle;\n  }\n\n  /**\n   * Quantify a line according to view information.\n   *\n   * @param {object} viewController The associated view controller.\n   * @returns {object} A quantification object.\n   */\n  quantify(viewController) {\n    const quant = {};\n    // length\n    const spacing = viewController.get2DSpacing();\n    const length = this.getWorldLength(spacing[0], spacing[1]);\n    if (length !== null) {\n      quant.length = {value: length, unit: i18n.t('unit.mm')};\n    }\n    // return\n    return quant;\n  }\n\n} // Line class\n\n/**\n * Get the angle between two lines in degree.\n *\n * @param {Line} line0 The first line.\n * @param {Line} line1 The second line.\n * @returns {number} The angle.\n */\nexport function getAngle(line0, line1) {\n  const dx0 = line0.getDeltaX();\n  const dy0 = line0.getDeltaY();\n  const dx1 = line1.getDeltaX();\n  const dy1 = line1.getDeltaY();\n  // dot = ||a||*||b||*cos(theta)\n  const dot = dx0 * dx1 + dy0 * dy1;\n  // cross = ||a||*||b||*sin(theta)\n  const det = dx0 * dy1 - dy0 * dx1;\n  // tan = sin / cos\n  const angle = Math.atan2(det, dot) * 180 / Math.PI;\n  // complementary angle\n  // shift?\n  return 360 - (180 - angle);\n}\n\n/**\n * Get a perpendicular line to an input one.\n *\n * @param {Line} line The line to be perpendicular to.\n * @param {Point2D} point The middle point of the perpendicular line.\n * @param {number} length The length of the perpendicular line.\n * @returns {object} A perpendicular line.\n */\nexport function getPerpendicularLine(line, point, length) {\n  // begin point\n  let beginX = 0;\n  let beginY = 0;\n  // end point\n  let endX = 0;\n  let endY = 0;\n\n  // check slope:\n  // 0 -> horizontal\n  // Infinite -> vertical (a/Infinite = 0)\n  if (line.getSlope() !== 0) {\n    // a0 * a1 = -1\n    const slope = -1 / line.getSlope();\n    // y0 = a1*x0 + b1 -> b1 = y0 - a1*x0\n    const intercept = point.getY() - slope * point.getX();\n\n    // 1. (x - x0)^2 + (y - y0)^2 = d^2\n    // 2. a = (y - y0) / (x - x0) -> y = a*(x - x0) + y0\n    // ->  (x - x0)^2 + m^2 * (x - x0)^2 = d^2\n    // -> x = x0 +- d / sqrt(1+m^2)\n\n    // length is the distance between begin and end,\n    // point is half way between both -> d = length / 2\n    const dx = length / (2 * Math.sqrt(1 + slope * slope));\n\n    // begin point\n    beginX = point.getX() - dx;\n    beginY = slope * beginX + intercept;\n    // end point\n    endX = point.getX() + dx;\n    endY = slope * endX + intercept;\n  } else {\n    // horizontal input line -> perpendicular is vertical!\n    // begin point\n    beginX = point.getX();\n    beginY = point.getY() - length / 2;\n    // end point\n    endX = point.getX();\n    endY = point.getY() + length / 2;\n  }\n  // perpendicalar line\n  return new Line(\n    new Point2D(beginX, beginY),\n    new Point2D(endX, endY));\n}\n","/**\n * Get the minimum, maximum, mean and standard deviation\n * of an array of values.\n * Note: could use {@link https://github.com/tmcw/simple-statistics}.\n *\n * @param {Array} array The array of values to extract stats from.\n * @param {Array} flags A list of stat values to calculate.\n * @returns {object} A stats object.\n */\nexport function getStats(array, flags) {\n  if (includesFullStatsFlags(flags)) {\n    return getFullStats(array);\n  } else {\n    return getSimpleStats(array);\n  }\n}\n\n/**\n * Does the input flag list contain a full stat element?\n *\n * @param {Array} flags A list of stat values to calculate.\n * @returns {boolean} True if one of the flags is a full stat flag.\n */\nfunction includesFullStatsFlags(flags) {\n  return typeof flags !== 'undefined' &&\n    flags !== null &&\n    (flags.includes('median') ||\n    flags.includes('p25') ||\n    flags.includes('p75'));\n}\n\n/**\n * Get simple stats: minimum, maximum, mean and standard deviation\n * of an array of values.\n *\n * @param {Array} array The array of values to extract stats from.\n * @returns {object} A simple stats object.\n */\nfunction getSimpleStats(array) {\n  let min = array[0];\n  let max = min;\n  let sum = 0;\n  let sumSqr = 0;\n  let val = 0;\n  const length = array.length;\n  for (let i = 0; i < length; ++i) {\n    val = array[i];\n    if (val < min) {\n      min = val;\n    } else if (val > max) {\n      max = val;\n    }\n    sum += val;\n    sumSqr += val * val;\n  }\n\n  const mean = sum / length;\n  // see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance\n  const variance = sumSqr / length - mean * mean;\n  const stdDev = Math.sqrt(variance);\n\n  return {\n    min: min,\n    max: max,\n    mean: mean,\n    stdDev: stdDev\n  };\n}\n\n/**\n * Get full stats: minimum, maximum, mean, standard deviation, median, 25%\n * and 75% percentile of an array of values.\n *\n * @param {Array} array The array of values to extract stats from.\n * @returns {object} A full stats object.\n */\nfunction getFullStats(array) {\n  // get simple stats\n  const stats = getSimpleStats(array);\n\n  // sort array... can get slow...\n  array.sort(function (a, b) {\n    return a - b;\n  });\n\n  stats.median = getPercentile(array, 0.5);\n  stats.p25 = getPercentile(array, 0.25);\n  stats.p75 = getPercentile(array, 0.75);\n\n  return stats;\n}\n\n/**\n * Get an arrays' percentile. Uses linear interpolation for percentiles\n * that lie between data points.\n * see https://en.wikipedia.org/wiki/Percentile (second variant interpolation)\n *\n * @param {Array} array The sorted array of values.\n * @param {number} ratio The percentile ratio [0-1].\n * @returns {number} The percentile,\n */\nfunction getPercentile(array, ratio) {\n  // check input\n  if (array.length === 0) {\n    throw new Error('Empty array provided for percentile calculation.');\n  }\n  if (ratio < 0 || ratio > 1) {\n    throw new Error(\n      'Invalid ratio provided for percentile calculation: ' + ratio);\n  }\n  // return min for ratio=0 amd max for ratio=1\n  if (ratio === 0) {\n    return array[0];\n  } else if (ratio === 1) {\n    return array[array.length - 1];\n  }\n  // general case: interpolate between indices if needed\n  const i = (array.length - 1) * ratio;\n  const i0 = Math.floor(i);\n  const v0 = array[i0];\n  const v1 = array[i0 + 1];\n  return v0 + (v1 - v0) * (i - i0);\n}\n\n/**\n * Unique ID generator.\n * See {@link http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript}\n * and this {@link http://stackoverflow.com/a/13403498 answer}.\n *\n * @returns {string} A unique ID.\n */\nexport function guid() {\n  return Math.random().toString(36).substring(2, 15);\n}\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {logger} from '../utils/logger';\nimport {getShapeDisplayName, ChangeGroupCommand} from './drawCommands';\nimport {validateAnchorPosition} from './draw';\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Get the default anchor shape.\n *\n * @param {number} x The X position.\n * @param {number} y The Y position.\n * @param {string} id The shape id.\n * @param {object} style The application style.\n * @returns {object} The default anchor shape.\n */\nexport function getDefaultAnchor(x, y, id, style) {\n  const radius = style.applyZoomScale(3);\n  const absRadius = {\n    x: Math.abs(radius.x),\n    y: Math.abs(radius.y)\n  };\n  return new Konva.Ellipse({\n    x: x,\n    y: y,\n    stroke: '#999',\n    fill: 'rgba(100,100,100,0.7',\n    strokeWidth: style.getStrokeWidth(),\n    strokeScaleEnabled: false,\n    radius: absRadius,\n    radiusX: absRadius.x,\n    radiusY: absRadius.y,\n    name: 'anchor',\n    id: id.toString(),\n    dragOnTop: false,\n    draggable: true,\n    visible: false\n  });\n}\n\n/**\n * Shape editor.\n */\nexport class ShapeEditor {\n\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Shape factory list\n   *\n   * @type {object}\n   */\n  #shapeFactoryList = null;\n\n  /**\n   * Current shape factory.\n   *\n   * @type {object}\n   */\n  #currentFactory = null;\n\n  /**\n   * Edited shape.\n   *\n   * @type {object}\n   */\n  #shape = null;\n\n  /**\n   * Edited view controller. Used for quantification update.\n   *\n   * @type {object}\n   */\n  #viewController = null;\n\n  /**\n   * Active flag.\n   *\n   * @type {boolean}\n   */\n  #isActive = false;\n\n  /**\n   * @callback eventFn\n   * @param {object} event The event.\n   */\n\n  /**\n   * Draw event callback.\n   *\n   * @type {eventFn}\n   */\n  #drawEventCallback = null;\n\n  /**\n   * Set the tool options.\n   *\n   * @param {Array} list The list of shape classes.\n   */\n  setFactoryList(list) {\n    this.#shapeFactoryList = list;\n  }\n\n  /**\n   * Set the shape to edit.\n   *\n   * @param {object} inshape The shape to edit.\n   */\n  setShape(inshape) {\n    this.#shape = inshape;\n    if (this.#shape) {\n      // remove old anchors\n      this.#removeAnchors();\n      // find a factory for the input shape\n      const group = this.#shape.getParent();\n      const keys = Object.keys(this.#shapeFactoryList);\n      this.#currentFactory = null;\n      for (let i = 0; i < keys.length; ++i) {\n        const factory = new this.#shapeFactoryList[keys[i]];\n        if (factory.isFactoryGroup(group)) {\n          this.#currentFactory = factory;\n          // stop at first find\n          break;\n        }\n      }\n      if (this.#currentFactory === null) {\n        throw new Error('Could not find a factory to update shape.');\n      }\n      // add new anchors\n      this.#addAnchors();\n    }\n  }\n\n  /**\n   * Set the associated image.\n   *\n   * @param {object} vc The associated view controller.\n   */\n  setViewController(vc) {\n    this.#viewController = vc;\n  }\n\n  /**\n   * Get the edited shape.\n   *\n   * @returns {object} The edited shape.\n   */\n  getShape() {\n    return this.#shape;\n  }\n\n  /**\n   * Get the active flag.\n   *\n   * @returns {boolean} The active flag.\n   */\n  isActive() {\n    return this.#isActive;\n  }\n\n  /**\n   * Set the draw event callback.\n   *\n   * @param {object} callback The callback.\n   */\n  setDrawEventCallback(callback) {\n    this.#drawEventCallback = callback;\n  }\n\n  /**\n   * Enable the editor. Redraws the layer.\n   */\n  enable() {\n    this.#isActive = true;\n    if (this.#shape) {\n      this.#setAnchorsVisible(true);\n      if (this.#shape.getLayer()) {\n        this.#shape.getLayer().draw();\n      }\n    }\n  }\n\n  /**\n   * Disable the editor. Redraws the layer.\n   */\n  disable() {\n    this.#isActive = false;\n    if (this.#shape) {\n      this.#setAnchorsVisible(false);\n      if (this.#shape.getLayer()) {\n        this.#shape.getLayer().draw();\n      }\n    }\n  }\n\n  /**\n   * Reset the anchors.\n   */\n  resetAnchors() {\n    // remove previous controls\n    this.#removeAnchors();\n    // add anchors\n    this.#addAnchors();\n    // set them visible\n    this.#setAnchorsVisible(true);\n  }\n\n  /**\n   * Apply a function on all anchors.\n   *\n   * @param {object} func A f(shape) function.\n   */\n  #applyFuncToAnchors(func) {\n    if (this.#shape && this.#shape.getParent()) {\n      const anchors = this.#shape.getParent().find('.anchor');\n      anchors.forEach(func);\n    }\n  }\n\n  /**\n   * Set anchors visibility.\n   *\n   * @param {boolean} flag The visible flag.\n   */\n  #setAnchorsVisible(flag) {\n    this.#applyFuncToAnchors(function (anchor) {\n      anchor.visible(flag);\n    });\n  }\n\n  /**\n   * Set anchors active.\n   *\n   * @param {boolean} flag The active (on/off) flag.\n   */\n  setAnchorsActive(flag) {\n    let func = null;\n    if (flag) {\n      func = (anchor) => {\n        this.#setAnchorOn(anchor);\n      };\n    } else {\n      func = (anchor) => {\n        this.#setAnchorOff(anchor);\n      };\n    }\n    this.#applyFuncToAnchors(func);\n  }\n\n  /**\n   * Remove anchors.\n   */\n  #removeAnchors() {\n    this.#applyFuncToAnchors(function (anchor) {\n      anchor.remove();\n    });\n  }\n\n  /**\n   * Add the shape anchors.\n   */\n  #addAnchors() {\n    // exit if no shape or no layer\n    if (!this.#shape || !this.#shape.getLayer()) {\n      return;\n    }\n    // get shape group\n    const group = this.#shape.getParent();\n\n    // activate and add anchors to group\n    const anchors =\n      this.#currentFactory.getAnchors(this.#shape, this.#app.getStyle());\n    for (let i = 0; i < anchors.length; ++i) {\n      // set anchor on\n      this.#setAnchorOn(anchors[i]);\n      // add the anchor to the group\n      group.add(anchors[i]);\n    }\n  }\n\n  /**\n   * Get a simple clone of the input anchor.\n   *\n   * @param {object} anchor The anchor to clone.\n   * @returns {object} A clone of the input anchor.\n   */\n  #getClone(anchor) {\n    // create closure to properties\n    const parent = anchor.getParent();\n    const id = anchor.id();\n    const x = anchor.x();\n    const y = anchor.y();\n    // create clone object\n    const clone = {};\n    clone.getParent = function () {\n      return parent;\n    };\n    clone.id = function () {\n      return id;\n    };\n    clone.x = function () {\n      return x;\n    };\n    clone.y = function () {\n      return y;\n    };\n    return clone;\n  }\n\n  /**\n   * Set the anchor on listeners.\n   *\n   * @param {object} anchor The anchor to set on.\n   */\n  #setAnchorOn(anchor) {\n    let startAnchor = null;\n\n    // command name based on shape type\n    const shapeDisplayName = getShapeDisplayName(this.#shape);\n\n    // drag start listener\n    anchor.on('dragstart.edit', (event) => {\n      const anchor = event.target;\n      startAnchor = this.#getClone(anchor);\n      // prevent bubbling upwards\n      event.cancelBubble = true;\n    });\n    // drag move listener\n    anchor.on('dragmove.edit', (event) => {\n      const anchor = event.target;\n      const layerDetails = getLayerDetailsFromEvent(event.evt);\n      const layerGroup =\n        this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n      const drawLayer = layerGroup.getActiveDrawLayer();\n      // validate the anchor position\n      validateAnchorPosition(drawLayer.getBaseSize(), anchor);\n      // update shape\n      this.#currentFactory.update(\n        anchor, this.#app.getStyle(), this.#viewController);\n      // redraw\n      if (anchor.getLayer()) {\n        anchor.getLayer().draw();\n      } else {\n        logger.warn('No layer to draw the anchor!');\n      }\n      // prevent bubbling upwards\n      event.cancelBubble = true;\n    });\n    // drag end listener\n    anchor.on('dragend.edit', (event) => {\n      const anchor = event.target;\n      const endAnchor = this.#getClone(anchor);\n      // store the change command\n      const chgcmd = new ChangeGroupCommand(\n        shapeDisplayName,\n        this.#currentFactory,\n        startAnchor,\n        endAnchor,\n        anchor.getLayer(),\n        this.#viewController,\n        this.#app.getStyle()\n      );\n      chgcmd.onExecute = this.#drawEventCallback;\n      chgcmd.onUndo = this.#drawEventCallback;\n      chgcmd.execute();\n      this.#app.addToUndoStack(chgcmd);\n      // reset start anchor\n      startAnchor = endAnchor;\n      // prevent bubbling upwards\n      event.cancelBubble = true;\n    });\n    // mouse down listener\n    anchor.on('mousedown touchstart', (event) => {\n      const anchor = event.target;\n      anchor.moveToTop();\n    });\n    // mouse over styling\n    anchor.on('mouseover.edit', (event) => {\n      const anchor = event.target;\n      // style is handled by the group\n      anchor.stroke('#ddd');\n      if (anchor.getLayer()) {\n        anchor.getLayer().draw();\n      } else {\n        logger.warn('No layer to draw the anchor!');\n      }\n    });\n    // mouse out styling\n    anchor.on('mouseout.edit', (event) => {\n      const anchor = event.target;\n      // style is handled by the group\n      anchor.stroke('#999');\n      if (anchor.getLayer()) {\n        anchor.getLayer().draw();\n      } else {\n        logger.warn('No layer to draw the anchor!');\n      }\n    });\n  }\n\n  /**\n   * Set the anchor off listeners.\n   *\n   * @param {object} anchor The anchor to set off.\n   */\n  #setAnchorOff(anchor) {\n    anchor.off('dragstart.edit');\n    anchor.off('dragmove.edit');\n    anchor.off('dragend.edit');\n    anchor.off('mousedown touchstart');\n    anchor.off('mouseover.edit');\n    anchor.off('mouseout.edit');\n  }\n\n} // class Editor\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n  getEventOffset,\n  customUI\n} from '../gui/generic';\nimport {Point2D} from '../math/point';\nimport {guid} from '../math/stats';\nimport {logger} from '../utils/logger';\nimport {replaceFlags} from '../utils/string';\nimport {\n  getShapeDisplayName,\n  DrawGroupCommand,\n  DeleteGroupCommand,\n  MoveGroupCommand\n} from './drawCommands';\nimport {\n  canNodeChangeColour,\n  isNodeNameShape\n} from '../app/drawController';\nimport {ScrollWheel} from './scrollWheel';\nimport {ShapeEditor} from './editor';\n// external\nimport Konva from 'konva';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\nimport {Style} from '../gui/style';\nimport {LayerGroup} from '../gui/layerGroup';\n/* eslint-enable no-unused-vars */\n\n/**\n * Draw Debug flag.\n */\nexport const DRAW_DEBUG = false;\n\n/**\n * Drawing tool.\n *\n * This tool is responsible for the draw layer group structure. The layout is:\n *\n * drawLayer\n * |_ positionGroup: name=\"position-group\", id=\"#2-0#_#3-1\"\"\n *    |_ shapeGroup: name=\"{shape name}-group\", id=\"#\"\n *       |_ shape: name=\"shape\"\n *       |_ label: name=\"label\"\n *       |_ extra: line tick, protractor arc...\n *\n * Discussion:\n * - posGroup > shapeGroup\n *    pro: slice/frame display: 1 loop\n *    cons: multi-slice shape splitted in positionGroups\n * - shapeGroup > posGroup\n *    pros: more logical\n *    cons: slice/frame display: 2 loops\n */\nexport class Draw {\n\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * Scroll wheel handler.\n   *\n   * @type {ScrollWheel}\n   */\n  #scrollWhell;\n\n  /**\n   * Shape editor.\n   *\n   * @type {object}\n   */\n  #shapeEditor;\n\n  /**\n   * Trash draw: a cross.\n   *\n   * @type {object}\n   */\n  #trash;\n\n  /**\n   * Drawing style.\n   *\n   * @type {Style}\n   */\n  #style;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n    this.#scrollWhell = new ScrollWheel(app);\n    this.#shapeEditor = new ShapeEditor(app);\n    // associate the event listeners of the editor\n    //  with those of the draw tool\n    this.#shapeEditor.setDrawEventCallback(this.#fireEvent);\n\n    this.#style = app.getStyle();\n\n    // trash cross\n    this.#trash = new Konva.Group();\n    // first line of the cross\n    const trashLine1 = new Konva.Line({\n      points: [-10, -10, 10, 10],\n      stroke: 'red'\n    });\n    // second line of the cross\n    const trashLine2 = new Konva.Line({\n      points: [10, -10, -10, 10],\n      stroke: 'red'\n    });\n    this.#trash.width(20);\n    this.#trash.height(20);\n    this.#trash.add(trashLine1);\n    this.#trash.add(trashLine2);\n  }\n\n  /**\n   * Interaction start flag.\n   *\n   * @type {boolean}\n   */\n  #started = false;\n\n  /**\n   * Shape factory list\n   *\n   * @type {object}\n   */\n  #shapeFactoryList = null;\n\n  /**\n   * Current shape factory.\n   *\n   * @type {object}\n   */\n  #currentFactory = null;\n\n  /**\n   * Draw command.\n   *\n   * @type {object}\n   */\n  #command = null;\n\n  /**\n   * Current shape group.\n   *\n   * @type {object}\n   */\n  #tmpShapeGroup = null;\n\n  /**\n   * Shape name.\n   *\n   * @type {string}\n   */\n  #shapeName;\n\n  /**\n   * List of points.\n   *\n   * @type {Array}\n   */\n  #points = [];\n\n  /**\n   * Last selected point.\n   *\n   * @type {object}\n   */\n  #lastPoint = null;\n\n  /**\n   * Active shape, ie shape with mouse over.\n   *\n   * @type {object}\n   */\n  #activeShapeGroup;\n\n  /**\n   * Original mouse cursor.\n   *\n   * @type {string}\n   */\n  #originalCursor;\n\n  /**\n   * Mouse cursor.\n   *\n   * @type {string}\n   */\n  #mouseOverCursor = 'pointer';\n\n  /**\n   * Event listeners.\n   */\n  #listeners = {};\n\n  /**\n   * Handle mouse down event.\n   *\n   * @param {object} event The mouse down event.\n   */\n  mousedown = (event) => {\n    // exit if a draw was started (handle at mouse move or up)\n    if (this.#started) {\n      return;\n    }\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const drawLayer = layerGroup.getActiveDrawLayer();\n\n    // determine if the click happened in an existing shape\n    const stage = drawLayer.getKonvaStage();\n    const kshape = stage.getIntersection({\n      x: event._x,\n      y: event._y\n    });\n\n    // update scale\n    this.#style.setZoomScale(stage.scale());\n\n    if (kshape) {\n      const group = kshape.getParent();\n      const selectedShape = group.find('.shape')[0];\n      // reset editor if click on other shape\n      // (and avoid anchors mouse down)\n      if (selectedShape && selectedShape !== this.#shapeEditor.getShape()) {\n        this.#shapeEditor.disable();\n        this.#shapeEditor.setShape(selectedShape);\n        const viewController =\n          layerGroup.getActiveViewLayer().getViewController();\n        this.#shapeEditor.setViewController(viewController);\n        this.#shapeEditor.enable();\n      }\n    } else {\n      // disable edition\n      this.#shapeEditor.disable();\n      this.#shapeEditor.setShape(null);\n      this.#shapeEditor.setViewController(null);\n      // start storing points\n      this.#started = true;\n      // set factory\n      this.#currentFactory = new this.#shapeFactoryList[this.#shapeName]();\n      // clear array\n      this.#points = [];\n      // store point\n      const viewLayer = layerGroup.getActiveViewLayer();\n      const pos = viewLayer.displayToPlanePos(event._x, event._y);\n      this.#lastPoint = new Point2D(pos.x, pos.y);\n      this.#points.push(this.#lastPoint);\n    }\n  };\n\n  /**\n   * Handle mouse move event.\n   *\n   * @param {object} event The mouse move event.\n   */\n  mousemove = (event) => {\n    // exit if not started draw\n    if (!this.#started) {\n      return;\n    }\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const pos = viewLayer.displayToPlanePos(event._x, event._y);\n\n    // draw line to current pos\n    if (Math.abs(pos.x - this.#lastPoint.getX()) > 0 ||\n      Math.abs(pos.y - this.#lastPoint.getY()) > 0) {\n      // clear last added point from the list (but not the first one)\n      // if it was marked as temporary\n      if (this.#points.length !== 1 &&\n        typeof this.#points[this.#points.length - 1].tmp !== 'undefined') {\n        this.#points.pop();\n      }\n      // current point\n      this.#lastPoint = new Point2D(pos.x, pos.y);\n      // mark it as temporary\n      this.#lastPoint.tmp = true;\n      // add it to the list\n      this.#points.push(this.#lastPoint);\n      // update points\n      this.#onNewPoints(this.#points, layerGroup);\n    }\n  };\n\n  /**\n   * Handle mouse up event.\n   *\n   * @param {object} event The mouse up event.\n   */\n  mouseup = (event) => {\n    // exit if not started draw\n    if (!this.#started) {\n      return;\n    }\n    // exit if no points\n    if (this.#points.length === 0) {\n      logger.warn('Draw mouseup but no points...');\n      return;\n    }\n\n    // do we have all the needed points\n    if (this.#points.length === this.#currentFactory.getNPoints()) {\n      // store points\n      const layerDetails = getLayerDetailsFromEvent(event);\n      const layerGroup =\n        this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n      this.#onFinalPoints(this.#points, layerGroup);\n      // reset flag\n      this.#started = false;\n    } else {\n      // remove temporary flag\n      if (typeof this.#points[this.#points.length - 1].tmp !== 'undefined') {\n        delete this.#points[this.#points.length - 1].tmp;\n      }\n    }\n  };\n\n  /**\n   * Handle double click event: some tools use it to finish interaction.\n   *\n   * @param {object} event The double click event.\n   */\n  dblclick = (event) => {\n    // only end by double click undefined NPoints\n    if (typeof this.#currentFactory.getNPoints() !== 'undefined') {\n      return;\n    }\n    // exit if not started draw\n    if (!this.#started) {\n      return;\n    }\n    // exit if no points\n    if (this.#points.length === 0) {\n      logger.warn('Draw dblclick but no points...');\n      return;\n    }\n\n    // store points\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    this.#onFinalPoints(this.#points, layerGroup);\n    // reset flag\n    this.#started = false;\n  };\n\n  /**\n   * Handle mouse out event.\n   *\n   * @param {object} event The mouse out event.\n   */\n  mouseout = (event) => {\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle touch start event.\n   *\n   * @param {object} event The touch start event.\n   */\n  touchstart = (event) => {\n    this.mousedown(event);\n  };\n\n  /**\n   * Handle touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  touchmove = (event) => {\n    // exit if not started draw\n    if (!this.#started) {\n      return;\n    }\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const pos = viewLayer.displayToPlanePos(event._x, event._y);\n\n    if (Math.abs(pos.x - this.#lastPoint.getX()) > 0 ||\n      Math.abs(pos.y - this.#lastPoint.getY()) > 0) {\n      // clear last added point from the list (but not the first one)\n      if (this.#points.length !== 1) {\n        this.#points.pop();\n      }\n      // current point\n      this.#lastPoint = new Point2D(pos.x, pos.y);\n      // add current one to the list\n      this.#points.push(this.#lastPoint);\n      // allow for anchor points\n      if (this.#points.length < this.#currentFactory.getNPoints()) {\n        clearTimeout(this.timer);\n        this.timer = setTimeout(() => {\n          this.#points.push(this.#lastPoint);\n        }, this.#currentFactory.getTimeout());\n      }\n      // update points\n      this.#onNewPoints(this.#points, layerGroup);\n    }\n  };\n\n  /**\n   * Handle touch end event.\n   *\n   * @param {object} event The touch end event.\n   */\n  touchend = (event) => {\n    this.dblclick(event);\n  };\n\n  /**\n   * Handle mouse wheel event.\n   *\n   * @param {object} event The mouse wheel event.\n   */\n  wheel = (event) => {\n    this.#scrollWhell.wheel(event);\n  };\n\n  /**\n   * Handle key down event.\n   *\n   * @param {object} event The key down event.\n   */\n  keydown = (event) => {\n    // call app handler if we are not in the middle of a draw\n    if (!this.#started) {\n      event.context = 'Draw';\n      this.#app.onKeydown(event);\n    }\n    let konvaLayer;\n\n    // press delete or backspace key\n    if ((event.key === 'Delete' ||\n      event.key === 'Backspace') &&\n      this.#shapeEditor.isActive()) {\n      // get shape\n      const shapeGroup = this.#shapeEditor.getShape().getParent();\n      konvaLayer = shapeGroup.getLayer();\n      const shapeDisplayName = getShapeDisplayName(\n        shapeGroup.getChildren(isNodeNameShape)[0]);\n      // delete command\n      const delcmd = new DeleteGroupCommand(shapeGroup,\n        shapeDisplayName, konvaLayer);\n      delcmd.onExecute = this.#fireEvent;\n      delcmd.onUndo = this.#fireEvent;\n      delcmd.execute();\n      this.#app.addToUndoStack(delcmd);\n    }\n\n    // escape key: exit shape creation\n    if (event.key === 'Escape' && this.#tmpShapeGroup !== null) {\n      konvaLayer = this.#tmpShapeGroup.getLayer();\n      // reset temporary shape group\n      this.#tmpShapeGroup.destroy();\n      this.#tmpShapeGroup = null;\n      // reset flag and points\n      this.#started = false;\n      this.#points = [];\n      // redraw\n      konvaLayer.draw();\n    }\n  };\n\n  /**\n   * Update the current draw with new points.\n   *\n   * @param {Array} tmpPoints The array of new points.\n   * @param {LayerGroup} layerGroup The origin layer group.\n   */\n  #onNewPoints(tmpPoints, layerGroup) {\n    const drawLayer = layerGroup.getActiveDrawLayer();\n    const konvaLayer = drawLayer.getKonvaLayer();\n\n    // remove temporary shape draw\n    if (this.#tmpShapeGroup) {\n      this.#tmpShapeGroup.destroy();\n      this.#tmpShapeGroup = null;\n    }\n\n    // create shape group\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n    this.#tmpShapeGroup = this.#currentFactory.create(\n      tmpPoints, this.#style, viewController);\n    // do not listen during creation\n    const shape = this.#tmpShapeGroup.getChildren(isNodeNameShape)[0];\n    shape.listening(false);\n    konvaLayer.listening(false);\n    // draw shape\n    konvaLayer.add(this.#tmpShapeGroup);\n    konvaLayer.draw();\n  }\n\n  /**\n   * Create the final shape from a point list.\n   *\n   * @param {Array} finalPoints The array of points.\n   * @param {LayerGroup} layerGroup The origin layer group.\n   */\n  #onFinalPoints(finalPoints, layerGroup) {\n    const drawLayer = layerGroup.getActiveDrawLayer();\n    const konvaLayer = drawLayer.getKonvaLayer();\n\n    // reset temporary shape group\n    if (this.#tmpShapeGroup) {\n      this.#tmpShapeGroup.destroy();\n      this.#tmpShapeGroup = null;\n    }\n\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n    const drawController =\n      layerGroup.getActiveDrawLayer().getDrawController();\n\n    // create final shape\n    const finalShapeGroup = this.#currentFactory.create(\n      finalPoints, this.#style, viewController);\n    finalShapeGroup.id(guid());\n\n    // get the position group\n    const posGroup = drawController.getCurrentPosGroup();\n    // add shape group to position group\n    posGroup.add(finalShapeGroup);\n\n    // re-activate layer\n    konvaLayer.listening(true);\n    // draw shape command\n    this.#command = new DrawGroupCommand(\n      finalShapeGroup, this.#shapeName, konvaLayer);\n    this.#command.onExecute = this.#fireEvent;\n    this.#command.onUndo = this.#fireEvent;\n    // execute it\n    this.#command.execute();\n    // save it in undo stack\n    this.#app.addToUndoStack(this.#command);\n\n    // activate shape listeners\n    this.setShapeOn(finalShapeGroup, layerGroup);\n  }\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} flag The flag to activate or not.\n   */\n  activate(flag) {\n    // reset shape display properties\n    this.#shapeEditor.disable();\n    this.#shapeEditor.setShape(null);\n    this.#shapeEditor.setViewController(null);\n    // get the current draw layer\n    const layerGroup = this.#app.getActiveLayerGroup();\n    this.#activateCurrentPositionShapes(flag, layerGroup);\n    // listen to app change to update the draw layer\n    if (flag) {\n      // store cursor\n      this.#originalCursor = document.body.style.cursor;\n      // TODO: merge with drawController.activateDrawLayer?\n      this.#app.addEventListener('positionchange', () => {\n        this.#updateDrawLayer(layerGroup);\n      });\n      // same for colour\n      this.setFeatures({lineColour: this.#style.getLineColour()});\n    } else {\n      // reset shape and cursor\n      this.#resetActiveShapeGroup();\n      // reset local var\n      this.#originalCursor = undefined;\n      // remove listeners\n      this.#app.removeEventListener('positionchange', () => {\n        this.#updateDrawLayer(layerGroup);\n      });\n    }\n  }\n\n  /**\n   * Update the draw layer.\n   *\n   * @param {LayerGroup} layerGroup The origin layer group.\n   */\n  #updateDrawLayer(layerGroup) {\n    // activate the shape at current position\n    this.#activateCurrentPositionShapes(true, layerGroup);\n  }\n\n  /**\n   * Activate shapes at current position.\n   *\n   * @param {boolean} visible Set the draw layer visible or not.\n   * @param {LayerGroup} layerGroup The origin layer group.\n   */\n  #activateCurrentPositionShapes(visible, layerGroup) {\n    const drawController =\n      layerGroup.getActiveDrawLayer().getDrawController();\n\n    // get shape groups at the current position\n    const shapeGroups =\n      drawController.getCurrentPosGroup().getChildren();\n\n    // set shape display properties\n    if (visible) {\n      // activate shape listeners\n      shapeGroups.forEach((group) => {\n        this.setShapeOn(group, layerGroup);\n      });\n    } else {\n      // de-activate shape listeners\n      shapeGroups.forEach((group) => {\n        this.#setShapeOff(group);\n      });\n    }\n    // draw\n    const drawLayer = layerGroup.getActiveDrawLayer();\n    const konvaLayer = drawLayer.getKonvaLayer();\n    if (shapeGroups.length !== 0) {\n      konvaLayer.listening(true);\n    }\n    konvaLayer.draw();\n  }\n\n  /**\n   * Set shape group off properties.\n   *\n   * @param {object} shapeGroup The shape group to set off.\n   */\n  #setShapeOff(shapeGroup) {\n    // mouse styling\n    shapeGroup.off('mouseover');\n    shapeGroup.off('mouseout');\n    // drag\n    shapeGroup.draggable(false);\n    shapeGroup.off('dragstart.draw');\n    shapeGroup.off('dragmove.draw');\n    shapeGroup.off('dragend.draw');\n    shapeGroup.off('dblclick');\n  }\n\n  /**\n   * Get the real position from an event.\n   * TODO: use layer method?\n   *\n   * @param {object} index The input index as {x,y}.\n   * @param {LayerGroup} layerGroup The origin layer group.\n   * @returns {object} The real position in the image as {x,y}.\n   */\n  #getRealPosition(index, layerGroup) {\n    const drawLayer = layerGroup.getActiveDrawLayer();\n    const stage = drawLayer.getKonvaStage();\n    return {\n      x: stage.offset().x + index.x / stage.scale().x,\n      y: stage.offset().y + index.y / stage.scale().y\n    };\n  }\n\n  /**\n   * Reset the active shape group and mouse cursor to their original state.\n   */\n  #resetActiveShapeGroup() {\n    if (typeof this.#originalCursor !== 'undefined') {\n      document.body.style.cursor = this.#originalCursor;\n    }\n    if (typeof this.#activeShapeGroup !== 'undefined') {\n      this.#activeShapeGroup.opacity(1);\n      const colour = this.#style.getLineColour();\n      this.#activeShapeGroup.getChildren(canNodeChangeColour).forEach(\n        function (ashape) {\n          ashape.stroke(colour);\n        }\n      );\n    }\n  }\n\n  /**\n   * Set shape group on properties.\n   *\n   * @param {object} shapeGroup The shape group to set on.\n   * @param {LayerGroup} layerGroup The origin layer group.\n   */\n  setShapeOn(shapeGroup, layerGroup) {\n    // adapt shape and cursor when mouse over\n    const mouseOnShape = () => {\n      document.body.style.cursor = this.#mouseOverCursor;\n      shapeGroup.opacity(0.75);\n    };\n    // mouse over event hanlding\n    shapeGroup.on('mouseover', () => {\n      // save local vars\n      this.#activeShapeGroup = shapeGroup;\n      // adapt shape\n      mouseOnShape();\n    });\n    // mouse out event hanlding\n    shapeGroup.on('mouseout', () => {\n      // reset shape\n      this.#resetActiveShapeGroup();\n      // reset local vars\n      this.#activeShapeGroup = undefined;\n    });\n\n    const drawLayer = layerGroup.getActiveDrawLayer();\n    const konvaLayer = drawLayer.getKonvaLayer();\n\n    // make it draggable\n    shapeGroup.draggable(true);\n    // cache drag start position\n    let dragStartPos = {x: shapeGroup.x(), y: shapeGroup.y()};\n\n    // command name based on shape type\n    const shapeDisplayName = getShapeDisplayName(\n      shapeGroup.getChildren(isNodeNameShape)[0]);\n\n    let colour = null;\n\n    // drag start event handling\n    shapeGroup.on('dragstart.draw', (/*event*/) => {\n      // store colour\n      colour = shapeGroup.getChildren(isNodeNameShape)[0].stroke();\n      // display trash\n      const drawLayer = layerGroup.getActiveDrawLayer();\n      const stage = drawLayer.getKonvaStage();\n      const scale = stage.scale();\n      const invscale = {x: 1 / scale.x, y: 1 / scale.y};\n      this.#trash.x(stage.offset().x + (stage.width() / (2 * scale.x)));\n      this.#trash.y(stage.offset().y + (stage.height() / (15 * scale.y)));\n      this.#trash.scale(invscale);\n      konvaLayer.add(this.#trash);\n      // deactivate anchors to avoid events on null shape\n      this.#shapeEditor.setAnchorsActive(false);\n      // draw\n      konvaLayer.draw();\n    });\n    // drag move event handling\n    shapeGroup.on('dragmove.draw', (event) => {\n      const group = event.target;\n      const drawLayer = layerGroup.getActiveDrawLayer();\n      // validate the group position\n      validateGroupPosition(drawLayer.getBaseSize(), group);\n      // get appropriate factory\n      let factory;\n      const keys = Object.keys(this.#shapeFactoryList);\n      for (let i = 0; i < keys.length; ++i) {\n        factory = new this.#shapeFactoryList[keys[i]];\n        if (factory.isFactoryGroup(shapeGroup)) {\n          // stop at first find\n          break;\n        }\n      }\n      if (typeof factory === 'undefined') {\n        throw new Error('Cannot find factory to update quantification.');\n      }\n      // update quantification if possible\n      if (typeof factory.updateQuantification !== 'undefined') {\n        const vc = layerGroup.getActiveViewLayer().getViewController();\n        factory.updateQuantification(group, vc);\n      }\n      // highlight trash when on it\n      const offset = getEventOffset(event.evt)[0];\n      const eventPos = this.#getRealPosition(offset, layerGroup);\n      const trashHalfWidth = this.#trash.width() * this.#trash.scaleX() / 2;\n      const trashHalfHeight = this.#trash.height() * this.#trash.scaleY() / 2;\n      if (Math.abs(eventPos.x - this.#trash.x()) < trashHalfWidth &&\n        Math.abs(eventPos.y - this.#trash.y()) < trashHalfHeight) {\n        this.#trash.getChildren().forEach(function (tshape) {\n          tshape.stroke('orange');\n        });\n        // change the group shapes colour\n        shapeGroup.getChildren(canNodeChangeColour).forEach(\n          function (ashape) {\n            ashape.stroke('red');\n          });\n      } else {\n        this.#trash.getChildren().forEach(function (tshape) {\n          tshape.stroke('red');\n        });\n        // reset the group shapes colour\n        shapeGroup.getChildren(canNodeChangeColour).forEach(\n          function (ashape) {\n            if (typeof ashape.stroke !== 'undefined') {\n              ashape.stroke(colour);\n            }\n          });\n      }\n      // draw\n      konvaLayer.draw();\n    });\n    // drag end event handling\n    shapeGroup.on('dragend.draw', (event) => {\n      const group = event.target;\n      // remove trash\n      this.#trash.remove();\n      // activate(false) will also trigger a dragend.draw\n      if (typeof event === 'undefined' ||\n        typeof event.evt === 'undefined') {\n        return;\n      }\n      const pos = {x: group.x(), y: group.y()};\n      // delete case\n      const offset = getEventOffset(event.evt)[0];\n      const eventPos = this.#getRealPosition(offset, layerGroup);\n      const trashHalfWidth = this.#trash.width() * this.#trash.scaleX() / 2;\n      const trashHalfHeight = this.#trash.height() * this.#trash.scaleY() / 2;\n      if (Math.abs(eventPos.x - this.#trash.x()) < trashHalfWidth &&\n        Math.abs(eventPos.y - this.#trash.y()) < trashHalfHeight) {\n        // compensate for the drag translation\n        group.x(dragStartPos.x);\n        group.y(dragStartPos.y);\n        // disable editor\n        this.#shapeEditor.disable();\n        this.#shapeEditor.setShape(null);\n        this.#shapeEditor.setViewController(null);\n        // reset colour\n        shapeGroup.getChildren(canNodeChangeColour).forEach(\n          function (ashape) {\n            ashape.stroke(colour);\n          });\n        // reset cursor\n        document.body.style.cursor = this.#originalCursor;\n        // delete command\n        const delcmd = new DeleteGroupCommand(group,\n          shapeDisplayName, konvaLayer);\n        delcmd.onExecute = this.#fireEvent;\n        delcmd.onUndo = this.#fireEvent;\n        delcmd.execute();\n        this.#app.addToUndoStack(delcmd);\n      } else {\n        // save drag move\n        const translation = {\n          x: pos.x - dragStartPos.x,\n          y: pos.y - dragStartPos.y\n        };\n        if (translation.x !== 0 || translation.y !== 0) {\n          const mvcmd = new MoveGroupCommand(group,\n            shapeDisplayName, translation, konvaLayer);\n          mvcmd.onExecute = this.#fireEvent;\n          mvcmd.onUndo = this.#fireEvent;\n          this.#app.addToUndoStack(mvcmd);\n\n          // the move is handled by Konva, trigger an event manually\n          this.#fireEvent({\n            type: 'drawmove',\n            id: group.id()\n          });\n        }\n        // reset anchors\n        this.#shapeEditor.setAnchorsActive(true);\n        this.#shapeEditor.resetAnchors();\n      }\n      // draw\n      konvaLayer.draw();\n      // reset start position\n      dragStartPos = {x: group.x(), y: group.y()};\n    });\n    // double click handling: update label\n    shapeGroup.on('dblclick', (event) => {\n      const group = event.currentTarget;\n      // get the label object for this shape\n      const label = group.findOne('Label');\n      // should just be one\n      if (typeof label === 'undefined') {\n        throw new Error('Could not find the shape label.');\n      }\n      const ktext = label.getText();\n      // id for event\n      const groupId = group.id();\n\n      const onSaveCallback = (meta) => {\n        // store meta\n        ktext.meta = meta;\n        // update text expression\n        ktext.setText(replaceFlags(\n          ktext.meta.textExpr, ktext.meta.quantification));\n        label.setVisible(ktext.meta.textExpr.length !== 0);\n\n        // trigger event\n        this.#fireEvent({\n          type: 'drawchange',\n          id: groupId\n        });\n        // draw\n        konvaLayer.draw();\n      };\n\n      // call roi dialog\n      customUI.openRoiDialog(ktext.meta, onSaveCallback);\n    });\n  }\n\n  /**\n   * Set the tool configuration options.\n   *\n   * @param {object} options The list of shape names amd classes.\n   */\n  setOptions(options) {\n    // save the options as the shape factory list\n    this.#shapeFactoryList = options;\n    // pass them to the editor\n    this.#shapeEditor.setFactoryList(options);\n  }\n\n  /**\n   * Get the type of tool options: here 'factory' since the shape\n   * list contains factories to create each possible shape.\n   *\n   * @returns {string} The type.\n   */\n  getOptionsType() {\n    return 'factory';\n  }\n\n  /**\n   * Set the tool live features: shape colour and shape name.\n   *\n   * @param {object} features The list of features.\n   */\n  setFeatures(features) {\n    if (typeof features.shapeColour !== 'undefined') {\n      this.#style.setLineColour(features.shapeColour);\n    }\n    if (typeof features.shapeName !== 'undefined') {\n      // check if we have it\n      if (!this.hasShape(features.shapeName)) {\n        throw new Error('Unknown shape: \\'' + features.shapeName + '\\'');\n      }\n      this.#shapeName = features.shapeName;\n    }\n    if (typeof features.mouseOverCursor !== 'undefined') {\n      this.#mouseOverCursor = features.mouseOverCursor;\n    }\n  }\n\n  /**\n   * Initialise the tool.\n   */\n  init() {\n    // does nothing\n  }\n\n  /**\n   * Get the list of event names that this tool can fire.\n   *\n   * @returns {Array} The list of event names.\n   */\n  getEventNames() {\n    return [\n      'drawcreate', 'drawchange', 'drawmove', 'drawdelete', 'drawlabelchange'\n    ];\n  }\n\n  /**\n   * Add an event listener on the app.\n   *\n   * @param {string} type The event type.\n   * @param {Function} listener The function associated with the provided\n   *   event type.\n   */\n  addEventListener(type, listener) {\n    if (typeof this.#listeners[type] === 'undefined') {\n      this.#listeners[type] = [];\n    }\n    this.#listeners[type].push(listener);\n  }\n\n  /**\n   * Remove an event listener from the app.\n   *\n   * @param {string} type The event type.\n   * @param {Function} listener The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, listener) {\n    if (typeof this.#listeners[type] === 'undefined') {\n      return;\n    }\n    for (let i = 0; i < this.#listeners[type].length; ++i) {\n      if (this.#listeners[type][i] === listener) {\n        this.#listeners[type].splice(i, 1);\n      }\n    }\n  }\n\n  // Private Methods -----------------------------------------------------------\n\n  /**\n   * Fire an event: call all associated listeners.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    if (typeof this.#listeners[event.type] === 'undefined') {\n      return;\n    }\n    for (let i = 0; i < this.#listeners[event.type].length; ++i) {\n      this.#listeners[event.type][i](event);\n    }\n  };\n\n  /**\n   * Check if the shape is in the shape list.\n   *\n   * @param {string} name The name of the shape.\n   * @returns {boolean} True if there is a factory for the shape.\n   */\n  hasShape(name) {\n    return typeof this.#shapeFactoryList[name] !== 'undefined';\n  }\n\n} // Draw class\n\n/**\n * Get the minimum position in a groups' anchors.\n *\n * @param {object} group The group that contains anchors.\n * @returns {object|undefined} The minimum position as {x,y}.\n */\nfunction getAnchorMin(group) {\n  const anchors = group.find('.anchor');\n  if (anchors.length === 0) {\n    return undefined;\n  }\n  let minX = anchors[0].x();\n  let minY = anchors[0].y();\n  for (let i = 0; i < anchors.length; ++i) {\n    minX = Math.min(minX, anchors[i].x());\n    minY = Math.min(minY, anchors[i].y());\n  }\n\n  return {x: minX, y: minY};\n}\n\n/**\n * Bound a node position.\n *\n * @param {object} node The node to bound the position.\n * @param {object} min The minimum position as {x,y}.\n * @param {object} max The maximum position as {x,y}.\n * @returns {boolean} True if the position was corrected.\n */\nfunction boundNodePosition(node, min, max) {\n  let changed = false;\n  if (node.x() < min.x) {\n    node.x(min.x);\n    changed = true;\n  } else if (node.x() > max.x) {\n    node.x(max.x);\n    changed = true;\n  }\n  if (node.y() < min.y) {\n    node.y(min.y);\n    changed = true;\n  } else if (node.y() > max.y) {\n    node.y(max.y);\n    changed = true;\n  }\n  return changed;\n}\n\n/**\n * Validate a group position.\n *\n * @param {object} stageSize The stage size {x,y}.\n * @param {object} group The group to evaluate.\n * @returns {boolean} True if the position was corrected.\n */\nfunction validateGroupPosition(stageSize, group) {\n  // if anchors get mixed, width/height can be negative\n  const shape = group.getChildren(isNodeNameShape)[0];\n  const anchorMin = getAnchorMin(group);\n  // handle no anchor: when dragging the label, the editor does\n  //   not activate\n  if (typeof anchorMin === 'undefined') {\n    return null;\n  }\n\n  const min = {\n    x: -anchorMin.x,\n    y: -anchorMin.y\n  };\n  const max = {\n    x: stageSize.x -\n      (anchorMin.x + Math.abs(shape.width())),\n    y: stageSize.y -\n      (anchorMin.y + Math.abs(shape.height()))\n  };\n\n  return boundNodePosition(group, min, max);\n}\n\n/**\n * Validate an anchor position.\n *\n * @param {object} stageSize The stage size {x,y}.\n * @param {object} anchor The anchor to evaluate.\n * @returns {boolean} True if the position was corrected.\n */\nexport function validateAnchorPosition(stageSize, anchor) {\n  const group = anchor.getParent();\n\n  const min = {\n    x: -group.x(),\n    y: -group.y()\n  };\n  const max = {\n    x: stageSize.x - group.x(),\n    y: stageSize.y - group.y()\n  };\n\n  return boundNodePosition(anchor, min, max);\n}\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Region Of Interest shape.\n * Note: should be a closed path.\n */\nexport class ROI {\n\n  /**\n   * List of points.\n   *\n   * @type {Array}\n   */\n  #points = [];\n\n  /**\n   * Get a point of the list at a given index.\n   *\n   * @param {number} index The index of the point to get\n   *   (beware, no size check).\n   * @returns {Point2D} The Point2D at the given index.\n   */\n  getPoint(index) {\n    return this.#points[index];\n  }\n\n  /**\n   * Get the length of the point list.\n   *\n   * @returns {number} The length of the point list.\n   */\n  getLength() {\n    return this.#points.length;\n  }\n\n  /**\n   * Add a point to the ROI.\n   *\n   * @param {Point2D} point The Point2D to add.\n   */\n  addPoint(point) {\n    this.#points.push(point);\n  }\n\n  /**\n   * Add points to the ROI.\n   *\n   * @param {Array} rhs The array of POints2D to add.\n   */\n  addPoints(rhs) {\n    this.#points = this.#points.concat(rhs);\n  }\n\n} // ROI class\n","import {ROI} from '../math/roi';\nimport {getDefaultAnchor} from './editor';\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultRoiLabelText = '';\n\n/**\n * ROI factory.\n */\nexport class RoiFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'roi-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number|undefined} The number of points.\n   */\n  getNPoints() {\n    // undefined to end with double click\n    return undefined;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 100;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create a roi shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the line.\n   * @param {object} style The drawing style.\n   * @param {object} _viewController The associated view controller.\n   * @returns {object} The Konva group.\n   */\n  create(points, style, _viewController) {\n    // physical shape\n    const roi = new ROI();\n    // add input points to the ROI\n    roi.addPoints(points);\n    // points stored the Konvajs way\n    const arr = [];\n    for (let i = 0; i < roi.getLength(); ++i) {\n      arr.push(roi.getPoint(i).getX());\n      arr.push(roi.getPoint(i).getY());\n    }\n    // draw shape\n    const kshape = new Konva.Line({\n      points: arr,\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape',\n      closed: true\n    });\n\n    // text\n    const ktext = new Konva.Text({\n      fontSize: style.getFontSize(),\n      fontFamily: style.getFontFamily(),\n      fill: style.getLineColour(),\n      name: 'text'\n    });\n    let textExpr = '';\n    // todo: allow overrride?\n    // if (typeof roiLabelText !== 'undefined') {\n    //   textExpr = roiLabelText;\n    // } else {\n    textExpr = defaultRoiLabelText;\n    // }\n    ktext.setText(textExpr);\n    // augment text with meta\n    // @ts-ignore\n    ktext.meta = {\n      textExpr: textExpr,\n      quantification: {}\n    };\n\n    // label\n    const klabel = new Konva.Label({\n      x: roi.getPoint(0).getX(),\n      y: roi.getPoint(0).getY() + style.scale(10),\n      scale: style.applyZoomScale(1),\n      visible: textExpr.length !== 0,\n      name: 'label'\n    });\n    klabel.add(ktext);\n    klabel.add(new Konva.Tag({\n      fill: style.getLineColour(),\n      opacity: style.getTagOpacity()\n    }));\n\n    // return group\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    group.add(klabel);\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    return group;\n  }\n\n  /**\n   * Get anchors to update a roi shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const points = shape.points();\n\n    const anchors = [];\n    for (let i = 0; i < points.length; i = i + 2) {\n      const px = points[i] + shape.x();\n      const py = points[i + 1] + shape.y();\n      const name = i.toString();\n      anchors.push(getDefaultAnchor(\n        px, py, name, style\n      ));\n    }\n    return anchors;\n  }\n\n  /**\n   * Update a roi shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} style The app style.\n   * @param {object} _viewController The associated view controller.\n   */\n  update(anchor, style, _viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const kroi = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n      // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n\n    // update self\n    const point = group.getChildren(function (node) {\n      return node.id() === anchor.id();\n    })[0];\n    point.x(anchor.x());\n    point.y(anchor.y());\n    // update the roi point and compensate for possible drag\n    // (the anchor id is the index of the point in the list)\n    const points = kroi.points();\n    points[anchor.id()] = anchor.x() - kroi.x();\n    points[anchor.id() + 1] = anchor.y() - kroi.y();\n    kroi.points(points);\n\n    // update text\n    const ktext = klabel.getText();\n    ktext.setText(ktext.meta.textExpr);\n    // update position\n    const textPos = {\n      x: points[0] + kroi.x(),\n      y: points[1] + kroi.y() + style.scale(10)\n    };\n    klabel.position(textPos);\n  }\n\n} // class RoiFactory\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\n/* eslint-enable no-unused-vars */\n\n/**\n * Path shape.\n */\nexport class Path {\n\n  /**\n   * @param {Array} [inputPointArray] The list of Point2D that make\n   *   the path (optional).\n   * @param {Array} [inputControlPointIndexArray] The list of control\n   *  point of path, as indexes (optional).\n   * Note: first and last point do not need to be equal.\n   */\n  constructor(inputPointArray, inputControlPointIndexArray) {\n    /**\n     * List of points.\n     *\n     * @type {Array}\n     */\n    this.pointArray = inputPointArray ? inputPointArray.slice() : [];\n    /**\n     * List of control points.\n     *\n     * @type {Array}\n     */\n    this.controlPointIndexArray = inputControlPointIndexArray\n      ? inputControlPointIndexArray.slice() : [];\n  }\n\n  /**\n   * Get a point of the list.\n   *\n   * @param {number} index The index of the point\n   *   to get (beware, no size check).\n   * @returns {Point2D} The Point2D at the given index.\n   */\n  getPoint(index) {\n    return this.pointArray[index];\n  }\n\n  /**\n   * Is the given point a control point.\n   *\n   * @param {Point2D} point The Point2D to check.\n   * @returns {boolean} True if a control point.\n   */\n  isControlPoint(point) {\n    const index = this.pointArray.indexOf(point);\n    if (index !== -1) {\n      return this.controlPointIndexArray.indexOf(index) !== -1;\n    } else {\n      throw new Error('Error: isControlPoint called with not in list point.');\n    }\n  }\n\n  /**\n   * Get the length of the path.\n   *\n   * @returns {number} The length of the path.\n   */\n  getLength() {\n    return this.pointArray.length;\n  }\n\n  /**\n   * Add a point to the path.\n   *\n   * @param {Point2D} point The Point2D to add.\n   */\n  addPoint(point) {\n    this.pointArray.push(point);\n  }\n\n  /**\n   * Add a control point to the path.\n   *\n   * @param {Point2D} point The Point2D to make a control point.\n   */\n  addControlPoint(point) {\n    const index = this.pointArray.indexOf(point);\n    if (index !== -1) {\n      this.controlPointIndexArray.push(index);\n    } else {\n      throw new Error(\n        'Cannot mark a non registered point as control point.');\n    }\n  }\n\n  /**\n   * Add points to the path.\n   *\n   * @param {Array} newPointArray The list of Point2D to add.\n   */\n  addPoints(newPointArray) {\n    this.pointArray = this.pointArray.concat(newPointArray);\n  }\n\n  /**\n   * Append a Path to this one.\n   *\n   * @param {Path} other The Path to append.\n   */\n  appenPath(other) {\n    const oldSize = this.pointArray.length;\n    this.pointArray = this.pointArray.concat(other.pointArray);\n    const indexArray = [];\n    for (let i = 0; i < other.controlPointIndexArray.length; ++i) {\n      indexArray[i] = other.controlPointIndexArray[i] + oldSize;\n    }\n    this.controlPointIndexArray =\n      this.controlPointIndexArray.concat(indexArray);\n  }\n\n} // Path class\n","/**\n * Circular Bucket Queue.\n *\n * Returns input'd points in sorted order. All operations run in roughly O(1)\n * time (for input with small cost values), but it has a strict requirement:\n *\n * If the most recent point had a cost of c, any points added should have a cost\n * c' in the range c <= c' <= c + (capacity - 1).\n */\nexport class BucketQueue {\n\n  /**\n   * @param {number} bits Number of bits.\n   * @param {Function} cost_functor The cost functor.\n   */\n  constructor(bits, cost_functor) {\n    this.bucketCount = 1 << bits; // # of buckets = 2^bits\n    this.mask = this.bucketCount - 1; // 2^bits - 1 = index mask\n    this.size = 0;\n\n    this.loc = 0; // Current index in bucket list\n    // Cost defaults to item value\n    this.cost = (typeof (cost_functor) !== 'undefined')\n      ? cost_functor : function (item) {\n        return item;\n      };\n    this.buckets = this.buildArray(this.bucketCount);\n  }\n\n  push(item) {\n    // Prepend item to the list in the appropriate bucket\n    const bucket = this.getBucket(item);\n    item.next = this.buckets[bucket];\n    this.buckets[bucket] = item;\n\n    this.size++;\n  }\n\n  pop() {\n    if (this.size === 0) {\n      throw new Error('Cannot pop, bucketQueue is empty.');\n    }\n\n    // Find first empty bucket\n    while (this.buckets[this.loc] === null) {\n      this.loc = (this.loc + 1) % this.bucketCount;\n    }\n\n    // All items in bucket have same cost, return the first one\n    const ret = this.buckets[this.loc];\n    this.buckets[this.loc] = ret.next;\n    ret.next = null;\n\n    this.size--;\n    return ret;\n  }\n\n  // TODO: needs at least two items...\n  remove(item) {\n    // Tries to remove item from queue. Returns true on success, false otherwise\n    if (!item) {\n      return false;\n    }\n\n    // To find node, go to bucket and search through unsorted list.\n    const bucket = this.getBucket(item);\n    let node = this.buckets[bucket];\n\n    while (node !== null &&\n      !(node.next !== null &&\n      item.x === node.next.x &&\n      item.y === node.next.y)) {\n      node = node.next;\n    }\n\n    if (node === null) {\n      // Item not in list, ergo item not in queue\n      return false;\n    } else {\n      // Found item, do standard list node deletion\n      node.next = node.next.next;\n\n      this.size--;\n      return true;\n    }\n  }\n\n  isEmpty() {\n    return this.size === 0;\n  }\n\n  getBucket(item) {\n    // Bucket index is the masked cost\n    return this.cost(item) & this.mask;\n  }\n\n  buildArray(newSize) {\n    // Create array and initialze pointers to null\n    const buckets = new Array(newSize);\n\n    for (let i = 0; i < buckets.length; i++) {\n      buckets[i] = null;\n    }\n\n    return buckets;\n  }\n\n} // class BucketQueue\n","import {BucketQueue} from './bucketQueue';\n\n// Pre-created to reduce allocation in inner loops\nconst __twothirdpi = (2 / (3 * Math.PI));\n\n/**\n * @param {Array} data The input data.\n * @param {number} width The width of the output.\n * @param {number} height The height of the output.\n * @returns {object} A greyscale object\n */\nfunction computeGreyscale(data, width, height) {\n  // Returns 2D augmented array containing greyscale data\n  // Greyscale values found by averaging colour channels\n  // Input should be in a flat RGBA array, with values between 0 and 255\n  const greyscale = {\n    data: []\n  };\n\n  // Compute actual values\n  for (let y = 0; y < height; y++) {\n    greyscale.data[y] = [];\n\n    for (let x = 0; x < width; x++) {\n      const p = (y * width + x) * 4;\n      greyscale.data[y][x] = (data[p] + data[p + 1] + data[p + 2]) / (3 * 255);\n    }\n  }\n\n  // Augment with convenience functions\n  greyscale.dx = function (x, y) {\n    if (x + 1 === this.data[y].length) {\n      // If we're at the end, back up one\n      x--;\n    }\n    return this.data[y][x + 1] - this.data[y][x];\n  };\n\n  greyscale.dy = function (x, y) {\n    if (y + 1 === this.data.length) {\n      // If we're at the end, back up one\n      y--;\n    }\n    return this.data[y][x] - this.data[y + 1][x];\n  };\n\n  greyscale.gradMagnitude = function (x, y) {\n    const dx = this.dx(x, y);\n    const dy = this.dy(x, y);\n    return Math.sqrt(dx * dx + dy * dy);\n  };\n\n  greyscale.laplace = function (x, y) {\n    // Laplacian of Gaussian\n    let lap = -16 * this.data[y][x];\n    lap += this.data[y - 2][x];\n    lap += this.data[y - 1][x - 1] +\n      2 * this.data[y - 1][x] +\n      this.data[y - 1][x + 1];\n    lap += this.data[y][x - 2] +\n      2 * this.data[y][x - 1] +\n      2 * this.data[y][x + 1] +\n      this.data[y][x + 2];\n    lap += this.data[y + 1][x - 1] +\n      2 * this.data[y + 1][x] +\n      this.data[y + 1][x + 1];\n    lap += this.data[y + 2][x];\n\n    return lap;\n  };\n\n  return greyscale;\n}\n\n/**\n * @param {object} greyscale The input greyscale-\n * @returns {object} A gradient object\n */\nfunction computeGradient(greyscale) {\n  // Returns a 2D array of gradient magnitude values for greyscale. The values\n  // are scaled between 0 and 1, and then flipped, so that it works as a cost\n  // function.\n  const gradient = [];\n\n  let max = 0; // Maximum gradient found, for scaling purposes\n\n  let x = 0;\n  let y = 0;\n\n  for (y = 0; y < greyscale.data.length - 1; y++) {\n    gradient[y] = [];\n\n    for (x = 0; x < greyscale.data[y].length - 1; x++) {\n      gradient[y][x] = greyscale.gradMagnitude(x, y);\n      max = Math.max(gradient[y][x], max);\n    }\n\n    gradient[y][greyscale.data[y].length - 1] =\n      gradient[y][greyscale.data.length - 2];\n  }\n\n  gradient[greyscale.data.length - 1] = [];\n  for (let i = 0; i < gradient[0].length; i++) {\n    gradient[greyscale.data.length - 1][i] =\n      gradient[greyscale.data.length - 2][i];\n  }\n\n  // Flip and scale.\n  for (y = 0; y < gradient.length; y++) {\n    for (x = 0; x < gradient[y].length; x++) {\n      // @ts-ignore\n      gradient[y][x] = 1 - (gradient[y][x] / max);\n    }\n  }\n\n  return gradient;\n}\n\n/**\n * @param {object} greyscale The input greyscale.\n * @returns {object} A laplace object.\n */\nfunction computeLaplace(greyscale) {\n  // Returns a 2D array of Laplacian of Gaussian values\n  const laplace = [];\n\n  // Make the edges low cost here.\n\n  laplace[0] = [];\n  laplace[1] = [];\n  for (let i = 1; i < greyscale.data.length; i++) {\n    // Pad top, since we can't compute Laplacian\n    laplace[0][i] = 1;\n    laplace[1][i] = 1;\n  }\n\n  for (let y = 2; y < greyscale.data.length - 2; y++) {\n    laplace[y] = [];\n    // Pad left, ditto\n    laplace[y][0] = 1;\n    laplace[y][1] = 1;\n\n    for (let x = 2; x < greyscale.data[y].length - 2; x++) {\n      // Threshold needed to get rid of clutter.\n      laplace[y][x] = (greyscale.laplace(x, y) > 0.33) ? 0 : 1;\n    }\n\n    // Pad right, ditto\n    laplace[y][greyscale.data[y].length - 2] = 1;\n    laplace[y][greyscale.data[y].length - 1] = 1;\n  }\n\n  laplace[greyscale.data.length - 2] = [];\n  laplace[greyscale.data.length - 1] = [];\n  for (let j = 1; j < greyscale.data.length; j++) {\n    // Pad bottom, ditto\n    laplace[greyscale.data.length - 2][j] = 1;\n    laplace[greyscale.data.length - 1][j] = 1;\n  }\n\n  return laplace;\n}\n\n/**\n * Compute the X gradient.\n *\n * @param {object} greyscale The values.\n * @returns {Array} The gradient.\n */\nfunction computeGradX(greyscale) {\n  // Returns 2D array of x-gradient values for greyscale\n  const gradX = [];\n\n  for (let y = 0; y < greyscale.data.length; y++) {\n    gradX[y] = [];\n\n    for (let x = 0; x < greyscale.data[y].length - 1; x++) {\n      gradX[y][x] = greyscale.dx(x, y);\n    }\n\n    gradX[y][greyscale.data[y].length - 1] =\n      gradX[y][greyscale.data[y].length - 2];\n  }\n\n  return gradX;\n}\n\n/**\n * Compute the Y gradient.\n *\n * @param {object} greyscale The values.\n * @returns {Array} The gradient.\n */\nfunction computeGradY(greyscale) {\n  // Returns 2D array of y-gradient values for greyscale\n  const gradY = [];\n\n  for (let y = 0; y < greyscale.data.length - 1; y++) {\n    gradY[y] = [];\n\n    for (let x = 0; x < greyscale.data[y].length; x++) {\n      gradY[y][x] = greyscale.dy(x, y);\n    }\n  }\n\n  gradY[greyscale.data.length - 1] = [];\n  for (let i = 0; i < greyscale.data[0].length; i++) {\n    gradY[greyscale.data.length - 1][i] = gradY[greyscale.data.length - 2][i];\n  }\n\n  return gradY;\n}\n\n/**\n * Compute the gradient unit vector.\n *\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {number} px The point X.\n * @param {number} py The point Y.\n * @param {object} out The result.\n */\nfunction gradUnitVector(gradX, gradY, px, py, out) {\n  // Returns the gradient vector at (px,py), scaled to a magnitude of 1\n  const ox = gradX[py][px];\n  const oy = gradY[py][px];\n\n  let gvm = Math.sqrt(ox * ox + oy * oy);\n  gvm = Math.max(gvm, 1e-100); // To avoid possible divide-by-0 errors\n\n  out.x = ox / gvm;\n  out.y = oy / gvm;\n}\n\n/**\n * Compute the gradient direction.\n *\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {number} px The point X.\n * @param {number} py The point Y.\n * @param {number} qx The q X.\n * @param {number} qy The q Y.\n * @returns {number} The direction.\n */\nfunction gradDirection(gradX, gradY, px, py, qx, qy) {\n  const __dgpuv = {x: -1, y: -1};\n  const __gdquv = {x: -1, y: -1};\n  // Compute the gradiant direction, in radians, between to points\n  gradUnitVector(gradX, gradY, px, py, __dgpuv);\n  gradUnitVector(gradX, gradY, qx, qy, __gdquv);\n\n  let dp = __dgpuv.y * (qx - px) - __dgpuv.x * (qy - py);\n  let dq = __gdquv.y * (qx - px) - __gdquv.x * (qy - py);\n\n  // Make sure dp is positive, to keep things consistant\n  if (dp < 0) {\n    dp = -dp;\n    dq = -dq;\n  }\n\n  if (px !== qx && py !== qy) {\n    // We're going diagonally between pixels\n    dp *= Math.SQRT1_2;\n    dq *= Math.SQRT1_2;\n  }\n\n  return __twothirdpi * (Math.acos(dp) + Math.acos(dq));\n}\n\n/**\n * Compute the sides.\n *\n * @param {number} dist The distance.\n * @param {Array} gradX The X gradient.\n * @param {Array} gradY The Y gradient.\n * @param {object} greyscale The value.\n * @returns {object} The sides.\n */\nfunction computeSides(dist, gradX, gradY, greyscale) {\n  // Returns 2 2D arrays, containing inside and outside greyscale values.\n  // These greyscale values are the intensity just a little bit along the\n  // gradient vector, in either direction, from the supplied point. These\n  // values are used when using active-learning Intelligent Scissors\n\n  const sides = {};\n  sides.inside = [];\n  sides.outside = [];\n\n  const guv = {x: -1, y: -1}; // Current gradient unit vector\n\n  for (let y = 0; y < gradX.length; y++) {\n    sides.inside[y] = [];\n    sides.outside[y] = [];\n\n    for (let x = 0; x < gradX[y].length; x++) {\n      gradUnitVector(gradX, gradY, x, y, guv);\n\n      //(x, y) rotated 90 = (y, -x)\n\n      let ix = Math.round(x + dist * guv.y);\n      let iy = Math.round(y - dist * guv.x);\n      let ox = Math.round(x - dist * guv.y);\n      let oy = Math.round(y + dist * guv.x);\n\n      ix = Math.max(Math.min(ix, gradX[y].length - 1), 0);\n      ox = Math.max(Math.min(ox, gradX[y].length - 1), 0);\n      iy = Math.max(Math.min(iy, gradX.length - 1), 0);\n      oy = Math.max(Math.min(oy, gradX.length - 1), 0);\n\n      sides.inside[y][x] = greyscale.data[iy][ix];\n      sides.outside[y][x] = greyscale.data[oy][ox];\n    }\n  }\n\n  return sides;\n}\n\n/**\n * Gaussian blur an input buffer.\n *\n * @param {Array} buffer The input buffer.\n * @param {Array} out The result.\n */\nfunction gaussianBlur(buffer, out) {\n  // Smooth values over to fill in gaps in the mapping\n  out[0] = 0.4 * buffer[0] + 0.5 * buffer[1] + 0.1 * buffer[1];\n  out[1] = 0.25 * buffer[0] + 0.4 * buffer[1] + 0.25 * buffer[2] +\n    0.1 * buffer[3];\n\n  for (let i = 2; i < buffer.length - 2; i++) {\n    out[i] = 0.05 * buffer[i - 2] + 0.25 * buffer[i - 1] +\n      0.4 * buffer[i] + 0.25 * buffer[i + 1] + 0.05 * buffer[i + 2];\n  }\n\n  const len = buffer.length;\n  out[len - 2] = 0.25 * buffer[len - 1] + 0.4 * buffer[len - 2] +\n    0.25 * buffer[len - 3] + 0.1 * buffer[len - 4];\n  out[len - 1] = 0.4 * buffer[len - 1] + 0.5 * buffer[len - 2] +\n    0.1 * buffer[len - 3];\n}\n\n/**\n * Scissors\n *\n * Ref: Eric N. Mortensen, William A. Barrett, Interactive Segmentation with\n *   Intelligent Scissors, Graphical Models and Image Processing, Volume 60,\n *   Issue 5, September 1998, Pages 349-384, ISSN 1077-3169,\n *   DOI: 10.1006/gmip.1998.0480.\n *\n * {@link http://www.sciencedirect.com/science/article/B6WG4-45JB8WN-9/2/6fe59d8089fd1892c2bfb82283065579}\n *\n * Highly inspired from {@link http://code.google.com/p/livewire-javascript/}\n */\nexport class Scissors {\n\n  constructor() {\n    this.width = -1;\n    this.height = -1;\n\n    this.curPoint = null; // Corrent point we're searching on.\n    this.searchGranBits = 8; // Bits of resolution for BucketQueue.\n    this.searchGran = 1 << this.searchGranBits; //bits.\n    this.pointsPerPost = 500;\n\n    // Precomputed image data. All in ranges 0 >= x >= 1 and\n    //   all inverted (1 - x).\n    this.greyscale = null; // Greyscale of image\n    this.laplace = null; // Laplace zero-crossings (either 0 or 1).\n    this.gradient = null; // Gradient magnitudes.\n    this.gradX = null; // X-differences.\n    this.gradY = null; // Y-differences.\n\n    // Matrix mapping point => parent along shortest-path to root.\n    this.parents = null;\n\n    this.working = false; // Currently computing shortest paths?\n\n    // Begin Training:\n    this.trained = false;\n    this.trainingPoints = null;\n\n    this.edgeWidth = 2;\n    this.trainingLength = 32;\n\n    this.edgeGran = 256;\n    this.edgeTraining = null;\n\n    this.gradPointsNeeded = 32;\n    this.gradGran = 1024;\n    this.gradTraining = null;\n\n    this.insideGran = 256;\n    this.insideTraining = null;\n\n    this.outsideGran = 256;\n    this.outsideTraining = null;\n  }\n  // End Training\n\n\n  // Begin training methods //\n  getTrainingIdx(granularity, value) {\n    return Math.round((granularity - 1) * value);\n  }\n\n  getTrainedEdge(edge) {\n    return this.edgeTraining[this.getTrainingIdx(this.edgeGran, edge)];\n  }\n\n  getTrainedGrad(grad) {\n    return this.gradTraining[this.getTrainingIdx(this.gradGran, grad)];\n  }\n\n  getTrainedInside(inside) {\n    return this.insideTraining[this.getTrainingIdx(this.insideGran, inside)];\n  }\n\n  getTrainedOutside(outside) {\n    return this.outsideTraining[this.getTrainingIdx(this.outsideGran, outside)];\n  }\n  // End training methods //\n\n  setWorking(working) {\n    // Sets working flag\n    this.working = working;\n  }\n\n  setDimensions(width, height) {\n    this.width = width;\n    this.height = height;\n  }\n\n  setData(data) {\n    if (this.width === -1 || this.height === -1) {\n      // The width and height should have already been set\n      throw new Error('Dimensions have not been set.');\n    }\n\n    this.greyscale = computeGreyscale(data, this.width, this.height);\n    this.laplace = computeLaplace(this.greyscale);\n    this.gradient = computeGradient(this.greyscale);\n    this.gradX = computeGradX(this.greyscale);\n    this.gradY = computeGradY(this.greyscale);\n\n    const sides = computeSides(\n      this.edgeWidth, this.gradX, this.gradY, this.greyscale);\n    this.inside = sides.inside;\n    this.outside = sides.outside;\n    this.edgeTraining = [];\n    this.gradTraining = [];\n    this.insideTraining = [];\n    this.outsideTraining = [];\n  }\n\n  findTrainingPoints(p) {\n    // Grab the last handful of points for training\n    const points = [];\n\n    if (this.parents !== null) {\n      for (let i = 0; i < this.trainingLength && p; i++) {\n        points.push(p);\n        p = this.parents[p.y][p.x];\n      }\n    }\n\n    return points;\n  }\n\n  resetTraining() {\n    this.trained = false; // Training is ignored with this flag set\n  }\n\n  doTraining(p) {\n    // Compute training weights and measures\n    this.trainingPoints = this.findTrainingPoints(p);\n\n    if (this.trainingPoints.length < 8) {\n      return; // Not enough points, I think. It might crash if length = 0.\n    }\n\n    const buffer = [];\n    this.calculateTraining(\n      buffer, this.edgeGran, this.greyscale, this.edgeTraining);\n    this.calculateTraining(\n      buffer, this.gradGran, this.gradient, this.gradTraining);\n    this.calculateTraining(\n      buffer, this.insideGran, this.inside, this.insideTraining);\n    this.calculateTraining(\n      buffer, this.outsideGran, this.outside, this.outsideTraining);\n\n    if (this.trainingPoints.length < this.gradPointsNeeded) {\n      // If we have two few training points, the gradient weight map might not\n      // be smooth enough, so average with normal weights.\n      this.addInStaticGrad(this.trainingPoints.length, this.gradPointsNeeded);\n    }\n\n    this.trained = true;\n  }\n\n  calculateTraining(\n    buffer, granularity, input, output) {\n    let i = 0;\n    // Build a map of raw-weights to trained-weights by favoring input values\n    buffer.length = granularity;\n    for (i = 0; i < granularity; i++) {\n      buffer[i] = 0;\n    }\n\n    let maxVal = 1;\n    for (i = 0; i < this.trainingPoints.length; i++) {\n      const p = this.trainingPoints[i];\n      const idx = this.getTrainingIdx(granularity, input[p.y][p.x]);\n      buffer[idx] += 1;\n\n      maxVal = Math.max(maxVal, buffer[idx]);\n    }\n\n    // Invert and scale.\n    for (i = 0; i < granularity; i++) {\n      buffer[i] = 1 - buffer[i] / maxVal;\n    }\n\n    // Blur it, as suggested. Gets rid of static.\n    gaussianBlur(buffer, output);\n  }\n\n  addInStaticGrad(have, need) {\n    // Average gradient raw-weights to trained-weights map with standard weight\n    // map so that we don't end up with something to spiky\n    for (let i = 0; i < this.gradGran; i++) {\n      this.gradTraining[i] = Math.min(\n        this.gradTraining[i],\n        1 - i * (need - have) / (need * this.gradGran)\n      );\n    }\n  }\n\n  gradDirection(px, py, qx, qy) {\n    return gradDirection(this.gradX, this.gradY, px, py, qx, qy);\n  }\n\n  dist(px, py, qx, qy) {\n    // The grand culmunation of most of the code: the weighted distance function\n    let grad = this.gradient[qy][qx];\n\n    if (px === qx || py === qy) {\n      // The distance is Euclidean-ish; non-diagonal edges should be shorter\n      grad *= Math.SQRT1_2;\n    }\n\n    const lap = this.laplace[qy][qx];\n    const dir = this.gradDirection(px, py, qx, qy);\n\n    if (this.trained) {\n      // Apply training magic\n      const gradT = this.getTrainedGrad(grad);\n      const edgeT = this.getTrainedEdge(this.greyscale.data[py][px]);\n      const insideT = this.getTrainedInside(this.inside[py][px]);\n      const outsideT = this.getTrainedOutside(this.outside[py][px]);\n\n      return 0.3 * gradT + 0.3 * lap + 0.1 * (dir + edgeT + insideT + outsideT);\n    } else {\n      // Normal weights\n      return 0.43 * grad + 0.43 * lap + 0.11 * dir;\n    }\n  }\n\n  adj(p) {\n    const list = [];\n\n    const sx = Math.max(p.x - 1, 0);\n    const sy = Math.max(p.y - 1, 0);\n    const ex = Math.min(p.x + 1, this.greyscale.data[0].length - 1);\n    const ey = Math.min(p.y + 1, this.greyscale.data.length - 1);\n\n    let idx = 0;\n    for (let y = sy; y <= ey; y++) {\n      for (let x = sx; x <= ex; x++) {\n        if (x !== p.x || y !== p.y) {\n          list[idx++] = {x: x, y: y};\n        }\n      }\n    }\n\n    return list;\n  }\n\n  #costFunction = (p) => {\n    return Math.round(this.searchGran * this.cost[p.y][p.x]);\n  };\n\n  setPoint(sp) {\n    this.setWorking(true);\n\n    this.curPoint = sp;\n\n    let x = 0;\n    let y = 0;\n\n    this.visited = [];\n    for (y = 0; y < this.height; y++) {\n      this.visited[y] = [];\n      for (x = 0; x < this.width; x++) {\n        this.visited[y][x] = false;\n      }\n    }\n\n    this.parents = [];\n    for (y = 0; y < this.height; y++) {\n      this.parents[y] = [];\n    }\n\n    this.cost = [];\n    for (y = 0; y < this.height; y++) {\n      this.cost[y] = [];\n      for (x = 0; x < this.width; x++) {\n        this.cost[y][x] = Number.MAX_VALUE;\n      }\n    }\n    this.cost[sp.y][sp.x] = 0;\n\n    this.pq = new BucketQueue(this.searchGranBits, this.#costFunction);\n    this.pq.push(sp);\n  }\n\n  doWork() {\n    if (!this.working) {\n      return;\n    }\n\n    this.timeout = null;\n\n    let pointCount = 0;\n    const newPoints = [];\n    while (!this.pq.isEmpty() && pointCount < this.pointsPerPost) {\n      const p = this.pq.pop();\n      newPoints.push(p);\n      newPoints.push(this.parents[p.y][p.x]);\n\n      this.visited[p.y][p.x] = true;\n\n      const adjList = this.adj(p);\n      for (let i = 0; i < adjList.length; i++) {\n        const q = adjList[i];\n\n        const pqCost = this.cost[p.y][p.x] + this.dist(p.x, p.y, q.x, q.y);\n\n        if (pqCost < this.cost[q.y][q.x]) {\n          if (this.cost[q.y][q.x] !== Number.MAX_VALUE) {\n            // Already in PQ, must remove it so we can re-add it.\n            this.pq.remove(q);\n          }\n\n          this.cost[q.y][q.x] = pqCost;\n          this.parents[q.y][q.x] = p;\n          this.pq.push(q);\n        }\n      }\n\n      pointCount++;\n    }\n\n    return newPoints;\n  }\n\n} // Scissors class\n","import {i18n} from '../utils/i18n';\nimport {getStats} from './stats';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n *  null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n  let res = null;\n  if (b !== null && c !== null) {\n    res = a * b * c;\n  }\n  return res;\n}\n\n/**\n * Circle shape.\n */\nexport class Circle {\n\n  /**\n   * Circle centre.\n   *\n   * @type {Point2D}\n   */\n  #centre;\n\n  /**\n   * Circle radius.\n   *\n   * @type {number}\n   */\n  #radius;\n\n  /**\n   * @param {Point2D} centre A Point2D representing the centre\n   *   of the circle.\n   * @param {number} radius The radius of the circle.\n   */\n  constructor(centre, radius) {\n    this.#centre = centre;\n    this.#radius = radius;\n  }\n\n  /**\n   * Get the centre (point) of the circle.\n   *\n   * @returns {Point2D} The center (point) of the circle.\n   */\n  getCenter() {\n    return this.#centre;\n  }\n\n  /**\n   * Get the radius of the circle.\n   *\n   * @returns {number} The radius of the circle.\n   */\n  getRadius() {\n    return this.#radius;\n  }\n\n\n  /**\n   * Check for equality.\n   *\n   * @param {Circle} rhs The object to compare to.\n   * @returns {boolean} True if both objects are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getCenter().equals(rhs.getCenter()) &&\n      this.getRadius() === rhs.getRadius();\n  }\n\n  /**\n   * Get the surface of the circle.\n   *\n   * @returns {number} The surface of the circle.\n   */\n  getSurface() {\n    return Math.PI * this.getRadius() * this.getRadius();\n  }\n\n  /**\n   * Get the surface of the circle according to a spacing.\n   *\n   * @param {number} spacingX The X spacing.\n   * @param {number} spacingY The Y spacing.\n   * @returns {number} The surface of the circle multiplied by the given\n   *  spacing or null for null spacings.\n   */\n  getWorldSurface(spacingX, spacingY) {\n    return mulABC(this.getSurface(), spacingX, spacingY);\n  }\n\n  /**\n   * Get the rounded limits of the circle.\n   * (see https://en.wikipedia.org/wiki/Circle#Equations)\n   * Circle formula: x*x + y*y = r*r\n   * => y = (+-) sqrt(r*r - x*x)\n   *\n   * @returns {Array} The rounded limits.\n   */\n  getRound() {\n    const centerX = this.getCenter().getX();\n    const centerY = this.getCenter().getY();\n    const radius = this.getRadius();\n    const rSquare = Math.pow(radius, 2);\n    // Y bounds\n    const minY = centerY - radius;\n    const maxY = centerY + radius;\n    const regions = [];\n    // loop through lines and store limits\n    for (let y = minY; y < maxY; ++y) {\n      const diff = rSquare - Math.pow(y - centerY, 2);\n      // remove small values (possibly negative)\n      if (Math.abs(diff) < 1e-7) {\n        continue;\n      }\n      const transX = Math.sqrt(diff);\n      // remove small values\n      if (transX < 0.5) {\n        continue;\n      }\n      regions.push([\n        [Math.round(centerX - transX), Math.round(y)],\n        [Math.round(centerX + transX), Math.round(y)]\n      ]);\n    }\n    return regions;\n  }\n\n  /**\n   * Quantify an circle according to view information.\n   *\n   * @param {ViewController} viewController The associated view\n   *   controller.\n   * @param {Array} flags A list of stat values to calculate.\n   * @returns {object} A quantification object.\n   */\n  quantify(viewController, flags) {\n    const quant = {};\n    // surface\n    const spacing = viewController.get2DSpacing();\n    const surface = this.getWorldSurface(spacing[0], spacing[1]);\n    if (surface !== null) {\n      quant.surface = {value: surface / 100, unit: i18n.t('unit.cm2')};\n    }\n\n    // pixel quantification\n    if (viewController.canQuantifyImage()) {\n      const regions = this.getRound();\n      if (regions.length !== 0) {\n        const values = viewController.getImageVariableRegionValues(regions);\n        const quantif = getStats(values, flags);\n        quant.min = {value: quantif.min, unit: ''};\n        quant.max = {value: quantif.max, unit: ''};\n        quant.mean = {value: quantif.mean, unit: ''};\n        quant.stdDev = {value: quantif.stdDev, unit: ''};\n        if (typeof quantif.median !== 'undefined') {\n          quant.median = {value: quantif.median, unit: ''};\n        }\n        if (typeof quantif.p25 !== 'undefined') {\n          quant.p25 = {value: quantif.p25, unit: ''};\n        }\n        if (typeof quantif.p75 !== 'undefined') {\n          quant.p75 = {value: quantif.p75, unit: ''};\n        }\n      }\n    }\n\n    // return\n    return quant;\n  }\n\n} // Circle class\n","import {i18n} from '../utils/i18n';\nimport {getStats} from './stats';\nimport {Index} from './index';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {Point2D} from '../math/point';\nimport {ViewController} from '../app/viewController';\n/* eslint-enable no-unused-vars */\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n *  null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n  let res = null;\n  if (b !== null && c !== null) {\n    res = a * b * c;\n  }\n  return res;\n}\n\n/**\n * Ellipse shape.\n */\nexport class Ellipse {\n\n  /**\n   * Ellipse centre.\n   *\n   * @type {Point2D}\n   */\n  #centre;\n\n  /**\n   * Ellipse horizontal radius.\n   *\n   * @type {number}\n   */\n  #a;\n\n  /**\n   * Ellipse vertical radius.\n   *\n   * @type {number}\n   */\n  #b;\n\n  /**\n   * @param {Point2D} centre A Point2D representing the centre\n   *   of the ellipse.\n   * @param {number} a The radius of the ellipse on the horizontal axe.\n   * @param {number} b The radius of the ellipse on the vertical axe.\n   */\n  constructor(centre, a, b) {\n    this.#centre = centre;\n    this.#a = a;\n    this.#b = b;\n  }\n\n  /**\n   * Get the centre (point) of the ellipse.\n   *\n   * @returns {Point2D} The center (point) of the ellipse.\n   */\n  getCenter() {\n    return this.#centre;\n  }\n\n  /**\n   * Get the radius of the ellipse on the horizontal axe.\n   *\n   * @returns {number} The radius of the ellipse on the horizontal axe.\n   */\n  getA() {\n    return this.#a;\n  }\n\n  /**\n   * Get the radius of the ellipse on the vertical axe.\n   *\n   * @returns {number} The radius of the ellipse on the vertical axe.\n   */\n  getB() {\n    return this.#b;\n  }\n\n  /**\n   * Check for equality.\n   *\n   * @param {Ellipse} rhs The object to compare to.\n   * @returns {boolean} True if both objects are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getCenter().equals(rhs.getCenter()) &&\n      this.getA() === rhs.getA() &&\n      this.getB() === rhs.getB();\n  }\n\n  /**\n   * Get the surface of the ellipse.\n   *\n   * @returns {number} The surface of the ellipse.\n   */\n  getSurface() {\n    return Math.PI * this.getA() * this.getB();\n  }\n\n  /**\n   * Get the surface of the ellipse according to a spacing.\n   *\n   * @param {number} spacingX The X spacing.\n   * @param {number} spacingY The Y spacing.\n   * @returns {number} The surface of the ellipse multiplied by the given\n   *  spacing or null for null spacings.\n   */\n  getWorldSurface(spacingX, spacingY) {\n    return mulABC(this.getSurface(), spacingX, spacingY);\n  }\n\n  /**\n   * Get the rounded limits of the ellipse.\n   * (see https://en.wikipedia.org/wiki/Ellipse#Standard_equation)\n   * Ellipse formula: x*x / a*a + y*y / b*b = 1\n   * => y = (+-)(b/a) * sqrt(a*a - x*x)\n   *\n   * @returns {Array} The rounded limits.\n   */\n  getRound() {\n    const centerX = this.getCenter().getX();\n    const centerY = this.getCenter().getY();\n    const radiusX = this.getA();\n    const radiusY = this.getB();\n    const radiusRatio = radiusX / radiusY;\n    const rySquare = Math.pow(radiusY, 2);\n    // Y bounds\n    const minY = centerY - radiusY;\n    const maxY = centerY + radiusY;\n    const regions = [];\n    // loop through lines and store limits\n    for (let y = minY; y < maxY; ++y) {\n      const diff = rySquare - Math.pow(y - centerY, 2);\n      // remove small values (possibly negative)\n      if (Math.abs(diff) < 1e-7) {\n        continue;\n      }\n      const transX = radiusRatio * Math.sqrt(diff);\n      // remove small values\n      if (transX < 0.5) {\n        continue;\n      }\n      regions.push([\n        [Math.round(centerX - transX), Math.round(y)],\n        [Math.round(centerX + transX), Math.round(y)]\n      ]);\n    }\n    return regions;\n  }\n\n  /**\n   * Quantify an ellipse according to view information.\n   *\n   * @param {ViewController} viewController The associated view\n   *   controller.\n   * @param {Array} flags A list of stat values to calculate.\n   * @returns {object} A quantification object.\n   */\n  quantify(viewController, flags) {\n    const quant = {};\n    // surface\n    const spacing = viewController.get2DSpacing();\n    const surface = this.getWorldSurface(spacing[0], spacing[1]);\n    if (surface !== null) {\n      quant.surface = {value: surface / 100, unit: i18n.t('unit.cm2')};\n    }\n\n    // pixel quantification\n    if (viewController.canQuantifyImage()) {\n      const regions = this.getRound();\n      if (regions.length !== 0) {\n        const values = viewController.getImageVariableRegionValues(regions);\n        const quantif = getStats(values, flags);\n        quant.min = {value: quantif.min, unit: ''};\n        quant.max = {value: quantif.max, unit: ''};\n        quant.mean = {value: quantif.mean, unit: ''};\n        quant.stdDev = {value: quantif.stdDev, unit: ''};\n        if (typeof quantif.median !== 'undefined') {\n          quant.median = {value: quantif.median, unit: ''};\n        }\n        if (typeof quantif.p25 !== 'undefined') {\n          quant.p25 = {value: quantif.p25, unit: ''};\n        }\n        if (typeof quantif.p75 !== 'undefined') {\n          quant.p75 = {value: quantif.p75, unit: ''};\n        }\n      }\n    }\n\n    // return\n    return quant;\n  }\n\n} // Ellipse class\n\n/**\n * Get the indices that form a ellpise.\n *\n * @param {Index} center The ellipse center.\n * @param {Array} radius The 2 ellipse radiuses.\n * @param {Array} dir The 2 ellipse directions.\n * @returns {Array} The indices of the ellipse.\n */\nexport function getEllipseIndices(center, radius, dir) {\n  const centerValues = center.getValues();\n  // keep all values for possible extra dimensions\n  const values = centerValues.slice();\n  const indices = [];\n  const radiusI = radius[0];\n  const radiusJ = radius[1];\n  const radiusRatio = radiusI / radiusJ;\n  const radiusJ2 = Math.pow(radiusJ, 2);\n  const di = dir[0];\n  const dj = dir[1];\n  // deduce 4 positions from top right\n  for (let j = 0; j < radiusJ; ++j) {\n    // right triangle formed by radiuses, j and len\n    // ellipse: i*i / a*a + j*j / b*b = 1\n    // -> i = a/b * sqrt(b*b - j*j)\n    const len = Math.round(\n      radiusRatio * Math.sqrt(radiusJ2 - Math.pow(j, 2)));\n    const jmax = centerValues[dj] + j;\n    const jmin = centerValues[dj] - j;\n    for (let i = 0; i < len; ++i) {\n      const imax = centerValues[di] + i;\n      const imin = centerValues[di] - i;\n\n      // right\n      values[di] = imax;\n      // right - top\n      values[dj] = jmax;\n      indices.push(new Index(values.slice()));\n      // right - bottom\n      if (jmin !== jmax) {\n        values[dj] = jmin;\n        indices.push(new Index(values.slice()));\n      }\n\n      // left\n      if (imin !== imax) {\n        values[di] = imin;\n        // left - top\n        values[dj] = jmax;\n        indices.push(new Index(values.slice()));\n        // left - bottom\n        if (jmin !== jmax) {\n          values[dj] = jmin;\n          indices.push(new Index(values.slice()));\n        }\n      }\n    }\n  }\n  return indices;\n}\n","import {Point2D} from './point';\nimport {getStats} from './stats';\nimport {i18n} from '../utils/i18n';\n\n/**\n * Mulitply the three inputs if the last two are not null.\n *\n * @param {number} a The first input.\n * @param {number} b The second input.\n * @param {number} c The third input.\n * @returns {number} The multiplication of the three inputs or\n *  null if one of the last two is null.\n */\nfunction mulABC(a, b, c) {\n  let res = null;\n  if (b !== null && c !== null) {\n    res = a * b * c;\n  }\n  return res;\n}\n\n/**\n * Rectangle shape.\n */\nexport class Rectangle {\n\n  /**\n   * Rectangle begin point.\n   *\n   * @type {Point2D}\n   */\n  #begin;\n\n  /**\n   * Rectangle end point.\n   *\n   * @type {Point2D}\n   */\n  #end;\n\n  /**\n   * @param {Point2D} begin A Point2D representing the beginning\n   *   of the rectangle.\n   * @param {Point2D} end A Point2D representing the end\n   *   of the rectangle.\n   */\n  constructor(begin, end) {\n    this.#begin = new Point2D(\n      Math.min(begin.getX(), end.getX()),\n      Math.min(begin.getY(), end.getY())\n    );\n    this.#end = new Point2D(\n      Math.max(begin.getX(), end.getX()),\n      Math.max(begin.getY(), end.getY())\n    );\n  }\n\n  /**\n   * Get the begin point of the rectangle.\n   *\n   * @returns {Point2D} The begin point of the rectangle\n   */\n  getBegin() {\n    return this.#begin;\n  }\n\n  /**\n   * Get the end point of the rectangle.\n   *\n   * @returns {Point2D} The end point of the rectangle\n   */\n  getEnd() {\n    return this.#end;\n  }\n\n  /**\n   * Check for equality.\n   *\n   * @param {Rectangle} rhs The object to compare to.\n   * @returns {boolean} True if both objects are equal.\n   */\n  equals(rhs) {\n    return rhs !== null &&\n      this.getBegin().equals(rhs.getBegin()) &&\n      this.getEnd().equals(rhs.getEnd());\n  }\n\n  /**\n   * Get the surface of the rectangle.\n   *\n   * @returns {number} The surface of the rectangle.\n   */\n  getSurface() {\n    const begin = this.getBegin();\n    const end = this.getEnd();\n    return Math.abs(end.getX() - begin.getX()) *\n      Math.abs(end.getY() - begin.getY());\n  }\n\n  /**\n   * Get the surface of the rectangle according to a spacing.\n   *\n   * @param {number} spacingX The X spacing.\n   * @param {number} spacingY The Y spacing.\n   * @returns {number} The surface of the rectangle multiplied by the given\n   *  spacing or null for null spacings.\n   */\n  getWorldSurface(spacingX, spacingY) {\n    return mulABC(this.getSurface(), spacingX, spacingY);\n  }\n\n  /**\n   * Get the real width of the rectangle.\n   *\n   * @returns {number} The real width of the rectangle.\n   */\n  getRealWidth() {\n    return this.getEnd().getX() - this.getBegin().getX();\n  }\n\n  /**\n   * Get the real height of the rectangle.\n   *\n   * @returns {number} The real height of the rectangle.\n   */\n  getRealHeight() {\n    return this.getEnd().getY() - this.getBegin().getY();\n  }\n\n  /**\n   * Get the width of the rectangle.\n   *\n   * @returns {number} The width of the rectangle.\n   */\n  getWidth() {\n    return Math.abs(this.getRealWidth());\n  }\n\n  /**\n   * Get the height of the rectangle.\n   *\n   * @returns {number} The height of the rectangle.\n   */\n  getHeight() {\n    return Math.abs(this.getRealHeight());\n  }\n\n  /**\n   * Get the rounded limits of the rectangle.\n   *\n   * @returns {object} The rounded limits.\n   */\n  getRound() {\n    return {\n      min: this.getBegin().getRound(),\n      max: this.getEnd().getRound()\n    };\n  }\n\n  /**\n   * Quantify a rectangle according to view information.\n   *\n   * @param {object} viewController The associated view controller.\n   * @param {Array} flags A list of stat values to calculate.\n   * @returns {object} A quantification object.\n   */\n  quantify(viewController, flags) {\n    const quant = {};\n    // surface\n    const spacing = viewController.get2DSpacing();\n    const surface = this.getWorldSurface(spacing[0], spacing[1]);\n    if (surface !== null) {\n      quant.surface = {value: surface / 100, unit: i18n.t('unit.cm2')};\n    }\n\n    // pixel quantification\n    if (viewController.canQuantifyImage()) {\n      const round = this.getRound();\n      const values = viewController.getImageRegionValues(round.min, round.max);\n      const quantif = getStats(values, flags);\n      quant.min = {value: quantif.min, unit: ''};\n      quant.max = {value: quantif.max, unit: ''};\n      quant.mean = {value: quantif.mean, unit: ''};\n      quant.stdDev = {value: quantif.stdDev, unit: ''};\n      if (typeof quantif.median !== 'undefined') {\n        quant.median = {value: quantif.median, unit: ''};\n      }\n      if (typeof quantif.p25 !== 'undefined') {\n        quant.p25 = {value: quantif.p25, unit: ''};\n      }\n      if (typeof quantif.p75 !== 'undefined') {\n        quant.p75 = {value: quantif.p75, unit: ''};\n      }\n    }\n\n    // return\n    return quant;\n  }\n\n} // Rectangle class\n","// doc imports\n/* eslint-disable no-unused-vars */\nimport {Image} from './image';\n/* eslint-enable no-unused-vars */\n\n/**\n * Threshold an image between an input minimum and maximum.\n */\nexport class Threshold {\n  /**\n   * Threshold minimum.\n   *\n   * @type {number}\n   */\n  #min = 0;\n\n  /**\n   * Threshold maximum.\n   *\n   * @type {number}\n   */\n  #max = 0;\n\n  /**\n   * Get the threshold minimum.\n   *\n   * @returns {number} The threshold minimum.\n   */\n  getMin() {\n    return this.#min;\n  }\n\n  /**\n   * Set the threshold minimum.\n   *\n   * @param {number} val The threshold minimum.\n   */\n  setMin(val) {\n    this.#min = val;\n  }\n\n  /**\n   * Get the threshold maximum.\n   *\n   * @returns {number} The threshold maximum.\n   */\n  getMax() {\n    return this.#max;\n  }\n\n  /**\n   * Set the threshold maximum.\n   *\n   * @param {number} val The threshold maximum.\n   */\n  setMax(val) {\n    this.#max = val;\n  }\n\n  /**\n   * Get the name of the filter.\n   *\n   * @returns {string} The name of the filter.\n   */\n  getName() {\n    return 'Threshold';\n  }\n\n  /**\n   * Original image.\n   *\n   * @type {Image}\n   */\n  #originalImage = null;\n\n  /**\n   * Set the original image.\n   *\n   * @param {Image} image The original image.\n   */\n  setOriginalImage(image) {\n    this.#originalImage = image;\n  }\n\n  /**\n   * Get the original image.\n   *\n   * @returns {Image} image The original image.\n   */\n  getOriginalImage() {\n    return this.#originalImage;\n  }\n\n  /**\n   * Transform the main image using this filter.\n   *\n   * @returns {Image} The transformed image.\n   */\n  update() {\n    const image = this.getOriginalImage();\n    const imageMin = image.getDataRange().min;\n    const threshFunction = (value) => {\n      if (value < this.getMin() || value > this.getMax()) {\n        return imageMin;\n      } else {\n        return value;\n      }\n    };\n    return image.transform(threshFunction);\n  }\n\n} // class Threshold\n\n/**\n * Sharpen an image using a sharpen convolution matrix.\n */\nexport class Sharpen {\n  /**\n   * Get the name of the filter.\n   *\n   * @returns {string} The name of the filter.\n   */\n  getName() {\n    return 'Sharpen';\n  }\n\n  /**\n   * Original image.\n   *\n   * @type {Image}\n   */\n  #originalImage = null;\n\n  /**\n   * Set the original image.\n   *\n   * @param {Image} image The original image.\n   */\n  setOriginalImage(image) {\n    this.#originalImage = image;\n  }\n\n  /**\n   * Get the original image.\n   *\n   * @returns {Image} image The original image.\n   */\n  getOriginalImage() {\n    return this.#originalImage;\n  }\n\n  /**\n   * Transform the main image using this filter.\n   *\n   * @returns {Image} The transformed image.\n   */\n  update() {\n    const image = this.getOriginalImage();\n    /* eslint-disable array-element-newline */\n    return image.convolute2D([\n      0, -1, 0,\n      -1, 5, -1,\n      0, -1, 0\n    ]);\n    /* eslint-enable array-element-newline */\n  }\n\n} // class Sharpen\n\n/**\n * Apply a Sobel filter to an image.\n */\nexport class Sobel {\n  /**\n   * Get the name of the filter.\n   *\n   * @returns {string} The name of the filter.\n   */\n  getName() {\n    return 'Sobel';\n  }\n\n  /**\n   * Original image.\n   *\n   * @type {Image}\n   */\n  #originalImage = null;\n\n  /**\n   * Set the original image.\n   *\n   * @param {Image} image The original image.\n   */\n  setOriginalImage(image) {\n    this.#originalImage = image;\n  }\n\n  /**\n   * Get the original image.\n   *\n   * @returns {Image} image The original image.\n   */\n  getOriginalImage() {\n    return this.#originalImage;\n  }\n\n  /**\n   * Transform the main image using this filter.\n   *\n   * @returns {Image} The transformed image.\n   */\n  update() {\n    const image = this.getOriginalImage();\n    /* eslint-disable array-element-newline */\n    const gradX = image.convolute2D([\n      1, 0, -1,\n      2, 0, -2,\n      1, 0, -1\n    ]);\n    const gradY = image.convolute2D([\n      1, 2, 1,\n      0, 0, 0,\n      -1, -2, -1\n    ]);\n    /* eslint-enable array-element-newline */\n    return gradX.compose(gradY, function (x, y) {\n      return Math.sqrt(x * x + y * y);\n    });\n  }\n\n} // class Sobel\n","import {ListenerHandler} from '../utils/listen';\nimport {\n  Threshold as ThresholdFilter,\n  Sobel as SobelFilter,\n  Sharpen as SharpenFilter\n} from '../image/filter';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Filter tool.\n */\nexport class Filter {\n\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Filter list\n   *\n   * @type {object}\n   */\n  #filterList = null;\n\n  /**\n   * Selected filter.\n   *\n   * @type {object}\n   */\n  #selectedFilter = 0;\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} bool Flag to activate or not.\n   */\n  activate(bool) {\n    // setup event listening\n    for (const key in this.#filterList) {\n      if (bool) {\n        this.#filterList[key].addEventListener('filterrun', this.#fireEvent);\n        this.#filterList[key].addEventListener('filter-undo', this.#fireEvent);\n      } else {\n        this.#filterList[key].removeEventListener(\n          'filterrun', this.#fireEvent);\n        this.#filterList[key].removeEventListener(\n          'filter-undo', this.#fireEvent);\n      }\n    }\n  }\n\n  /**\n   * Set the tool options.\n   *\n   * @param {object} options The list of filter names amd classes.\n   */\n  setOptions(options) {\n    this.#filterList = {};\n    // try to instanciate filters from the options\n    for (const key in options) {\n      this.#filterList[key] = new options[key](this.#app);\n    }\n  }\n\n  /**\n   * Get the type of tool options: here 'instance' since the filter\n   * list contains instances of each possible filter.\n   *\n   * @returns {string} The type.\n   */\n  getOptionsType() {\n    return 'instance';\n  }\n\n  /**\n   * Initialise the filter. Called once the image is loaded.\n   */\n  init() {\n    // setup event listening\n    for (const key in this.#filterList) {\n      this.#filterList[key].init();\n    }\n  }\n\n  /**\n   * Handle keydown event.\n   *\n   * @param {object} event The keydown event.\n   */\n  keydown = (event) => {\n    event.context = 'Filter';\n    this.#app.onKeydown(event);\n  };\n\n  /**\n   * Get the list of event names that this tool can fire.\n   *\n   * @returns {Array} The list of event names.\n   */\n  getEventNames() {\n    return ['filterrun', 'filterundo'];\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  /**\n   * Get the selected filter.\n   *\n   * @returns {object} The selected filter.\n   */\n  getSelectedFilter() {\n    return this.#selectedFilter;\n  }\n\n  /**\n   * Set the tool live features: filter name.\n   *\n   * @param {object} features The list of features.\n   */\n  setFeatures(features) {\n    if (typeof features.filterName !== 'undefined') {\n      // check if we have it\n      if (!this.hasFilter(features.filterName)) {\n        throw new Error('Unknown filter: \\'' + features.filterName + '\\'');\n      }\n      // de-activate last selected\n      if (this.#selectedFilter) {\n        this.#selectedFilter.activate(false);\n      }\n      // enable new one\n      this.#selectedFilter = this.#filterList[features.filterName];\n      // activate the selected filter\n      this.#selectedFilter.activate(true);\n    }\n    if (typeof features.run !== 'undefined' && features.run) {\n      let args = {};\n      if (typeof features.runArgs !== 'undefined') {\n        args = features.runArgs;\n      }\n      this.getSelectedFilter().run(args);\n    }\n  }\n\n  /**\n   * Get the list of filters.\n   *\n   * @returns {Array} The list of filter objects.\n   */\n  getFilterList() {\n    return this.#filterList;\n  }\n\n  /**\n   * Check if a filter is in the filter list.\n   *\n   * @param {string} name The name to check.\n   * @returns {string} The filter list element for the given name.\n   */\n  hasFilter(name) {\n    return this.#filterList[name];\n  }\n\n} // class Filter\n\n/**\n * Threshold filter tool.\n */\nexport class Threshold {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Associated filter.\n   *\n   * @type {object}\n   */\n  #filter = new ThresholdFilter();\n\n  /**\n   * Flag to know wether to reset the image or not.\n   *\n   * @type {boolean}\n   */\n  #resetImage = true;\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Activate the filter.\n   *\n   * @param {boolean} bool Flag to activate or not.\n   */\n  activate(bool) {\n    // reset the image when the tool is activated\n    if (bool) {\n      this.#resetImage = true;\n    }\n  }\n\n  /**\n   * Initialise the filter. Called once the image is loaded.\n   */\n  init() {\n    // does nothing\n  }\n\n  /**\n   * Run the filter.\n   *\n   * @param {*} args The filter arguments.\n   */\n  run(args) {\n    this.#filter.setMin(args.min);\n    this.#filter.setMax(args.max);\n    // reset the image if asked\n    if (this.#resetImage) {\n      this.#filter.setOriginalImage(this.#app.getLastImage());\n      this.#resetImage = false;\n    }\n    const command = new RunFilterCommand(this.#filter, this.#app);\n    command.onExecute = this.#fireEvent;\n    command.onUndo = this.#fireEvent;\n    command.execute();\n    // save command in undo stack\n    this.#app.addToUndoStack(command);\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *  event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n} // class Threshold\n\n/**\n * Sharpen filter tool.\n */\nexport class Sharpen {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Activate the filter.\n   *\n   * @param {boolean} _bool Flag to activate or not.\n   */\n  activate(_bool) {\n    // does nothing\n  }\n\n  /**\n   * Initialise the filter. Called once the image is loaded.\n   */\n  init() {\n    // does nothing\n  }\n\n  /**\n   * Run the filter.\n   *\n   * @param {*} _args The filter arguments.\n   */\n  run(_args) {\n    const filter = new SharpenFilter();\n    filter.setOriginalImage(this.#app.getLastImage());\n    const command = new RunFilterCommand(filter, this.#app);\n    command.onExecute = this.#fireEvent;\n    command.onUndo = this.#fireEvent;\n    command.execute();\n    // save command in undo stack\n    this.#app.addToUndoStack(command);\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *    event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n} // filter.Sharpen\n\n/**\n * Sobel filter tool.\n */\nexport class Sobel {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Activate the filter.\n   *\n   * @param {boolean} _bool Flag to activate or not.\n   */\n  activate(_bool) {\n    // does nothing\n  }\n\n  /**\n   * Initialise the filter. Called once the image is loaded.\n   */\n  init() {\n    // does nothing\n  }\n\n  /**\n   * Run the filter.\n   *\n   * @param {*} _args The filter arguments.\n   */\n  run(_args) {\n    const filter = new SobelFilter();\n    filter.setOriginalImage(this.#app.getLastImage());\n    const command = new RunFilterCommand(filter, this.#app);\n    command.onExecute = this.#fireEvent;\n    command.onUndo = this.#fireEvent;\n    command.execute();\n    // save command in undo stack\n    this.#app.addToUndoStack(command);\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *  event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n} // class filter.Sobel\n\n/**\n * Run filter command.\n */\nexport class RunFilterCommand {\n\n  /**\n   * The filter to run.\n   *\n   * @type {object}\n   */\n  #filter;\n\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {object} filter The filter to run.\n   * @param {App} app The associated application.\n   */\n  constructor(filter, app) {\n    this.#filter = filter;\n    this.#app = app;\n  }\n\n  /**\n   * Get the command name.\n   *\n   * @returns {string} The command name.\n   */\n  getName() {\n    return 'Filter-' + this.#filter.getName();\n  }\n\n  /**\n   * Execute the command.\n   *\n   * @fires RunFilterCommand#filterrun\n   */\n  execute() {\n    // run filter and set app image\n    this.#app.setLastImage(this.#filter.update());\n    // update display\n    this.#app.render(0); //todo: fix\n    /**\n     * Filter run event.\n     *\n     * @event RunFilterCommand#filterrun\n     * @type {object}\n     * @property {string} type The event type: filterrun.\n     * @property {number} id The id of the run command.\n     */\n    const event = {\n      type: 'filterrun',\n      id: this.getName()\n    };\n    // callback\n    this.onExecute(event);\n  }\n\n  /**\n   * Undo the command.\n   *\n   * @fires RunFilterCommand#filterundo\n   */\n  undo() {\n    // reset the image\n    this.#app.setLastImage(this.#filter.getOriginalImage());\n    // update display\n    this.#app.render(0); //todo: fix\n    /**\n     * Filter undo event.\n     *\n     * @event RunFilterCommand#filterundo\n     * @type {object}\n     * @property {string} type The event type: filterundo.\n     * @property {number} id The id of the undone run command.\n     */\n    const event = {\n      type: 'filterundo',\n      id: this.getName()\n    }; // callback\n    this.onUndo(event);\n  }\n\n  /**\n   * Handle an execute event.\n   *\n   * @param {object} _event The execute event with type and id.\n   */\n  onExecute(_event) {\n    // default does nothing.\n  }\n\n  /**\n   * Handle an undo event.\n   *\n   * @param {object} _event The undo event with type and id.\n   */\n  onUndo(_event) {\n    // default does nothing.\n  }\n\n} // RunFilterCommand class\n","import {WindowLevel} from './windowLevel';\nimport {Scroll} from './scroll';\nimport {ZoomAndPan} from './zoomPan';\nimport {Opacity} from './opacity';\nimport {Draw} from './draw';\nimport {Floodfill} from './floodfill';\nimport {Livewire} from './livewire';\n\nimport {ArrowFactory} from './arrow';\nimport {CircleFactory} from './circle';\nimport {EllipseFactory} from './ellipse';\nimport {FreeHandFactory} from './freeHand';\nimport {ProtractorFactory} from './protractor';\nimport {RectangleFactory} from './rectangle';\nimport {RoiFactory} from './roi';\nimport {RulerFactory} from './ruler';\n\nimport {Filter, Threshold, Sobel, Sharpen} from './filter';\n\nexport const toolList = {\n  WindowLevel,\n  Scroll,\n  ZoomAndPan,\n  Opacity,\n  Draw,\n  Filter,\n  Floodfill,\n  Livewire\n};\n\nexport const toolOptions = {\n  draw: {\n    ArrowFactory,\n    CircleFactory,\n    EllipseFactory,\n    FreeHandFactory,\n    ProtractorFactory,\n    RectangleFactory,\n    RoiFactory,\n    RulerFactory\n  },\n  filter: {\n    Threshold,\n    Sobel,\n    Sharpen\n  }\n};","import {ScrollWheel} from './scrollWheel';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {\n  WindowCenterAndWidth,\n  validateWindowWidth\n} from '../image/windowCenterAndWidth';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * WindowLevel tool: handle window/level related events.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {WindowLevel: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n *   app.setTool('WindowLevel');\n * });\n * // load dicom data\n * app.loadURLs([\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class WindowLevel {\n\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * Interaction start flag.\n   *\n   * @type {boolean}\n   */\n  #started = false;\n\n  /**\n   * Scroll wheel handler.\n   *\n   * @type {ScrollWheel}\n   */\n  #scrollWhell;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n    this.#scrollWhell = new ScrollWheel(app);\n  }\n\n  /**\n   * Handle mouse down event.\n   *\n   * @param {object} event The mouse down event.\n   */\n  mousedown = (event) => {\n    // set start flag\n    this.#started = true;\n    // store initial position\n    this.x0 = event._x;\n    this.y0 = event._y;\n  };\n\n  /**\n   * Handle mouse move event.\n   *\n   * @param {object} event The mouse move event.\n   */\n  mousemove = (event) => {\n    // check start flag\n    if (!this.#started) {\n      return;\n    }\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n\n    // difference to last position\n    const diffX = event._x - this.x0;\n    const diffY = this.y0 - event._y;\n    // data range\n    const range = viewController.getImageRescaledDataRange();\n    // 1/1000 seems to give reasonable results...\n    const pixelToIntensity = (range.max - range.min) * 0.01;\n\n    // calculate new window level\n    const center = parseInt(viewController.getWindowLevel().center, 10);\n    const width = parseInt(viewController.getWindowLevel().width, 10);\n    const windowCenter = center + Math.round(diffY * pixelToIntensity);\n    let windowWidth = width + Math.round(diffX * pixelToIntensity);\n    // bound window width\n    windowWidth = validateWindowWidth(windowWidth);\n\n    // add the manual preset to the view\n    viewController.addWindowLevelPresets({\n      manual: {\n        wl: [new WindowCenterAndWidth(windowCenter, windowWidth)],\n        name: 'manual'\n      }\n    });\n    viewController.setWindowLevelPreset('manual');\n\n    // store position\n    this.x0 = event._x;\n    this.y0 = event._y;\n  };\n\n  /**\n   * Handle mouse up event.\n   *\n   * @param {object} _event The mouse up event.\n   */\n  mouseup = (_event) => {\n    // set start flag\n    if (this.#started) {\n      this.#started = false;\n    }\n  };\n\n  /**\n   * Handle mouse out event.\n   *\n   * @param {object} event The mouse out event.\n   */\n  mouseout = (event) => {\n    // treat as mouse up\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle touch start event.\n   *\n   * @param {object} event The touch start event.\n   */\n  touchstart = (event) => {\n    this.mousedown(event);\n  };\n\n  /**\n   * Handle touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  touchmove = (event) => {\n    this.mousemove(event);\n  };\n\n  /**\n   * Handle touch end event.\n   *\n   * @param {object} event The touch end event.\n   */\n  touchend = (event) => {\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle double click event.\n   *\n   * @param {object} event The double click event.\n   */\n  dblclick = (event) => {\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const index = viewLayer.displayToPlaneIndex(event._x, event._y);\n    const viewController = viewLayer.getViewController();\n    const image = this.#app.getImage(viewLayer.getDataIndex());\n\n    // update view controller\n    viewController.setWindowLevel(\n      image.getRescaledValueAtIndex(\n        viewController.getCurrentIndex().getWithNew2D(\n          index.get(0),\n          index.get(1)\n        )\n      ),\n      parseInt(viewController.getWindowLevel().width, 10));\n  };\n\n  /**\n   * Handle mouse wheel event.\n   *\n   * @param {object} event The mouse wheel event.\n   */\n  wheel = (event) => {\n    this.#scrollWhell.wheel(event);\n  };\n\n  /**\n   * Handle key down event.\n   *\n   * @param {object} event The key down event.\n   */\n  keydown = (event) => {\n    event.context = 'WindowLevel';\n    this.#app.onKeydown(event);\n  };\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} _bool The flag to activate or not.\n   */\n  activate(_bool) {\n    // does nothing\n  }\n\n  /**\n   * Initialise the tool.\n   */\n  init() {\n    // does nothing\n  }\n\n} // WindowLevel class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {precisionRound} from '../utils/string';\nimport {ScrollWheel} from './scrollWheel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Scroll class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Scroll: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n *   app.setTool('Scroll');\n * });\n * // load dicom data\n * app.loadURLs([\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm',\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323707.dcm',\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323563.dcm'\n * ]);\n * @example <caption>Example with slider</caption>\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Scroll: new dwv.ToolConfig()};\n * app.init(options);\n * // create range\n * const range = document.createElement('input');\n * range.type = 'range';\n * range.min = 0;\n * range.id = 'sliceRange';\n * document.body.appendChild(range);\n * // update app on slider change\n * range.oninput = function () {\n *   const lg = app.getLayerGroupByDivId('layerGroup0');\n *   const vc = lg.getActiveViewLayer().getViewController();\n *   const index = vc.getCurrentIndex();\n *   const values = index.getValues();\n *   values[2] = this.value;\n *   vc.setCurrentIndex(new dwv.Index(values));\n * }\n * // activate tool and update range max on load\n * app.addEventListener('load', function () {\n *   app.setTool('Scroll');\n *   const size = app.getImage(0).getGeometry().getSize();\n *   range.max = size.get(2) - 1;\n * });\n * // update slider on slice change (for ex via mouse wheel)\n * app.addEventListener('positionchange', function () {\n *   const lg = app.getLayerGroupByDivId('layerGroup0');\n *   const vc = lg.getActiveViewLayer().getViewController();\n *   range.value = vc.getCurrentIndex().get(2);\n * });\n * // load dicom data\n * app.loadURLs([\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm',\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323707.dcm',\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323563.dcm'\n * ]);\n */\nexport class Scroll {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * Interaction start flag.\n   *\n   * @type {boolean}\n   */\n  #started = false;\n\n  /**\n   * Scroll wheel handler.\n   *\n   * @type {ScrollWheel}\n   */\n  #scrollWhell;\n\n  /**\n   * Touch timer ID (created by setTimeout).\n   *\n   * @type {number}\n   */\n  #touchTimerID;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n    this.#scrollWhell = new ScrollWheel(app);\n  }\n\n  /**\n   * Option to show or not a value tooltip on mousemove.\n   *\n   * @type {boolean}\n   */\n  #displayTooltip = false;\n\n  /**\n   * Handle mouse down event.\n   *\n   * @param {object} event The mouse down event.\n   */\n  mousedown = (event) => {\n    // optional tooltip\n    this.#removeTooltipDiv();\n\n    // stop viewer if playing\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const viewController = viewLayer.getViewController();\n    if (viewController.isPlaying()) {\n      viewController.stop();\n    }\n    // start flag\n    this.#started = true;\n    // first position\n    this.x0 = event._x;\n    this.y0 = event._y;\n\n    // update controller position\n    const planePos = viewLayer.displayToPlanePos(event._x, event._y);\n    const position = viewController.getPositionFromPlanePoint(\n      planePos.x, planePos.y);\n    viewController.setCurrentPosition(position);\n  };\n\n  /**\n   * Handle mouse move event.\n   *\n   * @param {object} event The mouse move event.\n   */\n  mousemove = (event) => {\n    if (!this.#started) {\n      // optional tooltip\n      if (this.#displayTooltip) {\n        this.#showTooltip(event);\n      }\n      return;\n    }\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const viewController = viewLayer.getViewController();\n\n    // difference to last Y position\n    const diffY = event._y - this.y0;\n    const yMove = (Math.abs(diffY) > 15);\n    // do not trigger for small moves\n    if (yMove && viewController.canScroll()) {\n      // update view controller\n      if (diffY > 0) {\n        viewController.decrementScrollIndex();\n      } else {\n        viewController.incrementScrollIndex();\n      }\n    }\n\n    // difference to last X position\n    const diffX = event._x - this.x0;\n    const xMove = (Math.abs(diffX) > 15);\n    // do not trigger for small moves\n    const imageSize = viewController.getImageSize();\n    if (xMove && imageSize.moreThanOne(3)) {\n      // update view controller\n      if (diffX > 0) {\n        viewController.incrementIndex(3);\n      } else {\n        viewController.decrementIndex(3);\n      }\n    }\n\n    // reset origin point\n    if (xMove) {\n      this.x0 = event._x;\n    }\n    if (yMove) {\n      this.y0 = event._y;\n    }\n  };\n\n  /**\n   * Handle mouse up event.\n   *\n   * @param {object} _event The mouse up event.\n   */\n  mouseup = (_event) => {\n    if (this.#started) {\n      // stop recording\n      this.#started = false;\n    }\n  };\n\n  /**\n   * Handle mouse out event.\n   *\n   * @param {object} event The mouse out event.\n   */\n  mouseout = (event) => {\n    this.mouseup(event);\n    // remove possible tooltip div\n    this.#removeTooltipDiv();\n  };\n\n  /**\n   * Handle touch start event.\n   *\n   * @param {object} event The touch start event.\n   */\n  touchstart = (event) => {\n    // long touch triggers the dblclick\n    // @ts-ignore\n    this.#touchTimerID = setTimeout(this.dblclick, 500);\n    // call mouse equivalent\n    this.mousedown(event);\n  };\n\n  /**\n   * Handle touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  touchmove = (event) => {\n    // abort timer if move\n    if (this.#touchTimerID !== null) {\n      clearTimeout(this.#touchTimerID);\n      this.#touchTimerID = null;\n    }\n    // call mouse equivalent\n    this.mousemove(event);\n  };\n\n  /**\n   * Handle touch end event.\n   *\n   * @param {object} event The touch end event.\n   */\n  touchend = (event) => {\n    // abort timer\n    if (this.#touchTimerID !== null) {\n      clearTimeout(this.#touchTimerID);\n      this.#touchTimerID = null;\n    }\n    // call mouse equivalent\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle mouse wheel event.\n   *\n   * @param {object} event The mouse wheel event.\n   */\n  wheel = (event) => {\n    this.#scrollWhell.wheel(event);\n  };\n\n  /**\n   * Handle key down event.\n   *\n   * @param {object} event The key down event.\n   */\n  keydown = (event) => {\n    event.context = 'Scroll';\n    this.#app.onKeydown(event);\n  };\n\n  /**\n   * Handle double click.\n   *\n   * @param {object} event The key down event.\n   */\n  dblclick = (event) => {\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n    viewController.play();\n  };\n\n  /**\n   * Displays a tooltip in a temparary `span`.\n   * Works with css to hide/show the span only on mouse hover.\n   *\n   * @param {object} event The mouse move event.\n   */\n  #showTooltip(event) {\n    // remove previous div\n    this.#removeTooltipDiv();\n\n    // get image value at position\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const viewController = viewLayer.getViewController();\n    const planePos = viewLayer.displayToPlanePos(event._x, event._y);\n    const position = viewController.getPositionFromPlanePoint(\n      planePos.x, planePos.y);\n    const value = viewController.getRescaledImageValue(position);\n\n    // create\n    if (typeof value !== 'undefined') {\n      const span = document.createElement('span');\n      span.id = 'scroll-tooltip';\n      // place span in layer group to avoid upper layer opacity\n      const layerDiv = document.getElementById(viewLayer.getId());\n      layerDiv.parentElement.appendChild(span);\n      // position tooltip\n      span.style.left = (event._x + 10) + 'px';\n      span.style.top = (event._y + 10) + 'px';\n      let text = precisionRound(value, 3).toString();\n      if (typeof viewController.getPixelUnit() !== 'undefined') {\n        text += ' ' + viewController.getPixelUnit();\n      }\n      span.appendChild(document.createTextNode(text));\n    }\n  }\n\n  /**\n   * Remove the tooltip html div.\n   */\n  #removeTooltipDiv() {\n    const div = document.getElementById('scroll-tooltip');\n    if (div) {\n      div.remove();\n    }\n  }\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} _bool The flag to activate or not.\n   */\n  activate(_bool) {\n    // remove tooltip html when deactivating\n    if (!_bool) {\n      this.#removeTooltipDiv();\n    }\n  }\n\n  /**\n   * Set the tool live features: disaply tooltip.\n   *\n   * @param {object} features The list of features.\n   */\n  setFeatures(features) {\n    if (typeof features.displayTooltip !== 'undefined') {\n      this.#displayTooltip = features.displayTooltip;\n    }\n  }\n\n  /**\n   * Initialise the tool.\n   */\n  init() {\n    // does nothing\n  }\n\n} // Scroll class\n","import {Point2D} from '../math/point';\nimport {Line} from '../math/line';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * ZoomAndPan class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {ZoomAndPan: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n *   app.setTool('ZoomAndPan');\n * });\n * // load dicom data\n * app.loadURLs([\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class ZoomAndPan {\n\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * Interaction start flag.\n   *\n   * @type {boolean}\n   */\n  #started = false;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Handle mouse down event.\n   *\n   * @param {object} event The mouse down event.\n   */\n  mousedown = (event) => {\n    this.#started = true;\n    // first position\n    this.x0 = event._x;\n    this.y0 = event._y;\n  };\n\n  /**\n   * Handle two touch down event.\n   *\n   * @param {object} event The touch down event.\n   */\n  twotouchdown = (event) => {\n    this.#started = true;\n    // store first point\n    this.x0 = event._x;\n    this.y0 = event._y;\n    // first line\n    const point0 = new Point2D(event._x, event._y);\n    const point1 = new Point2D(event._x1, event._y1);\n    this.line0 = new Line(point0, point1);\n    this.midPoint = this.line0.getMidpoint();\n  };\n\n  /**\n   * Handle mouse move event.\n   *\n   * @param {object} event The mouse move event.\n   */\n  mousemove = (event) => {\n    if (!this.#started) {\n      return;\n    }\n    // calculate translation\n    const tx = event._x - this.x0;\n    const ty = event._y - this.y0;\n    // apply translation\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const viewController = viewLayer.getViewController();\n    const planeOffset = viewLayer.displayToPlaneScale(tx, ty);\n    const offset3D = viewController.getOffset3DFromPlaneOffset(planeOffset);\n    layerGroup.addTranslation({\n      x: offset3D.getX(),\n      y: offset3D.getY(),\n      z: offset3D.getZ()\n    });\n    layerGroup.draw();\n    // reset origin point\n    this.x0 = event._x;\n    this.y0 = event._y;\n  };\n\n  /**\n   * Handle two touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  twotouchmove = (event) => {\n    if (!this.#started) {\n      return;\n    }\n    const point0 = new Point2D(event._x, event._y);\n    const point1 = new Point2D(event._x1, event._y1);\n    const newLine = new Line(point0, point1);\n    const lineRatio = newLine.getLength() / this.line0.getLength();\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const viewController = viewLayer.getViewController();\n\n    if (lineRatio === 1) {\n      // scroll mode\n      // difference  to last position\n      const diffY = event._y - this.y0;\n      // do not trigger for small moves\n      if (Math.abs(diffY) < 15) {\n        return;\n      }\n      // update view controller\n      if (viewController.canScroll()) {\n        if (diffY > 0) {\n          viewController.incrementScrollIndex();\n        } else {\n          viewController.decrementScrollIndex();\n        }\n      }\n    } else {\n      // zoom mode\n      const zoom = (lineRatio - 1) / 10;\n      if (Math.abs(zoom) % 0.1 <= 0.05) {\n        const planePos = viewLayer.displayToMainPlanePos(\n          this.midPoint.getX(), this.midPoint.getY());\n        const center = viewController.getPlanePositionFromPlanePoint(planePos);\n        layerGroup.addScale(zoom, center);\n        layerGroup.draw();\n      }\n    }\n  };\n\n  /**\n   * Handle mouse up event.\n   *\n   * @param {object} _event The mouse up event.\n   */\n  mouseup = (_event) => {\n    if (this.#started) {\n      // stop recording\n      this.#started = false;\n    }\n  };\n\n  /**\n   * Handle mouse out event.\n   *\n   * @param {object} event The mouse out event.\n   */\n  mouseout = (event) => {\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle touch start event.\n   *\n   * @param {object} event The touch start event.\n   */\n  touchstart = (event) => {\n    const touches = event.targetTouches;\n    if (touches.length === 1) {\n      this.mousedown(event);\n    } else if (touches.length === 2) {\n      this.twotouchdown(event);\n    }\n  };\n\n  /**\n   * Handle touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  touchmove = (event) => {\n    const touches = event.targetTouches;\n    if (touches.length === 1) {\n      this.mousemove(event);\n    } else if (touches.length === 2) {\n      this.twotouchmove(event);\n    }\n  };\n\n  /**\n   * Handle touch end event.\n   *\n   * @param {object} event The touch end event.\n   */\n  touchend = (event) => {\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle mouse wheel event.\n   *\n   * @param {object} event The mouse wheel event.\n   */\n  wheel = (event) => {\n    // prevent default page scroll\n    event.preventDefault();\n\n    const step = -event.deltaY / 500;\n\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const viewController = viewLayer.getViewController();\n    const planePos = viewLayer.displayToMainPlanePos(event._x, event._y);\n    const center = viewController.getPlanePositionFromPlanePoint(planePos);\n    layerGroup.addScale(step, center);\n    layerGroup.draw();\n  };\n\n  /**\n   * Handle key down event.\n   *\n   * @param {object} event The key down event.\n   */\n  keydown = (event) => {\n    event.context = 'ZoomAndPan';\n    this.#app.onKeydown(event);\n  };\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} _bool The flag to activate or not.\n   */\n  activate(_bool) {\n    // does nothing\n  }\n\n  /**\n   * Initialise the tool.\n   */\n  init() {\n    // does nothing\n  }\n\n} // ZoomAndPan class\n","import {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ScrollWheel} from './scrollWheel';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Opacity class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * options.tools = {Opacity: new dwv.ToolConfig()};\n * app.init(options);\n * // activate tool\n * app.addEventListener('load', function () {\n *   app.setTool('Opacity');\n * });\n * // load dicom data\n * app.loadURLs([\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class Opacity {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * Interaction start flag.\n   *\n   * @type {boolean}\n   */\n  #started = false;\n\n  /**\n   * Scroll wheel handler.\n   *\n   * @type {ScrollWheel}\n   */\n  #scrollWhell;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n    this.#scrollWhell = new ScrollWheel(app);\n  }\n\n  /**\n   * Handle mouse down event.\n   *\n   * @param {object} event The mouse down event.\n   */\n  mousedown = (event) => {\n    // start flag\n    this.#started = true;\n    // first position\n    this.x0 = event._x;\n    this.y0 = event._y;\n  };\n\n  /**\n   * Handle mouse move event.\n   *\n   * @param {object} event The mouse move event.\n   */\n  mousemove = (event) => {\n    if (!this.#started) {\n      return;\n    }\n\n    // difference to last X position\n    const diffX = event._x - this.x0;\n    const xMove = (Math.abs(diffX) > 15);\n    // do not trigger for small moves\n    if (xMove) {\n      const layerDetails = getLayerDetailsFromEvent(event);\n      const layerGroup =\n        this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n      const viewLayer = layerGroup.getActiveViewLayer();\n      const op = viewLayer.getOpacity();\n      viewLayer.setOpacity(op + (diffX / 200));\n      viewLayer.draw();\n\n      // reset origin point\n      this.x0 = event._x;\n    }\n  };\n\n  /**\n   * Handle mouse up event.\n   *\n   * @param {object} _event The mouse up event.\n   */\n  mouseup = (_event) => {\n    if (this.#started) {\n      // stop recording\n      this.#started = false;\n    }\n  };\n\n  /**\n   * Handle mouse out event.\n   *\n   * @param {object} event The mouse out event.\n   */\n  mouseout = (event) => {\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle touch start event.\n   *\n   * @param {object} event The touch start event.\n   */\n  touchstart = (event) => {\n    // call mouse equivalent\n    this.mousedown(event);\n  };\n\n  /**\n   * Handle touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  touchmove = (event) => {\n    // call mouse equivalent\n    this.mousemove(event);\n  };\n\n  /**\n   * Handle touch end event.\n   *\n   * @param {object} event The touch end event.\n   */\n  touchend = (event) => {\n    // call mouse equivalent\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle mouse wheel event.\n   *\n   * @param {object} event The mouse wheel event.\n   */\n  wheel = (event) => {\n    this.#scrollWhell.wheel(event);\n  };\n\n  /**\n   * Handle key down event.\n   *\n   * @param {object} event The key down event.\n   */\n  keydown = (event) => {\n    event.context = 'Opacity';\n    this.#app.onKeydown(event);\n  };\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} _bool The flag to activate or not.\n   */\n  activate(_bool) {\n    // does nothing\n  }\n\n  /**\n   * Initialise the tool.\n   */\n  init() {\n    // does nothing\n  }\n\n} // Opacity class\n","import {DrawGroupCommand} from '../tools/drawCommands';\nimport {RoiFactory} from '../tools/roi';\nimport {guid} from '../math/stats';\nimport {Point2D} from '../math/point';\nimport {Style} from '../gui/style';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {logger} from '../utils/logger';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * The magic wand namespace.\n *\n * @external MagicWand\n * @see https://github.com/Tamersoul/magic-wand-js\n */\nimport MagicWand from 'magic-wand-tool';\n\n/**\n * Floodfill painting tool.\n */\nexport class Floodfill {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Original variables from external library. Used as in the lib example.\n   *\n   * @type {number}\n   */\n  #blurRadius = 5;\n  /**\n   * Original variables from external library. Used as in the lib example.\n   *\n   * @type {number}\n   */\n  #simplifyTolerant = 0;\n\n  /**\n   * Original variables from external library. Used as in the lib example.\n   *\n   * @type {number}\n   */\n  #simplifyCount = 2000;\n\n  /**\n   * Canvas info\n   *\n   * @type {object}\n   */\n  #imageInfo = null;\n\n  /**\n   * Object created by MagicWand lib containing border points\n   *\n   * @type {object}\n   */\n  #mask = null;\n\n  /**\n   * threshold default tolerance of the tool border\n   *\n   * @type {number}\n   */\n  #initialthreshold = 10;\n\n  /**\n   * threshold tolerance of the tool border\n   *\n   * @type {number}\n   */\n  #currentthreshold = null;\n\n  /**\n   * Interaction start flag.\n   *\n   * @type {boolean}\n   */\n  #started = false;\n  /**\n   * Draw command.\n   *\n   * @type {object}\n   */\n  #command = null;\n\n  /**\n   * Current shape group.\n   *\n   * @type {object}\n   */\n  #shapeGroup = null;\n\n  /**\n   * Coordinates of the fist mousedown event.\n   *\n   * @type {object}\n   */\n  #initialpoint;\n\n  /**\n   * Floodfill border.\n   *\n   * @type {object}\n   */\n  #border = null;\n\n  /**\n   * List of parent points.\n   *\n   * @type {Array}\n   */\n  #parentPoints = [];\n\n  /**\n   * Assistant variable to paint border on all slices.\n   *\n   * @type {boolean}\n   */\n  #extender = false;\n\n  /**\n   * Timeout for painting on mousemove.\n   *\n   */\n  #painterTimeout;\n\n  /**\n   * Drawing style.\n   *\n   * @type {Style}\n   */\n  #style = new Style();\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Set extend option for painting border on all slices.\n   *\n   * @param {boolean} bool The option to set\n   */\n  setExtend(bool) {\n    this.#extender = bool;\n  }\n\n  /**\n   * Get extend option for painting border on all slices.\n   *\n   * @returns {boolean} The actual value of of the variable to use Floodfill\n   *   on museup.\n   */\n  getExtend() {\n    return this.#extender;\n  }\n\n  /**\n   * Get (x, y) coordinates referenced to the canvas\n   *\n   * @param {object} event The original event.\n   * @returns {object} The coordinates as a {x,y}.\n   */\n  #getCoord = (event) => {\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const index = viewLayer.displayToPlaneIndex(event._x, event._y);\n    return {\n      x: index.get(0),\n      y: index.get(1)\n    };\n  };\n\n  /**\n   * Calculate border.\n   *\n   * @param {object} points The input points.\n   * @param {number} threshold The threshold of the floodfill.\n   * @param {boolean} simple Return first points or a list.\n   * @returns {Array} The parent points.\n   */\n  #calcBorder(points, threshold, simple) {\n\n    this.#parentPoints = [];\n    const image = {\n      data: this.#imageInfo.data,\n      width: this.#imageInfo.width,\n      height: this.#imageInfo.height,\n      bytes: 4\n    };\n\n    this.#mask = MagicWand.floodFill(image, points.x, points.y, threshold);\n    this.#mask = MagicWand.gaussBlurOnlyBorder(this.#mask, this.#blurRadius);\n\n    let cs = MagicWand.traceContours(this.#mask);\n    cs = MagicWand.simplifyContours(\n      cs, this.#simplifyTolerant, this.#simplifyCount);\n\n    if (cs.length > 0 && cs[0].points[0].x) {\n      if (simple) {\n        return cs[0].points;\n      }\n      for (let j = 0, icsl = cs[0].points.length; j < icsl; j++) {\n        this.#parentPoints.push(new Point2D(\n          cs[0].points[j].x,\n          cs[0].points[j].y\n        ));\n      }\n      return this.#parentPoints;\n    } else {\n      return [];\n    }\n  }\n\n  /**\n   * Paint Floodfill.\n   *\n   * @param {object} point The start point.\n   * @param {number} threshold The border threshold.\n   * @param {object} layerGroup The origin layer group.\n   * @returns {boolean} False if no border.\n   */\n  #paintBorder(point, threshold, layerGroup) {\n    // Calculate the border\n    this.#border = this.#calcBorder(point, threshold, false);\n    // Paint the border\n    if (this.#border) {\n      const factory = new RoiFactory();\n      this.#shapeGroup = factory.create(this.#border, this.#style);\n      this.#shapeGroup.id(guid());\n\n      const drawLayer = layerGroup.getActiveDrawLayer();\n      const drawController = drawLayer.getDrawController();\n\n      // get the position group\n      const posGroup = drawController.getCurrentPosGroup();\n      // add shape group to position group\n      posGroup.add(this.#shapeGroup);\n\n      // draw shape command\n      this.#command = new DrawGroupCommand(this.#shapeGroup, 'floodfill',\n        drawLayer.getKonvaLayer());\n      this.#command.onExecute = this.#fireEvent;\n      this.#command.onUndo = this.#fireEvent;\n      // // draw\n      this.#command.execute();\n      // save it in undo stack\n      this.#app.addToUndoStack(this.#command);\n\n      return true;\n    } else {\n      return false;\n    }\n  }\n\n  /**\n   * Create Floodfill in all the prev and next slices while border is found\n   *\n   * @param {number} ini The first slice to extend to.\n   * @param {number} end The last slice to extend to.\n   * @param {object} layerGroup The origin layer group.\n   */\n  extend(ini, end, layerGroup) {\n    //avoid errors\n    if (!this.#initialpoint) {\n      throw '\\'initialpoint\\' not found. User must click before use extend!';\n    }\n    // remove previous draw\n    if (this.#shapeGroup) {\n      this.#shapeGroup.destroy();\n    }\n\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n\n    const pos = viewController.getCurrentIndex();\n    const imageSize = viewController.getImageSize();\n    const threshold = this.#currentthreshold || this.#initialthreshold;\n\n    // Iterate over the next images and paint border on each slice.\n    for (let i = pos.get(2),\n      len = end\n        ? end : imageSize.get(2);\n      i < len; i++) {\n      if (!this.#paintBorder(this.#initialpoint, threshold, layerGroup)) {\n        break;\n      }\n      viewController.incrementIndex(2);\n    }\n    viewController.setCurrentPosition(pos);\n\n    // Iterate over the prev images and paint border on each slice.\n    for (let j = pos.get(2), jl = ini ? ini : 0; j > jl; j--) {\n      if (!this.#paintBorder(this.#initialpoint, threshold, layerGroup)) {\n        break;\n      }\n      viewController.decrementIndex(2);\n    }\n    viewController.setCurrentPosition(pos);\n  }\n\n  /**\n   * Modify tolerance threshold and redraw ROI.\n   *\n   * @param {number} modifyThreshold The new threshold.\n   * @param {object} shape The shape to update.\n   */\n  modifyThreshold(modifyThreshold, shape) {\n\n    if (!shape && this.#shapeGroup) {\n      shape = this.#shapeGroup.getChildren(function (node) {\n        return node.name() === 'shape';\n      })[0];\n    } else {\n      throw 'No shape found';\n    }\n\n    clearTimeout(this.#painterTimeout);\n    this.#painterTimeout = setTimeout(() => {\n      this.#border = this.#calcBorder(\n        this.#initialpoint, modifyThreshold, true);\n      if (!this.#border) {\n        return false;\n      }\n      const arr = [];\n      for (let i = 0, bl = this.#border.length; i < bl; ++i) {\n        arr.push(this.#border[i].x);\n        arr.push(this.#border[i].y);\n      }\n      shape.setPoints(arr);\n      const shapeLayer = shape.getLayer();\n      shapeLayer.draw();\n      this.onThresholdChange(modifyThreshold);\n    }, 100);\n  }\n\n  /**\n   * Event fired when threshold change\n   *\n   * @param {number} _value Current threshold\n   */\n  onThresholdChange(_value) {\n    // Defaults do nothing\n  }\n\n  /**\n   * Handle mouse down event.\n   *\n   * @param {object} event The mouse down event.\n   */\n  mousedown = (event) => {\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const drawLayer = layerGroup.getActiveDrawLayer();\n\n    this.#imageInfo = viewLayer.getImageData();\n    if (!this.#imageInfo) {\n      logger.error('No image found');\n      return;\n    }\n\n    // update zoom scale\n    this.#style.setZoomScale(\n      drawLayer.getKonvaLayer().getAbsoluteScale());\n\n    this.#started = true;\n    this.#initialpoint = this.#getCoord(event);\n    this.#paintBorder(this.#initialpoint, this.#initialthreshold, layerGroup);\n    this.onThresholdChange(this.#initialthreshold);\n  };\n\n  /**\n   * Handle mouse move event.\n   *\n   * @param {object} event The mouse move event.\n   */\n  mousemove = (event) => {\n    if (!this.#started) {\n      return;\n    }\n    const movedpoint = this.#getCoord(event);\n    this.#currentthreshold = Math.round(Math.sqrt(\n      Math.pow((this.#initialpoint.x - movedpoint.x), 2) +\n      Math.pow((this.#initialpoint.y - movedpoint.y), 2)) / 2);\n    this.#currentthreshold = this.#currentthreshold < this.#initialthreshold\n      ? this.#initialthreshold\n      : this.#currentthreshold - this.#initialthreshold;\n    this.modifyThreshold(this.#currentthreshold);\n  };\n\n  /**\n   * Handle mouse up event.\n   *\n   * @param {object} _event The mouse up event.\n   */\n  mouseup = (_event) => {\n    this.#started = false;\n    // TODO: re-activate\n    // if (this.#extender) {\n    //   const layerDetails = getLayerDetailsFromEvent(event);\n    //   const layerGroup =\n    //     this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    //   this.extend(layerGroup);\n    // }\n  };\n\n  /**\n   * Handle mouse out event.\n   *\n   * @param {object} event The mouse out event.\n   */\n  mouseout = (event) => {\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle touch start event.\n   *\n   * @param {object} event The touch start event.\n   */\n  touchstart = (event) => {\n    // treat as mouse down\n    this.mousedown(event);\n  };\n\n  /**\n   * Handle touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  touchmove = (event) => {\n    // treat as mouse move\n    this.mousemove(event);\n  };\n\n  /**\n   * Handle touch end event.\n   *\n   * @param {object} event The touch end event.\n   */\n  touchend = (event) => {\n    // treat as mouse up\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle key down event.\n   *\n   * @param {object} event The key down event.\n   */\n  keydown = (event) => {\n    event.context = 'Floodfill';\n    this.#app.onKeydown(event);\n  };\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} bool The flag to activate or not.\n   */\n  activate(bool) {\n    if (bool) {\n      // init with the app window scale\n      this.#style.setBaseScale(this.#app.getBaseScale());\n      // set the default to the first in the list\n      this.setFeatures({shapeColour: this.#style.getLineColour()});\n    }\n  }\n\n  /**\n   * Initialise the tool.\n   */\n  init() {\n    // does nothing\n  }\n\n  /**\n   * Get the list of event names that this tool can fire.\n   *\n   * @returns {Array} The list of event names.\n   */\n  getEventNames() {\n    return ['drawcreate', 'drawchange', 'drawmove', 'drawdelete'];\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  /**\n   * Set the tool live features: shape colour.\n   *\n   * @param {object} features The list of features.\n   */\n  setFeatures(features) {\n    if (typeof features.shapeColour !== 'undefined') {\n      this.#style.setLineColour(features.shapeColour);\n    }\n  }\n\n} // Floodfill class\n","import {Style} from '../gui/style';\nimport {Point2D} from '../math/point';\nimport {Path} from '../math/path';\nimport {Scissors} from '../math/scissors';\nimport {guid} from '../math/stats';\nimport {getLayerDetailsFromEvent} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {RoiFactory} from '../tools/roi';\nimport {DrawGroupCommand} from '../tools/drawCommands';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {App} from '../app/application';\n/* eslint-enable no-unused-vars */\n\n/**\n * Livewire painting tool.\n */\nexport class Livewire {\n  /**\n   * Associated app.\n   *\n   * @type {App}\n   */\n  #app;\n\n  /**\n   * @param {App} app The associated application.\n   */\n  constructor(app) {\n    this.#app = app;\n  }\n\n  /**\n   * Interaction start flag.\n   *\n   * @type {boolean}\n   */\n  #started = false;\n\n  /**\n   * Draw command.\n   *\n   * @type {object}\n   */\n  #command = null;\n\n  /**\n   * Current shape group.\n   *\n   * @type {object}\n   */\n  #shapeGroup = null;\n\n  /**\n   * Drawing style.\n   *\n   * @type {Style}\n   */\n  #style = new Style();\n\n  /**\n   * Path storage. Paths are stored in reverse order.\n   *\n   * @type {Path}\n   */\n  #path = new Path();\n\n  /**\n   * Current path storage. Paths are stored in reverse order.\n   *\n   * @type {Path}\n   */\n  #currentPath = new Path();\n\n  /**\n   * List of parent points.\n   *\n   * @type {Array}\n   */\n  #parentPoints = [];\n\n  /**\n   * Tolerance.\n   *\n   * @type {number}\n   */\n  #tolerance = 5;\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Clear the parent points list.\n   *\n   * @param {object} imageSize The image size.\n   */\n  #clearParentPoints(imageSize) {\n    const nrows = imageSize.get(1);\n    for (let i = 0; i < nrows; ++i) {\n      this.#parentPoints[i] = [];\n    }\n  }\n\n  /**\n   * Clear the stored paths.\n   */\n  #clearPaths() {\n    this.#path = new Path();\n    this.#currentPath = new Path();\n  }\n\n  /**\n   * Scissor representation.\n   *\n   * @type {Scissors}\n   */\n  #scissors = new Scissors();\n\n  /**\n   * Finish a livewire (roi) shape.\n   */\n  #finishShape() {\n    // fire creation event (was not propagated during draw)\n    this.#fireEvent({\n      type: 'drawcreate',\n      id: this.#shapeGroup.id()\n    });\n    // listen\n    this.#command.onExecute = this.#fireEvent;\n    this.#command.onUndo = this.#fireEvent;\n    // save command in undo stack\n    this.#app.addToUndoStack(this.#command);\n    // set flag\n    this.#started = false;\n  }\n\n  /**\n   * Handle mouse down event.\n   *\n   * @param {object} event The mouse down event.\n   */\n  mousedown = (event) => {\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const imageSize = viewLayer.getViewController().getImageSize();\n    const index = viewLayer.displayToPlaneIndex(event._x, event._y);\n\n    // first time\n    if (!this.#started) {\n      this.#started = true;\n      this.x0 = index.get(0);\n      this.y0 = index.get(1);\n      // clear vars\n      this.#clearPaths();\n      this.#clearParentPoints(imageSize);\n      this.#shapeGroup = null;\n      // update zoom scale\n      const drawLayer = layerGroup.getActiveDrawLayer();\n      this.#style.setZoomScale(\n        drawLayer.getKonvaLayer().getAbsoluteScale());\n      // do the training from the first point\n      const p = {x: index.get(0), y: index.get(1)};\n      this.#scissors.doTraining(p);\n      // add the initial point to the path\n      const p0 = new Point2D(index.get(0), index.get(1));\n      this.#path.addPoint(p0);\n      this.#path.addControlPoint(p0);\n    } else {\n      // final point: at 'tolerance' of the initial point\n      if ((Math.abs(index.get(0) - this.x0) < this.#tolerance) &&\n        (Math.abs(index.get(1) - this.y0) < this.#tolerance)) {\n        // finish\n        this.#finishShape();\n      } else {\n        // anchor point\n        this.#path = this.#currentPath;\n        this.#clearParentPoints(imageSize);\n        const pn = {x: index.get(0), y: index.get(1)};\n        this.#scissors.doTraining(pn);\n        this.#path.addControlPoint(this.#currentPath.getPoint(0));\n      }\n    }\n  };\n\n  /**\n   * Handle mouse move event.\n   *\n   * @param {object} event The mouse move event.\n   */\n  mousemove = (event) => {\n    if (!this.#started) {\n      return;\n    }\n    const layerDetails = getLayerDetailsFromEvent(event);\n    const layerGroup = this.#app.getLayerGroupByDivId(layerDetails.groupDivId);\n    const viewLayer = layerGroup.getActiveViewLayer();\n    const index = viewLayer.displayToPlaneIndex(event._x, event._y);\n\n    // set the point to find the path to\n    let p = {x: index.get(0), y: index.get(1)};\n    this.#scissors.setPoint(p);\n    // do the work\n    let results = [];\n    let stop = false;\n    while (!this.#parentPoints[p.y][p.x] && !stop) {\n      results = this.#scissors.doWork();\n\n      if (results.length === 0) {\n        stop = true;\n      } else {\n        // fill parents\n        for (let i = 0; i < results.length - 1; i += 2) {\n          const _p = results[i];\n          const _q = results[i + 1];\n          this.#parentPoints[_p.y][_p.x] = _q;\n        }\n      }\n    }\n\n    // get the path\n    this.#currentPath = new Path();\n    stop = false;\n    while (p && !stop) {\n      this.#currentPath.addPoint(new Point2D(p.x, p.y));\n      if (!this.#parentPoints[p.y]) {\n        stop = true;\n      } else {\n        if (!this.#parentPoints[p.y][p.x]) {\n          stop = true;\n        } else {\n          p = this.#parentPoints[p.y][p.x];\n        }\n      }\n    }\n    this.#currentPath.appenPath(this.#path);\n\n    // remove previous draw\n    if (this.#shapeGroup) {\n      this.#shapeGroup.destroy();\n    }\n    // create shape\n    const factory = new RoiFactory();\n    this.#shapeGroup = factory.create(\n      this.#currentPath.pointArray, this.#style);\n    this.#shapeGroup.id(guid());\n\n    const drawLayer = layerGroup.getActiveDrawLayer();\n    const drawController = drawLayer.getDrawController();\n\n    // get the position group\n    const posGroup = drawController.getCurrentPosGroup();\n    // add shape group to position group\n    posGroup.add(this.#shapeGroup);\n\n    // draw shape command\n    this.#command = new DrawGroupCommand(this.#shapeGroup, 'livewire',\n      drawLayer.getKonvaLayer());\n    // draw\n    this.#command.execute();\n  };\n\n  /**\n   * Handle mouse up event.\n   *\n   * @param {object} _event The mouse up event.\n   */\n  mouseup(_event) {\n    // nothing to do\n  }\n\n  /**\n   * Handle mouse out event.\n   *\n   * @param {object} event The mouse out event.\n   */\n  mouseout = (event) => {\n    // treat as mouse up\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle double click event.\n   *\n   * @param {object} _event The double click event.\n   */\n  dblclick = (_event) => {\n    this.#finishShape();\n  };\n\n  /**\n   * Handle touch start event.\n   *\n   * @param {object} event The touch start event.\n   */\n  touchstart = (event) => {\n    // treat as mouse down\n    this.mousedown(event);\n  };\n\n  /**\n   * Handle touch move event.\n   *\n   * @param {object} event The touch move event.\n   */\n  touchmove = (event) => {\n    // treat as mouse move\n    this.mousemove(event);\n  };\n\n  /**\n   * Handle touch end event.\n   *\n   * @param {object} event The touch end event.\n   */\n  touchend = (event) => {\n    // treat as mouse up\n    this.mouseup(event);\n  };\n\n  /**\n   * Handle key down event.\n   *\n   * @param {object} event The key down event.\n   */\n  keydown = (event) => {\n    event.context = 'Livewire';\n    this.#app.onKeydown(event);\n  };\n\n  /**\n   * Activate the tool.\n   *\n   * @param {boolean} bool The flag to activate or not.\n   */\n  activate(bool) {\n    // start scissors if displayed\n    if (bool) {\n      const layerGroup = this.#app.getActiveLayerGroup();\n      const viewLayer = layerGroup.getActiveViewLayer();\n\n      //scissors = new Scissors();\n      const imageSize = viewLayer.getViewController().getImageSize();\n      this.#scissors.setDimensions(\n        imageSize.get(0),\n        imageSize.get(1));\n      this.#scissors.setData(viewLayer.getImageData().data);\n\n      // init with the app window scale\n      this.#style.setBaseScale(this.#app.getBaseScale());\n      // set the default to the first in the list\n      this.setFeatures({shapeColour: this.#style.getLineColour()});\n    }\n  }\n\n  /**\n   * Initialise the tool.\n   */\n  init() {\n    // does nothing\n  }\n\n  /**\n   * Get the list of event names that this tool can fire.\n   *\n   * @returns {Array} The list of event names.\n   */\n  getEventNames() {\n    return ['drawcreate', 'drawchange', 'drawmove', 'drawdelete'];\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *    event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  /**\n   * Set the tool live features: shape colour.\n   *\n   * @param {object} features The list of features.\n   */\n  setFeatures(features) {\n    if (typeof features.shapeColour !== 'undefined') {\n      this.#style.setLineColour(features.shapeColour);\n    }\n  }\n\n} // Livewire class\n","import {Point2D} from '../math/point';\nimport {Line, getPerpendicularLine, getAngle} from '../math/line';\nimport {getDefaultAnchor} from './editor';\n\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultArrowLabelText = '';\n\n/**\n * Arrow factory.\n */\nexport class ArrowFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'line-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number} The number of points.\n   */\n  getNPoints() {\n    return 2;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 0;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create an arrow shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the line.\n   * @param {object} style The drawing style.\n   * @param {object} _viewController The associated view controller.\n   * @returns {object} The Konva object.\n   */\n  create(points, style, _viewController) {\n    // physical shape\n    const line = new Line(points[0], points[1]);\n    // draw shape\n    const kshape = new Konva.Line({\n      points: [line.getBegin().getX(),\n        line.getBegin().getY(),\n        line.getEnd().getX(),\n        line.getEnd().getY()],\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape'\n    });\n    // larger hitfunc\n    const linePerp0 = getPerpendicularLine(\n      line, points[0], style.scale(10));\n    const linePerp1 = getPerpendicularLine(\n      line, points[1], style.scale(10));\n    kshape.hitFunc(function (context) {\n      context.beginPath();\n      context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n      context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n      context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n      context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n      context.closePath();\n      context.fillStrokeShape(kshape);\n    });\n    // triangle\n    const beginTy = new Point2D(\n      line.getBegin().getX(),\n      line.getBegin().getY() - 10);\n    const verticalLine = new Line(line.getBegin(), beginTy);\n    const angle = getAngle(line, verticalLine);\n    const angleRad = angle * Math.PI / 180;\n    const radius = 5 * style.getScaledStrokeWidth();\n    const kpoly = new Konva.RegularPolygon({\n      x: line.getBegin().getX() + radius * Math.sin(angleRad),\n      y: line.getBegin().getY() + radius * Math.cos(angleRad),\n      sides: 3,\n      radius: radius,\n      rotation: -angle,\n      fill: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape-triangle'\n    });\n    // quantification\n    const ktext = new Konva.Text({\n      fontSize: style.getFontSize(),\n      fontFamily: style.getFontFamily(),\n      fill: style.getLineColour(),\n      padding: style.getTextPadding(),\n      shadowColor: style.getShadowLineColour(),\n      shadowOffset: style.getShadowOffset(),\n      name: 'text'\n    });\n    let textExpr = '';\n    // TODO: allow override?\n    // if (typeof arrowLabelText !== 'undefined') {\n    //   textExpr = arrowLabelText;\n    // } else {\n    textExpr = defaultArrowLabelText;\n    // }\n    ktext.setText(textExpr);\n    // augment text with meta data\n    // @ts-ignore\n    ktext.meta = {\n      textExpr: textExpr,\n      quantification: {}\n    };\n    // label\n    const dX = line.getBegin().getX() > line.getEnd().getX() ? 0 : -1;\n    const dY = line.getBegin().getY() > line.getEnd().getY() ? -1 : 0;\n    const klabel = new Konva.Label({\n      x: line.getEnd().getX() + dX * ktext.width(),\n      y: line.getEnd().getY() + dY * style.applyZoomScale(15).y,\n      scale: style.applyZoomScale(1),\n      visible: textExpr.length !== 0,\n      name: 'label'\n    });\n    klabel.add(ktext);\n    klabel.add(new Konva.Tag({\n      fill: style.getLineColour(),\n      opacity: style.getTagOpacity()\n    }));\n\n    // return group\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    group.add(klabel);\n    group.add(kpoly);\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    return group;\n  }\n\n  /**\n   * Get anchors to update an arrow shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const points = shape.points();\n\n    const anchors = [];\n    anchors.push(getDefaultAnchor(\n      points[0] + shape.x(), points[1] + shape.y(), 'begin', style\n    ));\n    anchors.push(getDefaultAnchor(\n      points[2] + shape.x(), points[3] + shape.y(), 'end', style\n    ));\n    return anchors;\n  }\n\n  /**\n   * Update an arrow shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} style The app style.\n   * @param {object} _viewController The associated view controller.\n   */\n  update(anchor, style, _viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const kline = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n      // associated triangle shape\n    const ktriangle = group.getChildren(function (node) {\n      return node.name() === 'shape-triangle';\n    })[0];\n      // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n      // find special points\n    const begin = group.getChildren(function (node) {\n      return node.id() === 'begin';\n    })[0];\n    const end = group.getChildren(function (node) {\n      return node.id() === 'end';\n    })[0];\n      // update special points\n    switch (anchor.id()) {\n    case 'begin':\n      begin.x(anchor.x());\n      begin.y(anchor.y());\n      break;\n    case 'end':\n      end.x(anchor.x());\n      end.y(anchor.y());\n      break;\n    }\n    // update shape and compensate for possible drag\n    // note: shape.position() and shape.size() won't work...\n    const bx = begin.x() - kline.x();\n    const by = begin.y() - kline.y();\n    const ex = end.x() - kline.x();\n    const ey = end.y() - kline.y();\n    kline.points([bx, by, ex, ey]);\n    // new line\n    const p2d0 = new Point2D(begin.x(), begin.y());\n    const p2d1 = new Point2D(end.x(), end.y());\n    const line = new Line(p2d0, p2d1);\n    // larger hitfunc\n    const p2b = new Point2D(bx, by);\n    const p2e = new Point2D(ex, ey);\n    const linePerp0 = getPerpendicularLine(line, p2b, 10);\n    const linePerp1 = getPerpendicularLine(line, p2e, 10);\n    kline.hitFunc(function (context) {\n      context.beginPath();\n      context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n      context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n      context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n      context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n      context.closePath();\n      context.fillStrokeShape(kline);\n    });\n    // udate triangle\n    const beginTy = new Point2D(\n      line.getBegin().getX(),\n      line.getBegin().getY() - 10);\n    const verticalLine = new Line(line.getBegin(), beginTy);\n    const angle = getAngle(line, verticalLine);\n    const angleRad = angle * Math.PI / 180;\n    ktriangle.x(\n      line.getBegin().getX() + ktriangle.radius() * Math.sin(angleRad));\n    ktriangle.y(\n      line.getBegin().getY() + ktriangle.radius() * Math.cos(angleRad));\n    ktriangle.rotation(-angle);\n\n    // update text\n    const ktext = klabel.getText();\n    ktext.setText(ktext.meta.textExpr);\n    // update position\n    const dX = line.getBegin().getX() > line.getEnd().getX() ? 0 : -1;\n    const dY = line.getBegin().getY() > line.getEnd().getY() ? -1 : 0;\n    const textPos = {\n      x: line.getEnd().getX() + dX * ktext.width(),\n      y: line.getEnd().getY() + dY * style.applyZoomScale(15).y\n    };\n    klabel.position(textPos);\n  }\n\n} // class ArrowFactory\n","import {Circle} from '../math/circle';\nimport {Point2D} from '../math/point';\nimport {getFlags, replaceFlags} from '../utils/string';\nimport {logger} from '../utils/logger';\nimport {getDefaultAnchor} from './editor';\nimport {DRAW_DEBUG} from './draw';\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultCircleLabelText = '{surface}';\n\n/**\n * Circle factory.\n */\nexport class CircleFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'circle-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number} The number of points.\n   */\n  getNPoints() {\n    return 2;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 0;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create a circle shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the circle.\n   * @param {object} style The drawing style.\n   * @param {object} viewController The associated view controller.\n   * @returns {object} The Konva group.\n   */\n  create(\n    points, style, viewController) {\n    // calculate radius\n    const a = Math.abs(points[0].getX() - points[1].getX());\n    const b = Math.abs(points[0].getY() - points[1].getY());\n    const radius = Math.round(Math.sqrt(a * a + b * b));\n    // physical shape\n    const circle = new Circle(points[0], radius);\n    // draw shape\n    const kshape = new Konva.Circle({\n      x: circle.getCenter().getX(),\n      y: circle.getCenter().getY(),\n      radius: circle.getRadius(),\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape'\n    });\n    // quantification\n    const ktext = new Konva.Text({\n      fontSize: style.getFontSize(),\n      fontFamily: style.getFontFamily(),\n      fill: style.getLineColour(),\n      padding: style.getTextPadding(),\n      shadowColor: style.getShadowLineColour(),\n      shadowOffset: style.getShadowOffset(),\n      name: 'text'\n    });\n    let textExpr = '';\n    // TODO: allow override?\n    // if (typeof circleLabelText !== 'undefined') {\n    //   textExpr = circleLabelText;\n    // } else {\n    textExpr = defaultCircleLabelText;\n    // }\n    const quant = circle.quantify(\n      viewController,\n      getFlags(textExpr));\n    ktext.setText(replaceFlags(textExpr, quant));\n    // augment text with meta data\n    // @ts-ignore\n    ktext.meta = {\n      textExpr: textExpr,\n      quantification: quant\n    };\n    // label\n    const klabel = new Konva.Label({\n      x: circle.getCenter().getX(),\n      y: circle.getCenter().getY(),\n      scale: style.applyZoomScale(1),\n      visible: textExpr.length !== 0,\n      name: 'label'\n    });\n    klabel.add(ktext);\n    klabel.add(new Konva.Tag({\n      fill: style.getLineColour(),\n      opacity: style.getTagOpacity()\n    }));\n\n    // debug shadow\n    let kshadow;\n    if (DRAW_DEBUG) {\n      kshadow = this.#getShadowCircle(circle);\n    }\n\n    // return group\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    if (kshadow) {\n      group.add(kshadow);\n    }\n    group.add(klabel);\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    return group;\n  }\n\n  /**\n   * Get anchors to update a circle shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const centerX = shape.x();\n    const centerY = shape.y();\n    const radius = shape.radius();\n\n    const anchors = [];\n    anchors.push(getDefaultAnchor(\n      centerX - radius, centerY, 'left', style\n    ));\n    anchors.push(getDefaultAnchor(\n      centerX + radius, centerY, 'right', style\n    ));\n    anchors.push(getDefaultAnchor(\n      centerX, centerY - radius, 'bottom', style\n    ));\n    anchors.push(getDefaultAnchor(\n      centerX, centerY + radius, 'top', style\n    ));\n    return anchors;\n  }\n\n  /**\n   * Update a circle shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} _style The app style.\n   * @param {object} viewController The associated view controller.\n   */\n  update(anchor, _style, viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const kcircle = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n    // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n    // find special points\n    const left = group.getChildren(function (node) {\n      return node.id() === 'left';\n    })[0];\n    const right = group.getChildren(function (node) {\n      return node.id() === 'right';\n    })[0];\n    const bottom = group.getChildren(function (node) {\n      return node.id() === 'bottom';\n    })[0];\n    const top = group.getChildren(function (node) {\n      return node.id() === 'top';\n    })[0];\n    // debug shadow\n    let kshadow;\n    if (DRAW_DEBUG) {\n      kshadow = group.getChildren(function (node) {\n        return node.name() === 'shadow';\n      })[0];\n    }\n\n    // circle center\n    const center = {\n      x: kcircle.x(),\n      y: kcircle.y()\n    };\n\n    let radius;\n\n    // update 'self' (undo case) and special points\n    switch (anchor.id()) {\n    case 'left':\n      radius = center.x - anchor.x();\n      // force y\n      left.y(right.y());\n      // update others\n      right.x(center.x + radius);\n      bottom.y(center.y - radius);\n      top.y(center.y + radius);\n      break;\n    case 'right':\n      radius = anchor.x() - center.x;\n      // force y\n      right.y(left.y());\n      // update others\n      left.x(center.x - radius);\n      bottom.y(center.y - radius);\n      top.y(center.y + radius);\n      break;\n    case 'bottom':\n      radius = center.y - anchor.y();\n      // force x\n      bottom.x(top.x());\n      // update others\n      left.x(center.x - radius);\n      right.x(center.x + radius);\n      top.y(center.y + radius);\n      break;\n    case 'top':\n      radius = anchor.y() - center.y;\n      // force x\n      top.x(bottom.x());\n      // update others\n      left.x(center.x - radius);\n      right.x(center.x + radius);\n      bottom.y(center.y - radius);\n      break;\n    default :\n      logger.error('Unhandled anchor id: ' + anchor.id());\n      break;\n    }\n\n    // update shape: just update the radius\n    kcircle.radius(Math.abs(radius));\n    // new circle\n    const centerPoint = new Point2D(\n      group.x() + center.x,\n      group.y() + center.y\n    );\n    const circle = new Circle(centerPoint, radius);\n\n    // debug shadow\n    if (kshadow) {\n      // remove previous\n      kshadow.destroy();\n      // add new\n      group.add(this.#getShadowCircle(circle, group));\n    }\n\n    // update label position\n    const textPos = {x: center.x, y: center.y};\n    klabel.position(textPos);\n\n    // update quantification\n    this.#updateCircleQuantification(group, viewController);\n  }\n\n  /**\n   * Update the quantification of a Circle.\n   *\n   * @param {object} group The group with the shape.\n   * @param {object} viewController The associated view controller.\n   */\n  updateQuantification(group, viewController) {\n    this.#updateCircleQuantification(group, viewController);\n  }\n\n  /**\n   * Update the quantification of a Circle (as a static\n   *   function to be used in update).\n   *\n   * @param {object} group The group with the shape.\n   * @param {object} viewController The associated view controller.\n   */\n  #updateCircleQuantification(\n    group, viewController) {\n    // associated shape\n    const kcircle = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n    // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n\n    // positions: add possible group offset\n    const centerPoint = new Point2D(\n      group.x() + kcircle.x(),\n      group.y() + kcircle.y()\n    );\n    // circle\n    const circle = new Circle(centerPoint, kcircle.radius());\n\n    // update text\n    const ktext = klabel.getText();\n    const quantification = circle.quantify(\n      viewController,\n      getFlags(ktext.meta.textExpr));\n    ktext.setText(replaceFlags(ktext.meta.textExpr, quantification));\n    // update meta\n    ktext.meta.quantification = quantification;\n  }\n\n  /**\n   * Get the debug shadow.\n   *\n   * @param {Circle} circle The circle to shadow.\n   * @param {object} group The associated group.\n   * @returns {object} The shadow konva group.\n   */\n  #getShadowCircle(circle, group) {\n    // possible group offset\n    let offsetX = 0;\n    let offsetY = 0;\n    if (typeof group !== 'undefined') {\n      offsetX = group.x();\n      offsetY = group.y();\n    }\n    const kshadow = new Konva.Group();\n    kshadow.name('shadow');\n    const regions = circle.getRound();\n    for (let i = 0; i < regions.length; ++i) {\n      const region = regions[i];\n      const minX = region[0][0];\n      const minY = region[0][1];\n      const maxX = region[1][0];\n      const pixelLine = new Konva.Rect({\n        x: minX - offsetX,\n        y: minY - offsetY,\n        width: maxX - minX,\n        height: 1,\n        fill: 'grey',\n        strokeWidth: 0,\n        strokeScaleEnabled: false,\n        opacity: 0.3,\n        name: 'shadow-element'\n      });\n      kshadow.add(pixelLine);\n    }\n    return kshadow;\n  }\n\n} // class CircleFactory\n","import {DRAW_DEBUG} from './draw';\nimport {getDefaultAnchor} from './editor';\nimport {Ellipse} from '../math/ellipse';\nimport {Point2D} from '../math/point';\nimport {logger} from '../utils/logger';\nimport {getFlags, replaceFlags} from '../utils/string';\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultEllipseLabelText = '{surface}';\n\n/**\n * Ellipse factory.\n */\nexport class EllipseFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'ellipse-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number} The number of points.\n   */\n  getNPoints() {\n    return 2;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 0;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create an ellipse shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the ellipse.\n   * @param {object} style The drawing style.\n   * @param {object} viewController The associated view controller.\n   * @returns {object} The Konva group.\n   */\n  create(\n    points, style, viewController) {\n    // calculate radius\n    const a = Math.abs(points[0].getX() - points[1].getX());\n    const b = Math.abs(points[0].getY() - points[1].getY());\n    // physical shape\n    const ellipse = new Ellipse(points[0], a, b);\n    // draw shape\n    const radius = {x: ellipse.getA(), y: ellipse.getB()};\n    const kshape = new Konva.Ellipse({\n      x: ellipse.getCenter().getX(),\n      y: ellipse.getCenter().getY(),\n      radius: radius,\n      radiusX: radius.x,\n      radiusY: radius.y,\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape'\n    });\n    // quantification\n    const ktext = new Konva.Text({\n      fontSize: style.getFontSize(),\n      fontFamily: style.getFontFamily(),\n      fill: style.getLineColour(),\n      padding: style.getTextPadding(),\n      shadowColor: style.getShadowLineColour(),\n      shadowOffset: style.getShadowOffset(),\n      name: 'text'\n    });\n    let textExpr = '';\n    // TODO: allow override?\n    // if (typeof ellipseLabelText !== 'undefined') {\n    //   textExpr = ellipseLabelText;\n    // } else {\n    textExpr = defaultEllipseLabelText;\n    // }\n    const quant = ellipse.quantify(\n      viewController,\n      getFlags(textExpr));\n    ktext.setText(replaceFlags(textExpr, quant));\n    // augment text with meta\n    // @ts-ignore\n    ktext.meta = {\n      textExpr: textExpr,\n      quantification: quant\n    };\n    // label\n    const klabel = new Konva.Label({\n      x: ellipse.getCenter().getX(),\n      y: ellipse.getCenter().getY(),\n      scale: style.applyZoomScale(1),\n      visible: textExpr.length !== 0,\n      name: 'label'\n    });\n    klabel.add(ktext);\n    klabel.add(new Konva.Tag({\n      fill: style.getLineColour(),\n      opacity: style.getTagOpacity()\n    }));\n\n    // debug shadow\n    let kshadow;\n    if (DRAW_DEBUG) {\n      kshadow = this.#getShadowEllipse(ellipse);\n    }\n\n    // return group\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    if (kshadow) {\n      group.add(kshadow);\n    }\n    group.add(klabel);\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    return group;\n  }\n\n  /**\n   * Get anchors to update an ellipse shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const ellipseX = shape.x();\n    const ellipseY = shape.y();\n    const radius = shape.radius();\n\n    const anchors = [];\n    anchors.push(getDefaultAnchor(\n      ellipseX - radius.x, ellipseY - radius.y, 'topLeft', style\n    ));\n    anchors.push(getDefaultAnchor(\n      ellipseX + radius.x, ellipseY - radius.y, 'topRight', style\n    ));\n    anchors.push(getDefaultAnchor(\n      ellipseX + radius.x, ellipseY + radius.y, 'bottomRight', style\n    ));\n    anchors.push(getDefaultAnchor(\n      ellipseX - radius.x, ellipseY + radius.y, 'bottomLeft', style\n    ));\n    return anchors;\n  }\n\n  /**\n   * Update an ellipse shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} _style The app style.\n   * @param {object} viewController The associated view controller.\n   */\n  update(anchor, _style, viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const kellipse = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n      // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n      // find special points\n    const topLeft = group.getChildren(function (node) {\n      return node.id() === 'topLeft';\n    })[0];\n    const topRight = group.getChildren(function (node) {\n      return node.id() === 'topRight';\n    })[0];\n    const bottomRight = group.getChildren(function (node) {\n      return node.id() === 'bottomRight';\n    })[0];\n    const bottomLeft = group.getChildren(function (node) {\n      return node.id() === 'bottomLeft';\n    })[0];\n    // debug shadow\n    let kshadow;\n    if (DRAW_DEBUG) {\n      kshadow = group.getChildren(function (node) {\n        return node.name() === 'shadow';\n      })[0];\n    }\n\n    // update 'self' (undo case) and special points\n    switch (anchor.id()) {\n    case 'topLeft':\n      topLeft.x(anchor.x());\n      topLeft.y(anchor.y());\n      topRight.y(anchor.y());\n      bottomLeft.x(anchor.x());\n      break;\n    case 'topRight':\n      topRight.x(anchor.x());\n      topRight.y(anchor.y());\n      topLeft.y(anchor.y());\n      bottomRight.x(anchor.x());\n      break;\n    case 'bottomRight':\n      bottomRight.x(anchor.x());\n      bottomRight.y(anchor.y());\n      bottomLeft.y(anchor.y());\n      topRight.x(anchor.x());\n      break;\n    case 'bottomLeft':\n      bottomLeft.x(anchor.x());\n      bottomLeft.y(anchor.y());\n      bottomRight.y(anchor.y());\n      topLeft.x(anchor.x());\n      break;\n    default :\n      logger.error('Unhandled anchor id: ' + anchor.id());\n      break;\n    }\n    // update shape\n    const radiusX = (topRight.x() - topLeft.x()) / 2;\n    const radiusY = (bottomRight.y() - topRight.y()) / 2;\n    const center = {\n      x: topLeft.x() + radiusX,\n      y: topRight.y() + radiusY\n    };\n    kellipse.position(center);\n    const radiusAbs = {x: Math.abs(radiusX), y: Math.abs(radiusY)};\n    if (radiusAbs) {\n      kellipse.radius(radiusAbs);\n    }\n    // new ellipse\n    const centerPoint = new Point2D(\n      group.x() + center.x,\n      group.y() + center.y\n    );\n    const ellipse = new Ellipse(centerPoint, radiusAbs.x, radiusAbs.y);\n\n    // debug shadow\n    if (kshadow) {\n      // remove previous\n      kshadow.destroy();\n      // add new\n      group.add(this.#getShadowEllipse(ellipse, group));\n    }\n\n    // update label position\n    const textPos = {x: center.x, y: center.y};\n    klabel.position(textPos);\n\n    // update quantification\n    this.#updateEllipseQuantification(group, viewController);\n  }\n\n  /**\n   * Update the quantification of an Ellipse.\n   *\n   * @param {object} group The group with the shape.\n   * @param {object} viewController The associated view controller.\n   */\n  updateQuantification(group, viewController) {\n    this.#updateEllipseQuantification(group, viewController);\n  }\n\n  /**\n   * Update the quantification of an Ellipse (as a static\n   *   function to be used in update).\n   *\n   * @param {object} group The group with the shape.\n   * @param {object} viewController The associated view controller.\n   */\n  #updateEllipseQuantification(group, viewController) {\n    // associated shape\n    const kellipse = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n    // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n\n    // positions: add possible group offset\n    const centerPoint = new Point2D(\n      group.x() + kellipse.x(),\n      group.y() + kellipse.y()\n    );\n    // circle\n    const ellipse = new Ellipse(\n      centerPoint, kellipse.radius().x, kellipse.radius().y);\n\n    // update text\n    const ktext = klabel.getText();\n    const quantification = ellipse.quantify(\n      viewController,\n      getFlags(ktext.meta.textExpr));\n    ktext.setText(replaceFlags(ktext.meta.textExpr, quantification));\n    // update meta\n    ktext.meta.quantification = quantification;\n  }\n\n  /**\n   * Get the debug shadow.\n   *\n   * @param {Ellipse} ellipse The ellipse to shadow.\n   * @param {object} group The associated group.\n   * @returns {object} The shadow konva group.\n   */\n  #getShadowEllipse(ellipse, group) {\n    // possible group offset\n    let offsetX = 0;\n    let offsetY = 0;\n    if (typeof group !== 'undefined') {\n      offsetX = group.x();\n      offsetY = group.y();\n    }\n    const kshadow = new Konva.Group();\n    kshadow.name('shadow');\n    const regions = ellipse.getRound();\n    for (let i = 0; i < regions.length; ++i) {\n      const region = regions[i];\n      const minX = region[0][0];\n      const minY = region[0][1];\n      const maxX = region[1][0];\n      const pixelLine = new Konva.Rect({\n        x: minX - offsetX,\n        y: minY - offsetY,\n        width: maxX - minX,\n        height: 1,\n        fill: 'grey',\n        strokeWidth: 0,\n        strokeScaleEnabled: false,\n        opacity: 0.3,\n        name: 'shadow-element'\n      });\n      kshadow.add(pixelLine);\n    }\n    return kshadow;\n  }\n\n} // class EllipseFactory\n","import {getDefaultAnchor} from './editor';\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultFreeHandLabelText = '';\n\n/**\n * FreeHand factory.\n */\nexport class FreeHandFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'freeHand-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number|undefined} The number of points.\n   */\n  getNPoints() {\n    // undefined to end with double click\n    return undefined;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 25;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create a roi shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the line.\n   * @param {object} style The drawing style.\n   * @param {object} _viewController The associated view controller.\n   * @returns {object} The Konva group.\n   */\n  create(\n    points, style, _viewController) {\n    // points stored the Konvajs way\n    const arr = [];\n    for (let i = 0; i < points.length; ++i) {\n      arr.push(points[i].getX());\n      arr.push(points[i].getY());\n    }\n    // draw shape\n    const kshape = new Konva.Line({\n      points: arr,\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape',\n      tension: 0.5\n    });\n\n    // text\n    const ktext = new Konva.Text({\n      fontSize: style.getFontSize(),\n      fontFamily: style.getFontFamily(),\n      fill: style.getLineColour(),\n      name: 'text'\n    });\n    let textExpr = '';\n    // TODO: allow override?\n    // if (typeof freeHandLabelText !== 'undefined') {\n    //   textExpr = freeHandLabelText;\n    // } else {\n    textExpr = defaultFreeHandLabelText;\n    // }\n    ktext.setText(textExpr);\n    // augment text with meta\n    // @ts-ignore\n    ktext.meta = {\n      textExpr: textExpr,\n      quantification: {}\n    };\n\n    // label\n    const klabel = new Konva.Label({\n      x: points[0].getX(),\n      y: points[0].getY() + style.scale(10),\n      scale: style.applyZoomScale(1),\n      visible: textExpr.length !== 0,\n      name: 'label'\n    });\n    klabel.add(ktext);\n    klabel.add(new Konva.Tag({\n      fill: style.getLineColour(),\n      opacity: style.getTagOpacity()\n    }));\n\n    // return group\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    group.add(klabel);\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    return group;\n  }\n\n  /**\n   * Get anchors to update a free hand shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const points = shape.points();\n\n    const anchors = [];\n    for (let i = 0; i < points.length; i = i + 2) {\n      const px = points[i] + shape.x();\n      const py = points[i + 1] + shape.y();\n      const name = i.toString();\n      anchors.push(getDefaultAnchor(\n        px, py, name, style\n      ));\n    }\n    return anchors;\n  }\n\n  /**\n   * Update a FreeHand shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} style The app style.\n   * @param {object} _viewController The associated view controller.\n   */\n  update(anchor, style, _viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const kline = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n      // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n\n    // update self\n    const point = group.getChildren(function (node) {\n      return node.id() === anchor.id();\n    })[0];\n    point.x(anchor.x());\n    point.y(anchor.y());\n    // update the roi point and compensate for possible drag\n    // (the anchor id is the index of the point in the list)\n    const points = kline.points();\n    points[anchor.id()] = anchor.x() - kline.x();\n    points[anchor.id() + 1] = anchor.y() - kline.y();\n    // concat to make Konva think it is a new array\n    kline.points(points.concat());\n\n    // update text\n    const ktext = klabel.getText();\n    ktext.setText(ktext.meta.textExpr);\n    // update position\n    const textPos = {\n      x: points[0] + kline.x(),\n      y: points[1] + kline.y() + style.scale(10)\n    };\n    klabel.position(textPos);\n  }\n\n} // class FreeHandFactory\n","import {Line, getAngle} from '../math/line';\nimport {Point2D} from '../math/point';\nimport {replaceFlags} from '../utils/string';\nimport {i18n} from '../utils/i18n';\nimport {getDefaultAnchor} from './editor';\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultProtractorLabelText = '{angle}';\n\n/**\n * Protractor factory.\n */\nexport class ProtractorFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'protractor-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number} The number of points.\n   */\n  getNPoints() {\n    return 3;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 500;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create a protractor shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the protractor.\n   * @param {object} style The drawing style.\n   * @param {object} _viewController The associated view controller.\n   * @returns {object} The Konva group.\n   */\n  create(points, style, _viewController) {\n    // physical shape\n    const line0 = new Line(points[0], points[1]);\n    // points stored the Konvajs way\n    const pointsArray = [];\n    for (let i = 0; i < points.length; ++i) {\n      pointsArray.push(points[i].getX());\n      pointsArray.push(points[i].getY());\n    }\n    // draw shape\n    const kshape = new Konva.Line({\n      points: pointsArray,\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape'\n    });\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    // text and decoration\n    if (points.length === 3) {\n      const line1 = new Line(points[1], points[2]);\n      // larger hitfunc\n      kshape.hitFunc(function (context) {\n        context.beginPath();\n        context.moveTo(points[0].getX(), points[0].getY());\n        context.lineTo(points[1].getX(), points[1].getY());\n        context.lineTo(points[2].getX(), points[2].getY());\n        context.closePath();\n        context.fillStrokeShape(kshape);\n      });\n      // quantification\n      let angle = getAngle(line0, line1);\n      let inclination = line0.getInclination();\n      if (angle > 180) {\n        angle = 360 - angle;\n        inclination += angle;\n      }\n\n      // quantification\n      const ktext = new Konva.Text({\n        fontSize: style.getFontSize(),\n        fontFamily: style.getFontFamily(),\n        fill: style.getLineColour(),\n        padding: style.getTextPadding(),\n        shadowColor: style.getShadowLineColour(),\n        shadowOffset: style.getShadowOffset(),\n        name: 'text'\n      });\n      let textExpr = '';\n      // TODO: allow override?\n      // if (typeof protractorLabelText !== 'undefined') {\n      //   textExpr = protractorLabelText;\n      // } else {\n      textExpr = defaultProtractorLabelText;\n      // }\n      const quant = {\n        angle: {\n          value: angle,\n          unit: i18n.t('unit.degree')\n        }\n      };\n      ktext.setText(replaceFlags(textExpr, quant));\n      // augment text with meta\n      // @ts-ignore\n      ktext.meta = {\n        textExpr: textExpr,\n        quantification: quant\n      };\n\n      // label\n      const midX =\n        (line0.getMidpoint().getX() + line1.getMidpoint().getX()) / 2;\n      const midY =\n        (line0.getMidpoint().getY() + line1.getMidpoint().getY()) / 2;\n      const klabel = new Konva.Label({\n        x: midX,\n        y: midY - style.applyZoomScale(15).y,\n        scale: style.applyZoomScale(1),\n        visible: textExpr.length !== 0,\n        name: 'label'\n      });\n      klabel.add(ktext);\n      klabel.add(new Konva.Tag({\n        fill: style.getLineColour(),\n        opacity: style.getTagOpacity()\n      }));\n\n      // arc\n      const radius = Math.min(line0.getLength(), line1.getLength()) * 33 / 100;\n      const karc = new Konva.Arc({\n        innerRadius: radius,\n        outerRadius: radius,\n        stroke: style.getLineColour(),\n        strokeWidth: style.getStrokeWidth(),\n        strokeScaleEnabled: false,\n        angle: angle,\n        rotation: -inclination,\n        x: points[1].getX(),\n        y: points[1].getY(),\n        name: 'shape-arc'\n      });\n      // add to group\n      group.add(klabel);\n      group.add(karc);\n    }\n    // add shape to group\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    // return group\n    return group;\n  }\n\n  /**\n   * Get anchors to update a protractor shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const points = shape.points();\n\n    const anchors = [];\n    anchors.push(getDefaultAnchor(\n      points[0] + shape.x(), points[1] + shape.y(), 'begin', style\n    ));\n    anchors.push(getDefaultAnchor(\n      points[2] + shape.x(), points[3] + shape.y(), 'mid', style\n    ));\n    anchors.push(getDefaultAnchor(\n      points[4] + shape.x(), points[5] + shape.y(), 'end', style\n    ));\n    return anchors;\n  }\n\n  /**\n   * Update a protractor shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} style The app style.\n   * @param {object} _viewController The associated view controller.\n   */\n  update(anchor, style, _viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const kline = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n      // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n      // associated arc\n    const karc = group.getChildren(function (node) {\n      return node.name() === 'shape-arc';\n    })[0];\n      // find special points\n    const begin = group.getChildren(function (node) {\n      return node.id() === 'begin';\n    })[0];\n    const mid = group.getChildren(function (node) {\n      return node.id() === 'mid';\n    })[0];\n    const end = group.getChildren(function (node) {\n      return node.id() === 'end';\n    })[0];\n      // update special points\n    switch (anchor.id()) {\n    case 'begin':\n      begin.x(anchor.x());\n      begin.y(anchor.y());\n      break;\n    case 'mid':\n      mid.x(anchor.x());\n      mid.y(anchor.y());\n      break;\n    case 'end':\n      end.x(anchor.x());\n      end.y(anchor.y());\n      break;\n    }\n    // update shape and compensate for possible drag\n    // note: shape.position() and shape.size() won't work...\n    const bx = begin.x() - kline.x();\n    const by = begin.y() - kline.y();\n    const mx = mid.x() - kline.x();\n    const my = mid.y() - kline.y();\n    const ex = end.x() - kline.x();\n    const ey = end.y() - kline.y();\n    kline.points([bx, by, mx, my, ex, ey]);\n    // larger hitfunc\n    kline.hitFunc(function (context) {\n      context.beginPath();\n      context.moveTo(bx, by);\n      context.lineTo(mx, my);\n      context.lineTo(ex, ey);\n      context.closePath();\n      context.fillStrokeShape(kline);\n    });\n    // update text\n    const p2d0 = new Point2D(begin.x(), begin.y());\n    const p2d1 = new Point2D(mid.x(), mid.y());\n    const p2d2 = new Point2D(end.x(), end.y());\n    const line0 = new Line(p2d0, p2d1);\n    const line1 = new Line(p2d1, p2d2);\n    let angle = getAngle(line0, line1);\n    let inclination = line0.getInclination();\n    if (angle > 180) {\n      angle = 360 - angle;\n      inclination += angle;\n    }\n\n    // update text\n    const ktext = klabel.getText();\n    const quantification = {\n      angle: {value: angle, unit: i18n.t('unit.degree')}\n    };\n    ktext.setText(replaceFlags(ktext.meta.textExpr, quantification));\n    // update meta\n    ktext.meta.quantification = quantification;\n    // update position\n    const midX = (line0.getMidpoint().getX() + line1.getMidpoint().getX()) / 2;\n    const midY = (line0.getMidpoint().getY() + line1.getMidpoint().getY()) / 2;\n    const textPos = {\n      x: midX,\n      y: midY - style.applyZoomScale(15).y\n    };\n    klabel.position(textPos);\n\n    // arc\n    const radius = Math.min(line0.getLength(), line1.getLength()) * 33 / 100;\n    karc.innerRadius(radius);\n    karc.outerRadius(radius);\n    karc.angle(angle);\n    karc.rotation(-inclination);\n    const arcPos = {x: mid.x(), y: mid.y()};\n    karc.position(arcPos);\n  }\n\n} // class ProtractorFactory\n","import {Rectangle} from '../math/rectangle';\nimport {Point2D} from '../math/point';\nimport {getFlags, replaceFlags} from '../utils/string';\nimport {logger} from '../utils/logger';\nimport {DRAW_DEBUG} from './draw';\nimport {getDefaultAnchor} from './editor';\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultRectangleLabelText = '{surface}';\n\n/**\n * Rectangle factory.\n */\nexport class RectangleFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'rectangle-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number} The number of points.\n   */\n  getNPoints() {\n    return 2;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 0;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create a rectangle shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the rectangle.\n   * @param {object} style The drawing style.\n   * @param {object} viewController The associated view controller.\n   * @returns {object} The Konva group.\n   */\n  create(points, style, viewController) {\n    // physical shape\n    const rectangle = new Rectangle(points[0], points[1]);\n    // draw shape\n    const kshape = new Konva.Rect({\n      x: rectangle.getBegin().getX(),\n      y: rectangle.getBegin().getY(),\n      width: rectangle.getWidth(),\n      height: rectangle.getHeight(),\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape'\n    });\n    // label text\n    const ktext = new Konva.Text({\n      fontSize: style.getFontSize(),\n      fontFamily: style.getFontFamily(),\n      fill: style.getLineColour(),\n      padding: style.getTextPadding(),\n      shadowColor: style.getShadowLineColour(),\n      shadowOffset: style.getShadowOffset(),\n      name: 'text'\n    });\n    let textExpr = '';\n    // TODO: allow override?\n    // if (typeof rectangleLabelText !== 'undefined') {\n    //   textExpr = rectangleLabelText;\n    // } else {\n    textExpr = defaultRectangleLabelText;\n    // }\n    const quant = rectangle.quantify(\n      viewController,\n      getFlags(textExpr));\n    ktext.setText(replaceFlags(textExpr, quant));\n    // augment text with meta\n    // @ts-ignore\n    ktext.meta = {\n      textExpr: textExpr,\n      quantification: quant\n    };\n    // label\n    const klabel = new Konva.Label({\n      x: rectangle.getBegin().getX(),\n      y: rectangle.getEnd().getY(),\n      scale: style.applyZoomScale(1),\n      visible: textExpr.length !== 0,\n      name: 'label'\n    });\n    klabel.add(ktext);\n    klabel.add(new Konva.Tag({\n      fill: style.getLineColour(),\n      opacity: style.getTagOpacity()\n    }));\n\n    // debug shadow\n    let kshadow;\n    if (DRAW_DEBUG) {\n      kshadow = this.#getShadowRectangle(rectangle);\n    }\n\n    // return group\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    if (kshadow) {\n      group.add(kshadow);\n    }\n    group.add(klabel);\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    return group;\n  }\n\n  /**\n   * Get anchors to update a rectangle shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const rectX = shape.x();\n    const rectY = shape.y();\n    const rectWidth = shape.width();\n    const rectHeight = shape.height();\n\n    const anchors = [];\n    anchors.push(getDefaultAnchor(\n      rectX, rectY, 'topLeft', style\n    ));\n    anchors.push(getDefaultAnchor(\n      rectX + rectWidth, rectY, 'topRight', style\n    ));\n    anchors.push(getDefaultAnchor(\n      rectX + rectWidth, rectY + rectHeight, 'bottomRight', style\n    ));\n    anchors.push(getDefaultAnchor(\n      rectX, rectY + rectHeight, 'bottomLeft', style\n    ));\n    return anchors;\n  }\n\n  /**\n   * Update a rectangle shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} style The app style.\n   * @param {object} viewController The associated view controller.\n   */\n  update(anchor, style, viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const krect = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n    // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n      // find special points\n    const topLeft = group.getChildren(function (node) {\n      return node.id() === 'topLeft';\n    })[0];\n    const topRight = group.getChildren(function (node) {\n      return node.id() === 'topRight';\n    })[0];\n    const bottomRight = group.getChildren(function (node) {\n      return node.id() === 'bottomRight';\n    })[0];\n    const bottomLeft = group.getChildren(function (node) {\n      return node.id() === 'bottomLeft';\n    })[0];\n    // debug shadow\n    let kshadow;\n    if (DRAW_DEBUG) {\n      kshadow = group.getChildren(function (node) {\n        return node.name() === 'shadow';\n      })[0];\n    }\n\n    // update 'self' (undo case) and special points\n    switch (anchor.id()) {\n    case 'topLeft':\n      topLeft.x(anchor.x());\n      topLeft.y(anchor.y());\n      topRight.y(anchor.y());\n      bottomLeft.x(anchor.x());\n      break;\n    case 'topRight':\n      topRight.x(anchor.x());\n      topRight.y(anchor.y());\n      topLeft.y(anchor.y());\n      bottomRight.x(anchor.x());\n      break;\n    case 'bottomRight':\n      bottomRight.x(anchor.x());\n      bottomRight.y(anchor.y());\n      bottomLeft.y(anchor.y());\n      topRight.x(anchor.x());\n      break;\n    case 'bottomLeft':\n      bottomLeft.x(anchor.x());\n      bottomLeft.y(anchor.y());\n      bottomRight.y(anchor.y());\n      topLeft.x(anchor.x());\n      break;\n    default :\n      logger.error('Unhandled anchor id: ' + anchor.id());\n      break;\n    }\n    // update shape\n    krect.position(topLeft.position());\n    const width = topRight.x() - topLeft.x();\n    const height = bottomLeft.y() - topLeft.y();\n    if (width && height) {\n      krect.size({width: width, height: height});\n    }\n    // positions: add possible group offset\n    const p2d0 = new Point2D(\n      group.x() + topLeft.x(),\n      group.y() + topLeft.y()\n    );\n    const p2d1 = new Point2D(\n      group.x() + bottomRight.x(),\n      group.y() + bottomRight.y()\n    );\n    // new rect\n    const rect = new Rectangle(p2d0, p2d1);\n\n    // debug shadow based on round (used in quantification)\n    if (kshadow) {\n      const round = rect.getRound();\n      const rWidth = round.max.getX() - round.min.getX();\n      const rHeight = round.max.getY() - round.min.getY();\n      kshadow.position({\n        x: round.min.getX() - group.x(),\n        y: round.min.getY() - group.y()\n      });\n      kshadow.size({width: rWidth, height: rHeight});\n    }\n\n    // update label position\n    const textPos = {\n      x: rect.getBegin().getX() - group.x(),\n      y: rect.getEnd().getY() - group.y()\n    };\n    klabel.position(textPos);\n\n    // update quantification\n    this.#updateRectangleQuantification(group, viewController);\n  }\n\n  /**\n   * Update the quantification of a Rectangle.\n   *\n   * @param {object} group The group with the shape.\n   * @param {object} viewController The associated view controller.\n   */\n  updateQuantification(group, viewController) {\n    this.#updateRectangleQuantification(group, viewController);\n  }\n\n  /**\n   * Update the quantification of a Rectangle (as a static\n   *   function to be used in update).\n   *\n   * @param {object} group The group with the shape.\n   * @param {object} viewController The associated view controller.\n   */\n  #updateRectangleQuantification(group, viewController) {\n    // associated shape\n    const krect = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n    // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n\n    // positions: add possible group offset\n    const p2d0 = new Point2D(\n      group.x() + krect.x(),\n      group.y() + krect.y()\n    );\n    const p2d1 = new Point2D(\n      p2d0.getX() + krect.width(),\n      p2d0.getY() + krect.height()\n    );\n    // rectangle\n    const rect = new Rectangle(p2d0, p2d1);\n\n    // update text\n    const ktext = klabel.getText();\n    const quantification = rect.quantify(\n      viewController,\n      getFlags(ktext.meta.textExpr));\n    ktext.setText(replaceFlags(ktext.meta.textExpr, quantification));\n    // update meta\n    ktext.meta.quantification = quantification;\n  }\n\n  /**\n   * Get the debug shadow.\n   *\n   * @param {object} rectangle The rectangle to shadow.\n   * @returns {object} The shadow konva shape.\n   */\n  #getShadowRectangle(rectangle) {\n    const round = rectangle.getRound();\n    const rWidth = round.max.getX() - round.min.getX();\n    const rHeight = round.max.getY() - round.min.getY();\n    return new Konva.Rect({\n      x: round.min.getX(),\n      y: round.min.getY(),\n      width: rWidth,\n      height: rHeight,\n      fill: 'grey',\n      strokeWidth: 0,\n      strokeScaleEnabled: false,\n      opacity: 0.3,\n      name: 'shadow'\n    });\n  }\n\n} // class RectangleFactory\n","import {Line, getPerpendicularLine} from '../math/line';\nimport {Point2D} from '../math/point';\nimport {replaceFlags} from '../utils/string';\nimport {getDefaultAnchor} from './editor';\n// external\nimport Konva from 'konva';\n\n/**\n * Default draw label text.\n */\nconst defaultRulerLabelText = '{length}';\n\n/**\n * Ruler factory.\n */\nexport class RulerFactory {\n  /**\n   * Get the name of the shape group.\n   *\n   * @returns {string} The name.\n   */\n  getGroupName() {\n    return 'ruler-group';\n  }\n\n  /**\n   * Get the number of points needed to build the shape.\n   *\n   * @returns {number} The number of points.\n   */\n  getNPoints() {\n    return 2;\n  }\n\n  /**\n   * Get the timeout between point storage.\n   *\n   * @returns {number} The timeout in milliseconds.\n   */\n  getTimeout() {\n    return 0;\n  }\n\n  /**\n   * Is the input group a group of this factory?\n   *\n   * @param {object} group The group to test.\n   * @returns {boolean} True if the group is from this fcatory.\n   */\n  isFactoryGroup(group) {\n    return this.getGroupName() === group.name();\n  }\n\n  /**\n   * Create a ruler shape to be displayed.\n   *\n   * @param {Array} points The points from which to extract the line.\n   * @param {object} style The drawing style.\n   * @param {object} viewController The associated view controller.\n   * @returns {object} The Konva group.\n   */\n  create(points, style, viewController) {\n    // physical shape\n    const line = new Line(points[0], points[1]);\n    // draw shape\n    const kshape = new Konva.Line({\n      points: [line.getBegin().getX(),\n        line.getBegin().getY(),\n        line.getEnd().getX(),\n        line.getEnd().getY()],\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape'\n    });\n\n    const tickLen = style.scale(10);\n\n    // tick begin\n    const linePerp0 = getPerpendicularLine(line, points[0], tickLen);\n    const ktick0 = new Konva.Line({\n      points: [linePerp0.getBegin().getX(),\n        linePerp0.getBegin().getY(),\n        linePerp0.getEnd().getX(),\n        linePerp0.getEnd().getY()],\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape-tick0'\n    });\n\n    // tick end\n    const linePerp1 = getPerpendicularLine(line, points[1], tickLen);\n    const ktick1 = new Konva.Line({\n      points: [linePerp1.getBegin().getX(),\n        linePerp1.getBegin().getY(),\n        linePerp1.getEnd().getX(),\n        linePerp1.getEnd().getY()],\n      stroke: style.getLineColour(),\n      strokeWidth: style.getStrokeWidth(),\n      strokeScaleEnabled: false,\n      name: 'shape-tick1'\n    });\n\n    // larger hitfunc\n    kshape.hitFunc(function (context) {\n      context.beginPath();\n      context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n      context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n      context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n      context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n      context.closePath();\n      context.fillStrokeShape(kshape);\n    });\n\n    // quantification\n    const ktext = new Konva.Text({\n      fontSize: style.getFontSize(),\n      fontFamily: style.getFontFamily(),\n      fill: style.getLineColour(),\n      padding: style.getTextPadding(),\n      shadowColor: style.getShadowLineColour(),\n      shadowOffset: style.getShadowOffset(),\n      name: 'text'\n    });\n    let textExpr = '';\n    // TODO: allow override?\n    // if (typeof rulerLabelText !== 'undefined') {\n    //   textExpr = rulerLabelText;\n    // } else {\n    textExpr = defaultRulerLabelText;\n    // }\n    const quant = line.quantify(viewController);\n    ktext.setText(replaceFlags(textExpr, quant));\n    // augment text with meta\n    // @ts-ignore\n    ktext.meta = {\n      textExpr: textExpr,\n      quantification: quant\n    };\n\n    // label\n    const dX = line.getBegin().getX() > line.getEnd().getX() ? 0 : -1;\n    const dY = line.getBegin().getY() > line.getEnd().getY() ? -1 : 0;\n    const klabel = new Konva.Label({\n      x: line.getEnd().getX() + dX * ktext.width(),\n      y: line.getEnd().getY() + dY * style.applyZoomScale(15).y,\n      scale: style.applyZoomScale(1),\n      visible: textExpr.length !== 0,\n      name: 'label'\n    });\n    klabel.add(ktext);\n    klabel.add(new Konva.Tag({\n      fill: style.getLineColour(),\n      opacity: style.getTagOpacity()\n    }));\n\n    // return group\n    const group = new Konva.Group();\n    group.name(this.getGroupName());\n    group.add(klabel);\n    group.add(ktick0);\n    group.add(ktick1);\n    group.add(kshape);\n    group.visible(true); // dont inherit\n    return group;\n  }\n\n  /**\n   * Get anchors to update a ruler shape.\n   *\n   * @param {object} shape The associated shape.\n   * @param {object} style The application style.\n   * @returns {Array} A list of anchors.\n   */\n  getAnchors(shape, style) {\n    const points = shape.points();\n\n    const anchors = [];\n    anchors.push(getDefaultAnchor(\n      points[0] + shape.x(), points[1] + shape.y(), 'begin', style\n    ));\n    anchors.push(getDefaultAnchor(\n      points[2] + shape.x(), points[3] + shape.y(), 'end', style\n    ));\n    return anchors;\n  }\n\n  /**\n   * Update a ruler shape.\n   *\n   * @param {object} anchor The active anchor.\n   * @param {object} style The app style.\n   * @param {object} viewController The associated view controller.\n   */\n  update(anchor, style, viewController) {\n    // parent group\n    const group = anchor.getParent();\n    // associated shape\n    const kline = group.getChildren(function (node) {\n      return node.name() === 'shape';\n    })[0];\n      // associated tick0\n    const ktick0 = group.getChildren(function (node) {\n      return node.name() === 'shape-tick0';\n    })[0];\n      // associated tick1\n    const ktick1 = group.getChildren(function (node) {\n      return node.name() === 'shape-tick1';\n    })[0];\n      // associated label\n    const klabel = group.getChildren(function (node) {\n      return node.name() === 'label';\n    })[0];\n      // find special points\n    const begin = group.getChildren(function (node) {\n      return node.id() === 'begin';\n    })[0];\n    const end = group.getChildren(function (node) {\n      return node.id() === 'end';\n    })[0];\n      // update special points\n    switch (anchor.id()) {\n    case 'begin':\n      begin.x(anchor.x());\n      begin.y(anchor.y());\n      break;\n    case 'end':\n      end.x(anchor.x());\n      end.y(anchor.y());\n      break;\n    }\n    // update shape and compensate for possible drag\n    // note: shape.position() and shape.size() won't work...\n    const bx = begin.x() - kline.x();\n    const by = begin.y() - kline.y();\n    const ex = end.x() - kline.x();\n    const ey = end.y() - kline.y();\n    kline.points([bx, by, ex, ey]);\n    // new line\n    const p2d0 = new Point2D(begin.x(), begin.y());\n    const p2d1 = new Point2D(end.x(), end.y());\n    const line = new Line(p2d0, p2d1);\n    // tick\n    const p2b = new Point2D(bx, by);\n    const p2e = new Point2D(ex, ey);\n    const linePerp0 = getPerpendicularLine(line, p2b, style.scale(10));\n    ktick0.points([linePerp0.getBegin().getX(),\n      linePerp0.getBegin().getY(),\n      linePerp0.getEnd().getX(),\n      linePerp0.getEnd().getY()]);\n    const linePerp1 = getPerpendicularLine(line, p2e, style.scale(10));\n    ktick1.points([linePerp1.getBegin().getX(),\n      linePerp1.getBegin().getY(),\n      linePerp1.getEnd().getX(),\n      linePerp1.getEnd().getY()]);\n    // larger hitfunc\n    kline.hitFunc(function (context) {\n      context.beginPath();\n      context.moveTo(linePerp0.getBegin().getX(), linePerp0.getBegin().getY());\n      context.lineTo(linePerp0.getEnd().getX(), linePerp0.getEnd().getY());\n      context.lineTo(linePerp1.getEnd().getX(), linePerp1.getEnd().getY());\n      context.lineTo(linePerp1.getBegin().getX(), linePerp1.getBegin().getY());\n      context.closePath();\n      context.fillStrokeShape(kline);\n    });\n\n    // update text\n    const ktext = klabel.getText();\n    const quantification = line.quantify(viewController);\n    ktext.setText(replaceFlags(ktext.meta.textExpr, quantification));\n    // update meta\n    ktext.meta.quantification = quantification;\n    // update position\n    const dX = line.getBegin().getX() > line.getEnd().getX() ? 0 : -1;\n    const dY = line.getBegin().getY() > line.getEnd().getY() ? -1 : 0;\n    const textPos = {\n      x: line.getEnd().getX() + dX * ktext.width(),\n      y: line.getEnd().getY() + dY * style.applyZoomScale(15).y\n    };\n    klabel.position(textPos);\n  }\n\n} // class RulerFactory\n","import {viewEventNames} from '../image/view';\nimport {ViewFactory} from '../image/viewFactory';\nimport {luts} from '../image/luts';\nimport {getMatrixFromName} from '../math/matrix';\nimport {Point3D} from '../math/point';\nimport {Stage} from '../gui/stage';\nimport {Style} from '../gui/style';\nimport {getViewOrientation} from '../gui/layerGroup';\nimport {ListenerHandler} from '../utils/listen';\nimport {State} from '../io/state';\nimport {logger} from '../utils/logger';\nimport {getUriQuery, decodeQuery} from '../utils/uri';\nimport {UndoStack} from '../tools/undo';\nimport {ToolboxController} from './toolboxController';\nimport {LoadController} from './loadController';\nimport {DataController} from './dataController';\n\nimport {toolList, toolOptions} from '../tools';\nimport {binderList} from '../gui/stage';\n\n// doc imports\n/* eslint-disable no-unused-vars */\nimport {LayerGroup} from '../gui/layerGroup';\nimport {ViewLayer} from '../gui/viewLayer';\nimport {DrawLayer} from '../gui/drawLayer';\nimport {Image} from '../image/image';\nimport {ColourMap} from '../image/luts';\n/* eslint-enable no-unused-vars */\n\n/**\n * View configuration: mainly defines the ´divId´\n * of the associated HTML div.\n */\nexport class ViewConfig {\n  /**\n   * Associated HTML div id.\n   *\n   * @type {string}\n   */\n  divId;\n  /**\n   * Optional orientation of the data; 'axial', 'coronal' or 'sagittal'.\n   * If undefined, will use the data aquisition plane.\n   *\n   * @type {string|undefined}\n   */\n  orientation;\n  /**\n   * Optional view colour map.\n   *\n   * @type {ColourMap|undefined}\n   */\n  colourMap;\n  /**\n   * Optional layer opacity; in [0, 1] range.\n   *\n   * @type {number|undefined}\n   */\n  opacity;\n\n  /**\n   * @param {string} divId The associated HTML div id.\n   */\n  constructor(divId) {\n    this.divId = divId;\n  }\n}\n\n/**\n * Tool configuration.\n */\nexport class ToolConfig {\n  /**\n   * Optional tool options.\n   * For Draw: list of shape names.\n   * For Filter: list of filter names.\n   *\n   * @type {string[]|undefined}\n   */\n  options;\n\n  /**\n   * @param {string[]} [options] Optional tool options.\n   */\n  constructor(options) {\n    this.options = options;\n  }\n}\n\n/**\n * Application options.\n */\nexport class AppOptions {\n  /**\n   * DataId indexed object containing the data view configurations.\n   *\n   * @type {Object<string, ViewConfig[]>}\n   */\n  dataViewConfigs;\n  /**\n   * Tool name indexed object containing individual tool configurations.\n   *\n   * @type {Object<string, ToolConfig>|undefined}\n   */\n  tools;\n  /**\n   * Optional array of layerGroup binder names.\n   *\n   * @type {string[]|undefined}\n   */\n  binders;\n  /**\n   * Optional boolean flag to trigger the first data render\n   *   after the first loaded data or not. Defaults to true;\n   *\n   * @type {boolean|undefined}\n   */\n  viewOnFirstLoadItem;\n  /**\n   * Optional default chraracter set string used for DICOM parsing if\n   * not passed in DICOM file.\n   * Valid values: https://developer.mozilla.org/en-US/docs/Web/API/Encoding_API/Encodings\n   *\n   * @type {string|undefined}\n   */\n  defaultCharacterSet;\n\n  /**\n   * @param {Object<string, ViewConfig[]>} dataViewConfigs DataId\n   *   indexed object containing the data view configurations.\n   */\n  constructor(dataViewConfigs) {\n    this.dataViewConfigs = dataViewConfigs;\n  }\n}\n\n/**\n * List of ViewConfigs indexed by dataIds.\n *\n * @typedef {Object<string, ViewConfig[]>} DataViewConfigs\n */\n\n/**\n * Main application class.\n *\n * @example\n * // create the dwv app\n * const app = new dwv.App();\n * // initialise\n * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n * const viewConfigs = {'*': [viewConfig0]};\n * const options = new dwv.AppOptions(viewConfigs);\n * app.init(options);\n * // load dicom data\n * app.loadURLs([\n *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n * ]);\n */\nexport class App {\n\n  /**\n   * App options.\n   *\n   * @type {AppOptions}\n   */\n  #options = null;\n\n  /**\n   * Data controller.\n   *\n   * @type {DataController}\n   */\n  #dataController = null;\n\n  /**\n   * Toolbox controller.\n   *\n   * @type {ToolboxController}\n   */\n  #toolboxController = null;\n\n  /**\n   * Load controller.\n   *\n   * @type {LoadController}\n   */\n  #loadController = null;\n\n  /**\n   * Stage.\n   *\n   * @type {Stage}\n   */\n  #stage = null;\n\n  /**\n   * Undo stack.\n   *\n   * @type {UndoStack}\n   */\n  #undoStack = null;\n\n  /**\n   * Style.\n   *\n   * @type {Style}\n   */\n  #style = new Style();\n\n  /**\n   * Listener handler.\n   *\n   * @type {object}\n   */\n  #listenerHandler = new ListenerHandler();\n\n  /**\n   * Get the image.\n   *\n   * @param {number} index The data index.\n   * @returns {Image} The associated image.\n   */\n  getImage(index) {\n    return this.#dataController.get(index).image;\n  }\n\n  /**\n   * Get the last loaded image.\n   *\n   * @returns {Image} The image.\n   */\n  getLastImage() {\n    return this.#dataController.get(this.#dataController.length() - 1).image;\n  }\n\n  /**\n   * Set the image at the given index.\n   *\n   * @param {number} index The data index.\n   * @param {Image} img The associated image.\n   */\n  setImage(index, img) {\n    this.#dataController.setImage(index, img);\n  }\n\n  /**\n   * Set the last image.\n   *\n   * @param {Image} img The associated image.\n   */\n  setLastImage(img) {\n    this.#dataController.setImage(this.#dataController.length() - 1, img);\n  }\n\n  /**\n   * Add a new image.\n   *\n   * @param {Image} image The new image.\n   * @param {object} meta The image meta.\n   * @returns {number} The new image id.\n   */\n  addNewImage(image, meta) {\n    const id = this.#dataController.length();\n\n    // load start event\n    this.#fireEvent({\n      type: 'loadstart',\n      loadtype: 'image',\n      source: 'internal',\n      loadid: id\n    });\n\n    // add image to data controller\n    this.#dataController.addNew(id, image, meta);\n\n    // load item event\n    this.#fireEvent({\n      type: 'loaditem',\n      loadtype: 'image',\n      data: meta,\n      source: 'internal',\n      loadid: id,\n      isfirstitem: true\n    });\n\n    // optional render\n    if (this.#options.viewOnFirstLoadItem) {\n      this.render(id);\n    }\n\n    // load events\n    this.#fireEvent({\n      type: 'load',\n      loadtype: 'image',\n      source: 'internal',\n      loadid: id\n    });\n    this.#fireEvent({\n      type: 'loadend',\n      loadtype: 'image',\n      source: 'internal',\n      loadid: id\n    });\n\n    return id;\n  }\n\n  /**\n   * Get the meta data.\n   *\n   * @param {number} index The data index.\n   * @returns {object} The list of meta data.\n   */\n  getMetaData(index) {\n    return this.#dataController.get(index).meta;\n  }\n\n  /**\n   * Get the number of loaded data.\n   *\n   * @returns {number} The number.\n   */\n  getNumberOfLoadedData() {\n    return this.#dataController.length();\n  }\n\n  /**\n   * Can the data be scrolled?\n   *\n   * @returns {boolean} True if the data has a third dimension greater than one.\n   */\n  canScroll() {\n    const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n    const controller = viewLayer.getViewController();\n    return controller.canScroll();\n  }\n\n  /**\n   * Can window and level be applied to the data?\n   *\n   * @returns {boolean} True if the data is monochrome.\n   */\n  canWindowLevel() {\n    const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n    const controller = viewLayer.getViewController();\n    return controller.canWindowLevel();\n  }\n\n  /**\n   * Get the layer scale on top of the base scale.\n   *\n   * @returns {object} The scale as {x,y}.\n   */\n  getAddedScale() {\n    return this.#stage.getActiveLayerGroup().getAddedScale();\n  }\n\n  /**\n   * Get the base scale.\n   *\n   * @returns {object} The scale as {x,y}.\n   */\n  getBaseScale() {\n    return this.#stage.getActiveLayerGroup().getBaseScale();\n  }\n\n  /**\n   * Get the layer offset.\n   *\n   * @returns {object} The offset.\n   */\n  getOffset() {\n    return this.#stage.getActiveLayerGroup().getOffset();\n  }\n\n  /**\n   * Get the toolbox controller.\n   *\n   * @returns {ToolboxController} The controller.\n   */\n  getToolboxController() {\n    return this.#toolboxController;\n  }\n\n  /**\n   * Get the active layer group.\n   * The layer is available after the first loaded item.\n   *\n   * @returns {LayerGroup} The layer group.\n   */\n  getActiveLayerGroup() {\n    return this.#stage.getActiveLayerGroup();\n  }\n\n  /**\n   * Get the view layers associated to a data index.\n   * The layer are available after the first loaded item.\n   *\n   * @param {number} index The data index.\n   * @returns {ViewLayer[]} The layers.\n   */\n  getViewLayersByDataIndex(index) {\n    return this.#stage.getViewLayersByDataIndex(index);\n  }\n\n  /**\n   * Get the draw layers associated to a data index.\n   * The layer are available after the first loaded item.\n   *\n   * @param {number} index The data index.\n   * @returns {DrawLayer[]} The layers.\n   */\n  getDrawLayersByDataIndex(index) {\n    return this.#stage.getDrawLayersByDataIndex(index);\n  }\n\n  /**\n   * Get a layer group by div id.\n   * The layer is available after the first loaded item.\n   *\n   * @param {string} divId The div id.\n   * @returns {LayerGroup} The layer group.\n   */\n  getLayerGroupByDivId(divId) {\n    return this.#stage.getLayerGroupByDivId(divId);\n  }\n\n  /**\n   * Get the number of layer groups.\n   *\n   * @returns {number} The number of groups.\n   */\n  getNumberOfLayerGroups() {\n    return this.#stage.getNumberOfLayerGroups();\n  }\n\n  /**\n   * Get the app style.\n   *\n   * @returns {object} The app style.\n   */\n  getStyle() {\n    return this.#style;\n  }\n\n  /**\n   * Add a command to the undo stack.\n   *\n   * @param {object} cmd The command to add.\n   * @fires UndoStack#undoadd\n   * @function\n   */\n  addToUndoStack = (cmd) => {\n    if (this.#undoStack !== null) {\n      this.#undoStack.add(cmd);\n    }\n  };\n\n  /**\n   * Initialise the application.\n   *\n   * @param {AppOptions} opt The application options\n   * @example\n   * // create the dwv app\n   * const app = new dwv.App();\n   * // initialise\n   * const viewConfig0 = new dwv.ViewConfig('layerGroup0');\n   * const viewConfigs = {'*': [viewConfig0]};\n   * const options = new dwv.AppOptions(viewConfigs);\n   * options.viewOnFirstLoadItem = false;\n   * app.init(options);\n   * // render button\n   * const button = document.createElement('button');\n   * button.id = 'render';\n   * button.disabled = true;\n   * button.appendChild(document.createTextNode('render'));\n   * document.body.appendChild(button);\n   * app.addEventListener('load', function () {\n   *   const button = document.getElementById('render');\n   *   button.disabled = false;\n   *   button.onclick = function () {\n   *     // render data #0\n   *     app.render(0);\n   *   };\n   * });\n   * // load dicom data\n   * app.loadURLs([\n   *   'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm'\n   * ]);\n   */\n  init(opt) {\n    // store\n    this.#options = opt;\n    // defaults\n    if (typeof this.#options.viewOnFirstLoadItem === 'undefined') {\n      this.#options.viewOnFirstLoadItem = true;\n    }\n\n    // undo stack\n    this.#undoStack = new UndoStack();\n    this.#undoStack.addEventListener('undoadd', this.#fireEvent);\n    this.#undoStack.addEventListener('undo', this.#fireEvent);\n    this.#undoStack.addEventListener('redo', this.#fireEvent);\n\n    // tools\n    if (typeof this.#options.tools !== 'undefined') {\n      // setup the tool list\n      const appToolList = {};\n      const keys = Object.keys(this.#options.tools);\n      for (let t = 0; t < keys.length; ++t) {\n        const toolName = keys[t];\n        // find the tool in the Tools list\n        if (typeof toolList[toolName] !== 'undefined') {\n          // create tool instance\n          appToolList[toolName] = new toolList[toolName](this);\n          // register listeners\n          if (typeof appToolList[toolName].addEventListener !== 'undefined') {\n            const names = appToolList[toolName].getEventNames();\n            for (let j = 0; j < names.length; ++j) {\n              appToolList[toolName].addEventListener(names[j], this.#fireEvent);\n            }\n          }\n          // tool options\n          const toolParams = this.#options.tools[toolName];\n          if (typeof toolParams.options !== 'undefined' &&\n            toolParams.options.length !== 0) {\n            let type = 'raw';\n            if (typeof appToolList[toolName].getOptionsType !== 'undefined') {\n              type = appToolList[toolName].getOptionsType();\n            }\n            let appToolOptions;\n            if (type === 'instance' || type === 'factory') {\n              appToolOptions = {};\n              for (let i = 0; i < toolParams.options.length; ++i) {\n                const optionName = toolParams.options[i];\n                let optionClassName = optionName;\n                if (type === 'factory') {\n                  optionClassName += 'Factory';\n                }\n                const toolNamespace = toolName.charAt(0).toLowerCase() +\n                  toolName.slice(1);\n                if (typeof toolOptions[toolNamespace][optionClassName] !==\n                  'undefined') {\n                  appToolOptions[optionName] =\n                    toolOptions[toolNamespace][optionClassName];\n                } else {\n                  logger.warn('Could not find option class for: ' +\n                    optionName);\n                }\n              }\n            } else {\n              appToolOptions = toolParams.options;\n            }\n            appToolList[toolName].setOptions(appToolOptions);\n          }\n        } else {\n          logger.warn('Could not initialise unknown tool: ' + toolName);\n        }\n      }\n      // add tools to the controller\n      this.#toolboxController = new ToolboxController(appToolList);\n    }\n\n    // create load controller\n    this.#loadController =\n      new LoadController(this.#options.defaultCharacterSet);\n    this.#loadController.onloadstart = this.#onloadstart;\n    this.#loadController.onprogress = this.#onloadprogress;\n    this.#loadController.onloaditem = this.#onloaditem;\n    this.#loadController.onload = this.#onload;\n    this.#loadController.onloadend = this.#onloadend;\n    this.#loadController.onerror = this.#onloaderror;\n    this.#loadController.onabort = this.#onloadabort;\n\n    // create data controller\n    this.#dataController = new DataController();\n    // create stage\n    this.#stage = new Stage();\n    if (typeof this.#options.binders !== 'undefined') {\n      this.#stage.setBinders(this.#options.binders);\n    }\n  }\n\n  /**\n   * Reset the application.\n   */\n  reset() {\n    // clear objects\n    this.#dataController.reset();\n    this.#stage.empty();\n    // reset undo/redo\n    if (this.#undoStack) {\n      this.#undoStack = new UndoStack();\n      this.#undoStack.addEventListener('undoadd', this.#fireEvent);\n      this.#undoStack.addEventListener('undo', this.#fireEvent);\n      this.#undoStack.addEventListener('redo', this.#fireEvent);\n    }\n  }\n\n  /**\n   * Reset the layout of the application.\n   */\n  resetLayout() {\n    this.#stage.reset();\n    this.#stage.draw();\n  }\n\n  /**\n   * Add an event listener to this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type, will be called with the fired event.\n   */\n  addEventListener(type, callback) {\n    this.#listenerHandler.add(type, callback);\n  }\n\n  /**\n   * Remove an event listener from this class.\n   *\n   * @param {string} type The event type.\n   * @param {Function} callback The function associated with the provided\n   *   event type.\n   */\n  removeEventListener(type, callback) {\n    this.#listenerHandler.remove(type, callback);\n  }\n\n  // load API [begin] -------------------------------------------------------\n\n  /**\n   * Load a list of files. Can be image files or a state file.\n   *\n   * @param {File[]} files The list of files to load.\n   * @fires App#loadstart\n   * @fires App#loadprogress\n   * @fires App#loaditem\n   * @fires App#loadend\n   * @fires App#loaderror\n   * @fires App#loadabort\n   * @function\n   */\n  loadFiles = (files) => {\n    if (files.length === 0) {\n      logger.warn('Ignoring empty input file list.');\n      return;\n    }\n    this.#loadController.loadFiles(files);\n  };\n\n  /**\n   * Load a list of URLs. Can be image files or a state file.\n   *\n   * @param {string[]} urls The list of urls to load.\n   * @param {object} [options] The options object, can contain:\n   *  - requestHeaders: an array of {name, value} to use as request headers\n   *  - withCredentials: boolean xhr.withCredentials flag to pass to the request\n   *  - batchSize: the size of the request url batch\n   * @fires App#loadstart\n   * @fires App#loadprogress\n   * @fires App#loaditem\n   * @fires App#loadend\n   * @fires App#loaderror\n   * @fires App#loadabort\n   * @function\n   */\n  loadURLs = (urls, options) => {\n    if (urls.length === 0) {\n      logger.warn('Ignoring empty input url list.');\n      return;\n    }\n    this.#loadController.loadURLs(urls, options);\n  };\n\n  /**\n   * Load from an input uri.\n   *\n   * @param {string} uri The input uri, for example: 'window.location.href'.\n   * @param {object} [options] Optional url request options.\n   * @function\n   */\n  loadFromUri = (uri, options) => {\n    const query = getUriQuery(uri);\n\n    // load end callback: loads the state.\n    const onLoadEnd = (/*event*/) => {\n      this.removeEventListener('loadend', onLoadEnd);\n      this.loadURLs([query.state]);\n    };\n\n    // check query\n    if (query && typeof query.input !== 'undefined') {\n      // optional display state\n      if (typeof query.state !== 'undefined') {\n        // queue after main data load\n        this.addEventListener('loadend', onLoadEnd);\n      }\n      // load base image\n      decodeQuery(query, this.loadURLs, options);\n    }\n    // no else to allow for empty uris\n  };\n\n  /**\n   * Load a list of ArrayBuffers.\n   *\n   * @param {Array} data The list of ArrayBuffers to load\n   *   in the form of [{name: \"\", filename: \"\", data: data}].\n   * @fires App#loadstart\n   * @fires App#loadprogress\n   * @fires App#loaditem\n   * @fires App#loadend\n   * @fires App#loaderror\n   * @fires App#loadabort\n   * @function\n   */\n  loadImageObject = (data) => {\n    this.#loadController.loadImageObject(data);\n  };\n\n  /**\n   * Abort the current load.\n   */\n  abortLoad() {\n    this.#loadController.abort();\n  }\n\n  // load API [end] ---------------------------------------------------------\n\n  /**\n   * Fit the display to the data of each layer group.\n   * To be called once the image is loaded.\n   */\n  fitToContainer() {\n    this.#stage.syncLayerGroupScale();\n  }\n\n  /**\n   * Init the Window/Level display\n   */\n  initWLDisplay() {\n    const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n    const controller = viewLayer.getViewController();\n    controller.initialise();\n  }\n\n  /**\n   * Get the layer group configuration from a data index.\n   * Defaults to div id 'layerGroup' if no association object has been set.\n   *\n   * @param {number} dataIndex The data index.\n   * @returns {ViewConfig[]} The list of associated configs.\n   */\n  #getViewConfigs(dataIndex) {\n    // check options\n    if (this.#options.dataViewConfigs === null ||\n      typeof this.#options.dataViewConfigs === 'undefined') {\n      throw new Error('No available data view configuration');\n    }\n    let configs = [];\n    if (typeof this.#options.dataViewConfigs['*'] !== 'undefined') {\n      configs = this.#options.dataViewConfigs['*'];\n    } else if (\n      typeof this.#options.dataViewConfigs[dataIndex] !== 'undefined') {\n      configs = this.#options.dataViewConfigs[dataIndex];\n    }\n    return configs;\n  }\n\n  /**\n   * Get the data view config.\n   * Carefull, returns a reference, do not modify without resetting.\n   *\n   * @returns {Object<string, ViewConfig[]>} The configuration list.\n   */\n  getDataViewConfigs() {\n    return this.#options.dataViewConfigs;\n  }\n\n  /**\n   * Set the data view configuration.\n   * Resets the stage and recreates all the views.\n   *\n   * @param {Object<string, ViewConfig[]>} configs The configuration list.\n   */\n  setDataViewConfigs(configs) {\n    // clean up\n    this.#stage.empty();\n    // set new\n    this.#options.dataViewConfigs = configs;\n    // create layer groups\n    this.#createLayerGroups(configs);\n  }\n\n  /**\n   * Create layer groups according to a data view config:\n   * adds them to stage and bind them.\n   *\n   * @param {DataViewConfigs} dataViewConfigs The data view config.\n   */\n  #createLayerGroups(dataViewConfigs) {\n    const dataKeys = Object.keys(dataViewConfigs);\n    const divIds = [];\n    for (let i = 0; i < dataKeys.length; ++i) {\n      const viewConfigs = dataViewConfigs[dataKeys[i]];\n      for (let j = 0; j < viewConfigs.length; ++j) {\n        const viewConfig = viewConfigs[j];\n        // view configs can contain the same divIds, avoid duplicating\n        if (!divIds.includes(viewConfig.divId)) {\n          // create new layer group\n          const element = document.getElementById(viewConfig.divId);\n          const layerGroup = this.#stage.addLayerGroup(element);\n          // bind events\n          this.#bindLayerGroupToApp(layerGroup);\n          // optional orientation\n          if (typeof viewConfig.orientation !== 'undefined') {\n            layerGroup.setTargetOrientation(\n              getMatrixFromName(viewConfig.orientation));\n          }\n          divIds.push(viewConfig.divId);\n        }\n      }\n    }\n  }\n\n  /**\n   * Set the layer groups binders.\n   *\n   * @param {Array} list The list of binder names.\n   */\n  setLayerGroupsBinders(list) {\n    // create instances\n    const instances = [];\n    for (let i = 0; i < list.length; ++i) {\n      if (typeof binderList[list[i]] !== 'undefined') {\n        instances.push(new binderList[list[i]]);\n      }\n    }\n    // pass to stage\n    this.#stage.setBinders(instances);\n  }\n\n  /**\n   * Render the current data.\n   *\n   * @param {number} dataIndex The data index to render.\n   */\n  render(dataIndex) {\n    if (typeof dataIndex === 'undefined' || dataIndex === null) {\n      throw new Error('Cannot render without data index');\n    }\n\n    // create layer groups if not done yet\n    // (create all to allow for ratio sync)\n    if (this.#stage.getNumberOfLayerGroups() === 0) {\n      this.#createLayerGroups(this.#options.dataViewConfigs);\n    }\n\n    // loop on all configs\n    const viewConfigs = this.#getViewConfigs(dataIndex);\n    // nothing to do if no view config\n    if (viewConfigs.length === 0) {\n      logger.info('Not rendering data: ' + dataIndex +\n        ' (no data view config)');\n      return;\n    }\n    for (let i = 0; i < viewConfigs.length; ++i) {\n      const config = viewConfigs[i];\n      const layerGroup =\n      this.#stage.getLayerGroupByDivId(config.divId);\n      // layer group must exist\n      if (!layerGroup) {\n        throw new Error('No layer group for ' + config.divId);\n      }\n      // initialise or add view\n      // warn: needs a loaded DOM\n      if (layerGroup.getViewLayersByDataIndex(dataIndex).length === 0) {\n        if (layerGroup.getNumberOfLayers() === 0) {\n          this.#initialiseBaseLayers(dataIndex, config);\n        } else {\n          this.#addViewLayer(dataIndex, config);\n        }\n      }\n      // draw\n      layerGroup.draw();\n    }\n  }\n\n  /**\n   * Zoom to the layers.\n   *\n   * @param {number} step The step to add to the current zoom.\n   * @param {number} cx The zoom center X coordinate.\n   * @param {number} cy The zoom center Y coordinate.\n   */\n  zoom(step, cx, cy) {\n    const layerGroup = this.#stage.getActiveLayerGroup();\n    const viewController = layerGroup.getActiveViewLayer().getViewController();\n    const k = viewController.getCurrentScrollPosition();\n    const center = new Point3D(cx, cy, k);\n    layerGroup.addScale(step, center);\n    layerGroup.draw();\n  }\n\n  /**\n   * Apply a translation to the layers.\n   *\n   * @param {number} tx The translation along X.\n   * @param {number} ty The translation along Y.\n   */\n  translate(tx, ty) {\n    const layerGroup = this.#stage.getActiveLayerGroup();\n    layerGroup.addTranslation({x: tx, y: ty});\n    layerGroup.draw();\n  }\n\n  /**\n   * Set the image layer opacity.\n   *\n   * @param {number} alpha The opacity ([0:1] range).\n   */\n  setOpacity(alpha) {\n    const viewLayer = this.#stage.getActiveLayerGroup().getActiveViewLayer();\n    viewLayer.setOpacity(alpha);\n    viewLayer.draw();\n  }\n\n  /**\n   * Set the drawings on the current stage.\n   *\n   * @param {Array} drawings An array of drawings.\n   * @param {Array} drawingsDetails An array of drawings details.\n   */\n  setDrawings(drawings, drawingsDetails) {\n    const layerGroup = this.#stage.getActiveLayerGroup();\n    const viewController =\n      layerGroup.getActiveViewLayer().getViewController();\n    const drawController =\n      layerGroup.getActiveDrawLayer().getDrawController();\n\n    drawController.setDrawings(\n      drawings, drawingsDetails, this.#fireEvent, this.addToUndoStack);\n\n    drawController.activateDrawLayer(\n      viewController.getCurrentOrientedIndex(),\n      viewController.getScrollIndex());\n  }\n\n  /**\n   * Get the JSON state of the app.\n   *\n   * @returns {string} The state of the app as a JSON string.\n   */\n  getJsonState() {\n    const state = new State();\n    return state.toJSON(this);\n  }\n\n  /**\n   * Apply a JSON state to this app.\n   *\n   * @param {string} jsonState The state of the app as a JSON string.\n   */\n  applyJsonState(jsonState) {\n    const state = new State();\n    state.apply(this, state.fromJSON(jsonState));\n  }\n\n  // Handler Methods -----------------------------------------------------------\n\n  /**\n   * Handle resize: fit the display to the window.\n   * To be called once the image is loaded.\n   * Can be connected to a window 'resize' event.\n   *\n   * @function\n   */\n  onResize = () => {\n    this.fitToContainer();\n  };\n\n  /**\n   * Key down callback. Meant to be used in tools.\n   *\n   * @param {KeyboardEvent} event The key down event.\n   * @fires App#keydown\n   * @function\n   */\n  onKeydown = (event) => {\n    /**\n     * Key down event.\n     *\n     * @event App#keydown\n     * @type {KeyboardEvent}\n     * @property {string} type The event type: keydown.\n     * @property {string} context The tool where the event originated.\n     */\n    this.#fireEvent(event);\n  };\n\n  /**\n   * Key down event handler example.\n   * - CRTL-Z: undo\n   * - CRTL-Y: redo\n   * - CRTL-ARROW_LEFT: next element on fourth dim\n   * - CRTL-ARROW_UP: next element on third dim\n   * - CRTL-ARROW_RIGHT: previous element on fourth dim\n   * - CRTL-ARROW_DOWN: previous element on third dim\n   *\n   * @param {KeyboardEvent} event The key down event.\n   * @fires UndoStack#undo\n   * @fires UndoStack#redo\n   * @function\n   */\n  defaultOnKeydown = (event) => {\n    if (event.ctrlKey) {\n      if (event.shiftKey) {\n        const viewController =\n          this.#stage.getActiveLayerGroup()\n            .getActiveViewLayer().getViewController();\n        const size = viewController.getImageSize();\n        if (event.key === 'ArrowLeft') { // crtl-shift-arrow-left\n          if (size.moreThanOne(3)) {\n            viewController.decrementIndex(3);\n          }\n        } else if (event.key === 'ArrowUp') { // crtl-shift-arrow-up\n          if (viewController.canScroll()) {\n            viewController.incrementScrollIndex();\n          }\n        } else if (event.key === 'ArrowRight') { // crtl-shift-arrow-right\n          if (size.moreThanOne(3)) {\n            viewController.incrementIndex(3);\n          }\n        } else if (event.key === 'ArrowDown') { // crtl-shift-arrow-down\n          if (viewController.canScroll()) {\n            viewController.decrementScrollIndex();\n          }\n        }\n      } else if (event.key === 'y') { // crtl-y\n        this.#undoStack.redo();\n      } else if (event.key === 'z') { // crtl-z\n        this.#undoStack.undo();\n      } else if (event.key === ' ') { // crtl-space\n        for (let i = 0; i < this.#stage.getNumberOfLayerGroups(); ++i) {\n          this.#stage.getLayerGroup(i).setShowCrosshair(\n            !this.#stage.getLayerGroup(i).getShowCrosshair()\n          );\n        }\n      }\n    }\n  };\n\n  // Internal members shortcuts-----------------------------------------------\n\n  /**\n   * Reset the display\n   */\n  resetDisplay() {\n    this.resetLayout();\n    this.initWLDisplay();\n  }\n\n  /**\n   * Reset the app zoom.s\n   */\n  resetZoom() {\n    this.resetLayout();\n  }\n\n  /**\n   * Set the colour map.\n   *\n   * @param {string} name The colour map name.\n   */\n  setColourMap(name) {\n    const viewController =\n      this.#stage.getActiveLayerGroup()\n        .getActiveViewLayer().getViewController();\n    viewController.setColourMapFromName(name);\n  }\n\n  /**\n   * Set the window/level preset.\n   *\n   * @param {object} preset The window/level preset.\n   */\n  setWindowLevelPreset(preset) {\n    const viewController =\n      this.#stage.getActiveLayerGroup()\n        .getActiveViewLayer().getViewController();\n    viewController.setWindowLevelPreset(preset);\n  }\n\n  /**\n   * Set the tool\n   *\n   * @param {string} tool The tool.\n   */\n  setTool(tool) {\n    // bind tool to active layer\n    for (let i = 0; i < this.#stage.getNumberOfLayerGroups(); ++i) {\n      const layerGroup = this.#stage.getLayerGroup(i);\n      // draw or view layer\n      let layer = null;\n      if (tool === 'Draw' ||\n        tool === 'Livewire' ||\n        tool === 'Floodfill') {\n        layer = layerGroup.getActiveDrawLayer();\n      } else {\n        layer = layerGroup.getActiveViewLayer();\n      }\n      if (layer) {\n        this.#toolboxController.bindLayer(layer, layerGroup.getDivId());\n      }\n    }\n\n    // set toolbox tool\n    this.#toolboxController.setSelectedTool(tool);\n  }\n\n  /**\n   * Set the tool live features.\n   *\n   * @param {object} list The list of features.\n   */\n  setToolFeatures(list) {\n    this.#toolboxController.setToolFeatures(list);\n  }\n\n  /**\n   * Undo the last action\n   *\n   * @fires UndoStack#undo\n   */\n  undo() {\n    this.#undoStack.undo();\n  }\n\n  /**\n   * Redo the last action\n   *\n   * @fires UndoStack#redo\n   */\n  redo() {\n    this.#undoStack.redo();\n  }\n\n  /**\n   * Get the undo stack size.\n   *\n   * @returns {number} The size of the stack.\n   */\n  getStackSize() {\n    return this.#undoStack.getStackSize();\n  }\n\n  /**\n   * Get the current undo stack index.\n   *\n   * @returns {number} The stack index.\n   */\n  getCurrentStackIndex() {\n    return this.#undoStack.getCurrentStackIndex();\n  }\n\n  // Private Methods -----------------------------------------------------------\n\n  /**\n   * Fire an event: call all associated listeners with the input event object.\n   *\n   * @param {object} event The event to fire.\n   */\n  #fireEvent = (event) => {\n    this.#listenerHandler.fireEvent(event);\n  };\n\n  /**\n   * Data load start callback.\n   *\n   * @param {object} event The load start event.\n   */\n  #onloadstart = (event) => {\n    /**\n     * Load start event.\n     *\n     * @event App#loadstart\n     * @type {object}\n     * @property {string} type The event type: loadstart.\n     * @property {string} loadType The load type: image or state.\n     * @property {*} source The load source: string for an url,\n     *   File for a file.\n     */\n    event.type = 'loadstart';\n    this.#fireEvent(event);\n  };\n\n  /**\n   * Data load progress callback.\n   *\n   * @param {object} event The progress event.\n   */\n  #onloadprogress = (event) => {\n    /**\n     * Load progress event.\n     *\n     * @event App#loadprogress\n     * @type {object}\n     * @property {string} type The event type: loadprogress.\n     * @property {string} loadType The load type: image or state.\n     * @property {*} source The load source: string for an url,\n     *   File for a file.\n     * @property {number} loaded The loaded percentage.\n     * @property {number} total The total percentage.\n     */\n    event.type = 'loadprogress';\n    this.#fireEvent(event);\n  };\n\n  /**\n   * Data load callback.\n   *\n   * @param {object} event The load event.\n   */\n  #onloaditem = (event) => {\n    // check event\n    if (typeof event.data === 'undefined') {\n      logger.error('Missing loaditem event data.');\n    }\n    if (typeof event.loadtype === 'undefined') {\n      logger.error('Missing loaditem event load type.');\n    }\n\n    const isFirstLoadItem = event.isfirstitem;\n\n    let eventMetaData = null;\n    if (event.loadtype === 'image') {\n      if (isFirstLoadItem) {\n        this.#dataController.addNew(\n          event.loadid, event.data.image, event.data.info);\n      } else {\n        this.#dataController.update(\n          event.loadid, event.data.image, event.data.info);\n      }\n      eventMetaData = event.data.info;\n    } else if (event.loadtype === 'state') {\n      this.applyJsonState(event.data);\n      eventMetaData = 'state';\n    }\n\n    /**\n     * Load item event: fired when a load item is successfull.\n     *\n     * @event App#loaditem\n     * @type {object}\n     * @property {string} type The event type: loaditem.\n     * @property {string} loadType The load type: image or state.\n     * @property {*} source The load source: string for an url,\n     *   File for a file.\n     * @property {object} data The loaded meta data.\n     */\n    this.#fireEvent({\n      type: 'loaditem',\n      data: eventMetaData,\n      source: event.source,\n      loadtype: event.loadtype,\n      loadid: event.loadid,\n      isfirstitem: event.isfirstitem,\n      warn: event.warn\n    });\n\n    // render if first and flag allows\n    if (event.loadtype === 'image' &&\n    this.#getViewConfigs(event.loadid).length !== 0 &&\n      isFirstLoadItem && this.#options.viewOnFirstLoadItem) {\n      this.render(event.loadid);\n    }\n  };\n\n  /**\n   * Data load callback.\n   *\n   * @param {object} event The load event.\n   */\n  #onload = (event) => {\n    /**\n     * Load event: fired when a load finishes successfully.\n     *\n     * @event App#load\n     * @type {object}\n     * @property {string} type The event type: load.\n     * @property {string} loadType The load type: image or state.\n     */\n    event.type = 'load';\n    this.#fireEvent(event);\n  };\n\n  /**\n   * Data load end callback.\n   *\n   * @param {object} event The load end event.\n   */\n  #onloadend = (event) => {\n    /**\n     * Main load end event: fired when the load finishes,\n     *   successfully or not.\n     *\n     * @event App#loadend\n     * @type {object}\n     * @property {string} type The event type: loadend.\n     * @property {string} loadType The load type: image or state.\n     * @property {*} source The load source: string for an url,\n     *   File for a file.\n     */\n    event.type = 'loadend';\n    this.#fireEvent(event);\n  };\n\n  /**\n   * Data load error callback.\n   *\n   * @param {object} event The error event.\n   */\n  #onloaderror = (event) => {\n    /**\n     * Load error event.\n     *\n     * @event App#loaderror\n     * @type {object}\n     * @property {string} type The event type: error.\n     * @property {string} loadType The load type: image or state.\n     * @property {*} source The load source: string for an url,\n     *   File for a file.\n     * @property {object} error The error.\n     * @property {object} target The event target.\n     */\n    event.type = 'loaderror';\n    this.#fireEvent(event);\n  };\n\n  /**\n   * Data load abort callback.\n   *\n   * @param {object} event The abort event.\n   */\n  #onloadabort = (event) => {\n    /**\n     * Load abort event.\n     *\n     * @event App#loadabort\n     * @type {object}\n     * @property {string} type The event type: abort.\n     * @property {string} loadType The load type: image or state.\n     * @property {*} source The load source: string for an url,\n     *   File for a file.\n     */\n    event.type = 'loadabort';\n    this.#fireEvent(event);\n  };\n\n  /**\n   * Bind layer group events to app.\n   *\n   * @param {object} group The layer group.\n   */\n  #bindLayerGroupToApp(group) {\n    // propagate layer group events\n    group.addEventListener('zoomchange', this.#fireEvent);\n    group.addEventListener('offsetchange', this.#fireEvent);\n    // propagate viewLayer events\n    group.addEventListener('renderstart', this.#fireEvent);\n    group.addEventListener('renderend', this.#fireEvent);\n    // propagate view events\n    for (let j = 0; j < viewEventNames.length; ++j) {\n      group.addEventListener(viewEventNames[j], this.#fireEvent);\n    }\n    // propagate drawLayer events\n    if (this.#toolboxController && this.#toolboxController.hasTool('Draw')) {\n      group.addEventListener('drawcreate', this.#fireEvent);\n      group.addEventListener('drawdelete', this.#fireEvent);\n    }\n  }\n\n  /**\n   * Initialise the layers.\n   * To be called once the DICOM data has been loaded.\n   *\n   * @param {number} dataIndex The data index.\n   * @param {ViewConfig} viewConfig The view config.\n   */\n  #initialiseBaseLayers(dataIndex, viewConfig) {\n    // add layers\n    this.#addViewLayer(dataIndex, viewConfig);\n\n    // initialise the toolbox\n    if (this.#toolboxController) {\n      this.#toolboxController.init();\n    }\n  }\n\n  /**\n   * Add a view layer.\n   *\n   * @param {number} dataIndex The data index.\n   * @param {ViewConfig} viewConfig The data view config.\n   */\n  #addViewLayer(dataIndex, viewConfig) {\n    const data = this.#dataController.get(dataIndex);\n    if (!data) {\n      throw new Error('Cannot initialise layer with data id: ' + dataIndex);\n    }\n    const layerGroup = this.#stage.getLayerGroupByDivId(viewConfig.divId);\n    if (!layerGroup) {\n      throw new Error('Cannot initialise layer with group id: ' +\n        viewConfig.divId);\n    }\n    const imageGeometry = data.image.getGeometry();\n\n    // un-bind\n    this.#stage.unbindLayerGroups();\n\n    // create and setup view\n    const viewFactory = new ViewFactory();\n    const view = viewFactory.create(data.meta, data.image);\n    const viewOrientation = getViewOrientation(\n      imageGeometry.getOrientation(),\n      layerGroup.getTargetOrientation()\n    );\n    view.setOrientation(viewOrientation);\n\n    // make pixel of value 0 transparent for segmentation\n    // (assuming RGB data)\n    if (data.image.getMeta().Modality === 'SEG') {\n      view.setAlphaFunction(function (value /*, index*/) {\n        if (value[0] === 0 &&\n          value[1] === 0 &&\n          value[2] === 0) {\n          return 0;\n        } else {\n          return 0xff;\n        }\n      });\n    }\n\n    // colour map\n    if (typeof viewConfig.colourMap !== 'undefined') {\n      view.setColourMap(viewConfig.colourMap);\n    }\n\n    const isBaseLayer = layerGroup.getNumberOfLayers() === 0;\n\n    // opacity\n    let opacity = 1;\n    // do we have more than one layer\n    // (the layer has not been added to the layer group yet)\n    if (!isBaseLayer) {\n      opacity = 0.5;\n      // set color map if non was provided\n      if (typeof viewConfig.colourMap === 'undefined') {\n        view.setColourMap(luts.rainbow);\n      }\n    }\n\n    // view layer\n    const viewLayer = layerGroup.addViewLayer();\n    viewLayer.setView(view, dataIndex);\n    const size2D = imageGeometry.getSize(viewOrientation).get2D();\n    const spacing2D = imageGeometry.getSpacing(viewOrientation).get2D();\n    viewLayer.initialise(size2D, spacing2D, opacity);\n    const viewController = viewLayer.getViewController();\n\n    // listen to controller events\n    if (data.image.getMeta().Modality === 'SEG') {\n      viewController.addEventListener('masksegmentdelete', this.#fireEvent);\n      viewController.addEventListener('masksegmentredraw', this.#fireEvent);\n    }\n\n    // listen to image changes\n    this.#dataController.addEventListener('imageset', viewLayer.onimageset);\n    this.#dataController.addEventListener('imagechange', (event) => {\n      viewLayer.onimagechange(event);\n      this.render(event.dataid);\n    });\n\n    // bind\n    this.#stage.bindLayerGroups();\n    if (this.#toolboxController) {\n      this.#toolboxController.bindLayer(viewLayer, layerGroup.getDivId());\n    }\n\n    // optional draw layer\n    let drawLayer;\n    if (this.#toolboxController && this.#toolboxController.hasTool('Draw')) {\n      drawLayer = layerGroup.addDrawLayer();\n      drawLayer.initialise(size2D, spacing2D, dataIndex);\n      drawLayer.setPlaneHelper(viewLayer.getViewController().getPlaneHelper());\n    }\n\n    // sync layers position\n    const value = [\n      viewController.getCurrentIndex().getValues(),\n      viewController.getCurrentPosition().getValues()\n    ];\n    layerGroup.updateLayersToPositionChange({\n      value: value,\n      srclayerid: viewLayer.getId()\n    });\n\n    // sync layer groups\n    this.#stage.syncLayerGroupScale();\n\n    // major orientation axis\n    const major = imageGeometry.getOrientation().getThirdColMajorDirection();\n\n    // view layer offset (done before scale)\n    viewLayer.setOffset(layerGroup.getOffset());\n    // extra flip offset for oriented views...\n    if (typeof viewConfig.orientation !== 'undefined') {\n      if (major === 2) {\n        // flip offset Y for axial aquired data\n        if (viewConfig.orientation !== 'axial') {\n          viewLayer.addFlipOffsetY();\n          if (typeof drawLayer !== 'undefined') {\n            drawLayer.addFlipOffsetY();\n          }\n        }\n      } else if (major === 0) {\n        // flip offset X for sagittal aquired data\n        if (viewConfig.orientation !== 'sagittal') {\n          viewLayer.addFlipOffsetX();\n          if (typeof drawLayer !== 'undefined') {\n            drawLayer.addFlipOffsetX();\n          }\n        }\n      }\n    }\n\n    // view layer scale\n    // only flip scale for base layers\n    if (isBaseLayer) {\n      if (typeof viewConfig.orientation !== 'undefined') {\n        if (major === 0 || major === 2) {\n          // scale flip Z for oriented views...\n          layerGroup.flipScaleZ();\n        } else {\n          viewLayer.setScale(layerGroup.getScale());\n          if (typeof drawLayer !== 'undefined') {\n            drawLayer.setScale(layerGroup.getScale());\n          }\n        }\n      } else {\n        if (major === 0) {\n          // scale flip Z for sagittal and undefined target orientation\n          layerGroup.flipScaleZ();\n        } else {\n          viewLayer.setScale(layerGroup.getScale());\n          if (typeof drawLayer !== 'undefined') {\n            drawLayer.setScale(layerGroup.getScale());\n          }\n        }\n      }\n    } else {\n      viewLayer.setScale(layerGroup.getScale());\n      if (typeof drawLayer !== 'undefined') {\n        drawLayer.setScale(layerGroup.getScale());\n      }\n    }\n\n  }\n\n} // class App\n","/**\n * Data writer.\n */\nexport class DataWriter {\n\n  /**\n   * Is the endianness Little Endian.\n   *\n   * @type {boolean}\n   */\n  #isLittleEndian = true;\n\n  /**\n   * The main data view.\n   *\n   * @type {DataView}\n   */\n  #view;\n\n  /**\n   * @param {ArrayBuffer} buffer The input array buffer.\n   * @param {boolean} [isLittleEndian] Flag to tell if the data is\n   *   little or big endian.\n   */\n  constructor(buffer, isLittleEndian) {\n    // Set endian flag if not defined.\n    if (typeof isLittleEndian !== 'undefined') {\n      this.#isLittleEndian = isLittleEndian;\n    }\n    this.#view = new DataView(buffer);\n  }\n\n  /**\n   * Write Uint8 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint8(byteOffset, value) {\n    this.#view.setUint8(byteOffset, value);\n    return byteOffset + Uint8Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Int8 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt8(byteOffset, value) {\n    this.#view.setInt8(byteOffset, value);\n    return byteOffset + Int8Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Uint16 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint16(byteOffset, value) {\n    this.#view.setUint16(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + Uint16Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Int16 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt16(byteOffset, value) {\n    this.#view.setInt16(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + Int16Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Uint32 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint32(byteOffset, value) {\n    this.#view.setUint32(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + Uint32Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Uint64 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {bigint} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint64(byteOffset, value) {\n    this.#view.setBigUint64(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + BigUint64Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Int32 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt32(byteOffset, value) {\n    this.#view.setInt32(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + Int32Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Int64 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {bigint} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt64(byteOffset, value) {\n    this.#view.setBigInt64(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + BigInt64Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Float32 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeFloat32(byteOffset, value) {\n    this.#view.setFloat32(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + Float32Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write Float64 data.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {number} value The data to write.\n   * @returns {number} The new offset position.\n   */\n  writeFloat64(byteOffset, value) {\n    this.#view.setFloat64(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + Float64Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write string data of length 4 as hexadecimal (no '0x' prefix).\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {string} str The hexadecimal string to write ('####').\n   * @returns {number} The new offset position.\n   */\n  writeHex(byteOffset, str) {\n    // remove first two chars and parse\n    const value = parseInt(str, 16);\n    this.#view.setUint16(byteOffset, value, this.#isLittleEndian);\n    return byteOffset + Uint16Array.BYTES_PER_ELEMENT;\n  }\n\n  /**\n   * Write a boolean array as binary.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeBinaryArray(byteOffset, array) {\n    if (array.length % 8 !== 0) {\n      throw new Error('Cannot write boolean array as binary.');\n    }\n    let byte = null;\n    let val = null;\n    for (let i = 0, len = array.length; i < len; i += 8) {\n      byte = 0;\n      for (let j = 0; j < 8; ++j) {\n        val = array[i + j] === 0 ? 0 : 1;\n        byte += val << j;\n      }\n      byteOffset = this.writeUint8(byteOffset, byte);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Uint8 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array|Uint8Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint8Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeUint8(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Int8 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt8Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeInt8(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Uint16 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint16Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeUint16(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Int16 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt16Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeInt16(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Uint32 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint32Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeUint32(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Uint64 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeUint64Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeUint64(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Int32 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt32Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeInt32(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Int64 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeInt64Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeInt64(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Float32 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeFloat32Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeFloat32(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n  /**\n   * Write Float64 array.\n   *\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} array The array to write.\n   * @returns {number} The new offset position.\n   */\n  writeFloat64Array(byteOffset, array) {\n    for (let i = 0, len = array.length; i < len; ++i) {\n      byteOffset = this.writeFloat64(byteOffset, array[i]);\n    }\n    return byteOffset;\n  }\n\n} // class DataWriter\n","import {\n  is32bitVLVR,\n  isCharSetStringVR,\n  vrTypes\n} from './dictionary';\nimport {\n  Tag,\n  getTagFromDictionary,\n  getTagFromKey,\n  getItemTag,\n  getItemDelimitationItemTag,\n  getSequenceDelimitationItemTag,\n  getFileMetaInformationGroupLengthTag,\n  isPixelDataTag,\n  isItemTag,\n  tagCompareFunction\n} from './dicomTag';\nimport {\n  getDwvVersion,\n  isImplicitTransferSyntax,\n  isBigEndianTransferSyntax,\n  getDataElementPrefixByteSize\n} from './dicomParser';\nimport {DataElement} from './dataElement';\nimport {DataWriter} from './dataWriter';\nimport {logger} from '../utils/logger';\n\n/**\n * Get the dwv UID prefix.\n * Issued by Medical Connections Ltd (www.medicalconnections.co.uk)\n *   on 25/10/2017.\n *\n * @returns {string} The dwv UID prefix.\n */\nfunction getDwvUIDPrefix() {\n  return '1.2.826.0.1.3680043.9.7278.1';\n}\n\n// local generated uid counter\nlet _uidCount = 0;\n\n/**\n * Writer rule.\n */\nexport class WriterRule {\n  /**\n   * Rule action: `copy`, `remove`, `clear` or `replace`.\n   *\n   * @type {string}\n   */\n  action;\n  /**\n   * Optional value to use for replace action.\n   *\n   * @type {any|undefined}\n   */\n  value;\n\n  /**\n   * @param {string} action The rule action.\n   */\n  constructor(action) {\n    this.action = action;\n  }\n}\n\n/**\n * Get a UID for a DICOM tag.\n * Note: Use https://github.com/uuidjs/uuid?\n *\n * @see http://dicom.nema.org/dicom/2013/output/chtml/part05/chapter_9.html\n * @see http://dicomiseasy.blogspot.com/2011/12/chapter-4-dicom-objects-in-chapter-3.html\n * @see https://stackoverflow.com/questions/46304306/how-to-generate-unique-dicom-uid\n * @param {string} tagName The input tag.\n * @returns {string} The corresponding UID.\n */\nexport function getUID(tagName) {\n  const prefix = getDwvUIDPrefix() + '.';\n  let uid = '';\n  if (tagName === 'ImplementationClassUID') {\n    uid = prefix + getDwvVersion();\n  } else {\n    // date (only numbers), do not keep milliseconds\n    const date = (new Date()).toISOString().replace(/\\D/g, '');\n    const datePart = '.' + date.substring(0, 14);\n    // count\n    _uidCount += 1;\n    const countPart = '.' + _uidCount;\n\n    // uid = prefix . tag . date . count\n    uid = prefix;\n\n    // limit tag part to not exceed 64 length\n    const nonTagLength = prefix.length + countPart.length + datePart.length;\n    const leni = Math.min(tagName.length, 64 - nonTagLength);\n    if (leni > 1) {\n      let tagNumber = '';\n      for (let i = 0; i < leni; ++i) {\n        tagNumber += tagName.charCodeAt(i);\n      }\n      uid += tagNumber.substring(0, leni);\n    }\n\n    // finish\n    uid += datePart + countPart;\n  }\n  return uid;\n}\n\n/**\n * Return true if the input number is even.\n *\n * @param {number} number The number to check.\n * @returns {boolean} True is the number is even.\n */\nfunction isEven(number) {\n  return number % 2 === 0;\n}\n\n/**\n * Is the input VR a VR that stores data in a typed array.\n * TODO: include ox and xs?\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR is a typed array one.\n */\nfunction isTypedArrayVr(vr) {\n  const vrType = vrTypes[vr];\n  return typeof vrType !== 'undefined' &&\n    vrType !== 'string';\n}\n\n/**\n * Is the input VR a string VR.\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR is a string one.\n */\nfunction isStringVr(vr) {\n  const vrType = vrTypes[vr];\n  return typeof vrType !== 'undefined' &&\n    vrType === 'string';\n}\n\n/**\n * Is the input VR a VR that could need padding.\n * see http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html\n *\n * @param {string} vr The element VR.\n * @returns {boolean} True if the VR needs padding.\n */\nfunction isVrToPad(vr) {\n  return isStringVr(vr) || vr === 'OB';\n}\n\n/**\n * Get the VR specific padding value.\n *\n * @param {string} vr The element VR.\n * @returns {string} The value used to pad.\n */\nfunction getVrPad(vr) {\n  let pad = '';\n  if (isStringVr(vr)) {\n    if (vr === 'UI') {\n      pad = '\\0';\n    } else {\n      pad = ' ';\n    }\n  }\n  return pad;\n}\n\n/**\n * Push a value at the end of an input Uint8Array.\n *\n * @param {Array|Uint8Array} arr The input array.\n * @param {Array|Uint8Array} value The value to push.\n * @returns {Uint8Array} The new array.\n */\nfunction uint8ArrayPush(arr, value) {\n  const newArr = new Uint8Array(arr.length + 1);\n  newArr.set(arr);\n  newArr.set(value, arr.length);\n  return newArr;\n}\n\n/**\n * Pad an input OB value.\n *\n * @param {Array|Uint8Array} value The input value.\n * @returns {Array|Uint8Array} The padded input.\n */\nfunction padOBValue(value) {\n  if (value !== null &&\n    typeof value !== 'undefined' &&\n    typeof value.length !== 'undefined') {\n    // calculate size and pad if needed\n    if (value.length !== 0 &&\n      typeof value[0].length !== 'undefined') {\n      // handle array of array\n      let size = 0;\n      for (let i = 0; i < value.length; ++i) {\n        size += value[i].length;\n      }\n      if (!isEven(size)) {\n        value[value.length - 1] = uint8ArrayPush(\n          value[value.length - 1], [0]);\n      }\n    } else {\n      if (!isEven(value.length)) {\n        value = uint8ArrayPush(value, [0]);\n      }\n    }\n  } else {\n    throw new Error('Cannot pad undefined or null OB value.');\n  }\n  // uint8ArrayPush may create a new array so we\n  // need to return it\n  return value;\n}\n\n/**\n * Helper method to flatten an array of typed arrays to 2D typed array\n *\n * @param {Array} initialArray array of typed arrays\n * @returns {object} a typed array containing all values\n */\nfunction flattenArrayOfTypedArrays(initialArray) {\n  const initialArrayLength = initialArray.length;\n  const arrayLength = initialArray[0].length;\n  // If this is not a array of arrays, just return the initial one:\n  if (typeof arrayLength === 'undefined') {\n    return initialArray;\n  }\n\n  const flattenendArrayLength = initialArrayLength * arrayLength;\n\n  const flattenedArray = new initialArray[0].constructor(flattenendArrayLength);\n\n  for (let i = 0; i < initialArrayLength; i++) {\n    const indexFlattenedArray = i * arrayLength;\n    flattenedArray.set(initialArray[i], indexFlattenedArray);\n  }\n  return flattenedArray;\n}\n\n/**\n * Default text encoder.\n */\nclass DefaultTextEncoder {\n  /**\n   * Encode an input string.\n   *\n   * @param {string} str The string to encode.\n   * @returns {Uint8Array} The encoded string.\n   */\n  encode(str) {\n    const result = new Uint8Array(str.length);\n    for (let i = 0, leni = str.length; i < leni; ++i) {\n      result[i] = str.charCodeAt(i);\n    }\n    return result;\n  }\n}\n\n/**\n * DICOM writer.\n *\n * @example\n * // add link to html\n * const link = document.createElement(\"a\");\n * link.appendChild(document.createTextNode(\"download\"));\n * const div = document.getElementById(\"dwv\");\n * div.appendChild(link);\n * // XMLHttpRequest onload callback\n * const onload = function (event) {\n *   const parser = new dwv.DicomParser();\n *   parser.parse(event.target.response);\n *   // create writer\n *   const writer = new dwv.DicomWriter();\n *   // get buffer using default rules\n *   const dicomBuffer = writer.getBuffer(parser.getDicomElements());\n *   // create blob\n *   const blob = new Blob([dicomBuffer], {type: 'application/dicom'});\n *   // add blob to download link\n *   link.href = URL.createObjectURL(blob);\n *   link.download = \"anonym.dcm\";\n * };\n * // DICOM file request\n * const request = new XMLHttpRequest();\n * const url = 'https://raw.githubusercontent.com/ivmartel/dwv/master/tests/data/bbmri-53323851.dcm';\n * request.open('GET', url);\n * request.responseType = 'arraybuffer';\n * request.onload = onload;\n * request.send();\n */\nexport class DicomWriter {\n\n  // flag to use VR=UN for private sequences, default to false\n  // (mainly used in tests)\n  #useUnVrForPrivateSq = false;\n\n  /**\n   * Set the use UN VR for private sequence flag.\n   *\n   * @param {boolean} flag True to use UN VR.\n   */\n  setUseUnVrForPrivateSq(flag) {\n    this.#useUnVrForPrivateSq = flag;\n  }\n\n  /**\n   * Possible tag actions.\n   *\n   * @type {Object<string, Function>}\n   */\n  #actions = {\n    copy: function (item) {\n      return item;\n    },\n    remove: function () {\n      return null;\n    },\n    clear: function (item) {\n      item.value = [];\n      return item;\n    },\n    replace: function (item, value) {\n      item.value = [value];\n      return item;\n    }\n  };\n\n  /**\n   * Default rules: just copy\n   *\n   * @type {Object<string, WriterRule>}\n   */\n  #defaultRules = {\n    default: {action: 'copy', value: null}\n  };\n\n  /**\n   * Writing rules.\n   *\n   * @type {Object<string, WriterRule>}\n   */\n  #rules = this.#defaultRules;\n\n  /**\n   * Set the writing rules.\n   * List of writer rules indexed by either `default`, tagName or groupName.\n   * Each DICOM element will be checked to see if a rule is applicable.\n   * First checked by tagName and then by groupName,\n   * if nothing is found the default rule is applied.\n   *\n   * @param {Object<string, WriterRule>} rules The input rules.\n   */\n  setRules(rules) {\n    this.#rules = rules;\n  }\n\n  /**\n   * Default text encoder.\n   *\n   * @type {DefaultTextEncoder}\n   */\n  #defaultTextEncoder = new DefaultTextEncoder();\n\n  /**\n   * Special text encoder.\n   *\n   * @type {DefaultTextEncoder|TextEncoder}\n   */\n  #textEncoder = this.#defaultTextEncoder;\n\n  /**\n   * Encode string data.\n   *\n   * @param {string} str The string to encode.\n   * @returns {Uint8Array} The encoded string.\n   */\n  #encodeString(str) {\n    return this.#defaultTextEncoder.encode(str);\n  }\n\n  /**\n   * Encode data as a UTF-8.\n   *\n   * @param {string} str The string to write.\n   * @returns {Uint8Array} The encoded string.\n   */\n  #encodeSpecialString(str) {\n    return this.#textEncoder.encode(str);\n  }\n\n  /**\n   * Use a TextEncoder instead of the default text decoder.\n   */\n  useSpecialTextEncoder() {\n    /**\n     * The text encoder.\n     *\n     * @external TextEncoder\n     * @see https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder\n     */\n    this.#textEncoder = new TextEncoder();\n  }\n\n  /**\n   * Use default anonymisation rules.\n   */\n  useDefaultAnonymisationRules() {\n    this.setRules({\n      default: {action: 'remove', value: null},\n      PatientName: {action: 'replace', value: 'Anonymized'}, // tag\n      'Meta Element': {action: 'copy', value: null}, // group '0002'\n      Acquisition: {action: 'copy', value: null}, // group '0018'\n      'Image Presentation': {action: 'copy', value: null}, // group '0028'\n      Procedure: {action: 'copy', value: null}, // group '0040'\n      'Pixel Data': {action: 'copy', value: null} // group '7fe0'\n    });\n  }\n\n  /**\n   * Get the element to write according to the class rules.\n   * Priority order: tagName, groupName, default.\n   *\n   * @param {DataElement} element The element to check\n   * @returns {DataElement|null} The element to write, can be null.\n   */\n  getElementToWrite(element) {\n    // get group and tag string name\n    const groupName = element.tag.getGroupName();\n    const tagName = element.tag.getNameFromDictionary();\n\n    // apply rules:\n    let rule;\n    if (typeof this.#rules[element.tag.getKey()] !== 'undefined') {\n      // 1. tag itself\n      rule = this.#rules[element.tag.getKey()];\n    } else if (typeof tagName !== 'undefined' &&\n      typeof this.#rules[tagName] !== 'undefined') {\n      // 2. tag name\n      rule = this.#rules[tagName];\n    } else if (typeof this.#rules[groupName] !== 'undefined') {\n      // 3. group name\n      rule = this.#rules[groupName];\n    } else {\n      // 4. default\n      rule = this.#rules['default'];\n    }\n    // apply action on element and return\n    return this.#actions[rule.action](element, rule.value);\n  }\n\n  /**\n   * Write a list of items.\n   *\n   * @param {DataWriter} writer The raw data writer.\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} items The list of items to write.\n   * @param {boolean} isImplicit Is the DICOM VR implicit?\n   * @returns {number} The new offset position.\n   */\n  #writeDataElementItems(\n    writer, byteOffset, items, isImplicit) {\n    let item = null;\n    for (let i = 0; i < items.length; ++i) {\n      item = items[i];\n      const itemKeys = Object.keys(item);\n      if (itemKeys.length === 0) {\n        continue;\n      }\n      // item element (create new to not modify original)\n      let undefinedLength = false;\n      if (typeof item['FFFEE000'].undefinedLength !== 'undefined') {\n        undefinedLength = item['FFFEE000'].undefinedLength;\n      }\n      // const itemElement = {\n      //   tag: getItemTag(),\n      //   vr: 'NONE',\n      //   vl: undefinedLength ? 0xffffffff : item['FFFEE000'].vl,\n      //   value: []\n      // };\n      const itemElement = new DataElement('NONE');\n      itemElement.vl = undefinedLength ? 0xffffffff : item['FFFEE000'].vl,\n      itemElement.tag = getItemTag();\n      itemElement.value = [];\n      byteOffset = this.#writeDataElement(\n        writer, itemElement, byteOffset, isImplicit);\n      // write rest\n      for (let m = 0; m < itemKeys.length; ++m) {\n        if (itemKeys[m] !== 'FFFEE000' && itemKeys[m] !== 'FFFEE00D') {\n          byteOffset = this.#writeDataElement(\n            writer, item[itemKeys[m]], byteOffset, isImplicit);\n        }\n      }\n      // item delimitation\n      if (undefinedLength) {\n        // const itemDelimElement = {\n        //   tag: getItemDelimitationItemTag(),\n        //   vr: 'NONE',\n        //   vl: 0,\n        //   value: []\n        // };\n        const itemDelimElement = new DataElement('NONE');\n        itemDelimElement.vl = 0;\n        itemDelimElement.tag = getItemDelimitationItemTag();\n        itemDelimElement.value = [];\n        byteOffset = this.#writeDataElement(\n          writer, itemDelimElement, byteOffset, isImplicit);\n      }\n    }\n\n    // return new offset\n    return byteOffset;\n  }\n\n  /**\n   * Write data with a specific Value Representation (VR).\n   *\n   * @param {DataWriter} writer The raw data writer.\n   * @param {DataElement} element The element to write.\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} value The array to write.\n   * @param {boolean} isImplicit Is the DICOM VR implicit?\n   * @returns {number} The new offset position.\n   */\n  #writeDataElementValue(\n    writer, element, byteOffset, value, isImplicit) {\n\n    const startOffset = byteOffset;\n\n    if (element.vr === 'NONE') {\n      // nothing to do!\n    } else if (value instanceof Uint8Array) {\n      // binary data has been expanded 8 times at read\n      if (value.length === 8 * element.vl) {\n        byteOffset = writer.writeBinaryArray(byteOffset, value);\n      } else {\n        byteOffset = writer.writeUint8Array(byteOffset, value);\n      }\n    } else if (value instanceof Int8Array) {\n      byteOffset = writer.writeInt8Array(byteOffset, value);\n    } else if (value instanceof Uint16Array) {\n      byteOffset = writer.writeUint16Array(byteOffset, value);\n    } else if (value instanceof Int16Array) {\n      byteOffset = writer.writeInt16Array(byteOffset, value);\n    } else if (value instanceof Uint32Array) {\n      byteOffset = writer.writeUint32Array(byteOffset, value);\n    } else if (value instanceof Int32Array) {\n      byteOffset = writer.writeInt32Array(byteOffset, value);\n    } else if (value instanceof BigUint64Array) {\n      byteOffset = writer.writeUint64Array(byteOffset, value);\n    } else if (value instanceof BigInt64Array) {\n      byteOffset = writer.writeInt64Array(byteOffset, value);\n    } else {\n      // switch according to VR if input type is undefined\n      const vrType = vrTypes[element.vr];\n      if (typeof vrType !== 'undefined') {\n        if (vrType === 'Uint8') {\n          byteOffset = writer.writeUint8Array(byteOffset, value);\n        } else if (vrType === 'Uint16') {\n          byteOffset = writer.writeUint16Array(byteOffset, value);\n        } else if (vrType === 'Int16') {\n          byteOffset = writer.writeInt16Array(byteOffset, value);\n        } else if (vrType === 'Uint32') {\n          byteOffset = writer.writeUint32Array(byteOffset, value);\n        } else if (vrType === 'Int32') {\n          byteOffset = writer.writeInt32Array(byteOffset, value);\n        } else if (vrType === 'Uint64') {\n          byteOffset = writer.writeUint64Array(byteOffset, value);\n        } else if (vrType === 'Int64') {\n          byteOffset = writer.writeInt64Array(byteOffset, value);\n        } else if (vrType === 'Float32') {\n          byteOffset = writer.writeFloat32Array(byteOffset, value);\n        } else if (vrType === 'Float64') {\n          byteOffset = writer.writeFloat64Array(byteOffset, value);\n        } else if (vrType === 'string') {\n          byteOffset = writer.writeUint8Array(byteOffset, value);\n        } else {\n          throw Error('Unknown VR type: ' + vrType);\n        }\n      } else if (element.vr === 'SQ') {\n        byteOffset = this.#writeDataElementItems(\n          writer, byteOffset, value, isImplicit);\n      } else if (element.vr === 'AT') {\n        for (let i = 0; i < value.length; ++i) {\n          const hexString = value[i] + '';\n          const hexString1 = hexString.substring(1, 5);\n          const hexString2 = hexString.substring(6, 10);\n          const dec1 = parseInt(hexString1, 16);\n          const dec2 = parseInt(hexString2, 16);\n          const atValue = [dec1, dec2];\n          byteOffset = writer.writeUint16Array(byteOffset, atValue);\n        }\n      } else {\n        logger.warn('Unknown VR: ' + element.vr);\n      }\n    }\n\n    if (element.vr !== 'SQ' && element.vr !== 'NONE') {\n      const diff = byteOffset - startOffset;\n      if (diff !== element.vl) {\n        logger.warn('Offset difference and VL are not equal: ' +\n          diff + ' != ' + element.vl + ', vr:' + element.vr);\n      }\n    }\n\n    // return new offset\n    return byteOffset;\n  }\n\n  /**\n   * Write a pixel data element.\n   *\n   * @param {DataWriter} writer The raw data writer.\n   * @param {DataElement} element The element to write.\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {Array} value The array to write.\n   * @param {boolean} isImplicit Is the DICOM VR implicit?\n   * @returns {number} The new offset position.\n   */\n  #writePixelDataElementValue(\n    writer, element, byteOffset, value, isImplicit) {\n    // undefined length flag\n    let undefinedLength = false;\n    if (typeof element.undefinedLength !== 'undefined') {\n      undefinedLength = element.undefinedLength;\n    }\n    // explicit length\n    if (!undefinedLength) {\n      let finalValue = value[0];\n      // flatten multi frame\n      if (value.length > 1) {\n        finalValue = flattenArrayOfTypedArrays(value);\n      }\n      // write\n      byteOffset = this.#writeDataElementValue(\n        writer, element, byteOffset, finalValue, isImplicit);\n    } else {\n      // pixel data as sequence\n      const item = {};\n      // first item: basic offset table\n      item['FFFEE000'] = {\n        tag: getItemTag(),\n        vr: 'NONE',\n        vl: 0,\n        value: []\n      };\n      // data\n      for (let i = 0; i < value.length; ++i) {\n        item[i] = {\n          tag: getItemTag(),\n          vr: element.vr,\n          vl: value[i].length,\n          value: value[i]\n        };\n      }\n      // write\n      byteOffset = this.#writeDataElementItems(\n        writer, byteOffset, [item], isImplicit);\n    }\n\n    // return new offset\n    return byteOffset;\n  }\n\n  /**\n   * Write a data element.\n   *\n   * @param {DataWriter} writer The raw data writer.\n   * @param {DataElement} element The DICOM data element to write.\n   * @param {number} byteOffset The offset to start writing from.\n   * @param {boolean} isImplicit Is the DICOM VR implicit?\n   * @returns {number} The new offset position.\n   */\n  #writeDataElement(\n    writer, element, byteOffset, isImplicit) {\n    const isTagWithVR = element.tag.isWithVR();\n    const is32bitVL = (isImplicit || !isTagWithVR)\n      ? true : is32bitVLVR(element.vr);\n    // group\n    byteOffset = writer.writeHex(byteOffset, element.tag.getGroup());\n    // element\n    byteOffset = writer.writeHex(byteOffset, element.tag.getElement());\n    // VR\n    let vr = element.vr;\n    // use VR=UN for private sequence\n    if (this.#useUnVrForPrivateSq &&\n      element.tag.isPrivate() &&\n      vr === 'SQ') {\n      logger.warn('Write element using VR=UN for private sequence.');\n      vr = 'UN';\n    }\n    if (isTagWithVR && !isImplicit) {\n      byteOffset = writer.writeUint8Array(byteOffset, this.#encodeString(vr));\n      // reserved 2 bytes for 32bit VL\n      if (is32bitVL) {\n        byteOffset += 2;\n      }\n    }\n\n    let undefinedLengthSequence = false;\n    if (element.vr === 'SQ' ||\n      isPixelDataTag(element.tag)) {\n      if (typeof element.undefinedLength !== 'undefined') {\n        undefinedLengthSequence = element.undefinedLength;\n      }\n    }\n    let undefinedLengthItem = false;\n    if (isItemTag(element.tag)) {\n      if (typeof element.undefinedLength !== 'undefined') {\n        undefinedLengthItem = element.undefinedLength;\n      }\n    }\n\n    // update vl for sequence or item with undefined length\n    let vl = element.vl;\n    if (undefinedLengthSequence || undefinedLengthItem) {\n      vl = 0xffffffff;\n    }\n    // VL\n    if (is32bitVL) {\n      byteOffset = writer.writeUint32(byteOffset, vl);\n    } else {\n      byteOffset = writer.writeUint16(byteOffset, vl);\n    }\n\n    // value\n    let value = element.value;\n    // check value\n    if (typeof value === 'undefined') {\n      value = [];\n    }\n    // write\n    if (isPixelDataTag(element.tag)) {\n      byteOffset = this.#writePixelDataElementValue(\n        writer, element, byteOffset, value, isImplicit);\n    } else {\n      byteOffset = this.#writeDataElementValue(\n        writer, element, byteOffset, value, isImplicit);\n    }\n\n    // sequence delimitation item for sequence with undefined length\n    if (undefinedLengthSequence) {\n      // const seqDelimElement = {\n      //   tag: getSequenceDelimitationItemTag(),\n      //   vr: 'NONE',\n      //   vl: 0,\n      //   value: []\n      // };\n      const seqDelimElement = new DataElement('NONE');\n      seqDelimElement.vl = 0;\n      seqDelimElement.tag = getSequenceDelimitationItemTag();\n      seqDelimElement.value = [];\n      byteOffset = this.#writeDataElement(\n        writer, seqDelimElement, byteOffset, isImplicit);\n    }\n\n    // return new offset\n    return byteOffset;\n  }\n\n  /**\n   * Get the ArrayBuffer corresponding to input DICOM elements.\n   *\n   * @param {Object<string, DataElement>} dataElements The elements to write.\n   * @returns {ArrayBuffer} The elements as a buffer.\n   */\n  getBuffer(dataElements) {\n    // Transfer Syntax\n    // const el = dataElements['00020010'];\n    // el.value = 1;\n    // el.vl = 'a';\n    const syntax = dataElements['00020010'].value[0];\n    const isImplicit = isImplicitTransferSyntax(syntax);\n    const isBigEndian = isBigEndianTransferSyntax(syntax);\n    // Specific CharacterSet\n    if (typeof dataElements['00080005'] !== 'undefined') {\n      const oldscs = dataElements['00080005'].value[0];\n      // force UTF-8 if not default character set\n      if (typeof oldscs !== 'undefined' && oldscs !== 'ISO-IR 6') {\n        logger.debug('Change charset to UTF, was: ' + oldscs);\n        this.useSpecialTextEncoder();\n        dataElements['00080005'].value = ['ISO_IR 192'];\n      }\n    }\n    // Bits Allocated (for image data)\n    let bitsAllocated;\n    if (typeof dataElements['00280100'] !== 'undefined') {\n      bitsAllocated = dataElements['00280100'].value[0];\n    }\n\n    // calculate buffer size and split elements (meta and non meta)\n    let totalSize = 128 + 4; // DICM\n    let localSize = 0;\n    const metaElements = [];\n    const rawElements = [];\n    let element;\n    let groupName;\n    let metaLength = 0;\n    // FileMetaInformationGroupLength\n    const fmiglTag = getFileMetaInformationGroupLengthTag();\n    // FileMetaInformationVersion\n    const fmivTag = new Tag('0002', '0001');\n    // ImplementationClassUID\n    const icUIDTag = new Tag('0002', '0012');\n    // ImplementationVersionName\n    const ivnTag = new Tag('0002', '0013');\n\n    // loop through elements to get the buffer size\n    const keys = Object.keys(dataElements);\n    for (let i = 0, leni = keys.length; i < leni; ++i) {\n      const originalElement = dataElements[keys[i]];\n      originalElement.tag = getTagFromKey(keys[i]);\n      element = this.getElementToWrite(originalElement);\n      if (element !== null &&\n        !fmiglTag.equals(element.tag) &&\n        !fmivTag.equals(element.tag) &&\n        !icUIDTag.equals(element.tag) &&\n        !ivnTag.equals(element.tag)) {\n        localSize = 0;\n\n        // XB7 2020-04-17\n        // Check if UN can be converted to correct VR.\n        // This check must be done BEFORE calculating totalSize,\n        // otherwise there may be extra null bytes at the end of the file\n        // (dcmdump may crash because of these bytes)\n        checkUnknownVR(element);\n\n        // update value and vl\n        this.#setElementValue(\n          element, element.value, isImplicit, bitsAllocated);\n\n        // tag group name\n        groupName = element.tag.getGroupName();\n\n        // prefix\n        if (groupName === 'Meta Element') {\n          localSize += getDataElementPrefixByteSize(element.vr, false);\n        } else {\n          localSize += getDataElementPrefixByteSize(\n            element.vr, isImplicit);\n        }\n\n        // value\n        localSize += element.vl;\n\n        // sort elements\n        if (groupName === 'Meta Element') {\n          metaElements.push(element);\n          metaLength += localSize;\n        } else {\n          rawElements.push(element);\n        }\n\n        // add to total size\n        totalSize += localSize;\n      }\n    }\n\n    // FileMetaInformationVersion\n    const fmiv = getDataElement('FileMetaInformationVersion');\n    let fmivSize = getDataElementPrefixByteSize(fmiv.vr, false);\n    fmivSize += this.#setElementValue(fmiv, [0, 1], false);\n    metaElements.push(fmiv);\n    metaLength += fmivSize;\n    totalSize += fmivSize;\n    // ImplementationClassUID\n    const icUID = getDataElement('ImplementationClassUID');\n    let icUIDSize = getDataElementPrefixByteSize(icUID.vr, false);\n    icUIDSize += this.#setElementValue(\n      icUID, [getUID('ImplementationClassUID')], false);\n    metaElements.push(icUID);\n    metaLength += icUIDSize;\n    totalSize += icUIDSize;\n    // ImplementationVersionName\n    const ivn = getDataElement('ImplementationVersionName');\n    let ivnSize = getDataElementPrefixByteSize(ivn.vr, false);\n    const ivnValue = 'DWV_' + getDwvVersion();\n    ivnSize += this.#setElementValue(ivn, [ivnValue], false);\n    metaElements.push(ivn);\n    metaLength += ivnSize;\n    totalSize += ivnSize;\n\n    // sort elements\n    const elemSortFunc = function (a, b) {\n      return tagCompareFunction(a.tag, b.tag);\n    };\n    metaElements.sort(elemSortFunc);\n    rawElements.sort(elemSortFunc);\n\n    // create the FileMetaInformationGroupLength element\n    const fmigl = getDataElement('FileMetaInformationGroupLength');\n    let fmiglSize = getDataElementPrefixByteSize(fmigl.vr, false);\n    fmiglSize += this.#setElementValue(\n      fmigl, new Uint32Array([metaLength]), false);\n    totalSize += fmiglSize;\n\n    // create buffer\n    const buffer = new ArrayBuffer(totalSize);\n    const metaWriter = new DataWriter(buffer);\n    const dataWriter = new DataWriter(buffer, !isBigEndian);\n\n    let offset = 128;\n    // DICM\n    offset = metaWriter.writeUint8Array(offset, this.#encodeString('DICM'));\n    // FileMetaInformationGroupLength\n    offset = this.#writeDataElement(metaWriter, fmigl, offset, false);\n    // write meta\n    for (let j = 0, lenj = metaElements.length; j < lenj; ++j) {\n      offset = this.#writeDataElement(\n        metaWriter, metaElements[j], offset, false);\n    }\n\n    // check meta position\n    const preambleSize = 128 + 4;\n    const metaOffset = preambleSize + fmiglSize + metaLength;\n    if (offset !== metaOffset) {\n      logger.warn('Bad size calculation... meta offset: ' + offset +\n        ', calculated size:' + metaOffset +\n        ' (diff:' + (offset - metaOffset) + ')');\n    }\n\n    // write non meta\n    for (let k = 0, lenk = rawElements.length; k < lenk; ++k) {\n      offset = this.#writeDataElement(\n        dataWriter, rawElements[k], offset, isImplicit);\n    }\n\n    // check final position\n    if (offset !== totalSize) {\n      logger.warn('Bad size calculation... final offset: ' + offset +\n        ', calculated size:' + totalSize +\n        ' (diff:' + (offset - totalSize) + ')');\n    }\n    // return\n    return buffer;\n  }\n\n  /**\n   * Set a DICOM element value according to its VR (Value Representation).\n   *\n   * @param {DataElement} element The DICOM element to set the value.\n   * @param {object} value The value to set.\n   * @param {boolean} isImplicit Does the data use implicit VR?\n   * @param {number} [bitsAllocated] Bits allocated used for pixel data.\n   * @returns {number} The total element size.\n   */\n  #setElementValue(\n    element, value, isImplicit, bitsAllocated) {\n    // byte size of the element\n    let size = 0;\n    // special sequence case\n    if (element.vr === 'SQ') {\n\n      if (value !== null && value !== 0) {\n        const newItems = [];\n        let name;\n\n        // explicit or undefined length sequence\n        let undefinedLength = false;\n        if (typeof element.undefinedLength !== 'undefined') {\n          undefinedLength = element.undefinedLength;\n          delete element.undefinedLength;\n        }\n\n        // items\n        for (let i = 0; i < value.length; ++i) {\n          const oldItemElements = value[i];\n          const newItemElements = {};\n          let subSize = 0;\n\n          // check data\n          if (oldItemElements === null || oldItemElements === 0) {\n            continue;\n          }\n\n          // elements\n          const itemKeys = Object.keys(oldItemElements);\n          for (let j = 0, lenj = itemKeys.length; j < lenj; ++j) {\n            const itemKey = itemKeys[j];\n            const subElement = oldItemElements[itemKey];\n            subElement.tag = getTagFromKey(itemKey);\n\n            if (isItemTag(subElement.tag)) {\n              continue;\n            }\n            // set item value\n            subSize += this.#setElementValue(\n              subElement, subElement.value, isImplicit, bitsAllocated);\n            newItemElements[itemKey] = subElement;\n            // add prefix size\n            subSize += getDataElementPrefixByteSize(\n              subElement.vr, isImplicit);\n          }\n\n          // add item element (used to store its size)\n          const itemElement = {\n            tag: getItemTag(),\n            vr: 'NONE',\n            vl: subSize,\n            value: []\n          };\n          if (undefinedLength) {\n            itemElement.undefinedLength = undefinedLength;\n          }\n          name = itemElement.tag.getKey();\n          newItemElements[name] = itemElement;\n          subSize += getDataElementPrefixByteSize(\n            itemElement.vr, isImplicit);\n\n          // add item delimitation size\n          if (undefinedLength) {\n            subSize += getDataElementPrefixByteSize(\n              'NONE', isImplicit);\n          }\n\n          size += subSize;\n          newItems.push(newItemElements);\n        }\n\n        // add sequence delimitation size\n        if (undefinedLength) {\n          size += getDataElementPrefixByteSize('NONE', isImplicit);\n        }\n\n        // update sequence element\n        element.value = newItems;\n        element.vl = size;\n        if (undefinedLength) {\n          element.undefinedLength = undefinedLength;\n        }\n      }\n    } else {\n      // pad if necessary\n      if (isVrToPad(element.vr)) {\n        const padStr = getVrPad(element.vr);\n        // encode string\n        // TODO: not sure for UN...\n        if (isStringVr(element.vr)) {\n          let pad;\n          if (isCharSetStringVR(element.vr)) {\n            value = this.#encodeSpecialString(value.join('\\\\'));\n            pad = this.#encodeSpecialString(padStr);\n          } else {\n            value = this.#encodeString(value.join('\\\\'));\n            pad = this.#encodeString(padStr);\n          }\n          if (!isEven(value.length)) {\n            value = uint8ArrayPush(value, pad);\n          }\n        } else if (element.vr === 'OB') {\n          value = padOBValue(value);\n        }\n      }\n\n      // calculate byte size\n      size = 0;\n      if (element.vr === 'AT') {\n        size = 4 * value.length;\n      } else if (element.vr === 'xs') {\n        size = value.length * Uint16Array.BYTES_PER_ELEMENT;\n      } else if (isTypedArrayVr(element.vr) || element.vr === 'ox') {\n        if (isPixelDataTag(element.tag) &&\n          Array.isArray(value)) {\n          size = 0;\n          for (let b = 0; b < value.length; ++b) {\n            size += value[b].length;\n          }\n        } else {\n          size = value.length;\n        }\n\n        // convert size to bytes\n        const vrType = vrTypes[element.vr];\n        if (isPixelDataTag(element.tag) || element.vr === 'ox') {\n          if (element.undefinedLength) {\n            const itemPrefixSize =\n              getDataElementPrefixByteSize('NONE', isImplicit);\n            // offset table\n            size += itemPrefixSize;\n            // pixel items\n            size += itemPrefixSize * value.length;\n            // add sequence delimitation size\n            size += itemPrefixSize;\n          } else {\n            // use bitsAllocated for pixel data\n            // no need to multiply for 8 bits\n            if (typeof bitsAllocated !== 'undefined') {\n              if (bitsAllocated === 1) {\n                // binary data\n                size /= 8;\n              } else if (bitsAllocated === 16) {\n                size *= Uint16Array.BYTES_PER_ELEMENT;\n              }\n            }\n          }\n        } else if (typeof vrType !== 'undefined') {\n          const bpe = getBpeForVrType(vrType);\n          if (typeof bpe !== 'undefined') {\n            size *= bpe;\n          } else {\n            throw Error('Unknown bytes per element for VR type: ' + vrType);\n          }\n        } else {\n          throw Error('Unsupported element: ' + element.vr);\n        }\n      } else {\n        size = value.length;\n      }\n\n      element.value = value;\n      element.vl = size;\n    }\n\n    // return the size of that data\n    return size;\n  }\n\n} // class DicomWriter\n\n/**\n * Fix for broken DICOM elements: Replace \"UN\" with correct VR if the\n * element exists in dictionary\n *\n * @param {DataElement} element The DICOM element.\n */\nfunction checkUnknownVR(element) {\n  if (element.vr === 'UN') {\n    const dictVr = element.tag.getVrFromDictionary();\n    if (typeof dictVr !== 'undefined' && element.vr !== dictVr) {\n      element.vr = dictVr;\n      logger.info('Element ' + element.tag.getGroup() +\n        ' ' + element.tag.getElement() +\n        ' VR changed from UN to ' + element.vr);\n    }\n  }\n}\n\n/**\n * Get a DICOM element from its tag name (value set separatly).\n *\n * @param {string} tagName The string tag name.\n * @returns {DataElement} The DICOM element.\n */\nfunction getDataElement(tagName) {\n  const tag = getTagFromDictionary(tagName);\n  const element = new DataElement(tag.getVrFromDictionary());\n  element.tag = tag;\n  return element;\n}\n\n/**\n * Get the number of bytes per element for a given VR type.\n *\n * @param {string} vrType The VR type as defined in the dictionary.\n * @returns {number} The bytes per element.\n */\nfunction getBpeForVrType(vrType) {\n  let bpe;\n  if (vrType === 'Uint8') {\n    bpe = Uint8Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Uint16') {\n    bpe = Uint16Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Int16') {\n    bpe = Int16Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Uint32') {\n    bpe = Uint32Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Int32') {\n    bpe = Int32Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Float32') {\n    bpe = Float32Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Float64') {\n    bpe = Float64Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Uint64') {\n    bpe = BigUint64Array.BYTES_PER_ELEMENT;\n  } else if (vrType === 'Int64') {\n    bpe = BigInt64Array.BYTES_PER_ELEMENT;\n  }\n  return bpe;\n}\n\n/**\n * Get the DICOM elements from a 'simple' DICOM json tags object.\n * The json is a simplified version of the oficial DICOM json with\n * tag names instead of keys and direct values (no value property) for\n * simple tags. See synthetic test data (in tests/dicom) for examples.\n *\n * @param {Object<string, any>} jsonTags The DICOM\n *   json tags object.\n * @returns {Object<string, DataElement>} The DICOM elements.\n */\nexport function getElementsFromJSONTags(jsonTags) {\n  const keys = Object.keys(jsonTags);\n  const dataElements = {};\n  for (let k = 0, len = keys.length; k < len; ++k) {\n    // get the DICOM element definition from its name\n    const tag = getTagFromDictionary(keys[k]);\n    if (typeof tag === 'undefined') {\n      continue;\n    }\n    const vr = tag.getVrFromDictionary();\n    // tag value\n    let value;\n    let undefinedLength = false;\n    const jsonTag = jsonTags[keys[k]];\n    if (vr === 'SQ') {\n      const items = [];\n      if (typeof jsonTag.undefinedLength !== 'undefined') {\n        undefinedLength = jsonTag.undefinedLength;\n      }\n      if (typeof jsonTag.value !== 'undefined' &&\n        jsonTag.value !== null) {\n        for (let i = 0; i < jsonTag.value.length; ++i) {\n          items.push(getElementsFromJSONTags(jsonTag.value[i]));\n        }\n      } else {\n        logger.trace('Undefined or null jsonTag SQ value.');\n      }\n      value = items;\n    } else {\n      if (Array.isArray(jsonTag)) {\n        value = jsonTag;\n      } else {\n        value = [jsonTag];\n      }\n    }\n    // create element\n    const dataElement = new DataElement(vr);\n    dataElement.tag = tag;\n    dataElement.value = value;\n    if (undefinedLength) {\n      dataElement.undefinedLength = undefinedLength;\n    }\n    // store\n    dataElements[tag.getKey()] = dataElement;\n  }\n  // return\n  // @ts-expect-error\n  return dataElements;\n}\n"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE__436__","__WEBPACK_EXTERNAL_MODULE__626__","__WEBPACK_EXTERNAL_MODULE__812__","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","Index","constructor","values","Error","length","every","val","isNaN","i","toString","getValues","slice","canCompare","rhs","equals","leni","compare","diffDims","push","add","getWithNew2D","j","l","lenl","toStringId","dims","ii","res","getIndexFromStringId","inputStr","strIds","split","dim","pointLength","parseInt","substring","Array","fill","RescaleLut","rsi","bitsStored","Math","pow","getRSI","isReady","initialise","Float32Array","apply","getLength","getValue","offset","defaultPresets","CT","mediastinum","center","width","lung","bone","brain","head","WindowCenterAndWidth","c","getCenter","getWidth","setRange","min","max","setSignedOffset","WindowLut","rescaleLut","isSigned","getWindowLevel","getRescaleLut","setWindowLevel","wl","size","getSlope","update","Uint8ClampedArray","lut_range_max","buildLut","func","lut","id","invId","ColourMap","red","green","blue","luts","plain","invPlain","rainbow","hot","third","hot_iron","pet","hot_metal_blue","pet_20step","logger","levels","TRACE","DEBUG","INFO","WARN","ERROR","level","trace","msg","console","debug","info","warn","error","getShadowColour","hexColour","hexStr","rgbTriplet","g","b","isDarkColour","d65","x","y","z","colourNameToHex","name","dict","Yellow","Red","White","Green","Blue","Lime","Fuchsia","Black","Vector3D","getX","getY","getZ","norm","sqrt","crossProduct","vector3D","dotProduct","BIG_EPSILON","Number","EPSILON","isSimilar","tol","abs","Matrix33","row","col","getInverse","m","m00","m01","m02","m10","m11","m12","m20","m21","m22","a1212","a2012","a0112","det","getMatrixInverse","p","str","multiply","tmp","k","getAbs","multiplyArray3D","array3D","multiplyVector3D","multiplyPoint3D","point3D","Point3D","multiplyIndex3D","index3D","getRowAbsMax","absMax","index","indexOf","getColAbsMax","asOneAndZeros","sign","getThirdColMajorDirection","getIdentityMat33","getCoronalMat33","getMatrixFromName","matrix","Point2D","getDistance","point2D","getRound","round","minus","Point","get3D","values0","values1","mergeWith3D","dictionary","addTagsToDictionary","group","tags","tagGroups","vr32bitVL","OB","OD","OF","OL","OV","OW","SQ","SV","UC","UN","UR","UT","UV","ox","is32bitVLVR","vr","vrCharSetString","SH","LO","ST","LT","PN","isCharSetStringVR","vrTypes","AE","AS","AT","CS","DA","DS","DT","FL","FD","IS","SL","SS","TM","UI","UL","US","Tag","element","getGroup","getElement","getKey","getNameFromDictionary","getGroupName","isWithVR","isPrivate","getInfoFromDictionary","getVrFromDictionary","getTagFromKey","getItemTag","isItemTag","tag","isSequenceDelimitationItemTag","getPixelDataTag","isPixelDataTag","getTagFromDictionary","tagName","keys0","keys","keys1","foundTag","k0","lenK0","k1","lenK1","flipArrayEndianness","array","blen","byteLength","u8","Uint8Array","buffer","byteOffset","bpe","BYTES_PER_ELEMENT","DataReader","Int8Array","Int16Array","isNativeLittleEndian","isLittleEndian","DataView","readUint16","getUint16","readInt16","getInt16","readUint32","getUint32","readBigUint64","getBigUint64","readInt32","getInt32","readBigInt64","getBigInt64","readFloat32","getFloat32","readFloat64","getFloat64","readBinaryArray","bitArray","byteArrayLength","data","bitNumber","bitIndex","floor","readUint8Array","readInt8Array","readUint16Array","Uint16Array","arraySize","readInt16Array","readUint32Array","Uint32Array","readUint64Array","BigUint64Array","readInt32Array","Int32Array","readInt64Array","BigInt64Array","readFloat32Array","readFloat64Array","Float64Array","readHex","toUpperCase","startsWith","search","rawPos","pos","endsWith","getFlags","flags","regex","match","exec","replaceFlags","valueObj","valueStr","toPrecision","unit","flag","replace","getFileExtension","filePath","ext","pathSplit","toLowerCase","pop","test","includes","stringToUint8Array","arr","charCodeAt","precisionRound","number","precision","factor","delta","arraySortEquals","arr0","arr1","arrayEquals","sort","uint8ArrayToString","String","fromCharCode","findInArraySubset","callbackFn","start","end","getFindArrayInArrayCallback","buildMultipart","parts","boundary","lineBreak","partsSize","headers","headerStr","partKeys","header","trailer","set","DataElement","vl","undefinedLength","startOffset","endOffset","items","getDwvVersion","hasDicomPrefix","reduce","previous","current","ZWS","DefaultTextDecoder","decode","result","getReverseOrientation","ori","rlabels","L","R","A","P","H","F","rori","getOrientationName","orientation","isImplicitTransferSyntax","syntax","isBigEndianTransferSyntax","isJpegBaselineTransferSyntax","isJpegLosslessTransferSyntax","isJpeg2000TransferSyntax","isRleTransferSyntax","getTypedArray","bitsAllocated","pixelRepresentation","RangeError","powerOf2","log","getDataElementPrefixByteSize","isImplicit","DicomParser","getDefaultCharacterSet","setDefaultCharacterSet","characterSet","setDecoderCharacterSet","TextDecoder","getDicomElements","reader","implicit","itemData","item","isSeqDelim","isItemDelim","offsetTableVl","readTagRes","is32bitVL","concat","isKnownVR","pixItemData","sqEndOffset","vrType","from","stream","lastIndex","trim","cleanString","raw","stri","stri1","subElement","elements","parse","dataElement","metaReader","dataReader","magicword","metaEnd","tsElement","firstDataElement","oEightGroupLittleEndian","vr0","vr1","guessTransferSyntax","isReadSupportedTransferSyntax","isJpegRetiredTransferSyntax","isJpeglsTransferSyntax","getTransferSyntaxName","charSetTerm","label","getUtfLabel","numberOfFrames","pixItems","nItemPerFrame","newPixItems","f","newBuffer","fragOffset","ListenerHandler","type","callback","remove","splice","fireEvent","event","stack","range","dataAccessor","maxIter","increment","blockMaxIter","blockIncrement","reverse1","reverse2","nextIndex","finalBlockIncrement","mainCount","blockCount","next","done","getIteratorValues","iterator","ival","getSliceIterator","image","position","isRescaled","viewOrientation","getGeometry","getSize","dirMax2Index","posValues","posStart","map","indexToOffset","getRescaledValueAtOffset","getValueAtOffset","ncols","nrows","nslices","sliceSize","getDimSize","ncomp","getNumberOfComponents","isPlanar","getPlanarConfiguration","getRange","iters","r0","r1","r2","range3d","rangeObj","dirMax0","dirMax2","simpleRange","componentIncrement","nextIndex1","nextIndex2","simpleRange3d","colourRange","colours","nextColourIndex","colour","RescaleSlopeAndIntercept","slope","intercept","getIntercept","isID","Size","moreThanOne","dimension","canScroll3D","canScroll","getTotalSize","isInBounds","dirs","offsetToIndex","off","dimSize","get2D","Spacing","Geometry","origin","spacing","time","getInitialTime","getCurrentTotalNumberOfSlices","count","hasSlicesAtTime","getCurrentNumberOfSlicesBeforeTime","getOrigin","getOrigins","includesOrigin","getOrientedArray3D","geoSliceSpacing","getSliceGeometrySpacing","getSpacing","orientedValues","getRealSpacing","getOrientation","getSliceIndex","point","localOrigins","closestSliceIndex","minDist","dist","closestOrigin","pointDir","appendOrigin","appendFrame","sizeValues","spacingValues","isIndexInBounds","worldToIndex","indexToWorld","orientedPoint3D","pointToWorld","worldToPoint","getDeOrientedArray3D","origins","withCheck","invOrientation","origin1","origin2","sliceSpacing","deltas","diff","sumReducer","sum","mean","toFixed","getImage2DSize","rows","columns","TagValueExtractor","getTime","_elements","ImageFactory","checkElements","dataElements","create","pixelBuffer","numberOfFiles","size2D","frames","rowSpacing","columnSpacing","parseFloat","getPixelSpacing","jpeg2000","jpegBase","jpegLoss","imagePositionPatient","slicePosition","imageOrientationPatient","orientationMatrix","rowCosines","colCosines","normal","geometry","sopInstanceUid","siu","samplesPerPixel","spp","bufferSize","Image","photometricInterpretation","photo","setPhotometricInterpretation","planarConfiguration","setPlanarConfiguration","rescaleSlope","rescaleIntercept","setRescaleSlopeAndIntercept","meta","modality","Modality","sopClassUID","SOPClassUID","studyUID","StudyInstanceUID","seriesUID","SeriesInstanceUID","bits","BitsStored","pixelRep","PixelRepresentation","IsSigned","pixelUnit","getPixelUnit","frameOfReferenceUID","FrameOfReferenceUID","windowPresets","windowCenter","windowWidth","windowCWExplanation","getPhotometricInterpretation","redLutElement","greenLutElement","blueLutElement","redLut","greenLut","blueLut","descriptor","doScale","descSize","vlSize","scaleTo8","clone","paletteLut","recommendedDisplayFrameRate","RecommendedDisplayFrameRate","setMeta","equalPosPat","pos1","pos2","JSON","stringify","checkTag","tagDefinition","tagValue","isArray","enum","RequiredDicomSegTags","getCode","code","meaning","longValue","urnValue","schemeDesignator","getSegment","segment","algorithmType","algorithmName","displayValue","cielabElement","rgb","triplet","gammaFunc","ciexyzToSrgb","invLabFunc","illuminant","l0","cielabToCiexyz","cielabToSrgb","propertyCategoryCode","propertyTypeCode","trackingId","trackingUid","getSpacingFromMeasure","pixelSpacing","getSegmentFrameInfo","derivationImages","derivationImageSq","sourceImages","sourceImageSq","sourceImage","referencedSOPClassUID","referencedSOPInstanceUID","dimIndex","refSegmentNumber","imagePosPat","frameInfo","framePlaneOrientationSeq","frameImageOrientation","framePixelMeasuresSeq","frameSpacing","MaskFactory","_dicomElements","framesElem","orgSq","orgUID","indices","indexSqElem","indexSq","indexPointer","indexOrg","DimensionOrganizationUID","DimensionIndexPointer","DimensionDescriptionLabel","organizations","getDimensionOrganization","segSequence","segments","storeAsRGB","sharedFunctionalGroupsSeq","funcGroup0","planeOrientationSeq","pixelMeasuresSeq","includesPosPat","some","arrVal","findIndexPosPat","findIndex","perFrameFuncGroupSequence","frameInfos","framePosPats","p1","p2","getComparePosPat","point3DFromArray","frameOrigins","newSpacing","tmpGeometry","isNotSmall","REAL_WORLD_EPSILON","posPats","sliceIndex","frameOrigin","distPrevious","numberOfSlices","uids","getFindSegmentFunc","mul","sliceOffset","frameOffset","pixelValue","find","reqTag","getDefaultDicomSegJson","StudyDate","StudyTime","StudyID","SeriesNumber","ReferringPhysicianName","PatientName","PatientID","PatientBirthDate","PatientSex","Manufacturer","ManufacturerModelName","DeviceSerialNumber","SoftwareVersions","DimensionOrganizationSequence","DimensionIndexSequence","custom","SOPInstanceUID","lossyImageCompression","LossyImageCompression","createImage","createMaskImage","imageUids","getImageUid","uid","getSecondaryOffset","getBuffer","canQuantify","canWindowLevel","nFiles","getRescaleSlopeAndIntercept","isConstantRSI","inRsi","isIdentityRSI","interp","config","getMeta","getOffsets","offsets","equal","hasValues","finalValues","v1","equalFunc","getEqualCallback","valuesToFind","indicesToRemove","v","clonedBuffer","copy","tmpBuffer","appendSlice","rhsSize","timeId","isNewFrame","volumeGeometry","sliceGeometry","fullBufferSize","fullSliceIndex","indexOffset","maxOffset","subarray","numberOfImages","rhsPresets","pkey","rhsPreset","windowPreset","perslice","appendFrameBuffer","frameBuffer","frameIndex","frameSize","getDataRange","calculateDataRange","getRescaledDataRange","calculateRescaledDataRange","getHistogram","calculateHistogram","dataRange","rescaledDataRange","histogram","addEventListener","removeEventListener","setAtOffsets","setAtOffsetsAndGetOriginals","offsetsLists","originalColoursLists","previousColour","originalColours","currentColour","setAtOffsetsWithIterator","getValueAtIndex","getRescaledValue","getRescaledValueAtIndex","resmin","resmax","rmin","rmax","rvalue","histo","convolute2D","weights","newImage","imgSize","dimOffset","convoluteBuffer","componentOffset","wOff","wOff00","wOff0x","wOff0n","wOffx0","wOffxn","wOffn0","wOffnx","wOffnn","pixelOffset","newValue","wOffFinal","wi","transform","operator","compose","ViewFactory","view","View","setDefaultColourMap","minmax","preset","setWindowPresets","init","viewEventNames","createView","getCurrentIndex","setCurrentIndex","getImage","setImage","inImage","setOrientation","mat33","setInitialIndex","getPlaybackMilliseconds","_value","_index","getAlphaFunction","setAlphaFunction","getCurrentWindowLut","currentIndex","setWindowLevelPresetById","wlut","windowLut","addWindowLut","lutWl","wc","ww","skipGenerate","getWindowPresets","getWindowPresetsNames","presets","addWindowPresets","getColourMap","setColourMap","getCurrentPosition","canSetPosition","getScrollIndex","originIndex","setCurrentPosition","silent","valid","minLen","maxLen","posEvent","imageUid","pixValue","newWl","isNewWidth","isNewCenter","setWindowLevelPreset","getWindowLevelMinMax","setWindowLevelMinMax","generateImageData","photoInterpretation","alphaFunc","colourMap","pxValue","generateImageDataMonochrome","is16BitsStored","to8","generateImageDataPaletteColor","generateImageDataRgb","cb","cr","generateImageDataYbrFull","incrementIndex","incr","newIndex","decrementIndex","decrementScrollIndex","incrementScrollIndex","PlaneHelper","imageOrientation","targetOrientation","getTargetOrientation","getOffset3DFromPlaneOffset","offset2D","planeOffset","getTargetDeOrientedVector3D","getPlaneOffsetFromOffset3D","offset3D","getTargetOrientedVector3D","vector","planeVector","getTargetDeOrientedPoint3D","planePoint","getImageOrientedVector3D","getImageOrientedPoint3D","getImageDeOrientedVector3D","getImageDeOrientedPoint3D","getTargetOrientedPositiveXYZ","getNativeScrollIndex","MaskSegmentHelper","mask","hasSegment","segmentNumber","maskHasSegments","numbers","unknowns","getSegments","setSegments","list","setHiddenSegments","isHidden","addToHidden","removeFromHidden","getAlphaFunc","hiddenColours","deleteSegment","cmdCallback","exeCallback","delcmd","DeleteSegmentCommand","onExecute","onUndo","isValid","execute","getName","segmentnumber","undo","_event","ViewController","getPlaneHelper","isMask","getMaskSegmentHelper","applyHiddenSegments","setViewAlphaFunction","getPositionFromPlanePoint","getWindowLevelPresetsNames","addWindowLevelPresets","isPlaying","getCurrentOrientedIndex","getCurrentScrollIndexValue","getCurrentScrollPosition","scrollIndex","img","get2DSpacing","getRescaledImageValue","getImageRegionValues","rescaled","sliceValues","sliceOrigin","iter","rangeNumberOfColumns","regionSize","regionOffset","regionElementCount","rangeRegion","getRegionSliceIterator","getImageVariableRegionValues","regions","offsetRegions","region","regionIndex","regionCount","rangeRegions","getVariableRegionSliceIterator","canQuantifyImage","getImageSize","getImageWorldSize","getImageRescaledDataRange","equalImageMeta","imageMeta","metaKeys","metaKey","getPlanePositionFromPosition","getPlanePositionFromPlanePoint","play","milliseconds","setInterval","canDoMore","stop","clearInterval","setColourMapFromName","dataid","InteractionEventNames","customUI","openRoiDialog","textExpr","prompt","getTouchesPositions","touches","offsetLeft","offsetTop","target","offsetParent","positions","pageX","pageY","getEventOffset","targetTouches","changedTouches","offsetX","offsetY","canCreateCanvas","height","testCvs","document","createElement","cropCvs","testCtx","getContext","cropCtx","fillRect","drawImage","getImageData","ViewLayer","containerDiv","className","getDataIndex","enableImageSmoothing","setView","getViewController","onimageset","onimagechange","getId","getBaseSize","getOpacity","setOpacity","alpha","addFlipOffsetX","addFlipOffsetY","setScale","newScale","helper","orientedNewScale","finalNewScale","resetOffset","worldCenter","newOffset","getScaledOffset","newZoomOffset","setBaseOffset","scrollOffset","needsUpdate","setOffset","planeNewOffset","displayToPlaneIndex","planePos","displayToPlanePos","displayToPlaneScale","deScaled","planePosToDisplay","displayToMainPlanePos","display","style","isVisible","draw","layerid","globalAlpha","clear","setTransform","imageSmoothingEnabled","appendChild","alert","clearRect","createImageData","fitToContainer","fitScale1D","fitSize","fitOffset","needsDraw","previousFitScale","previousScale","newFitScale","newViewOffset","newFlipOffset","bindInteraction","pointerEvents","names","passive","unbindInteraction","srclayerid","putImageData","dims3D","indexScrollIndex","filter","save","restore","Style","getFontFamily","getFontSize","getStrokeWidth","getTextColour","getLineColour","setLineColour","setBaseScale","scale","setZoomScale","getBaseScale","getZoomScale","applyZoomScale","getShadowOffset","getTagOpacity","getTextPadding","getFontStr","getLineHeight","getScaledFontSize","getScaledStrokeWidth","getShadowLineColour","getShapeDisplayName","shape","displayName","Konva","points","DrawGroupCommand","layer","getParent","MoveGroupCommand","translation","move","minusTrans","ChangeGroupCommand","startAnchor","endAnchor","viewController","DeleteGroupCommand","isNodeNameShape","node","isNodeNameShapeExtra","isNodeNameLabel","isPositionNode","isNodeWithId","canNodeChangeColour","DrawController","konvaLayer","getCurrentPosGroup","posGroups","getChildren","posGroup","visible","reset","findOne","activateDrawLayer","getDrawDisplayDetails","groups","lenj","collec","text","shapeExtrakids","closed","extraName0","color","stroke","getDrawStoreDetails","drawingsDetails","posKids","anchors","texts","setDrawings","drawings","statePosGroups","statePosGroup","statePosKids","stateGroup","cmd","details","getText","setText","quantification","updateDraw","drawDetails","shapes","shapesExtra","shadowColor","kids","setVisible","deleteDrawGroup","shapeDisplayName","deleteDraw","deleteDraws","DrawLayer","getKonvaStage","getKonvaLayer","getLayers","getDrawController","setPlaneHelper","opacity","container","listening","getContent","setAttribute","isGroupVisible","toggleGroupVisibility","ratioX","ratioY","labels","getLayerDetailsFromEvent","layerDiv","closest","idString","groupDivId","layerId","getLayerDetailsFromLayerDivId","indexCenter","LayerGroup","setTargetOrientation","getShowCrosshair","setShowCrosshair","getDivId","getScale","getAddedScale","getOffset","getNumberOfLayers","getActiveViewLayer","getViewLayersByDataIndex","searchViewLayers","getViewDataIndices","getActiveDrawLayer","getDrawLayersByDataIndex","setActiveViewLayer","setActiveViewLayerByDataIndex","setActiveDrawLayer","setActiveDrawLayerByDataIndex","addViewLayer","viewLayerIndex","div","append","addDrawLayer","viewLayer","updateLayersToPositionChange","drawLayer","empty","getElementsByClassName","layer0","p2D","displayPos","lineH","offsetWidth","left","top","lineV","offsetHeight","getElementById","baseViewLayerOrigin0","baseViewLayerOrigin","hasSetOffset","vc","origin0","scrollDiff","planeDiff","hasSetPos","calculateFitScale","maxSize","getMaxSize","setFitScale","scaleIn","containerSize","flipScaleZ","addScale","scaleStep","addTranslation","binderList","WindowLevelBinder","getEventType","getCallback","layerGroup","viewLayers","PositionBinder","pointValues","currentPos","currentDims","inputDims","ZoomBinder","OffsetBinder","OpacityBinder","Stage","getLayerGroup","getNumberOfLayerGroups","getActiveLayerGroup","addLayerGroup","htmlElement","isBound","unbindLayerGroups","bindLayerGroups","getLayerGroupByDivId","setBinders","syncLayerGroupScale","minScale","hasScale","binder","binderObj","elem","State","toJSON","app","drawController","version","toObject","fromJSON","json","baseScale","scaleCenter","originX","originY","oldTx","oldTy","render","v02DAndD","inputDrawings","newDrawings","drawGroups","drawGroup","lenk","lenf","newFrameDrawings","leng","kshape","ktick0","ktick1","karcs","ktexts","ktext","klabel","txtLen","quant","surface","angle","longText","v01Tov02DrawingsAndDetails","v02Tov03Drawings","v03Tov04DrawingsDetails","v04Tov05Data","v04Tov05Drawings","groupDetails","v02Tov03DrawingsDetails","groupShapes","parentGroup","groupDrawings","currentPosition","draggable","forEach","gnode","detail","children","ids","attrs","sliceNumber","frameNumber","newId","getUrlFromUri","uri","URL","window","location","splitUri","sepIndex","base","hashIndex","query","pairs","pair","splitKeyValueString","UndoStack","getStackSize","getCurrentStackIndex","command","redo","ToolboxController","toolList","getToolList","hasTool","getSelectedTool","getSelectedToolEventHandler","eventType","setSelectedTool","activate","setToolFeatures","setFeatures","bindLayer","layerGroupDivId","applySelectedTool","_x","_y","_x1","_y1","augmentEventOffsets","MultiProgressHandler","setNumberOfDimensions","num","setNToLoad","onprogress","lengthComputable","subindex","percent","loaded","total","source","lenprog","getMonoProgressHandler","getUndefinedMonoProgressHandler","UrlsLoader","request","loader","onload","onloadend","load","options","onloadstart","status","onerror","responseURL","statusText","response","mproghandler","loaders","loaderList","foundLoader","canLoadUrl","setOptions","defaultCharacterSet","onloaditem","onabort","lastRunRequestIndex","requestOnLoadEnd","send","XMLHttpRequest","open","requestHeaders","setRequestHeader","withCredentials","loadUrlAs","responseType","batchSize","dicomDirUrl","urls","parser","dirSeq","records","series","study","recType","refFileIds","join","getFileListFromDicomDir","rootUrl","fullUrls","abort","readyState","isLoading","ThreadPool","poolSize","taskQueue","freeThreads","WorkerThread","runningThreads","addWorkerTask","workerTask","onworkstart","workerThread","shift","run","onworkend","onTaskEnd","onwork","handleWorkerError","onworkitem","parentPool","random","runningTask","worker","Worker","script","onmessage","postMessage","startMessage","terminate","itemNumber","numberOfItems","dataIndex","WorkerTask","message","hasJpegBaselineDecoder","JpegImage","hasJpegLosslessDecoder","jpeg","lossless","hasJpeg2000Decoder","JpxImage","decoderScripts","rle","AsynchPixelBufferDecoder","_numberOfData","pixelMeta","ondecodestart","ondecodeditem","ondecoded","ondecodeend","SynchPixelBufferDecoder","algoName","numberOfData","decoder","decodedBuffer","buf","Decoder","decoded","getData","tiles","dwvdecoder","RleDecoder","PixelBufferDecoder","DicomBufferToView","opt","decodedData","fullSize","convert","dicomParser","warning","algo","getSyntaxDecompressionName","needDecompression","columnsElement","rowsElement","samplesPerPixelElement","planarConfigurationElement","MemoryLoader","canLoadMemory","filename","imageDataToBuffer","imageData","dataLen","getDefaultImage","imageBuffer","imageSize","imageSpacing","canLoadFile","file","url","isDicom","urlObjext","pathname","hasNoExt","hasDcmExt","contentType","searchParams","mem","loadFileAs","fileContentTypes","ArrayBuffer","_opt","isJson","Text","memoryIO","progress","u8Array","partHeaderEndCb","partHeaderEndIndex","lines","boundaryStr","boundaryCb","boundaryLen","nextBoundaryIndex","part","partHeaderLines","line","semiColonIndex","dataBeginIndex","dataEndIndex","parseMultipart","_file","isMultipart","_mem","dataType","imageType","Blob","createObjectURL","domImage","canvas","ctx","lastModified","getViewFromDOMImage","src","isImage","hasImageExt","DataURL","bytes","videoDataStr","btoa","video","onloadedmetadata","videoWidth","videoHeight","ceil","duration","onseeked","imgBuffer","storeFrame","nextTime","currentTime","getViewFromDOMVideo","isVideo","content","unzipPercent","async","then","JSZip","zip","isZip","FilesLoader","FileReader","readAsText","readAsDataURL","readAsArrayBuffer","LoadController","loadFiles","files","loadURLs","loadImageObject","fileIO","urlIO","loadType","eventInfo","loadtype","loadId","loadid","isFirstItem","eventInfoItem","isfirstitem","DataController","addNew","dataToUpdate","idKey","obj1","obj2","valueKey","mergedObj1","merged","id1","id2","keys2","value1","subValue1","value2","subValue2","mergeObjects","ScrollWheel","wheel","scrollMin","deltaMode","deltaY","preventDefault","up","layerDetails","i18n","t","props","mm","cm2","degree","Line","begin","getBegin","getEnd","getDeltaX","getDeltaY","getWorldLength","spacingX","spacingY","wlen","dxs","dys","getMidpoint","getInclination","atan2","PI","quantify","getAngle","line0","line1","dx0","dy0","dx1","dy1","dot","getPerpendicularLine","beginX","beginY","endX","endY","dx","getStats","includesFullStatsFlags","stats","getSimpleStats","median","getPercentile","p25","p75","getFullStats","sumSqr","variance","stdDev","ratio","i0","v0","guid","getDefaultAnchor","radius","absRadius","strokeWidth","strokeScaleEnabled","radiusX","radiusY","dragOnTop","ShapeEditor","setFactoryList","setShape","inshape","isFactoryGroup","setViewController","getShape","isActive","setDrawEventCallback","enable","getLayer","disable","resetAnchors","anchor","setAnchorsActive","getAnchors","getStyle","parent","on","cancelBubble","evt","stageSize","boundNodePosition","validateAnchorPosition","chgcmd","addToUndoStack","moveToTop","changed","ROI","getPoint","addPoint","addPoints","RoiFactory","getNPoints","getTimeout","_viewController","roi","fontSize","fontFamily","px","py","kroi","textPos","Path","inputPointArray","inputControlPointIndexArray","pointArray","controlPointIndexArray","isControlPoint","addControlPoint","newPointArray","appenPath","other","oldSize","indexArray","BucketQueue","cost_functor","bucketCount","loc","cost","buckets","buildArray","bucket","getBucket","ret","isEmpty","newSize","__twothirdpi","gradUnitVector","gradX","gradY","out","oy","gvm","Scissors","curPoint","searchGranBits","searchGran","pointsPerPost","greyscale","laplace","gradient","parents","working","trained","trainingPoints","edgeWidth","trainingLength","edgeGran","edgeTraining","gradPointsNeeded","gradGran","gradTraining","insideGran","insideTraining","outsideGran","outsideTraining","getTrainingIdx","granularity","getTrainedEdge","edge","getTrainedGrad","grad","getTrainedInside","inside","getTrainedOutside","outside","setWorking","setDimensions","setData","dy","gradMagnitude","lap","computeGreyscale","computeLaplace","computeGradient","computeGradX","computeGradY","sides","guv","ix","iy","computeSides","findTrainingPoints","resetTraining","doTraining","calculateTraining","addInStaticGrad","input","output","maxVal","idx","len","gaussianBlur","have","need","gradDirection","qx","qy","__dgpuv","__gdquv","dp","dq","SQRT1_2","acos","dir","adj","sx","sy","ex","ey","setPoint","sp","visited","MAX_VALUE","pq","doWork","timeout","pointCount","newPoints","adjList","q","pqCost","Circle","centre","getRadius","getSurface","getWorldSurface","mulABC","centerX","centerY","rSquare","maxY","transX","quantif","Ellipse","getA","getB","radiusRatio","rySquare","Rectangle","getRealWidth","getRealHeight","getHeight","Threshold","getMin","setMin","getMax","setMax","setOriginalImage","getOriginalImage","imageMin","Sharpen","Sobel","RunFilterCommand","setLastImage","WindowLevel","mousedown","x0","y0","mousemove","diffX","diffY","pixelToIntensity","manual","mouseup","mouseout","touchstart","touchmove","touchend","dblclick","keydown","context","onKeydown","_bool","Scroll","yMove","xMove","setTimeout","clearTimeout","span","parentElement","createTextNode","features","displayTooltip","ZoomAndPan","twotouchdown","point0","point1","midPoint","tx","ty","twotouchmove","lineRatio","zoom","step","Opacity","op","Draw","trashLine1","trashLine2","stage","getIntersection","selectedShape","timer","shapeGroup","destroy","tmpPoints","finalPoints","finalShapeGroup","setShapeOn","body","cursor","lineColour","shapeGroups","ashape","mouseOnShape","dragStartPos","invscale","anchorMin","minX","minY","getAnchorMin","validateGroupPosition","updateQuantification","eventPos","trashHalfWidth","scaleX","trashHalfHeight","scaleY","tshape","mvcmd","currentTarget","groupId","getOptionsType","shapeColour","shapeName","hasShape","mouseOverCursor","getEventNames","listener","Filter","bool","getSelectedFilter","filterName","hasFilter","args","runArgs","getFilterList","Floodfill","setExtend","getExtend","threshold","simple","MagicWand","cs","icsl","extend","ini","jl","modifyThreshold","bl","setPoints","onThresholdChange","getAbsoluteScale","movedpoint","Livewire","pn","p0","results","_p","_q","toolOptions","ArrowFactory","linePerp0","linePerp1","hitFunc","beginPath","moveTo","lineTo","closePath","fillStrokeShape","beginTy","verticalLine","angleRad","kpoly","sin","cos","rotation","padding","shadowOffset","dX","dY","kline","ktriangle","bx","by","p2d0","p2d1","p2b","p2e","CircleFactory","circle","_style","kcircle","right","bottom","centerPoint","kshadow","maxX","pixelLine","EllipseFactory","ellipse","ellipseX","ellipseY","kellipse","topLeft","topRight","bottomRight","bottomLeft","radiusAbs","FreeHandFactory","tension","ProtractorFactory","pointsArray","inclination","midX","midY","karc","innerRadius","outerRadius","mid","mx","my","p2d2","arcPos","RectangleFactory","rectangle","rectX","rectY","rectWidth","rectHeight","krect","rect","rWidth","rHeight","RulerFactory","tickLen","ThresholdFilter","getLastImage","_args","SobelFilter","SharpenFilter","ViewConfig","divId","ToolConfig","AppOptions","dataViewConfigs","tools","binders","viewOnFirstLoadItem","App","addNewImage","getMetaData","getNumberOfLoadedData","getToolboxController","appToolList","toolName","toolParams","appToolOptions","optionName","optionClassName","toolNamespace","charAt","resetLayout","loadFromUri","getUriQuery","onLoadEnd","state","protocol","host","decodeURIComponent","manifest","rootURL","getElementsByTagName","getAttribute","patientList","studyList","seriesList","instanceList","link","decodeManifest","responseXML","decodeManifestQuery","replaceMode","repeatKeyReplaceMode","queryUri","inputQueryPairs","repeatKey","repeatList","baseUrl","gotOneArg","decodeKeyValueUri","dwvReplaceMode","decodeQuery","abortLoad","initWLDisplay","configs","getDataViewConfigs","setDataViewConfigs","dataKeys","divIds","viewConfigs","viewConfig","setLayerGroupsBinders","instances","cx","cy","translate","getJsonState","applyJsonState","jsonState","onResize","defaultOnKeydown","ctrlKey","shiftKey","resetDisplay","resetZoom","setTool","tool","isFirstLoadItem","eventMetaData","imageGeometry","getViewOrientation","isBaseLayer","spacing2D","major","DataWriter","writeUint8","setUint8","writeInt8","setInt8","writeUint16","setUint16","writeInt16","setInt16","writeUint32","setUint32","writeUint64","setBigUint64","writeInt32","setInt32","writeInt64","setBigInt64","writeFloat32","setFloat32","writeFloat64","setFloat64","writeHex","writeBinaryArray","byte","writeUint8Array","writeInt8Array","writeUint16Array","writeInt16Array","writeUint32Array","writeUint64Array","writeInt32Array","writeInt64Array","writeFloat32Array","writeFloat64Array","_uidCount","WriterRule","action","getUID","prefix","getDwvUIDPrefix","datePart","Date","toISOString","countPart","nonTagLength","tagNumber","isEven","isStringVr","uint8ArrayPush","newArr","DefaultTextEncoder","encode","DicomWriter","setUseUnVrForPrivateSq","default","setRules","rules","useSpecialTextEncoder","TextEncoder","useDefaultAnonymisationRules","Acquisition","Procedure","getElementToWrite","groupName","rule","writer","itemKeys","itemElement","itemDelimElement","hexString","hexString1","hexString2","atValue","finalValue","initialArray","initialArrayLength","arrayLength","flattenendArrayLength","flattenedArray","indexFlattenedArray","flattenArrayOfTypedArrays","isTagWithVR","undefinedLengthSequence","undefinedLengthItem","seqDelimElement","isBigEndian","oldscs","totalSize","localSize","metaElements","rawElements","metaLength","fmiglTag","fmivTag","icUIDTag","ivnTag","originalElement","checkUnknownVR","fmiv","getDataElement","fmivSize","icUID","icUIDSize","ivn","ivnSize","elemSortFunc","tagCompareFunction","fmigl","fmiglSize","metaWriter","dataWriter","metaOffset","newItems","oldItemElements","newItemElements","subSize","itemKey","padStr","pad","getVrPad","padOBValue","isTypedArrayVr","itemPrefixSize","getBpeForVrType","dictVr","getElementsFromJSONTags","jsonTags","jsonTag"],"sourceRoot":""}