{"version":3,"file":"aframe-extras.js","mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;;;;;;;;;ACVA,2DAA2D;AAC3D;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;;;;;;;;;;ACpBD;AACA;AACA;AACA;AACA;AACA;;AAEA;;;;;;;;;;;ACPA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,KAAK;;AAEL,iDAAiD;;AAEjD;AACA,eAAe,SAAS;;AAExB;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;;;;;;;;;AC1EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAsD;;AAEtD,qHAAqH;AACrH,sHAAsH;AACtH,uHAAuH;AACvH,wHAAwH;;AAExH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,6BAA6B;;AAE7B;AACA,+CAA+C;AAC/C,+CAA+C;AAC/C,gDAAgD;AAChD,iDAAiD;AACjD,mIAAmI;AACnI;AACA,IAAI;;AAEJ;AACA,oDAAoD;AACpD,+CAA+C;AAC/C,iDAAiD;AACjD,mDAAmD;AACnD,mDAAmD;AACnD;AACA,IAAI;;AAEJ;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,gBAAgB;AAC5B;AACA;AACA;AACA,YAAY,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;AACA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH,sBAAsB,qBAAqB;AAC3C,uBAAuB,sBAAsB;;AAE7C;AACA;;AAEA;AACA;;AAEA;AACA,iCAAiC,4BAA4B;AAC7D;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,iCAAiC,uBAAuB;;AAExD;AACA;AACA;AACA,iCAAiC,uBAAuB;AACxD;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,sCAAsC,uBAAuB;AAC7D;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACrFD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,sBAAsB,mBAAO,CAAC,uDAAyB;AACvD,yBAAyB,mBAAO,CAAC,iEAA8B;;AAE/D;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,eAAe,eAAe;;AAE9B;AACA,2BAA2B,cAAc;AACzC,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uGAAuG;;AAEvG;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,wBAAwB,cAAc;;AAEtC;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,yBAAyB;;AAEzB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,sBAAsB,4BAA4B;AAClD;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA,MAAM;AACN;AACA,wCAAwC;AACxC;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,cAAc;AACd;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sBAAsB,oCAAoC;AAC1D;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sBAAsB,wBAAwB;AAC9C;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,cAAc,QAAQ;AACtB,cAAc;AACd;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,cAAc,QAAQ;AACtB,cAAc,QAAQ;AACtB;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,cAAc,UAAU;AACxB,cAAc,eAAe;AAC7B,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,aAAa,eAAe;AAC5B,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACtVD,mBAAO,CAAC,oEAAuB;AAC/B,mBAAO,CAAC,8DAAoB;AAC5B,mBAAO,CAAC,gEAAqB;AAC7B,mBAAO,CAAC,0DAAkB;AAC1B,mBAAO,CAAC,gEAAqB;AAC7B,mBAAO,CAAC,gEAAqB;AAC7B,mBAAO,CAAC,4DAAmB;;;;;;;;;;;ACN3B;AACA;AACA,mBAAO,CAAC,+DAA6B;;AAErC;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,MAAM;AACjB;AACA;AACA;AACA,yBAAyB,eAAe;AACxC,yBAAyB;AACzB,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA,0CAA0C;AAC1C,0CAA0C;AAC1C,0CAA0C;AAC1C,0CAA0C;;AAE1C;AACA,4BAA4B;AAC5B;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,CAAC;;;;;;;;;;;ACjKD;AACA;AACA;AACA;AACA;;AAEA;AACA,uBAAuB;AACvB;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,0BAA0B,eAAe;AACzC,0BAA0B,uDAAuD;AACjF,0BAA0B,sBAAsB;AAChD,0BAA0B,gBAAgB;AAC1C,0BAA0B,gBAAgB;AAC1C,0BAA0B;AAC1B,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,0BAA0B;AAChD;AACA,qCAAqC,4BAA4B;AACjE;AACA;AACA,GAAG;;AAEH;AACA;;AAEA,oBAAoB,0BAA0B;AAC9C;AACA,mCAAmC,4BAA4B;AAC/D;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA,gDAAgD,OAAO;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA,UAAU;AACV;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,GAAG;AACH,CAAC;;;;;;;;;;;;;;;AC5ND;AACgC;;AAEhC;AACA;AACA,eAAe,eAAe;AAC9B,YAAY,0DAA0D;AACtE,2BAA2B,cAAc;AACzC,2BAA2B,eAAe;AAC1C,2BAA2B,eAAe;AAC1C,kBAAkB,iBAAiB;AACnC,oBAAoB,iBAAiB;AACrC,4BAA4B,2CAA2C;AACvE,4BAA4B,4CAA4C;AACxE,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,yBAAyB,EAAE,+BAA+B,GAAG,sBAAsB,SAAS,wBAAwB;AACpH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,yBAAyB,EAAE,+BAA+B,GAAG,sBAAsB,SAAS,wBAAwB;AACpH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,MAAM;AACN;AACA;;AAEA,wBAAwB,sDAAe;AACvC;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,MAAM;AACN;AACA;;AAEA,wBAAwB,sDAAe;AACvC;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH,CAAC;;;;;;;;;;;ACnND;AACA;AACA;AACA;AACA;AACA,eAAe,eAAe;AAC9B,sBAAsB;AACtB,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,gEAAgE,cAAc;AAC9E,4DAA4D,cAAc;AAC1E;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,qBAAqB;;AAErB;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,sBAAsB;AACtB;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACzFD;AACA;AACA;AACA;AACA;AACA,eAAe,eAAe;AAC9B,kBAAkB,eAAe;AACjC,kBAAkB,eAAe;AACjC,kBAAkB,eAAe;AACjC,kBAAkB,eAAe;AACjC,YAAY;;AAEZ,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;;AAEA,CAAC;;;;;;;;;;;;ACpMD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,cAAc;AAC1B,gBAAgB,eAAe;AAC/B,gBAAgB,YAAY;AAC5B,yBAAyB,iCAAiC;AAC1D,yBAAyB,YAAY;AACrC,YAAY,iDAAiD;AAC7D,mBAAmB,2BAA2B;AAC9C,iBAAiB,YAAY;AAC7B,eAAe;AACf,GAAG;;AAEH;AACA,eAAe,YAAY;AAC3B;AACA,eAAe,sBAAsB;AACrC;AACA,eAAe,8BAA8B;AAC7C;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA,OAAO;AACP;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,kCAAkC,0CAA0C;AAC5E,KAAK;AACL;AACA,sCAAsC,0CAA0C;AAChF,KAAK;AACL,sCAAsC;AACtC,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA,oBAAoB,+BAA+B;AACnD;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA,uDAAuD;;AAEvD;;AAEA;;AAEA,0BAA0B,mBAAmB;AAC7C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;;;;;;;;;;;;;;ACzJsE;AACtE,sBAAsB,gFAAa;;AAEnC;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,cAAc;;AAEzB;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA,gBAAgB;;AAEhB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,+BAA+B,qCAAqC;AACpE,KAAK;AACL,GAAG;;AAEH;AACA,uBAAuB;AACvB;AACA;AACA,CAAC;;;;;;;;;;;;;;AC9C6D;AAC9D,kBAAkB,wEAAS;;AAE3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,eAAe;AAClC,mBAAmB;AACnB,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,kCAAkC,4BAA4B;AAC9D,GAAG;;AAEH;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACrCD,oBAAoB,mBAAO,CAAC,qDAAwB;;AAEpD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,WAAW,cAAc;;AAEzB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,gBAAgB;;AAEhB;;AAEA;AACA;AACA;AACA;AACA;AACA,iCAAiC,kCAAkC;AACnE,OAAO;AACP,KAAK;AACL,GAAG;;AAEH;AACA,uBAAuB;AACvB;AACA;AACA,CAAC;;;;;;;;;;;ACnDD,mBAAO,CAAC,2DAAmB;AAC3B,mBAAO,CAAC,qEAAwB;AAChC,mBAAO,CAAC,+CAAa;AACrB,mBAAO,CAAC,+DAAqB;AAC7B,mBAAO,CAAC,qDAAgB;;;;;;;;;;;ACJxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,eAAe;AAClC,mBAAmB;AACnB,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA,kCAAkC,6BAA6B;AAC/D,GAAG;;AAEH;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACpDD;AACA;AACA,aAAa,UAAU,iBAAiB;AACxC,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH,sBAAsB,+CAA+C;AACrE,uBAAuB,kDAAkD;AACzE,wBAAwB,eAAe;;AAEvC;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,CAAC;;;;;;;;;;;AC/BD;AACA,YAAY,sCAAsC;AAClD,YAAY;AACZ;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA,IAAI;AACJ;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA,YAAY,gBAAgB;AAC5B,YAAY,eAAe;AAC3B,YAAY,eAAe;AAC3B,YAAY,QAAQ;AACpB;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,KAAK;;AAEL,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,WAAW,YAAY;AACvB,gBAAgB,sCAAsC;AACtD,uBAAuB,eAAe;AACtC,mBAAmB,2BAA2B;AAC9C,gBAAgB;AAChB,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,CAAC;;;;;;;;;;ACpID;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,iCAAiC,mBAAmB;AACpD,iCAAiC,mBAAmB;AACpD,iCAAiC,mBAAmB;;AAEpD;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,wEAAwE;AACxE;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACzED,mBAAO,CAAC,8CAAc;AACtB,mBAAO,CAAC,kDAAgB;AACxB,mBAAO,CAAC,kCAAQ;AAChB,mBAAO,CAAC,wDAAmB;AAC3B,mBAAO,CAAC,wDAAmB;;;;;;;;;;;ACJ3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,kBAAkB;AACpE;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,KAAK;AACL;AACA,CAAC;;;;;;;;;;;ACtBD;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ;AACtB,cAAc,QAAQ;AACtB;AACA;AACA;AACA;AACA,cAAc,cAAc;AAC5B,eAAe,YAAY;AAC3B,cAAc,YAAY;AAC1B,YAAY,oBAAoB;AAChC,aAAa,cAAc;AAC3B,YAAY;AACZ,GAAG;;AAEH;AACA,eAAe,kBAAkB;AACjC;AACA,eAAe,gBAAgB;AAC/B;AACA,eAAe,gBAAgB;AAC/B;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA,sCAAsC,+BAA+B;AACrE;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC;;AAEhC;AACA;AACA,0EAA0E;AAC1E;AACA;;AAEA;AACA;AACA;AACA;;AAEA,mBAAmB;;AAEnB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,4BAA4B;;AAE5B;;AAEA,qBAAqB;;AAErB;AACA;AACA;AACA;;AAEA,uBAAuB;;AAEvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA,kBAAkB,mBAAmB,OAAO;AAC5C;;;;;;;;;;;AChKA,mBAAO,CAAC,iDAAY;AACpB,mBAAO,CAAC,mDAAa;AACrB,mBAAO,CAAC,6CAAU;;;;;;;;;;;ACFlB;AACA;AACA,kBAAkB,aAAa;AAC/B,aAAa,eAAe;AAC5B,YAAY;AACZ,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,2CAA2C,cAAc;AACzD;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,6CAA6C,cAAc;AAC3D;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,iCAAiC;AACjC;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH,CAAC;;;;;;;;;;;ACtGD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;AC3CD,QAAQ,cAAc,EAAE,mBAAO,CAAC,4FAAmB;;AAEnD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,aAAa,gBAAgB;AAC7B;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,cAAc;AACd;AACA;AACA;AACA,GAAG;;AAEH;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA,GAAG;;AAEH;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA,GAAG;;AAEH;AACA,cAAc,eAAe;AAC7B,cAAc,eAAe;AAC7B,cAAc,QAAQ;AACtB,cAAc;AACd;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,aAAa,eAAe;AAC5B,cAAc;AACd;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,cAAc,eAAe;AAC7B,cAAc,QAAQ;AACtB,cAAc;AACd;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,cAAc,eAAe;AAC7B,cAAc,eAAe;AAC7B,cAAc,QAAQ;AACtB,cAAc,MAAM;AACpB,cAAc,eAAe;AAC7B,cAAc,MAAM;AACpB;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACjGD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,eAAe,mBAAmB;AAClC;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACvBD;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA,aAAa;AACb,eAAe;AACf,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED,wBAAwB;AACxB;AACA;AACA,YAAY,oBAAoB;AAChC,YAAY,oBAAoB;;AAEhC;AACA,cAAc,YAAY;;AAE1B;AACA,gBAAgB,aAAa;AAC7B,wBAAwB,aAAa;;AAErC;AACA,YAAY,WAAW;AACvB,oBAAoB,WAAW;;AAE/B;AACA,YAAY,kCAAkC;AAC9C,cAAc;AACd,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oBAAoB,wBAAwB;AAC5C;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA,oBAAoB,wBAAwB;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACjGD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA,sBAAsB;AACtB,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED,wBAAwB;AACxB;AACA,qBAAqB,YAAY;AACjC,qBAAqB,YAAY;AACjC,qBAAqB,WAAW;AAChC,qBAAqB,WAAW;AAChC,qBAAqB;AACrB,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,CAAC;;;;;;;;;;;ACpED,mBAAO,CAAC,4CAAU;AAClB,mBAAO,CAAC,8CAAW;AACnB,mBAAO,CAAC,4CAAU;;;;;;;;;;;;ACFlB;;;;;;;;;;;;;;;;;ACIe;AACuC;;AAEtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,yBAAyB,wCAAK;;AAE9B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,0BAA0B;;AAE7C;AACA;AACA,iCAAiC,0CAAO;;AAExC;;AAEA;;AAEA,mCAAmC,0CAAO;;AAE1C;;AAEA,8GAA8G;;AAE9G;AACA,iBAAiB,mEAA2B;;AAE5C;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,qCAAqC,0CAAO;;AAE5C;;AAEA;AACA,eAAe,uEAA+B;AAC9C;;AAEA;;AAEA;;AAEA;;AAEsB;;;;;;;;;;;;;;;;;;;;;;;;;;AC5EP;;AAEf;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,IAAI;;AAEJ;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,kBAAkB,QAAQ;;AAE1B;AACA;;AAEA;;AAEA,mBAAmB,OAAO;;AAE1B;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,eAAe,0CAAO;;AAEtB,kBAAkB,QAAQ;;AAE1B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,kBAAkB,QAAQ;AAC1B;;AAEA;;AAEA,kBAAkB,QAAQ;AAC1B;;AAEA;;AAEA,kBAAkB,QAAQ;AAC1B;;AAEA;;AAEA;AACA;;AAEA,kBAAkB,QAAQ;;AAE1B;AACA;;AAEA;;AAEA,mBAAmB,OAAO;;AAE1B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,kBAAkB,QAAQ;;AAE1B;;AAEA;;AAEA,kBAAkB,QAAQ;;AAE1B;AACA;;AAEA;AACA,mBAAmB,QAAQ;;AAE3B;;AAEA;;AAEA;;AAEA,mBAAmB,QAAQ;;AAE3B;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA,qBAAqB,SAAS;;AAE9B;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,kBAAkB,QAAQ;;AAE1B,mBAAmB,QAAQ;;AAE3B;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB,cAAc;;AAEhC;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA,kBAAkB,SAAS;;AAE3B;;AAEA,mBAAmB,QAAQ;;AAE3B;;AAEA;;AAEA;;AAEA;;AAEA,uBAAuB,aAAa;;AAEpC,gBAAgB,0CAAO;;AAEvB;;AAEA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,kBAAkB,QAAQ;;AAE1B;;AAEA;;AAEA;;AAEA,kBAAkB,QAAQ;;AAE1B;;AAEA;;AAEA,kBAAkB,YAAY;;AAE9B;;AAEA;;AAEA;;AAEA;;;AAGA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,kBAAkB,QAAQ;;AAE1B;AACA,mBAAmB,0CAAO;AAC1B;;AAEA;;AAEA;;AAEA,kBAAkB,QAAQ;;AAE1B;;AAEA,mBAAmB,QAAQ;;AAE3B;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB,QAAQ;;AAE1B,kBAAkB,0CAAO;AACzB,mBAAmB,QAAQ;;AAE3B;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA,gBAAgB,0CAAO;AACvB,kBAAkB,QAAQ;;AAE1B;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB,QAAQ;;AAE1B;;AAEA,mBAAmB,QAAQ;;AAE3B,wBAAwB,0CAAO;AAC/B,oBAAoB,QAAQ;;AAE5B;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA,gBAAgB,0CAAO;AACvB,kBAAkB,QAAQ;AAC1B,mBAAmB,QAAQ;;AAE3B;;AAEA;AACA;;AAEA;AACA;;AAEA;;;AAcE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7hBF;AACA;AACA;AACA;AACA;AACA;;AAEA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,qCAAqC,UAAU,aAAa,+BAA+B,EAAE;AAC3G,SAAS,yBAAyB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA,oBAAoB,QAAQ;AAC5B,2BAA2B,cAAc;AACzC;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,4DAA4D;AAC5D;AACA;AACA;AACA;AACA,gBAAgB,WAAW;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA,gBAAgB,QAAQ;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,QAAQ;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA,gBAAgB,SAAS;AACzB;AACA,kBAAkB,SAAS;AAC3B;AACA,kBAAkB,SAAS;AAC3B;AACA,kBAAkB,SAAS;AAC3B;AACA;AACA;AACA,gBAAgB,QAAQ;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,cAAc;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,WAAW;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,OAAO;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,WAAW;AACtC;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,cAAc;AAClC;AACA,qBAAqB,eAAe;AACpC;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA,iBAAiB;AACjB;AACA,6BAA6B,mBAAmB;AAChD;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,wCAAwC;AAC1E,eAAe,OAAO;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,cAAc;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA,uBAAuB,WAAW;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,SAAS;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iBAAiB;AACrC;AACA,oBAAoB,iBAAiB;AACrC;AACA;AACA;AACA,WAAW,kCAAkC;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,UAAU;AAClC;AACA;AACA;AACA,yBAAyB,QAAQ;AACjC;AACA,4BAA4B,iBAAiB;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,WAAW;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,SAAS;AAC7C;AACA,oCAAoC,QAAQ;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,6CAA6C;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gDAAgD,SAAS;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,OAAO;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,aAAa;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,SAAS;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,cAAc;AAC1C;AACA;AACA,SAAS;AACT,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,OAAO;AACnC;AACA,uBAAuB,OAAO;AAC9B;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC;AACjC,wBAAwB,OAAO;AAC/B;AACA,mBAAmB;AACnB;AACA,mBAAmB;AACnB,2BAA2B,sBAAsB,sCAAsC,kCAAkC;AACzH;AACA;AACA,2BAA2B;AAC3B,0BAA0B;AAC1B;AACA,wBAAwB;AACxB;AACA,yBAAyB;AACzB;AACA,wBAAwB;AACxB;AACA,yBAAyB;AACzB;AACA,2BAA2B;AAC3B;AACA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,yBAAyB;AACzB;AACA;AACA;AACA,0CAA0C;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC;AACnC;AACA,mCAAmC;AACnC;AACA;AACA;AACA,2BAA2B;AAC3B;AACA,2BAA2B;AAC3B,2BAA2B;AAC3B;AACA;AACA,WAAW,GAAG;AACd;AACA;AACA;AACA;AACA;AACA,8FAA8F;AAC9F;AACA;AACA;AACA;AACA,wBAAwB,gBAAgB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,QAAQ;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACkB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,CAAC;AACuB;AACjB;AACP;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,kDAAkD;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACkB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,CAAC;AACuB;AACjB;AACP;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,wDAAwD;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP,yBAAyB,MAAM;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACe;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,CAAC;AACoB;AACd;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB,uBAAuB,+CAA+C;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA,CAAC;AACiB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA,gDAAgD;AAChD;AACA,SAAS,4BAA4B,kDAAkD;AACvF;AACA;AACA,CAAC;AACsB;AAChB;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB,uBAAuB,iDAAiD;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA,0CAA0C,MAAM;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACe;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,CAAC;AACoB;AACd;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB,uBAAuB,+CAA+C;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACiB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,CAAC;AACsB;AAChB;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB,uBAAuB,uDAAuD;AAC9E;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP,0EAA0E,MAAM;AAChF;AACA;AACwD;AACF;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACqB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAC0B;AACpB;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,cAAc;AAClC;AACA;AACA;AACA;AACA;AACA,4BAA4B;AAC5B;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C,cAAc;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACqB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACqB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,wBAAwB,gBAAgB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,wBAAwB,gBAAgB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,eAAe;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACyB;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACqB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAC0B;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,oBAAoB;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,sCAAsC,gBAAgB;AACtD;AACA;AACA;AACA;AACA,sCAAsC,gBAAgB;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC,gBAAgB;AACtD;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACc;AACR;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,iBAAiB;AACzC;AACA;AACA;AACA,yBAAyB,WAAW;AACpC;AACA,qBAAqB,WAAW;AAChC;AACA;AACA;AACA,wBAAwB,UAAU;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,UAAU;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,oBAAoB,kBAAkB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAC2B;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACuB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AAC4B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8EAA8E;AAC9E,sEAAsE,oBAAoB;AAC1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mBAAmB,WAAW;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACgB;AACjB,+HAA+H;AACxH;AACP;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,iBAAiB;AACzC;AACA;AACA;AACA;AACA,yBAAyB,WAAW;AACpC;AACA,qBAAqB,WAAW;AAChC;AACA,WAAW,0BAA0B;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0DAA0D,iBAAiB;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA,kDAAkD,UAAU;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,OAAO;AAC/B;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,WAAW,0BAA0B;AACrC;AACA;AACA;AACA;AACA;AAC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tD;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,iCAAiC;AACjC;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,QAAQ;;AAER;;AAEA,QAAQ;;AAER;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA,+CAA+C,OAAO;;AAEtD;;AAEA;;AAEA;;AAEA;AACA,iCAAiC;AACjC;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA,+CAA+C,OAAO;;AAEtD;;AA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CA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,KAAK;;AAEL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,cAAc,2DAAwB;;AAEtC;;AAEA;;AAEA;;AAEqB;;;;;;;UCpgBrB;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;;;;WCtBA;WACA;WACA;WACA;WACA;WACA,iCAAiC,WAAW;WAC5C;WACA;;;;;WCPA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA;;;;;WCPA;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;;;;;;ACNA,mBAAO,CAAC,+CAAgB;AACxB,mBAAO,CAAC,6CAAe;AACvB,mBAAO,CAAC,uCAAY;AACpB,mBAAO,CAAC,qDAAmB;AAC3B,mBAAO,CAAC,mDAAkB","sources":["webpack://aframe-extras/webpack/universalModuleDefinition","webpack://aframe-extras/./lib/GamepadButton.js","webpack://aframe-extras/./lib/GamepadButtonEvent.js","webpack://aframe-extras/./lib/fetch-script.js","webpack://aframe-extras/./lib/keyboard.polyfill.js","webpack://aframe-extras/./node_modules/nipplejs/dist/nipplejs.js","webpack://aframe-extras/./node_modules/three-pathfinding/dist/three-pathfinding.module.js","webpack://aframe-extras/./src/controls/checkpoint-controls.js","webpack://aframe-extras/./src/controls/gamepad-controls.js","webpack://aframe-extras/./src/controls/index.js","webpack://aframe-extras/./src/controls/keyboard-controls.js","webpack://aframe-extras/./src/controls/movement-controls.js","webpack://aframe-extras/./src/controls/nipple-controls.js","webpack://aframe-extras/./src/controls/touch-controls.js","webpack://aframe-extras/./src/controls/trackpad-controls.js","webpack://aframe-extras/./src/loaders/animation-mixer.js","webpack://aframe-extras/./src/loaders/collada-model-legacy.js","webpack://aframe-extras/./src/loaders/fbx-model.js","webpack://aframe-extras/./src/loaders/gltf-model-legacy.js","webpack://aframe-extras/./src/loaders/index.js","webpack://aframe-extras/./src/loaders/object-model.js","webpack://aframe-extras/./src/misc/checkpoint.js","webpack://aframe-extras/./src/misc/cube-env-map.js","webpack://aframe-extras/./src/misc/grab.js","webpack://aframe-extras/./src/misc/index.js","webpack://aframe-extras/./src/misc/normal-material.js","webpack://aframe-extras/./src/misc/sphere-collider.js","webpack://aframe-extras/./src/pathfinding/index.js","webpack://aframe-extras/./src/pathfinding/nav-agent.js","webpack://aframe-extras/./src/pathfinding/nav-mesh.js","webpack://aframe-extras/./src/pathfinding/system.js","webpack://aframe-extras/./src/primitives/a-grid.js","webpack://aframe-extras/./src/primitives/a-ocean.js","webpack://aframe-extras/./src/primitives/a-tube.js","webpack://aframe-extras/./src/primitives/index.js","webpack://aframe-extras/external umd \"THREE\"","webpack://aframe-extras/./node_modules/three/examples/jsm/curves/NURBSCurve.js","webpack://aframe-extras/./node_modules/three/examples/jsm/curves/NURBSUtils.js","webpack://aframe-extras/./node_modules/three/examples/jsm/libs/fflate.module.js","webpack://aframe-extras/./node_modules/three/examples/jsm/loaders/ColladaLoader.js","webpack://aframe-extras/./node_modules/three/examples/jsm/loaders/FBXLoader.js","webpack://aframe-extras/./node_modules/three/examples/jsm/loaders/TGALoader.js","webpack://aframe-extras/webpack/bootstrap","webpack://aframe-extras/webpack/runtime/compat get default export","webpack://aframe-extras/webpack/runtime/define property getters","webpack://aframe-extras/webpack/runtime/hasOwnProperty shorthand","webpack://aframe-extras/webpack/runtime/make namespace object","webpack://aframe-extras/./index.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"THREE\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"THREE\"], factory);\n\telse {\n\t\tvar a = typeof exports === 'object' ? factory(require(\"THREE\")) : factory(root[\"THREE\"]);\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(self, (__WEBPACK_EXTERNAL_MODULE_three__) => {\nreturn ","module.exports = Object.assign(function GamepadButton () {}, {\n\tFACE_1: 0,\n\tFACE_2: 1,\n\tFACE_3: 2,\n\tFACE_4: 3,\n\n\tL_SHOULDER_1: 4,\n\tR_SHOULDER_1: 5,\n\tL_SHOULDER_2: 6,\n\tR_SHOULDER_2: 7,\n\n\tSELECT: 8,\n\tSTART: 9,\n\n\tDPAD_UP: 12,\n\tDPAD_DOWN: 13,\n\tDPAD_LEFT: 14,\n\tDPAD_RIGHT: 15,\n\n\tVENDOR: 16,\n});\n","function GamepadButtonEvent (type, index, details) {\n  this.type = type;\n  this.index = index;\n  this.pressed = details.pressed;\n  this.value = details.value;\n}\n\nmodule.exports = GamepadButtonEvent;\n","/**\n * Source: https://github.com/Adobe-Marketing-Cloud/fetch-script\n */\n\nfunction getScriptId() {\n  return 'script_' + Date.now() + '_' + Math.ceil(Math.random() * 100000);\n}\n\nfunction createScript(url, id) {\n  var script = document.createElement('script');\n  script.type = 'text/javascript';\n  script.async = true;\n  script.id = id;\n  script.src = url;\n\n  return script;\n}\n\nfunction removeScript(id) {\n  const script = document.getElementById(id);\n  const parent = script.parentNode;\n\n  try {\n    parent && parent.removeChild(script);\n  } catch (e) {\n    // ignore\n  }\n}\n\nfunction appendScript(script) {\n  const firstScript = document.getElementsByTagName('script')[0];\n  firstScript.parentNode.insertBefore(script, firstScript);\n}\n\nfunction fetchScriptInternal(url, options, Promise) {\n  return new Promise(function(resolve, reject) {\n    const timeout = options.timeout || 5000;\n    const scriptId = getScriptId();\n    const script = createScript(url, scriptId);\n\n    const timeoutId = setTimeout(function() {\n      reject(new Error('Script request to ' + url + ' timed out'));\n\n      removeScript(scriptId);\n    }, timeout);\n\n    const disableTimeout = function(timeoutId) { clearTimeout(timeoutId); };\n\n    script.addEventListener('load', function(e) {\n      resolve({ok: true});\n\n      disableTimeout(timeoutId);\n      removeScript(scriptId);\n    });\n\n    script.addEventListener('error', function(e) {\n      reject(new Error('Script request to ' + url + ' failed ' + e));\n\n      disableTimeout(timeoutId);\n      removeScript(scriptId);\n    });\n\n    appendScript(script);\n  });\n}\n\nfunction fetchScript(settings) {\n  settings = settings || {};\n  return function (url, options) {\n    options = options || {};\n    return fetchScriptInternal(url, options, settings.Promise || Promise);\n  };\n}\n\nmodule.exports = fetchScript;\n","/**\n * Polyfill for the additional KeyboardEvent properties defined in the D3E and\n * D4E draft specifications, by @inexorabletash.\n *\n * See: https://github.com/inexorabletash/polyfill\n */\n(function(global) {\n  var nativeKeyboardEvent = ('KeyboardEvent' in global);\n  if (!nativeKeyboardEvent)\n    global.KeyboardEvent = function KeyboardEvent() { throw TypeError('Illegal constructor'); };\n\n  if (!('DOM_KEY_LOCATION_STANDARD' in global.KeyboardEvent)) global.KeyboardEvent.DOM_KEY_LOCATION_STANDARD = 0x00; // Default or unknown location\n  if (!('DOM_KEY_LOCATION_LEFT' in global.KeyboardEvent)) global.KeyboardEvent.DOM_KEY_LOCATION_LEFT          = 0x01; // e.g. Left Alt key\n  if (!('DOM_KEY_LOCATION_RIGHT' in global.KeyboardEvent)) global.KeyboardEvent.DOM_KEY_LOCATION_RIGHT         = 0x02; // e.g. Right Alt key\n  if (!('DOM_KEY_LOCATION_NUMPAD' in global.KeyboardEvent)) global.KeyboardEvent.DOM_KEY_LOCATION_NUMPAD        = 0x03; // e.g. Numpad 0 or +\n\n  var STANDARD = window.KeyboardEvent.DOM_KEY_LOCATION_STANDARD,\n      LEFT = window.KeyboardEvent.DOM_KEY_LOCATION_LEFT,\n      RIGHT = window.KeyboardEvent.DOM_KEY_LOCATION_RIGHT,\n      NUMPAD = window.KeyboardEvent.DOM_KEY_LOCATION_NUMPAD;\n\n  //--------------------------------------------------------------------\n  //\n  // Utilities\n  //\n  //--------------------------------------------------------------------\n\n  function contains(s, ss) { return String(s).indexOf(ss) !== -1; }\n\n  var os = (function() {\n    if (contains(navigator.platform, 'Win')) { return 'win'; }\n    if (contains(navigator.platform, 'Mac')) { return 'mac'; }\n    if (contains(navigator.platform, 'CrOS')) { return 'cros'; }\n    if (contains(navigator.platform, 'Linux')) { return 'linux'; }\n    if (contains(navigator.userAgent, 'iPad') || contains(navigator.platform, 'iPod') || contains(navigator.platform, 'iPhone')) { return 'ios'; }\n    return '';\n  } ());\n\n  var browser = (function() {\n    if (contains(navigator.userAgent, 'Chrome/')) { return 'chrome'; }\n    if (contains(navigator.vendor, 'Apple')) { return 'safari'; }\n    if (contains(navigator.userAgent, 'MSIE')) { return 'ie'; }\n    if (contains(navigator.userAgent, 'Gecko/')) { return 'moz'; }\n    if (contains(navigator.userAgent, 'Opera/')) { return 'opera'; }\n    return '';\n  } ());\n\n  var browser_os = browser + '-' + os;\n\n  function mergeIf(baseTable, select, table) {\n    if (browser_os === select || browser === select || os === select) {\n      Object.keys(table).forEach(function(keyCode) {\n        baseTable[keyCode] = table[keyCode];\n      });\n    }\n  }\n\n  function remap(o, key) {\n    var r = {};\n    Object.keys(o).forEach(function(k) {\n      var item = o[k];\n      if (key in item) {\n        r[item[key]] = item;\n      }\n    });\n    return r;\n  }\n\n  function invert(o) {\n    var r = {};\n    Object.keys(o).forEach(function(k) {\n      r[o[k]] = k;\n    });\n    return r;\n  }\n\n  //--------------------------------------------------------------------\n  //\n  // Generic Mappings\n  //\n  //--------------------------------------------------------------------\n\n  // \"keyInfo\" is a dictionary:\n  //   code: string - name from DOM Level 3 KeyboardEvent code Values\n  //     https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-code.html\n  //   location (optional): number - one of the DOM_KEY_LOCATION values\n  //   keyCap (optional): string - keyboard label in en-US locale\n  // USB code Usage ID from page 0x07 unless otherwise noted (Informative)\n\n  // Map of keyCode to keyInfo\n  var keyCodeToInfoTable = {\n    // 0x01 - VK_LBUTTON\n    // 0x02 - VK_RBUTTON\n    0x03: { code: 'Cancel' }, // [USB: 0x9b] char \\x0018 ??? (Not in D3E)\n    // 0x04 - VK_MBUTTON\n    // 0x05 - VK_XBUTTON1\n    // 0x06 - VK_XBUTTON2\n    0x06: { code: 'Help' }, // [USB: 0x75] ???\n    // 0x07 - undefined\n    0x08: { code: 'Backspace' }, // [USB: 0x2a] Labelled Delete on Macintosh keyboards.\n    0x09: { code: 'Tab' }, // [USB: 0x2b]\n    // 0x0A-0x0B - reserved\n    0X0C: { code: 'Clear' }, // [USB: 0x9c] NumPad Center (Not in D3E)\n    0X0D: { code: 'Enter' }, // [USB: 0x28]\n    // 0x0E-0x0F - undefined\n\n    0x10: { code: 'Shift' },\n    0x11: { code: 'Control' },\n    0x12: { code: 'Alt' },\n    0x13: { code: 'Pause' }, // [USB: 0x48]\n    0x14: { code: 'CapsLock' }, // [USB: 0x39]\n    0x15: { code: 'KanaMode' }, // [USB: 0x88] - \"HangulMode\" for Korean layout\n    0x16: { code: 'HangulMode' }, // [USB: 0x90] 0x15 as well in MSDN VK table ???\n    0x17: { code: 'JunjaMode' }, // (Not in D3E)\n    0x18: { code: 'FinalMode' }, // (Not in D3E)\n    0x19: { code: 'KanjiMode' }, // [USB: 0x91] - \"HanjaMode\" for Korean layout\n    // 0x1A - undefined\n    0x1B: { code: 'Escape' }, // [USB: 0x29]\n    0x1C: { code: 'Convert' }, // [USB: 0x8a]\n    0x1D: { code: 'NonConvert' }, // [USB: 0x8b]\n    0x1E: { code: 'Accept' }, // (Not in D3E)\n    0x1F: { code: 'ModeChange' }, // (Not in D3E)\n\n    0x20: { code: 'Space' }, // [USB: 0x2c]\n    0x21: { code: 'PageUp' }, // [USB: 0x4b]\n    0x22: { code: 'PageDown' }, // [USB: 0x4e]\n    0x23: { code: 'End' }, // [USB: 0x4d]\n    0x24: { code: 'Home' }, // [USB: 0x4a]\n    0x25: { code: 'ArrowLeft' }, // [USB: 0x50]\n    0x26: { code: 'ArrowUp' }, // [USB: 0x52]\n    0x27: { code: 'ArrowRight' }, // [USB: 0x4f]\n    0x28: { code: 'ArrowDown' }, // [USB: 0x51]\n    0x29: { code: 'Select' }, // (Not in D3E)\n    0x2A: { code: 'Print' }, // (Not in D3E)\n    0x2B: { code: 'Execute' }, // [USB: 0x74] (Not in D3E)\n    0x2C: { code: 'PrintScreen' }, // [USB: 0x46]\n    0x2D: { code: 'Insert' }, // [USB: 0x49]\n    0x2E: { code: 'Delete' }, // [USB: 0x4c]\n    0x2F: { code: 'Help' }, // [USB: 0x75] ???\n\n    0x30: { code: 'Digit0', keyCap: '0' }, // [USB: 0x27] 0)\n    0x31: { code: 'Digit1', keyCap: '1' }, // [USB: 0x1e] 1!\n    0x32: { code: 'Digit2', keyCap: '2' }, // [USB: 0x1f] 2@\n    0x33: { code: 'Digit3', keyCap: '3' }, // [USB: 0x20] 3#\n    0x34: { code: 'Digit4', keyCap: '4' }, // [USB: 0x21] 4$\n    0x35: { code: 'Digit5', keyCap: '5' }, // [USB: 0x22] 5%\n    0x36: { code: 'Digit6', keyCap: '6' }, // [USB: 0x23] 6^\n    0x37: { code: 'Digit7', keyCap: '7' }, // [USB: 0x24] 7&\n    0x38: { code: 'Digit8', keyCap: '8' }, // [USB: 0x25] 8*\n    0x39: { code: 'Digit9', keyCap: '9' }, // [USB: 0x26] 9(\n    // 0x3A-0x40 - undefined\n\n    0x41: { code: 'KeyA', keyCap: 'a' }, // [USB: 0x04]\n    0x42: { code: 'KeyB', keyCap: 'b' }, // [USB: 0x05]\n    0x43: { code: 'KeyC', keyCap: 'c' }, // [USB: 0x06]\n    0x44: { code: 'KeyD', keyCap: 'd' }, // [USB: 0x07]\n    0x45: { code: 'KeyE', keyCap: 'e' }, // [USB: 0x08]\n    0x46: { code: 'KeyF', keyCap: 'f' }, // [USB: 0x09]\n    0x47: { code: 'KeyG', keyCap: 'g' }, // [USB: 0x0a]\n    0x48: { code: 'KeyH', keyCap: 'h' }, // [USB: 0x0b]\n    0x49: { code: 'KeyI', keyCap: 'i' }, // [USB: 0x0c]\n    0x4A: { code: 'KeyJ', keyCap: 'j' }, // [USB: 0x0d]\n    0x4B: { code: 'KeyK', keyCap: 'k' }, // [USB: 0x0e]\n    0x4C: { code: 'KeyL', keyCap: 'l' }, // [USB: 0x0f]\n    0x4D: { code: 'KeyM', keyCap: 'm' }, // [USB: 0x10]\n    0x4E: { code: 'KeyN', keyCap: 'n' }, // [USB: 0x11]\n    0x4F: { code: 'KeyO', keyCap: 'o' }, // [USB: 0x12]\n\n    0x50: { code: 'KeyP', keyCap: 'p' }, // [USB: 0x13]\n    0x51: { code: 'KeyQ', keyCap: 'q' }, // [USB: 0x14]\n    0x52: { code: 'KeyR', keyCap: 'r' }, // [USB: 0x15]\n    0x53: { code: 'KeyS', keyCap: 's' }, // [USB: 0x16]\n    0x54: { code: 'KeyT', keyCap: 't' }, // [USB: 0x17]\n    0x55: { code: 'KeyU', keyCap: 'u' }, // [USB: 0x18]\n    0x56: { code: 'KeyV', keyCap: 'v' }, // [USB: 0x19]\n    0x57: { code: 'KeyW', keyCap: 'w' }, // [USB: 0x1a]\n    0x58: { code: 'KeyX', keyCap: 'x' }, // [USB: 0x1b]\n    0x59: { code: 'KeyY', keyCap: 'y' }, // [USB: 0x1c]\n    0x5A: { code: 'KeyZ', keyCap: 'z' }, // [USB: 0x1d]\n    0x5B: { code: 'OSLeft', location: LEFT }, // [USB: 0xe3]\n    0x5C: { code: 'OSRight', location: RIGHT }, // [USB: 0xe7]\n    0x5D: { code: 'ContextMenu' }, // [USB: 0x65] Context Menu\n    // 0x5E - reserved\n    0x5F: { code: 'Standby' }, // [USB: 0x82] Sleep\n\n    0x60: { code: 'Numpad0', keyCap: '0', location: NUMPAD }, // [USB: 0x62]\n    0x61: { code: 'Numpad1', keyCap: '1', location: NUMPAD }, // [USB: 0x59]\n    0x62: { code: 'Numpad2', keyCap: '2', location: NUMPAD }, // [USB: 0x5a]\n    0x63: { code: 'Numpad3', keyCap: '3', location: NUMPAD }, // [USB: 0x5b]\n    0x64: { code: 'Numpad4', keyCap: '4', location: NUMPAD }, // [USB: 0x5c]\n    0x65: { code: 'Numpad5', keyCap: '5', location: NUMPAD }, // [USB: 0x5d]\n    0x66: { code: 'Numpad6', keyCap: '6', location: NUMPAD }, // [USB: 0x5e]\n    0x67: { code: 'Numpad7', keyCap: '7', location: NUMPAD }, // [USB: 0x5f]\n    0x68: { code: 'Numpad8', keyCap: '8', location: NUMPAD }, // [USB: 0x60]\n    0x69: { code: 'Numpad9', keyCap: '9', location: NUMPAD }, // [USB: 0x61]\n    0x6A: { code: 'NumpadMultiply', keyCap: '*', location: NUMPAD }, // [USB: 0x55]\n    0x6B: { code: 'NumpadAdd', keyCap: '+', location: NUMPAD }, // [USB: 0x57]\n    0x6C: { code: 'NumpadComma', keyCap: ',', location: NUMPAD }, // [USB: 0x85]\n    0x6D: { code: 'NumpadSubtract', keyCap: '-', location: NUMPAD }, // [USB: 0x56]\n    0x6E: { code: 'NumpadDecimal', keyCap: '.', location: NUMPAD }, // [USB: 0x63]\n    0x6F: { code: 'NumpadDivide', keyCap: '/', location: NUMPAD }, // [USB: 0x54]\n\n    0x70: { code: 'F1' }, // [USB: 0x3a]\n    0x71: { code: 'F2' }, // [USB: 0x3b]\n    0x72: { code: 'F3' }, // [USB: 0x3c]\n    0x73: { code: 'F4' }, // [USB: 0x3d]\n    0x74: { code: 'F5' }, // [USB: 0x3e]\n    0x75: { code: 'F6' }, // [USB: 0x3f]\n    0x76: { code: 'F7' }, // [USB: 0x40]\n    0x77: { code: 'F8' }, // [USB: 0x41]\n    0x78: { code: 'F9' }, // [USB: 0x42]\n    0x79: { code: 'F10' }, // [USB: 0x43]\n    0x7A: { code: 'F11' }, // [USB: 0x44]\n    0x7B: { code: 'F12' }, // [USB: 0x45]\n    0x7C: { code: 'F13' }, // [USB: 0x68]\n    0x7D: { code: 'F14' }, // [USB: 0x69]\n    0x7E: { code: 'F15' }, // [USB: 0x6a]\n    0x7F: { code: 'F16' }, // [USB: 0x6b]\n\n    0x80: { code: 'F17' }, // [USB: 0x6c]\n    0x81: { code: 'F18' }, // [USB: 0x6d]\n    0x82: { code: 'F19' }, // [USB: 0x6e]\n    0x83: { code: 'F20' }, // [USB: 0x6f]\n    0x84: { code: 'F21' }, // [USB: 0x70]\n    0x85: { code: 'F22' }, // [USB: 0x71]\n    0x86: { code: 'F23' }, // [USB: 0x72]\n    0x87: { code: 'F24' }, // [USB: 0x73]\n    // 0x88-0x8F - unassigned\n\n    0x90: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]\n    0x91: { code: 'ScrollLock' }, // [USB: 0x47]\n    // 0x92-0x96 - OEM specific\n    // 0x97-0x9F - unassigned\n\n    // NOTE: 0xA0-0xA5 usually mapped to 0x10-0x12 in browsers\n    0xA0: { code: 'ShiftLeft', location: LEFT }, // [USB: 0xe1]\n    0xA1: { code: 'ShiftRight', location: RIGHT }, // [USB: 0xe5]\n    0xA2: { code: 'ControlLeft', location: LEFT }, // [USB: 0xe0]\n    0xA3: { code: 'ControlRight', location: RIGHT }, // [USB: 0xe4]\n    0xA4: { code: 'AltLeft', location: LEFT }, // [USB: 0xe2]\n    0xA5: { code: 'AltRight', location: RIGHT }, // [USB: 0xe6]\n\n    0xA6: { code: 'BrowserBack' }, // [USB: 0x0c/0x0224]\n    0xA7: { code: 'BrowserForward' }, // [USB: 0x0c/0x0225]\n    0xA8: { code: 'BrowserRefresh' }, // [USB: 0x0c/0x0227]\n    0xA9: { code: 'BrowserStop' }, // [USB: 0x0c/0x0226]\n    0xAA: { code: 'BrowserSearch' }, // [USB: 0x0c/0x0221]\n    0xAB: { code: 'BrowserFavorites' }, // [USB: 0x0c/0x0228]\n    0xAC: { code: 'BrowserHome' }, // [USB: 0x0c/0x0222]\n    0xAD: { code: 'VolumeMute' }, // [USB: 0x7f]\n    0xAE: { code: 'VolumeDown' }, // [USB: 0x81]\n    0xAF: { code: 'VolumeUp' }, // [USB: 0x80]\n\n    0xB0: { code: 'MediaTrackNext' }, // [USB: 0x0c/0x00b5]\n    0xB1: { code: 'MediaTrackPrevious' }, // [USB: 0x0c/0x00b6]\n    0xB2: { code: 'MediaStop' }, // [USB: 0x0c/0x00b7]\n    0xB3: { code: 'MediaPlayPause' }, // [USB: 0x0c/0x00cd]\n    0xB4: { code: 'LaunchMail' }, // [USB: 0x0c/0x018a]\n    0xB5: { code: 'MediaSelect' },\n    0xB6: { code: 'LaunchApp1' },\n    0xB7: { code: 'LaunchApp2' },\n    // 0xB8-0xB9 - reserved\n    0xBA: { code: 'Semicolon',  keyCap: ';' }, // [USB: 0x33] ;: (US Standard 101)\n    0xBB: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+\n    0xBC: { code: 'Comma', keyCap: ',' }, // [USB: 0x36] ,<\n    0xBD: { code: 'Minus', keyCap: '-' }, // [USB: 0x2d] -_\n    0xBE: { code: 'Period', keyCap: '.' }, // [USB: 0x37] .>\n    0xBF: { code: 'Slash', keyCap: '/' }, // [USB: 0x38] /? (US Standard 101)\n\n    0xC0: { code: 'Backquote', keyCap: '`' }, // [USB: 0x35] `~ (US Standard 101)\n    // 0xC1-0xCF - reserved\n\n    // 0xD0-0xD7 - reserved\n    // 0xD8-0xDA - unassigned\n    0xDB: { code: 'BracketLeft', keyCap: '[' }, // [USB: 0x2f] [{ (US Standard 101)\n    0xDC: { code: 'Backslash',  keyCap: '\\\\' }, // [USB: 0x31] \\| (US Standard 101)\n    0xDD: { code: 'BracketRight', keyCap: ']' }, // [USB: 0x30] ]} (US Standard 101)\n    0xDE: { code: 'Quote', keyCap: '\\'' }, // [USB: 0x34] '\" (US Standard 101)\n    // 0xDF - miscellaneous/varies\n\n    // 0xE0 - reserved\n    // 0xE1 - OEM specific\n    0xE2: { code: 'IntlBackslash',  keyCap: '\\\\' }, // [USB: 0x64] \\| (UK Standard 102)\n    // 0xE3-0xE4 - OEM specific\n    0xE5: { code: 'Process' }, // (Not in D3E)\n    // 0xE6 - OEM specific\n    // 0xE7 - VK_PACKET\n    // 0xE8 - unassigned\n    // 0xE9-0xEF - OEM specific\n\n    // 0xF0-0xF5 - OEM specific\n    0xF6: { code: 'Attn' }, // [USB: 0x9a] (Not in D3E)\n    0xF7: { code: 'CrSel' }, // [USB: 0xa3] (Not in D3E)\n    0xF8: { code: 'ExSel' }, // [USB: 0xa4] (Not in D3E)\n    0xF9: { code: 'EraseEof' }, // (Not in D3E)\n    0xFA: { code: 'Play' }, // (Not in D3E)\n    0xFB: { code: 'ZoomToggle' }, // (Not in D3E)\n    // 0xFC - VK_NONAME - reserved\n    // 0xFD - VK_PA1\n    0xFE: { code: 'Clear' } // [USB: 0x9c] (Not in D3E)\n  };\n\n  // No legacy keyCode, but listed in D3E:\n\n  // code: usb\n  // 'IntlHash': 0x070032,\n  // 'IntlRo': 0x070087,\n  // 'IntlYen': 0x070089,\n  // 'NumpadBackspace': 0x0700bb,\n  // 'NumpadClear': 0x0700d8,\n  // 'NumpadClearEntry': 0x0700d9,\n  // 'NumpadMemoryAdd': 0x0700d3,\n  // 'NumpadMemoryClear': 0x0700d2,\n  // 'NumpadMemoryRecall': 0x0700d1,\n  // 'NumpadMemoryStore': 0x0700d0,\n  // 'NumpadMemorySubtract': 0x0700d4,\n  // 'NumpadParenLeft': 0x0700b6,\n  // 'NumpadParenRight': 0x0700b7,\n\n  //--------------------------------------------------------------------\n  //\n  // Browser/OS Specific Mappings\n  //\n  //--------------------------------------------------------------------\n\n  mergeIf(keyCodeToInfoTable,\n          'moz', {\n            0x3B: { code: 'Semicolon', keyCap: ';' }, // [USB: 0x33] ;: (US Standard 101)\n            0x3D: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+\n            0x6B: { code: 'Equal', keyCap: '=' }, // [USB: 0x2e] =+\n            0x6D: { code: 'Minus', keyCap: '-' }, // [USB: 0x2d] -_\n            0xBB: { code: 'NumpadAdd', keyCap: '+', location: NUMPAD }, // [USB: 0x57]\n            0xBD: { code: 'NumpadSubtract', keyCap: '-', location: NUMPAD } // [USB: 0x56]\n          });\n\n  mergeIf(keyCodeToInfoTable,\n          'moz-mac', {\n            0x0C: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]\n            0xAD: { code: 'Minus', keyCap: '-' } // [USB: 0x2d] -_\n          });\n\n  mergeIf(keyCodeToInfoTable,\n          'moz-win', {\n            0xAD: { code: 'Minus', keyCap: '-' } // [USB: 0x2d] -_\n          });\n\n  mergeIf(keyCodeToInfoTable,\n          'chrome-mac', {\n            0x5D: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]\n          });\n\n  // Windows via Bootcamp (!)\n  if (0) {\n    mergeIf(keyCodeToInfoTable,\n            'chrome-win', {\n              0xC0: { code: 'Quote', keyCap: '\\'' }, // [USB: 0x34] '\" (US Standard 101)\n              0xDE: { code: 'Backslash',  keyCap: '\\\\' }, // [USB: 0x31] \\| (US Standard 101)\n              0xDF: { code: 'Backquote', keyCap: '`' } // [USB: 0x35] `~ (US Standard 101)\n            });\n\n    mergeIf(keyCodeToInfoTable,\n            'ie', {\n              0xC0: { code: 'Quote', keyCap: '\\'' }, // [USB: 0x34] '\" (US Standard 101)\n              0xDE: { code: 'Backslash',  keyCap: '\\\\' }, // [USB: 0x31] \\| (US Standard 101)\n              0xDF: { code: 'Backquote', keyCap: '`' } // [USB: 0x35] `~ (US Standard 101)\n            });\n  }\n\n  mergeIf(keyCodeToInfoTable,\n          'safari', {\n            0x03: { code: 'Enter' }, // [USB: 0x28] old Safari\n            0x19: { code: 'Tab' } // [USB: 0x2b] old Safari for Shift+Tab\n          });\n\n  mergeIf(keyCodeToInfoTable,\n          'ios', {\n            0x0A: { code: 'Enter', location: STANDARD } // [USB: 0x28]\n          });\n\n  mergeIf(keyCodeToInfoTable,\n          'safari-mac', {\n            0x5B: { code: 'OSLeft', location: LEFT }, // [USB: 0xe3]\n            0x5D: { code: 'OSRight', location: RIGHT }, // [USB: 0xe7]\n            0xE5: { code: 'KeyQ', keyCap: 'Q' } // [USB: 0x14] On alternate presses, Ctrl+Q sends this\n          });\n\n  //--------------------------------------------------------------------\n  //\n  // Identifier Mappings\n  //\n  //--------------------------------------------------------------------\n\n  // Cases where newer-ish browsers send keyIdentifier which can be\n  // used to disambiguate keys.\n\n  // keyIdentifierTable[keyIdentifier] -> keyInfo\n\n  var keyIdentifierTable = {};\n  if ('cros' === os) {\n    keyIdentifierTable['U+00A0'] = { code: 'ShiftLeft', location: LEFT };\n    keyIdentifierTable['U+00A1'] = { code: 'ShiftRight', location: RIGHT };\n    keyIdentifierTable['U+00A2'] = { code: 'ControlLeft', location: LEFT };\n    keyIdentifierTable['U+00A3'] = { code: 'ControlRight', location: RIGHT };\n    keyIdentifierTable['U+00A4'] = { code: 'AltLeft', location: LEFT };\n    keyIdentifierTable['U+00A5'] = { code: 'AltRight', location: RIGHT };\n  }\n  if ('chrome-mac' === browser_os) {\n    keyIdentifierTable['U+0010'] = { code: 'ContextMenu' };\n  }\n  if ('safari-mac' === browser_os) {\n    keyIdentifierTable['U+0010'] = { code: 'ContextMenu' };\n  }\n  if ('ios' === os) {\n    // These only generate keyup events\n    keyIdentifierTable['U+0010'] = { code: 'Function' };\n\n    keyIdentifierTable['U+001C'] = { code: 'ArrowLeft' };\n    keyIdentifierTable['U+001D'] = { code: 'ArrowRight' };\n    keyIdentifierTable['U+001E'] = { code: 'ArrowUp' };\n    keyIdentifierTable['U+001F'] = { code: 'ArrowDown' };\n\n    keyIdentifierTable['U+0001'] = { code: 'Home' }; // [USB: 0x4a] Fn + ArrowLeft\n    keyIdentifierTable['U+0004'] = { code: 'End' }; // [USB: 0x4d] Fn + ArrowRight\n    keyIdentifierTable['U+000B'] = { code: 'PageUp' }; // [USB: 0x4b] Fn + ArrowUp\n    keyIdentifierTable['U+000C'] = { code: 'PageDown' }; // [USB: 0x4e] Fn + ArrowDown\n  }\n\n  //--------------------------------------------------------------------\n  //\n  // Location Mappings\n  //\n  //--------------------------------------------------------------------\n\n  // Cases where newer-ish browsers send location/keyLocation which\n  // can be used to disambiguate keys.\n\n  // locationTable[location][keyCode] -> keyInfo\n  var locationTable = [];\n  locationTable[LEFT] = {\n    0x10: { code: 'ShiftLeft', location: LEFT }, // [USB: 0xe1]\n    0x11: { code: 'ControlLeft', location: LEFT }, // [USB: 0xe0]\n    0x12: { code: 'AltLeft', location: LEFT } // [USB: 0xe2]\n  };\n  locationTable[RIGHT] = {\n    0x10: { code: 'ShiftRight', location: RIGHT }, // [USB: 0xe5]\n    0x11: { code: 'ControlRight', location: RIGHT }, // [USB: 0xe4]\n    0x12: { code: 'AltRight', location: RIGHT } // [USB: 0xe6]\n  };\n  locationTable[NUMPAD] = {\n    0x0D: { code: 'NumpadEnter', location: NUMPAD } // [USB: 0x58]\n  };\n\n  mergeIf(locationTable[NUMPAD], 'moz', {\n    0x6D: { code: 'NumpadSubtract', location: NUMPAD }, // [USB: 0x56]\n    0x6B: { code: 'NumpadAdd', location: NUMPAD } // [USB: 0x57]\n  });\n  mergeIf(locationTable[LEFT], 'moz-mac', {\n    0xE0: { code: 'OSLeft', location: LEFT } // [USB: 0xe3]\n  });\n  mergeIf(locationTable[RIGHT], 'moz-mac', {\n    0xE0: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]\n  });\n  mergeIf(locationTable[RIGHT], 'moz-win', {\n    0x5B: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]\n  });\n\n\n  mergeIf(locationTable[RIGHT], 'mac', {\n    0x5D: { code: 'OSRight', location: RIGHT } // [USB: 0xe7]\n  });\n\n  mergeIf(locationTable[NUMPAD], 'chrome-mac', {\n    0x0C: { code: 'NumLock', location: NUMPAD } // [USB: 0x53]\n  });\n\n  mergeIf(locationTable[NUMPAD], 'safari-mac', {\n    0x0C: { code: 'NumLock', location: NUMPAD }, // [USB: 0x53]\n    0xBB: { code: 'NumpadAdd', location: NUMPAD }, // [USB: 0x57]\n    0xBD: { code: 'NumpadSubtract', location: NUMPAD }, // [USB: 0x56]\n    0xBE: { code: 'NumpadDecimal', location: NUMPAD }, // [USB: 0x63]\n    0xBF: { code: 'NumpadDivide', location: NUMPAD } // [USB: 0x54]\n  });\n\n\n  //--------------------------------------------------------------------\n  //\n  // Key Values\n  //\n  //--------------------------------------------------------------------\n\n  // Mapping from `code` values to `key` values. Values defined at:\n  // https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3Events-key.html\n  // Entries are only provided when `key` differs from `code`. If\n  // printable, `shiftKey` has the shifted printable character. This\n  // assumes US Standard 101 layout\n\n  var codeToKeyTable = {\n    // Modifier Keys\n    ShiftLeft: { key: 'Shift' },\n    ShiftRight: { key: 'Shift' },\n    ControlLeft: { key: 'Control' },\n    ControlRight: { key: 'Control' },\n    AltLeft: { key: 'Alt' },\n    AltRight: { key: 'Alt' },\n    OSLeft: { key: 'OS' },\n    OSRight: { key: 'OS' },\n\n    // Whitespace Keys\n    NumpadEnter: { key: 'Enter' },\n    Space: { key: ' ' },\n\n    // Printable Keys\n    Digit0: { key: '0', shiftKey: ')' },\n    Digit1: { key: '1', shiftKey: '!' },\n    Digit2: { key: '2', shiftKey: '@' },\n    Digit3: { key: '3', shiftKey: '#' },\n    Digit4: { key: '4', shiftKey: '$' },\n    Digit5: { key: '5', shiftKey: '%' },\n    Digit6: { key: '6', shiftKey: '^' },\n    Digit7: { key: '7', shiftKey: '&' },\n    Digit8: { key: '8', shiftKey: '*' },\n    Digit9: { key: '9', shiftKey: '(' },\n    KeyA: { key: 'a', shiftKey: 'A' },\n    KeyB: { key: 'b', shiftKey: 'B' },\n    KeyC: { key: 'c', shiftKey: 'C' },\n    KeyD: { key: 'd', shiftKey: 'D' },\n    KeyE: { key: 'e', shiftKey: 'E' },\n    KeyF: { key: 'f', shiftKey: 'F' },\n    KeyG: { key: 'g', shiftKey: 'G' },\n    KeyH: { key: 'h', shiftKey: 'H' },\n    KeyI: { key: 'i', shiftKey: 'I' },\n    KeyJ: { key: 'j', shiftKey: 'J' },\n    KeyK: { key: 'k', shiftKey: 'K' },\n    KeyL: { key: 'l', shiftKey: 'L' },\n    KeyM: { key: 'm', shiftKey: 'M' },\n    KeyN: { key: 'n', shiftKey: 'N' },\n    KeyO: { key: 'o', shiftKey: 'O' },\n    KeyP: { key: 'p', shiftKey: 'P' },\n    KeyQ: { key: 'q', shiftKey: 'Q' },\n    KeyR: { key: 'r', shiftKey: 'R' },\n    KeyS: { key: 's', shiftKey: 'S' },\n    KeyT: { key: 't', shiftKey: 'T' },\n    KeyU: { key: 'u', shiftKey: 'U' },\n    KeyV: { key: 'v', shiftKey: 'V' },\n    KeyW: { key: 'w', shiftKey: 'W' },\n    KeyX: { key: 'x', shiftKey: 'X' },\n    KeyY: { key: 'y', shiftKey: 'Y' },\n    KeyZ: { key: 'z', shiftKey: 'Z' },\n    Numpad0: { key: '0' },\n    Numpad1: { key: '1' },\n    Numpad2: { key: '2' },\n    Numpad3: { key: '3' },\n    Numpad4: { key: '4' },\n    Numpad5: { key: '5' },\n    Numpad6: { key: '6' },\n    Numpad7: { key: '7' },\n    Numpad8: { key: '8' },\n    Numpad9: { key: '9' },\n    NumpadMultiply: { key: '*' },\n    NumpadAdd: { key: '+' },\n    NumpadComma: { key: ',' },\n    NumpadSubtract: { key: '-' },\n    NumpadDecimal: { key: '.' },\n    NumpadDivide: { key: '/' },\n    Semicolon: { key: ';', shiftKey: ':' },\n    Equal: { key: '=', shiftKey: '+' },\n    Comma: { key: ',', shiftKey: '<' },\n    Minus: { key: '-', shiftKey: '_' },\n    Period: { key: '.', shiftKey: '>' },\n    Slash: { key: '/', shiftKey: '?' },\n    Backquote: { key: '`', shiftKey: '~' },\n    BracketLeft: { key: '[', shiftKey: '{' },\n    Backslash: { key: '\\\\', shiftKey: '|' },\n    BracketRight: { key: ']', shiftKey: '}' },\n    Quote: { key: '\\'', shiftKey: '\"' },\n    IntlBackslash: { key: '\\\\', shiftKey: '|' }\n  };\n\n  mergeIf(codeToKeyTable, 'mac', {\n    OSLeft: { key: 'Meta' },\n    OSRight: { key: 'Meta' }\n  });\n\n  // Corrections for 'key' names in older browsers (e.g. FF36-)\n  // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent.key#Key_values\n  var keyFixTable = {\n    Esc: 'Escape',\n    Nonconvert: 'NonConvert',\n    Left: 'ArrowLeft',\n    Up: 'ArrowUp',\n    Right: 'ArrowRight',\n    Down: 'ArrowDown',\n    Del: 'Delete',\n    Menu: 'ContextMenu',\n    MediaNextTrack: 'MediaTrackNext',\n    MediaPreviousTrack: 'MediaTrackPrevious',\n    SelectMedia: 'MediaSelect',\n    HalfWidth: 'Hankaku',\n    FullWidth: 'Zenkaku',\n    RomanCharacters: 'Romaji',\n    Crsel: 'CrSel',\n    Exsel: 'ExSel',\n    Zoom: 'ZoomToggle'\n  };\n\n  //--------------------------------------------------------------------\n  //\n  // Exported Functions\n  //\n  //--------------------------------------------------------------------\n\n\n  var codeTable = remap(keyCodeToInfoTable, 'code');\n\n  try {\n    var nativeLocation = nativeKeyboardEvent && ('location' in new KeyboardEvent(''));\n  } catch (_) {}\n\n  function keyInfoForEvent(event) {\n    var keyCode = 'keyCode' in event ? event.keyCode : 'which' in event ? event.which : 0;\n\n    var keyInfo = (function(){\n      if (nativeLocation || 'keyLocation' in event) {\n        var location = nativeLocation ? event.location : event.keyLocation;\n        if (location && keyCode in locationTable[location]) {\n          return locationTable[location][keyCode];\n        }\n      }\n      if ('keyIdentifier' in event && event.keyIdentifier in keyIdentifierTable) {\n        return keyIdentifierTable[event.keyIdentifier];\n      }\n      if (keyCode in keyCodeToInfoTable) {\n        return keyCodeToInfoTable[keyCode];\n      }\n      return null;\n    }());\n\n    // TODO: Track these down and move to general tables\n    if (0) {\n      // TODO: Map these for newerish browsers?\n      // TODO: iOS only?\n      // TODO: Override with more common keyIdentifier name?\n      switch (event.keyIdentifier) {\n      case 'U+0010': keyInfo = { code: 'Function' }; break;\n      case 'U+001C': keyInfo = { code: 'ArrowLeft' }; break;\n      case 'U+001D': keyInfo = { code: 'ArrowRight' }; break;\n      case 'U+001E': keyInfo = { code: 'ArrowUp' }; break;\n      case 'U+001F': keyInfo = { code: 'ArrowDown' }; break;\n      }\n    }\n\n    if (!keyInfo)\n      return null;\n\n    var key = (function() {\n      var entry = codeToKeyTable[keyInfo.code];\n      if (!entry) return keyInfo.code;\n      return (event.shiftKey && 'shiftKey' in entry) ? entry.shiftKey : entry.key;\n    }());\n\n    return {\n      code: keyInfo.code,\n      key: key,\n      location: keyInfo.location,\n      keyCap: keyInfo.keyCap\n    };\n  }\n\n  function queryKeyCap(code, locale) {\n    code = String(code);\n    if (!codeTable.hasOwnProperty(code)) return 'Undefined';\n    if (locale && String(locale).toLowerCase() !== 'en-us') throw Error('Unsupported locale');\n    var keyInfo = codeTable[code];\n    return keyInfo.keyCap || keyInfo.code || 'Undefined';\n  }\n\n  if ('KeyboardEvent' in global && 'defineProperty' in Object) {\n    (function() {\n      function define(o, p, v) {\n        if (p in o) return;\n        Object.defineProperty(o, p, v);\n      }\n\n      define(KeyboardEvent.prototype, 'code', { get: function() {\n        var keyInfo = keyInfoForEvent(this);\n        return keyInfo ? keyInfo.code : '';\n      }});\n\n      // Fix for nonstandard `key` values (FF36-)\n      if ('key' in KeyboardEvent.prototype) {\n        var desc = Object.getOwnPropertyDescriptor(KeyboardEvent.prototype, 'key');\n        Object.defineProperty(KeyboardEvent.prototype, 'key', { get: function() {\n          var key = desc.get.call(this);\n          return keyFixTable.hasOwnProperty(key) ? keyFixTable[key] : key;\n        }});\n      }\n\n      define(KeyboardEvent.prototype, 'key', { get: function() {\n        var keyInfo = keyInfoForEvent(this);\n        return (keyInfo && 'key' in keyInfo) ? keyInfo.key : 'Unidentified';\n      }});\n\n      define(KeyboardEvent.prototype, 'location', { get: function() {\n        var keyInfo = keyInfoForEvent(this);\n        return (keyInfo && 'location' in keyInfo) ? keyInfo.location : STANDARD;\n      }});\n\n      define(KeyboardEvent.prototype, 'locale', { get: function() {\n        return '';\n      }});\n    }());\n  }\n\n  if (!('queryKeyCap' in global.KeyboardEvent))\n    global.KeyboardEvent.queryKeyCap = queryKeyCap;\n\n  // Helper for IE8-\n  global.identifyKey = function(event) {\n    if ('code' in event)\n      return;\n\n    var keyInfo = keyInfoForEvent(event);\n    event.code = keyInfo ? keyInfo.code : '';\n    event.key = (keyInfo && 'key' in keyInfo) ? keyInfo.key : 'Unidentified';\n    event.location = ('location' in event) ? event.location :\n      ('keyLocation' in event) ? event.keyLocation :\n      (keyInfo && 'location' in keyInfo) ? keyInfo.location : STANDARD;\n    event.locale = '';\n  };\n\n} (window));\n","!function(t,i){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=i():\"function\"==typeof define&&define.amd?define(\"nipplejs\",[],i):\"object\"==typeof exports?exports.nipplejs=i():t.nipplejs=i()}(window,function(){return function(t){var i={};function e(o){if(i[o])return i[o].exports;var n=i[o]={i:o,l:!1,exports:{}};return t[o].call(n.exports,n,n.exports,e),n.l=!0,n.exports}return e.m=t,e.c=i,e.d=function(t,i,o){e.o(t,i)||Object.defineProperty(t,i,{enumerable:!0,get:o})},e.r=function(t){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(t,\"__esModule\",{value:!0})},e.t=function(t,i){if(1&i&&(t=e(t)),8&i)return t;if(4&i&&\"object\"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(e.r(o),Object.defineProperty(o,\"default\",{enumerable:!0,value:t}),2&i&&\"string\"!=typeof t)for(var n in t)e.d(o,n,function(i){return t[i]}.bind(null,n));return o},e.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(i,\"a\",i),i},e.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},e.p=\"\",e(e.s=0)}([function(t,i,e){\"use strict\";e.r(i);var o,n=function(t,i){var e=i.x-t.x,o=i.y-t.y;return Math.sqrt(e*e+o*o)},s=function(t){return t*(Math.PI/180)},r=function(t){return t*(180/Math.PI)},d=new Map,a=function(t){d.has(t)&&clearTimeout(d.get(t)),d.set(t,setTimeout(t,100))},p=function(t,i,e){for(var o,n=i.split(/[ ,]+/g),s=0;s<n.length;s+=1)o=n[s],t.addEventListener?t.addEventListener(o,e,!1):t.attachEvent&&t.attachEvent(o,e)},c=function(t,i,e){for(var o,n=i.split(/[ ,]+/g),s=0;s<n.length;s+=1)o=n[s],t.removeEventListener?t.removeEventListener(o,e):t.detachEvent&&t.detachEvent(o,e)},l=function(t){return t.preventDefault(),t.type.match(/^touch/)?t.changedTouches:t},h=function(){return{x:void 0!==window.pageXOffset?window.pageXOffset:(document.documentElement||document.body.parentNode||document.body).scrollLeft,y:void 0!==window.pageYOffset?window.pageYOffset:(document.documentElement||document.body.parentNode||document.body).scrollTop}},u=function(t,i){i.top||i.right||i.bottom||i.left?(t.style.top=i.top,t.style.right=i.right,t.style.bottom=i.bottom,t.style.left=i.left):(t.style.left=i.x+\"px\",t.style.top=i.y+\"px\")},f=function(t,i,e){var o=y(t);for(var n in o)if(o.hasOwnProperty(n))if(\"string\"==typeof i)o[n]=i+\" \"+e;else{for(var s=\"\",r=0,d=i.length;r<d;r+=1)s+=i[r]+\" \"+e+\", \";o[n]=s.slice(0,-2)}return o},y=function(t){var i={};i[t]=\"\";return[\"webkit\",\"Moz\",\"o\"].forEach(function(e){i[e+t.charAt(0).toUpperCase()+t.slice(1)]=\"\"}),i},m=function(t,i){for(var e in i)i.hasOwnProperty(e)&&(t[e]=i[e]);return t},v=function(t,i){if(t.length)for(var e=0,o=t.length;e<o;e+=1)i(t[e]);else i(t)},g=!!(\"ontouchstart\"in window),b=!!window.PointerEvent,x=!!window.MSPointerEvent,O={start:\"mousedown\",move:\"mousemove\",end:\"mouseup\"},w={};function _(){}b?o={start:\"pointerdown\",move:\"pointermove\",end:\"pointerup, pointercancel\"}:x?o={start:\"MSPointerDown\",move:\"MSPointerMove\",end:\"MSPointerUp\"}:g?(o={start:\"touchstart\",move:\"touchmove\",end:\"touchend, touchcancel\"},w=O):o=O,_.prototype.on=function(t,i){var e,o=t.split(/[ ,]+/g);this._handlers_=this._handlers_||{};for(var n=0;n<o.length;n+=1)e=o[n],this._handlers_[e]=this._handlers_[e]||[],this._handlers_[e].push(i);return this},_.prototype.off=function(t,i){return this._handlers_=this._handlers_||{},void 0===t?this._handlers_={}:void 0===i?this._handlers_[t]=null:this._handlers_[t]&&this._handlers_[t].indexOf(i)>=0&&this._handlers_[t].splice(this._handlers_[t].indexOf(i),1),this},_.prototype.trigger=function(t,i){var e,o=this,n=t.split(/[ ,]+/g);o._handlers_=o._handlers_||{};for(var s=0;s<n.length;s+=1)e=n[s],o._handlers_[e]&&o._handlers_[e].length&&o._handlers_[e].forEach(function(t){t.call(o,{type:e,target:o},i)})},_.prototype.config=function(t){this.options=this.defaults||{},t&&(this.options=function(t,i){var e={};for(var o in t)t.hasOwnProperty(o)&&i.hasOwnProperty(o)?e[o]=i[o]:t.hasOwnProperty(o)&&(e[o]=t[o]);return e}(this.options,t))},_.prototype.bindEvt=function(t,i){var e=this;return e._domHandlers_=e._domHandlers_||{},e._domHandlers_[i]=function(){\"function\"==typeof e[\"on\"+i]?e[\"on\"+i].apply(e,arguments):console.warn('[WARNING] : Missing \"on'+i+'\" handler.')},p(t,o[i],e._domHandlers_[i]),w[i]&&p(t,w[i],e._domHandlers_[i]),e},_.prototype.unbindEvt=function(t,i){return this._domHandlers_=this._domHandlers_||{},c(t,o[i],this._domHandlers_[i]),w[i]&&c(t,w[i],this._domHandlers_[i]),delete this._domHandlers_[i],this};var T=_;function k(t,i){return this.identifier=i.identifier,this.position=i.position,this.frontPosition=i.frontPosition,this.collection=t,this.defaults={size:100,threshold:.1,color:\"white\",fadeTime:250,dataOnly:!1,restJoystick:!0,restOpacity:.5,mode:\"dynamic\",zone:document.body,lockX:!1,lockY:!1,shape:\"circle\"},this.config(i),\"dynamic\"===this.options.mode&&(this.options.restOpacity=0),this.id=k.id,k.id+=1,this.buildEl().stylize(),this.instance={el:this.ui.el,on:this.on.bind(this),off:this.off.bind(this),show:this.show.bind(this),hide:this.hide.bind(this),add:this.addToDom.bind(this),remove:this.removeFromDom.bind(this),destroy:this.destroy.bind(this),setPosition:this.setPosition.bind(this),resetDirection:this.resetDirection.bind(this),computeDirection:this.computeDirection.bind(this),trigger:this.trigger.bind(this),position:this.position,frontPosition:this.frontPosition,ui:this.ui,identifier:this.identifier,id:this.id,options:this.options},this.instance}k.prototype=new T,k.constructor=k,k.id=0,k.prototype.buildEl=function(t){return this.ui={},this.options.dataOnly?this:(this.ui.el=document.createElement(\"div\"),this.ui.back=document.createElement(\"div\"),this.ui.front=document.createElement(\"div\"),this.ui.el.className=\"nipple collection_\"+this.collection.id,this.ui.back.className=\"back\",this.ui.front.className=\"front\",this.ui.el.setAttribute(\"id\",\"nipple_\"+this.collection.id+\"_\"+this.id),this.ui.el.appendChild(this.ui.back),this.ui.el.appendChild(this.ui.front),this)},k.prototype.stylize=function(){if(this.options.dataOnly)return this;var t=this.options.fadeTime+\"ms\",i=function(t,i){var e=y(t);for(var o in e)e.hasOwnProperty(o)&&(e[o]=i);return e}(\"borderRadius\",\"50%\"),e=f(\"transition\",\"opacity\",t),o={};return o.el={position:\"absolute\",opacity:this.options.restOpacity,display:\"block\",zIndex:999},o.back={position:\"absolute\",display:\"block\",width:this.options.size+\"px\",height:this.options.size+\"px\",left:0,marginLeft:-this.options.size/2+\"px\",marginTop:-this.options.size/2+\"px\",background:this.options.color,opacity:\".5\"},o.front={width:this.options.size/2+\"px\",height:this.options.size/2+\"px\",position:\"absolute\",display:\"block\",left:0,marginLeft:-this.options.size/4+\"px\",marginTop:-this.options.size/4+\"px\",background:this.options.color,opacity:\".5\",transform:\"translate(0px, 0px)\"},m(o.el,e),\"circle\"===this.options.shape&&m(o.back,i),m(o.front,i),this.applyStyles(o),this},k.prototype.applyStyles=function(t){for(var i in this.ui)if(this.ui.hasOwnProperty(i))for(var e in t[i])this.ui[i].style[e]=t[i][e];return this},k.prototype.addToDom=function(){return this.options.dataOnly||document.body.contains(this.ui.el)?this:(this.options.zone.appendChild(this.ui.el),this)},k.prototype.removeFromDom=function(){return this.options.dataOnly||!document.body.contains(this.ui.el)?this:(this.options.zone.removeChild(this.ui.el),this)},k.prototype.destroy=function(){clearTimeout(this.removeTimeout),clearTimeout(this.showTimeout),clearTimeout(this.restTimeout),this.trigger(\"destroyed\",this.instance),this.removeFromDom(),this.off()},k.prototype.show=function(t){var i=this;return i.options.dataOnly?i:(clearTimeout(i.removeTimeout),clearTimeout(i.showTimeout),clearTimeout(i.restTimeout),i.addToDom(),i.restCallback(),setTimeout(function(){i.ui.el.style.opacity=1},0),i.showTimeout=setTimeout(function(){i.trigger(\"shown\",i.instance),\"function\"==typeof t&&t.call(this)},i.options.fadeTime),i)},k.prototype.hide=function(t){var i=this;if(i.options.dataOnly)return i;if(i.ui.el.style.opacity=i.options.restOpacity,clearTimeout(i.removeTimeout),clearTimeout(i.showTimeout),clearTimeout(i.restTimeout),i.removeTimeout=setTimeout(function(){var e=\"dynamic\"===i.options.mode?\"none\":\"block\";i.ui.el.style.display=e,\"function\"==typeof t&&t.call(i),i.trigger(\"hidden\",i.instance)},i.options.fadeTime),i.options.restJoystick){var e=i.options.restJoystick,o={};o.x=!0===e||!1!==e.x?0:i.instance.frontPosition.x,o.y=!0===e||!1!==e.y?0:i.instance.frontPosition.y,i.setPosition(t,o)}return i},k.prototype.setPosition=function(t,i){var e=this;e.frontPosition={x:i.x,y:i.y};var o=e.options.fadeTime+\"ms\",n={};n.front=f(\"transition\",[\"transform\"],o);var s={front:{}};s.front={transform:\"translate(\"+e.frontPosition.x+\"px,\"+e.frontPosition.y+\"px)\"},e.applyStyles(n),e.applyStyles(s),e.restTimeout=setTimeout(function(){\"function\"==typeof t&&t.call(e),e.restCallback()},e.options.fadeTime)},k.prototype.restCallback=function(){var t={};t.front=f(\"transition\",\"none\",\"\"),this.applyStyles(t),this.trigger(\"rested\",this.instance)},k.prototype.resetDirection=function(){this.direction={x:!1,y:!1,angle:!1}},k.prototype.computeDirection=function(t){var i,e,o,n=t.angle.radian,s=Math.PI/4,r=Math.PI/2;if(n>s&&n<3*s&&!t.lockX?i=\"up\":n>-s&&n<=s&&!t.lockY?i=\"left\":n>3*-s&&n<=-s&&!t.lockX?i=\"down\":t.lockY||(i=\"right\"),t.lockY||(e=n>-r&&n<r?\"left\":\"right\"),t.lockX||(o=n>0?\"up\":\"down\"),t.force>this.options.threshold){var d,a={};for(d in this.direction)this.direction.hasOwnProperty(d)&&(a[d]=this.direction[d]);var p={};for(d in this.direction={x:e,y:o,angle:i},t.direction=this.direction,a)a[d]===this.direction[d]&&(p[d]=!0);if(p.x&&p.y&&p.angle)return t;p.x&&p.y||this.trigger(\"plain\",t),p.x||this.trigger(\"plain:\"+e,t),p.y||this.trigger(\"plain:\"+o,t),p.angle||this.trigger(\"dir dir:\"+i,t)}else this.resetDirection();return t};var P=k;function E(t,i){this.nipples=[],this.idles=[],this.actives=[],this.ids=[],this.pressureIntervals={},this.manager=t,this.id=E.id,E.id+=1,this.defaults={zone:document.body,multitouch:!1,maxNumberOfNipples:10,mode:\"dynamic\",position:{top:0,left:0},catchDistance:200,size:100,threshold:.1,color:\"white\",fadeTime:250,dataOnly:!1,restJoystick:!0,restOpacity:.5,lockX:!1,lockY:!1,shape:\"circle\",dynamicPage:!1,follow:!1},this.config(i),\"static\"!==this.options.mode&&\"semi\"!==this.options.mode||(this.options.multitouch=!1),this.options.multitouch||(this.options.maxNumberOfNipples=1);var e=getComputedStyle(this.options.zone.parentElement);return e&&\"flex\"===e.display&&(this.parentIsFlex=!0),this.updateBox(),this.prepareNipples(),this.bindings(),this.begin(),this.nipples}E.prototype=new T,E.constructor=E,E.id=0,E.prototype.prepareNipples=function(){var t=this.nipples;t.on=this.on.bind(this),t.off=this.off.bind(this),t.options=this.options,t.destroy=this.destroy.bind(this),t.ids=this.ids,t.id=this.id,t.processOnMove=this.processOnMove.bind(this),t.processOnEnd=this.processOnEnd.bind(this),t.get=function(i){if(void 0===i)return t[0];for(var e=0,o=t.length;e<o;e+=1)if(t[e].identifier===i)return t[e];return!1}},E.prototype.bindings=function(){this.bindEvt(this.options.zone,\"start\"),this.options.zone.style.touchAction=\"none\",this.options.zone.style.msTouchAction=\"none\"},E.prototype.begin=function(){var t=this.options;if(\"static\"===t.mode){var i=this.createNipple(t.position,this.manager.getIdentifier());i.add(),this.idles.push(i)}},E.prototype.createNipple=function(t,i){var e=this.manager.scroll,o={},n=this.options,s=this.parentIsFlex?e.x:e.x+this.box.left,r=this.parentIsFlex?e.y:e.y+this.box.top;if(t.x&&t.y)o={x:t.x-s,y:t.y-r};else if(t.top||t.right||t.bottom||t.left){var d=document.createElement(\"DIV\");d.style.display=\"hidden\",d.style.top=t.top,d.style.right=t.right,d.style.bottom=t.bottom,d.style.left=t.left,d.style.position=\"absolute\",n.zone.appendChild(d);var a=d.getBoundingClientRect();n.zone.removeChild(d),o=t,t={x:a.left+e.x,y:a.top+e.y}}var p=new P(this,{color:n.color,size:n.size,threshold:n.threshold,fadeTime:n.fadeTime,dataOnly:n.dataOnly,restJoystick:n.restJoystick,restOpacity:n.restOpacity,mode:n.mode,identifier:i,position:t,zone:n.zone,frontPosition:{x:0,y:0},shape:n.shape});return n.dataOnly||(u(p.ui.el,o),u(p.ui.front,p.frontPosition)),this.nipples.push(p),this.trigger(\"added \"+p.identifier+\":added\",p),this.manager.trigger(\"added \"+p.identifier+\":added\",p),this.bindNipple(p),p},E.prototype.updateBox=function(){this.box=this.options.zone.getBoundingClientRect()},E.prototype.bindNipple=function(t){var i,e=this,o=function(t,o){i=t.type+\" \"+o.id+\":\"+t.type,e.trigger(i,o)};t.on(\"destroyed\",e.onDestroyed.bind(e)),t.on(\"shown hidden rested dir plain\",o),t.on(\"dir:up dir:right dir:down dir:left\",o),t.on(\"plain:up plain:right plain:down plain:left\",o)},E.prototype.pressureFn=function(t,i,e){var o=this,n=0;clearInterval(o.pressureIntervals[e]),o.pressureIntervals[e]=setInterval(function(){var e=t.force||t.pressure||t.webkitForce||0;e!==n&&(i.trigger(\"pressure\",e),o.trigger(\"pressure \"+i.identifier+\":pressure\",e),n=e)}.bind(o),100)},E.prototype.onstart=function(t){var i=this,e=i.options,o=t;t=l(t),i.updateBox();return v(t,function(n){i.actives.length<e.maxNumberOfNipples?i.processOnStart(n):o.type.match(/^touch/)&&(Object.keys(i.manager.ids).forEach(function(e){if(Object.values(o.touches).findIndex(function(t){return t.identifier===e})<0){var n=[t[0]];n.identifier=e,i.processOnEnd(n)}}),i.actives.length<e.maxNumberOfNipples&&i.processOnStart(n))}),i.manager.bindDocument(),!1},E.prototype.processOnStart=function(t){var i,e=this,o=e.options,s=e.manager.getIdentifier(t),r=t.force||t.pressure||t.webkitForce||0,d={x:t.pageX,y:t.pageY},a=e.getOrCreate(s,d);a.identifier!==s&&e.manager.removeIdentifier(a.identifier),a.identifier=s;var p=function(i){i.trigger(\"start\",i),e.trigger(\"start \"+i.id+\":start\",i),i.show(),r>0&&e.pressureFn(t,i,i.identifier),e.processOnMove(t)};if((i=e.idles.indexOf(a))>=0&&e.idles.splice(i,1),e.actives.push(a),e.ids.push(a.identifier),\"semi\"!==o.mode)p(a);else{if(!(n(d,a.position)<=o.catchDistance))return a.destroy(),void e.processOnStart(t);p(a)}return a},E.prototype.getOrCreate=function(t,i){var e,o=this.options;return/(semi|static)/.test(o.mode)?(e=this.idles[0])?(this.idles.splice(0,1),e):\"semi\"===o.mode?this.createNipple(i,t):(console.warn(\"Coudln't find the needed nipple.\"),!1):e=this.createNipple(i,t)},E.prototype.processOnMove=function(t){var i=this.options,e=this.manager.getIdentifier(t),o=this.nipples.get(e),d=this.manager.scroll;if(function(t){return isNaN(t.buttons)?0!==t.pressure:0!==t.buttons}(t)){if(!o)return console.error(\"Found zombie joystick with ID \"+e),void this.manager.removeIdentifier(e);if(i.dynamicPage){var a=o.el.getBoundingClientRect();o.position={x:d.x+a.left,y:d.y+a.top}}o.identifier=e;var p=o.options.size/2,c={x:t.pageX,y:t.pageY};i.lockX&&(c.y=o.position.y),i.lockY&&(c.x=o.position.x);var l,h,u,f,y,m,v,g,b,x,O=n(c,o.position),w=(l=c,h=o.position,u=h.x-l.x,f=h.y-l.y,r(Math.atan2(f,u))),_=s(w),T=O/p,k={distance:O,position:c};if(\"circle\"===o.options.shape?(y=Math.min(O,p),v=o.position,g=y,x={x:0,y:0},b=s(b=w),x.x=v.x-g*Math.cos(b),x.y=v.y-g*Math.sin(b),m=x):(m=function(t,i,e){return{x:Math.min(Math.max(t.x,i.x-e),i.x+e),y:Math.min(Math.max(t.y,i.y-e),i.y+e)}}(c,o.position,p),y=n(m,o.position)),i.follow){if(O>p){var P=c.x-m.x,E=c.y-m.y;o.position.x+=P,o.position.y+=E,o.el.style.top=o.position.y-(this.box.top+d.y)+\"px\",o.el.style.left=o.position.x-(this.box.left+d.x)+\"px\",O=n(c,o.position)}}else c=m,O=y;var I=c.x-o.position.x,z=c.y-o.position.y;o.frontPosition={x:I,y:z},i.dataOnly||(o.ui.front.style.transform=\"translate(\"+I+\"px,\"+z+\"px)\");var D={identifier:o.identifier,position:c,force:T,pressure:t.force||t.pressure||t.webkitForce||0,distance:O,angle:{radian:_,degree:w},vector:{x:I/p,y:-z/p},raw:k,instance:o,lockX:i.lockX,lockY:i.lockY};(D=o.computeDirection(D)).angle={radian:s(180-w),degree:180-w},o.trigger(\"move\",D),this.trigger(\"move \"+o.id+\":move\",D)}else this.processOnEnd(t)},E.prototype.processOnEnd=function(t){var i=this,e=i.options,o=i.manager.getIdentifier(t),n=i.nipples.get(o),s=i.manager.removeIdentifier(n.identifier);n&&(e.dataOnly||n.hide(function(){\"dynamic\"===e.mode&&(n.trigger(\"removed\",n),i.trigger(\"removed \"+n.id+\":removed\",n),i.manager.trigger(\"removed \"+n.id+\":removed\",n),n.destroy())}),clearInterval(i.pressureIntervals[n.identifier]),n.resetDirection(),n.trigger(\"end\",n),i.trigger(\"end \"+n.id+\":end\",n),i.ids.indexOf(n.identifier)>=0&&i.ids.splice(i.ids.indexOf(n.identifier),1),i.actives.indexOf(n)>=0&&i.actives.splice(i.actives.indexOf(n),1),/(semi|static)/.test(e.mode)?i.idles.push(n):i.nipples.indexOf(n)>=0&&i.nipples.splice(i.nipples.indexOf(n),1),i.manager.unbindDocument(),/(semi|static)/.test(e.mode)&&(i.manager.ids[s.id]=s.identifier))},E.prototype.onDestroyed=function(t,i){this.nipples.indexOf(i)>=0&&this.nipples.splice(this.nipples.indexOf(i),1),this.actives.indexOf(i)>=0&&this.actives.splice(this.actives.indexOf(i),1),this.idles.indexOf(i)>=0&&this.idles.splice(this.idles.indexOf(i),1),this.ids.indexOf(i.identifier)>=0&&this.ids.splice(this.ids.indexOf(i.identifier),1),this.manager.removeIdentifier(i.identifier),this.manager.unbindDocument()},E.prototype.destroy=function(){for(var t in this.unbindEvt(this.options.zone,\"start\"),this.nipples.forEach(function(t){t.destroy()}),this.pressureIntervals)this.pressureIntervals.hasOwnProperty(t)&&clearInterval(this.pressureIntervals[t]);this.trigger(\"destroyed\",this.nipples),this.manager.unbindDocument(),this.off()};var I=E;function z(t){var i=this;i.ids={},i.index=0,i.collections=[],i.scroll=h(),i.config(t),i.prepareCollections();var e=function(){var t;i.collections.forEach(function(e){e.forEach(function(e){t=e.el.getBoundingClientRect(),e.position={x:i.scroll.x+t.left,y:i.scroll.y+t.top}})})};p(window,\"resize\",function(){a(e)});var o=function(){i.scroll=h()};return p(window,\"scroll\",function(){a(o)}),i.collections}z.prototype=new T,z.constructor=z,z.prototype.prepareCollections=function(){var t=this;t.collections.create=t.create.bind(t),t.collections.on=t.on.bind(t),t.collections.off=t.off.bind(t),t.collections.destroy=t.destroy.bind(t),t.collections.get=function(i){var e;return t.collections.every(function(t){return!(e=t.get(i))}),e}},z.prototype.create=function(t){return this.createCollection(t)},z.prototype.createCollection=function(t){var i=new I(this,t);return this.bindCollection(i),this.collections.push(i),i},z.prototype.bindCollection=function(t){var i,e=this,o=function(t,o){i=t.type+\" \"+o.id+\":\"+t.type,e.trigger(i,o)};t.on(\"destroyed\",e.onDestroyed.bind(e)),t.on(\"shown hidden rested dir plain\",o),t.on(\"dir:up dir:right dir:down dir:left\",o),t.on(\"plain:up plain:right plain:down plain:left\",o)},z.prototype.bindDocument=function(){this.binded||(this.bindEvt(document,\"move\").bindEvt(document,\"end\"),this.binded=!0)},z.prototype.unbindDocument=function(t){Object.keys(this.ids).length&&!0!==t||(this.unbindEvt(document,\"move\").unbindEvt(document,\"end\"),this.binded=!1)},z.prototype.getIdentifier=function(t){var i;return t?void 0===(i=void 0===t.identifier?t.pointerId:t.identifier)&&(i=this.latest||0):i=this.index,void 0===this.ids[i]&&(this.ids[i]=this.index,this.index+=1),this.latest=i,this.ids[i]},z.prototype.removeIdentifier=function(t){var i={};for(var e in this.ids)if(this.ids[e]===t){i.id=e,i.identifier=this.ids[e],delete this.ids[e];break}return i},z.prototype.onmove=function(t){return this.onAny(\"move\",t),!1},z.prototype.onend=function(t){return this.onAny(\"end\",t),!1},z.prototype.oncancel=function(t){return this.onAny(\"end\",t),!1},z.prototype.onAny=function(t,i){var e,o=this,n=\"processOn\"+t.charAt(0).toUpperCase()+t.slice(1);i=l(i);return v(i,function(t){e=o.getIdentifier(t),v(o.collections,function(t,i,e){e.ids.indexOf(i)>=0&&(e[n](t),t._found_=!0)}.bind(null,t,e)),t._found_||o.removeIdentifier(e)}),!1},z.prototype.destroy=function(){this.unbindDocument(!0),this.ids={},this.index=0,this.collections.forEach(function(t){t.destroy()}),this.off()},z.prototype.onDestroyed=function(t,i){if(this.collections.indexOf(i)<0)return!1;this.collections.splice(this.collections.indexOf(i),1)};var D=new z;i.default={create:function(t){return D.create(t)},factory:D}}]).default});","import{BufferAttribute as t,BufferGeometry as e,Vector3 as s,Plane as r,Triangle as n,Object3D as o,Mesh as i,SphereGeometry as h,MeshBasicMaterial as c,BoxGeometry as a,LineBasicMaterial as u,Line as l}from\"three\";class d{static roundNumber(t,e){const s=Math.pow(10,e);return Math.round(t*s)/s}static sample(t){return t[Math.floor(Math.random()*t.length)]}static distanceToSquared(t,e){var s=t.x-e.x,r=t.y-e.y,n=t.z-e.z;return s*s+r*r+n*n}static isPointInPoly(t,e){for(var s=!1,r=-1,n=t.length,o=n-1;++r<n;o=r)(t[r].z<=e.z&&e.z<t[o].z||t[o].z<=e.z&&e.z<t[r].z)&&e.x<(t[o].x-t[r].x)*(e.z-t[r].z)/(t[o].z-t[r].z)+t[r].x&&(s=!s);return s}static isVectorInPolygon(t,e,s){var r=1e5,n=-1e5,o=[];return e.vertexIds.forEach(t=>{r=Math.min(s[t].y,r),n=Math.max(s[t].y,n),o.push(s[t])}),!!(t.y<n+.5&&t.y>r-.5&&this.isPointInPoly(o,t))}static triarea2(t,e,s){return(s.x-t.x)*(e.z-t.z)-(e.x-t.x)*(s.z-t.z)}static vequal(t,e){return this.distanceToSquared(t,e)<1e-5}static mergeVertices(s,r=1e-4){r=Math.max(r,Number.EPSILON);for(var n={},o=s.getIndex(),i=s.getAttribute(\"position\"),h=o?o.count:i.count,c=0,a=[],u=[],l=Math.log10(1/r),d=Math.pow(10,l),p=0;p<h;p++){var g=o?o.getX(p):p,f=\"\";f+=~~(i.getX(g)*d)+\",\",f+=~~(i.getY(g)*d)+\",\",(f+=~~(i.getZ(g)*d)+\",\")in n?a.push(n[f]):(u.push(i.getX(g)),u.push(i.getY(g)),u.push(i.getZ(g)),n[f]=c,a.push(c),c++)}const v=new t(new Float32Array(u),i.itemSize,i.normalized),b=new e;return b.setAttribute(\"position\",v),b.setIndex(a),b}}class p{constructor(t){this.content=[],this.scoreFunction=t}push(t){this.content.push(t),this.sinkDown(this.content.length-1)}pop(){const t=this.content[0],e=this.content.pop();return this.content.length>0&&(this.content[0]=e,this.bubbleUp(0)),t}remove(t){const e=this.content.indexOf(t),s=this.content.pop();e!==this.content.length-1&&(this.content[e]=s,this.scoreFunction(s)<this.scoreFunction(t)?this.sinkDown(e):this.bubbleUp(e))}size(){return this.content.length}rescoreElement(t){this.sinkDown(this.content.indexOf(t))}sinkDown(t){const e=this.content[t];for(;t>0;){const s=(t+1>>1)-1,r=this.content[s];if(!(this.scoreFunction(e)<this.scoreFunction(r)))break;this.content[s]=e,this.content[t]=r,t=s}}bubbleUp(t){const e=this.content.length,s=this.content[t],r=this.scoreFunction(s);for(;;){const n=t+1<<1,o=n-1;let i,h=null;if(o<e&&(i=this.scoreFunction(this.content[o]),i<r&&(h=o)),n<e&&this.scoreFunction(this.content[n])<(null===h?r:i)&&(h=n),null===h)break;this.content[t]=this.content[h],this.content[h]=s,t=h}}}class g{constructor(){this.portals=[]}push(t,e){void 0===e&&(e=t),this.portals.push({left:t,right:e})}stringPull(){const t=this.portals,e=[];let s,r,n,o=0,i=0,h=0;s=t[0].left,r=t[0].left,n=t[0].right,e.push(s);for(let c=1;c<t.length;c++){const a=t[c].left,u=t[c].right;if(d.triarea2(s,n,u)<=0){if(!(d.vequal(s,n)||d.triarea2(s,r,u)>0)){e.push(r),s=r,o=i,r=s,n=s,i=o,h=o,c=o;continue}n=u,h=c}if(d.triarea2(s,r,a)>=0){if(!(d.vequal(s,r)||d.triarea2(s,n,a)<0)){e.push(n),s=n,o=h,r=s,n=s,i=o,h=o,c=o;continue}r=a,i=c}}return 0!==e.length&&d.vequal(e[e.length-1],t[t.length-1].left)||e.push(t[t.length-1].left),this.path=e,e}}class f{constructor(){this.zones={}}static createZone(t,e=1e-4){return class{static buildZone(t,e){const r=this._buildNavigationMesh(t,e),n={};r.vertices.forEach(t=>{t.x=d.roundNumber(t.x,2),t.y=d.roundNumber(t.y,2),t.z=d.roundNumber(t.z,2)}),n.vertices=r.vertices;const o=this._buildPolygonGroups(r);return n.groups=new Array(o.length),o.forEach((t,e)=>{const r=new Map;t.forEach((t,e)=>{r.set(t,e)});const o=new Array(t.length);t.forEach((t,e)=>{const i=[];t.neighbours.forEach(t=>i.push(r.get(t)));const h=[];t.neighbours.forEach(e=>h.push(this._getSharedVerticesInOrder(t,e)));const c=new s(0,0,0);c.add(n.vertices[t.vertexIds[0]]),c.add(n.vertices[t.vertexIds[1]]),c.add(n.vertices[t.vertexIds[2]]),c.divideScalar(3),c.x=d.roundNumber(c.x,2),c.y=d.roundNumber(c.y,2),c.z=d.roundNumber(c.z,2),o[e]={id:e,neighbours:i,vertexIds:t.vertexIds,centroid:c,portals:h}}),n.groups[e]=o}),n}static _buildNavigationMesh(t,e){return t=d.mergeVertices(t,e),this._buildPolygonsFromGeometry(t)}static _spreadGroupId(t){let e=new Set([t]);for(;e.size>0;){const s=e;e=new Set,s.forEach(s=>{s.group=t.group,s.neighbours.forEach(t=>{void 0===t.group&&e.add(t)})})}}static _buildPolygonGroups(t){const e=[];return t.polygons.forEach(t=>{void 0!==t.group?e[t.group].push(t):(t.group=e.length,this._spreadGroupId(t),e.push([t]))}),e}static _buildPolygonNeighbours(t,e){const s=new Set,r=e[t.vertexIds[1]],n=e[t.vertexIds[2]];return e[t.vertexIds[0]].forEach(e=>{e!==t&&(r.includes(e)||n.includes(e))&&s.add(e)}),r.forEach(e=>{e!==t&&n.includes(e)&&s.add(e)}),s}static _buildPolygonsFromGeometry(t){const e=[],r=[],n=t.attributes.position,o=t.index,i=[];for(let t=0;t<n.count;t++)r.push((new s).fromBufferAttribute(n,t)),i[t]=[];for(let s=0;s<t.index.count;s+=3){const t=o.getX(s),r=o.getX(s+1),n=o.getX(s+2),h={vertexIds:[t,r,n],neighbours:null};e.push(h),i[t].push(h),i[r].push(h),i[n].push(h)}return e.forEach(t=>{t.neighbours=this._buildPolygonNeighbours(t,i)}),{polygons:e,vertices:r}}static _getSharedVerticesInOrder(t,e){const s=t.vertexIds,r=s[0],n=s[1],o=s[2],i=e.vertexIds,h=i.includes(r),c=i.includes(n),a=i.includes(o);return h&&c&&a?Array.from(s):h&&c?[r,n]:c&&a?[n,o]:h&&a?[o,r]:(console.warn(\"Error processing navigation mesh neighbors; neighbors with <2 shared vertices found.\"),[])}}.buildZone(t,e)}setZoneData(t,e){this.zones[t]=e}getRandomNode(t,e,r,n){if(!this.zones[t])return new s;r=r||null,n=n||0;const o=[];return this.zones[t].groups[e].forEach(t=>{r&&n?d.distanceToSquared(r,t.centroid)<n*n&&o.push(t.centroid):o.push(t.centroid)}),d.sample(o)||new s}getClosestNode(t,e,s,r=!1){const n=this.zones[e].vertices;let o=null,i=Infinity;return this.zones[e].groups[s].forEach(e=>{const s=d.distanceToSquared(e.centroid,t);s<i&&(!r||d.isVectorInPolygon(t,e,n))&&(o=e,i=s)}),o}findPath(t,e,r,n){const o=this.zones[r].groups[n],i=this.zones[r].vertices,h=this.getClosestNode(t,r,n,!0),c=this.getClosestNode(e,r,n,!0);if(!h||!c)return null;const a=class{static init(t){for(let e=0;e<t.length;e++){const s=t[e];s.f=0,s.g=0,s.h=0,s.cost=1,s.visited=!1,s.closed=!1,s.parent=null}}static cleanUp(t){for(let e=0;e<t.length;e++){const s=t[e];delete s.f,delete s.g,delete s.h,delete s.cost,delete s.visited,delete s.closed,delete s.parent}}static heap(){return new p(function(t){return t.f})}static search(t,e,s){this.init(t);const r=this.heap();for(r.push(e);r.size()>0;){const e=r.pop();if(e===s){let t=e;const s=[];for(;t.parent;)s.push(t),t=t.parent;return this.cleanUp(s),s.reverse()}e.closed=!0;const n=this.neighbours(t,e);for(let t=0,o=n.length;t<o;t++){const o=n[t];if(o.closed)continue;const i=e.g+o.cost,h=o.visited;if(!h||i<o.g){if(o.visited=!0,o.parent=e,!o.centroid||!s.centroid)throw new Error(\"Unexpected state\");o.h=o.h||this.heuristic(o.centroid,s.centroid),o.g=i,o.f=o.g+o.h,h?r.rescoreElement(o):r.push(o)}}}return[]}static heuristic(t,e){return d.distanceToSquared(t,e)}static neighbours(t,e){const s=[];for(let r=0;r<e.neighbours.length;r++)s.push(t[e.neighbours[r]]);return s}}.search(o,h,c),u=function(t,e){for(var s=0;s<t.neighbours.length;s++)if(t.neighbours[s]===e.id)return t.portals[s]},l=new g;l.push(t);for(let t=0;t<a.length;t++){const e=a[t],s=a[t+1];if(s){const t=u(e,s);l.push(i[t[0]],i[t[1]])}}l.push(e),l.stringPull();const f=l.path.map(t=>new s(t.x,t.y,t.z));return f.shift(),f}}f.prototype.getGroup=function(){const t=new r;return function(e,s,r=!1){if(!this.zones[e])return null;let n=null,o=Math.pow(50,2);const i=this.zones[e];for(let e=0;e<i.groups.length;e++){const h=i.groups[e];for(const c of h){if(r&&(t.setFromCoplanarPoints(i.vertices[c.vertexIds[0]],i.vertices[c.vertexIds[1]],i.vertices[c.vertexIds[2]]),Math.abs(t.distanceToPoint(s))<.01)&&d.isPointInPoly([i.vertices[c.vertexIds[0]],i.vertices[c.vertexIds[1]],i.vertices[c.vertexIds[2]]],s))return e;const h=d.distanceToSquared(c.centroid,s);h<o&&(n=e,o=h)}}return n}}(),f.prototype.clampStep=function(){const t=new s,e=new r,o=new n,i=new s;let h,c,a=new s;return function(s,r,n,u,l,d){const p=this.zones[u].vertices,g=this.zones[u].groups[l],f=[n],v={};v[n.id]=0,h=void 0,a.set(0,0,0),c=Infinity,e.setFromCoplanarPoints(p[n.vertexIds[0]],p[n.vertexIds[1]],p[n.vertexIds[2]]),e.projectPoint(r,t),i.copy(t);for(let e=f.pop();e;e=f.pop()){o.set(p[e.vertexIds[0]],p[e.vertexIds[1]],p[e.vertexIds[2]]),o.closestPointToPoint(i,t),t.distanceToSquared(i)<c&&(h=e,a.copy(t),c=t.distanceToSquared(i));const s=v[e.id];if(!(s>2))for(let t=0;t<e.neighbours.length;t++){const r=g[e.neighbours[t]];r.id in v||(f.push(r),v[r.id]=s+1)}}return d.copy(a),h}}();class v extends o{constructor(){super(),this._playerMarker=new i(new h(.25,32,32),new c({color:15631215})),this._targetMarker=new i(new a(.3,.3,.3),new c({color:14469912})),this._nodeMarker=new i(new a(.1,.8,.1),new c({color:4417387})),this._stepMarker=new i(new a(.1,1,.1),new c({color:14472114})),this._pathMarker=new o,this._pathLineMaterial=new u({color:41903,linewidth:2}),this._pathPointMaterial=new c({color:41903}),this._pathPointGeometry=new h(.08),this._markers=[this._playerMarker,this._targetMarker,this._nodeMarker,this._stepMarker,this._pathMarker],this._markers.forEach(t=>{t.visible=!1,this.add(t)})}setPath(s){for(;this._pathMarker.children.length;)this._pathMarker.children[0].visible=!1,this._pathMarker.remove(this._pathMarker.children[0]);s=[this._playerMarker.position].concat(s);const r=new e;r.setAttribute(\"position\",new t(new Float32Array(3*s.length),3));for(let t=0;t<s.length;t++)r.attributes.position.setXYZ(t,s[t].x,s[t].y+.2,s[t].z);this._pathMarker.add(new l(r,this._pathLineMaterial));for(let t=0;t<s.length-1;t++){const e=new i(this._pathPointGeometry,this._pathPointMaterial);e.position.copy(s[t]),e.position.y+=.2,this._pathMarker.add(e)}return this._pathMarker.visible=!0,this}setPlayerPosition(t){return this._playerMarker.position.copy(t),this._playerMarker.visible=!0,this}setTargetPosition(t){return this._targetMarker.position.copy(t),this._targetMarker.visible=!0,this}setNodePosition(t){return this._nodeMarker.position.copy(t),this._nodeMarker.visible=!0,this}setStepPosition(t){return this._stepMarker.position.copy(t),this._stepMarker.visible=!0,this}reset(){for(;this._pathMarker.children.length;)this._pathMarker.children[0].visible=!1,this._pathMarker.remove(this._pathMarker.children[0]);return this._markers.forEach(t=>{t.visible=!1}),this}}export{f as Pathfinding,v as PathfindingHelper};\n//# sourceMappingURL=three-pathfinding.module.js.map\n","const EPS = 0.1;\n\nmodule.exports = AFRAME.registerComponent('checkpoint-controls', {\n  schema: {\n    enabled: {default: true},\n    mode: {default: 'teleport', oneOf: ['teleport', 'animate']},\n    animateSpeed: {default: 3.0}\n  },\n\n  init: function () {\n    this.active = true;\n    this.checkpoint = null;\n\n    this.isNavMeshConstrained = false;\n\n    this.offset = new THREE.Vector3();\n    this.position = new THREE.Vector3();\n    this.targetPosition = new THREE.Vector3();\n  },\n\n  play: function () { this.active = true; },\n  pause: function () { this.active = false; },\n\n  setCheckpoint: function (checkpoint) {\n    const el = this.el;\n\n    if (!this.active) return;\n    if (this.checkpoint === checkpoint) return;\n\n    if (this.checkpoint) {\n      el.emit('navigation-end', {checkpoint: this.checkpoint});\n    }\n\n    this.checkpoint = checkpoint;\n    this.sync();\n\n    // Ignore new checkpoint if we're already there.\n    if (this.position.distanceTo(this.targetPosition) < EPS) {\n      this.checkpoint = null;\n      return;\n    }\n\n    el.emit('navigation-start', {checkpoint: checkpoint});\n\n    if (this.data.mode === 'teleport') {\n      this.el.setAttribute('position', this.targetPosition);\n      this.checkpoint = null;\n      el.emit('navigation-end', {checkpoint: checkpoint});\n      el.components['movement-controls'].updateNavLocation();\n    }\n  },\n\n  isVelocityActive: function () {\n    return !!(this.active && this.checkpoint);\n  },\n\n  getVelocity: function () {\n    if (!this.active) return;\n\n    const data = this.data;\n    const offset = this.offset;\n    const position = this.position;\n    const targetPosition = this.targetPosition;\n    const checkpoint = this.checkpoint;\n\n    this.sync();\n    if (position.distanceTo(targetPosition) < EPS) {\n      this.checkpoint = null;\n      this.el.emit('navigation-end', {checkpoint: checkpoint});\n      return offset.set(0, 0, 0);\n    }\n    offset.setLength(data.animateSpeed);\n    return offset;\n  },\n\n  sync: function () {\n    const offset = this.offset;\n    const position = this.position;\n    const targetPosition = this.targetPosition;\n\n    position.copy(this.el.getAttribute('position'));\n    this.checkpoint.object3D.getWorldPosition(targetPosition);\n    targetPosition.add(this.checkpoint.components.checkpoint.getOffset());\n    offset.copy(targetPosition).sub(position);\n  }\n});\n","/**\n * Gamepad controls for A-Frame.\n *\n * Stripped-down version of: https://github.com/donmccurdy/aframe-gamepad-controls\n *\n * For more information about the Gamepad API, see:\n * https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API\n */\n\nconst GamepadButton = require('../../lib/GamepadButton'),\n    GamepadButtonEvent = require('../../lib/GamepadButtonEvent');\n\nconst JOYSTICK_EPS = 0.2;\n\nconst Hand = {\n  LEFT: 'left',\n  RIGHT: 'right'\n};\n\nconst Joystick = {\n  MOVEMENT: 1,\n  ROTATION: 2\n};\n\nmodule.exports = AFRAME.registerComponent('gamepad-controls', {\n\n  /*******************************************************************\n   * Statics\n   */\n\n  GamepadButton: GamepadButton,\n\n  /*******************************************************************\n   * Schema\n   */\n\n  schema: {\n    // Enable/disable gamepad-controls\n    enabled: { default: true },\n\n    // Rotation sensitivity\n    rotationSensitivity: { default: 2.0 },\n  },\n\n  /*******************************************************************\n   * Core\n   */\n\n  /**\n   * Called once when component is attached. Generally for initial setup.\n   */\n  init: function () {\n    const sceneEl = this.el.sceneEl;\n\n    // tracked-controls-webxr was renamed to tracked-controls in aframe 1.7.0\n    // tracked-controls-webxr is for aframe 1.6.0 and below\n    this.system = sceneEl.systems['tracked-controls'] || sceneEl.systems['tracked-controls-webxr'] || {controllers: []};\n\n    this.prevTime = window.performance.now();\n\n    // Button state\n    this.buttons = {};\n\n    // Rotation\n    const rotation = this.el.object3D.rotation;\n    this.pitch = new THREE.Object3D();\n    this.pitch.rotation.x = rotation.x;\n    this.yaw = new THREE.Object3D();\n    this.yaw.position.y = 10;\n    this.yaw.rotation.y = rotation.y;\n    this.yaw.add(this.pitch);\n\n    this._lookVector = new THREE.Vector2();\n    this._moveVector = new THREE.Vector2();\n    this._dpadVector = new THREE.Vector2();\n\n    sceneEl.addBehavior(this);\n  },\n\n  /**\n   * Called when component is attached and when component data changes.\n   * Generally modifies the entity based on the data.\n   */\n  update: function () { this.tick(); },\n\n  /**\n   * Called on each iteration of main render loop.\n   */\n  tick: function (t, dt) {\n    this.updateButtonState();\n    this.updateRotation(dt);\n  },\n\n  /**\n   * Called when a component is removed (e.g., via removeAttribute).\n   * Generally undoes all modifications to the entity.\n   */\n  remove: function () { },\n\n  /*******************************************************************\n   * Movement\n   */\n\n  isVelocityActive: function () {\n    if (!this.data.enabled || !this.isConnected()) return false;\n\n    const dpad = this._dpadVector;\n    const joystick = this._moveVector;\n\n    this.getDpad(dpad);\n    this.getJoystick(Joystick.MOVEMENT, joystick);\n\n    const inputX = dpad.x || joystick.x;\n    const inputY = dpad.y || joystick.y;\n\n    return Math.abs(inputX) > JOYSTICK_EPS || Math.abs(inputY) > JOYSTICK_EPS;\n  },\n\n  getVelocityDelta: function () {\n    const dpad = this._dpadVector;\n    const joystick = this._moveVector;\n\n    this.getDpad(dpad);\n    this.getJoystick(Joystick.MOVEMENT, joystick);\n\n    const inputX = dpad.x || joystick.x;\n    const inputY = dpad.y || joystick.y;\n    const dVelocity = new THREE.Vector3();\n\n    if (Math.abs(inputX) > JOYSTICK_EPS) {\n      dVelocity.x += inputX;\n    }\n    if (Math.abs(inputY) > JOYSTICK_EPS) {\n      dVelocity.z += inputY;\n    }\n\n    return dVelocity;\n  },\n\n  /*******************************************************************\n   * Rotation\n   */\n\n  isRotationActive: function () {\n    if (!this.data.enabled || !this.isConnected()) return false;\n\n    const joystick = this._lookVector;\n\n    this.getJoystick(Joystick.ROTATION, joystick);\n\n    return Math.abs(joystick.x) > JOYSTICK_EPS || Math.abs(joystick.y) > JOYSTICK_EPS;\n  },\n\n  updateRotation: function (dt) {\n    if (!this.isRotationActive()) return;\n\n    const data = this.data;\n    const yaw = this.yaw;\n    const pitch = this.pitch;\n\n    // First copy camera rig pitch/yaw, it may have been changed from\n    // another component.\n    yaw.rotation.y = this.el.object3D.rotation.y;\n    pitch.rotation.x = this.el.object3D.rotation.x;\n\n    const lookVector = this._lookVector;\n\n    this.getJoystick(Joystick.ROTATION, lookVector);\n\n    if (Math.abs(lookVector.x) <= JOYSTICK_EPS) lookVector.x = 0;\n    if (Math.abs(lookVector.y) <= JOYSTICK_EPS) lookVector.y = 0;\n\n    lookVector.multiplyScalar(data.rotationSensitivity * dt / 1000);\n    yaw.rotation.y -= lookVector.x;\n    pitch.rotation.x -= lookVector.y;\n    pitch.rotation.x = Math.max(- Math.PI / 2, Math.min(Math.PI / 2, pitch.rotation.x));\n    this.el.object3D.rotation.set(pitch.rotation.x, yaw.rotation.y, 0);\n  },\n\n  /*******************************************************************\n   * Button events\n   */\n\n  updateButtonState: function () {\n    const gamepad = this.getGamepad(Hand.RIGHT);\n    if (this.data.enabled && gamepad) {\n\n      // Fire DOM events for button state changes.\n      for (var i = 0; i < gamepad.buttons.length; i++) {\n        if (gamepad.buttons[i].pressed && !this.buttons[i]) {\n          this.emit(new GamepadButtonEvent('gamepadbuttondown', i, gamepad.buttons[i]));\n        } else if (!gamepad.buttons[i].pressed && this.buttons[i]) {\n          this.emit(new GamepadButtonEvent('gamepadbuttonup', i, gamepad.buttons[i]));\n        }\n        this.buttons[i] = gamepad.buttons[i].pressed;\n      }\n\n    } else {\n      // Reset state if controls are disabled or controller is lost.\n      for (const key in this.buttons) { this.buttons[key] = false; }\n    }\n  },\n\n  emit: function (event) {\n    // Emit original event.\n    this.el.emit(event.type, event);\n\n    // Emit convenience event, identifying button index.\n    this.el.emit(\n      event.type + ':' + event.index,\n      new GamepadButtonEvent(event.type, event.index, event)\n    );\n  },\n\n  /*******************************************************************\n   * Gamepad state\n   */\n\n  /**\n   * Returns the Gamepad instance attached to the component. If connected,\n   * a proxy-controls component may provide access to Gamepad input from a\n   * remote device.\n   *\n   * @param {string} handPreference\n   * @return {Gamepad}\n   */\n  getGamepad: (function () {\n    const _xrGamepads = [];\n    const _empty = [];\n\n    return function (handPreference) {\n      // https://github.com/donmccurdy/aframe-proxy-controls\n      const proxyControls = this.el.sceneEl.components['proxy-controls'];\n      const proxyGamepad = proxyControls && proxyControls.isConnected()\n        && proxyControls.getGamepad(0);\n      if (proxyGamepad) return proxyGamepad;\n\n      // https://www.w3.org/TR/webxr/#dom-xrinputsource-handedness\n      _xrGamepads.length = 0;\n      for (let i = 0; i < this.system.controllers.length; i++) {\n        const xrController = this.system.controllers[i];\n        const xrGamepad = xrController ? xrController.gamepad : null;\n        _xrGamepads.push(xrGamepad);\n        if (xrGamepad && xrController.handedness === handPreference) return xrGamepad;\n      }\n\n      // https://developer.mozilla.org/en-US/docs/Web/API/Gamepad/hand\n      const navGamepads = navigator.getGamepads ? navigator.getGamepads() : _empty;\n      for (let i = 0; i < navGamepads.length; i++) {\n        const navGamepad = navGamepads[i];\n        if (navGamepad && navGamepad.hand === handPreference) return navGamepad;\n      }\n\n      return _xrGamepads[0] || navGamepads[0];\n    };\n  })(),\n\n  /**\n   * Returns the state of the given button.\n   * @param  {number} index The button (0-N) for which to find state.\n   * @return {GamepadButton}\n   */\n  getButton: function (index) {\n    return this.getGamepad(Hand.RIGHT).buttons[index];\n  },\n\n  /**\n   * Returns state of the given axis. Axes are labelled 0-N, where 0-1 will\n   * represent X/Y on the first joystick, and 2-3 X/Y on the second.\n   * @param  {number} index The axis (0-N) for which to find state.\n   * @return {number} On the interval [-1,1].\n   */\n  getAxis: function (index) {\n    return this.getGamepad(index > 1 ? Hand.RIGHT : Hand.LEFT).axes[index];\n  },\n\n  /**\n   * Returns the state of the specified joystick as a THREE.Vector2.\n   * @param  {Joystick} role\n   * @param  {THREE.Vector2} target\n   * @return {THREE.Vector2}\n   */\n  getJoystick: function (index, target) {\n    const gamepad = this.getGamepad(index === Joystick.MOVEMENT ? Hand.LEFT : Hand.RIGHT);\n    // gamepad can be null here if it becomes disconnected even if isConnected() was called\n    // in the same tick before calling getJoystick.\n    if (!gamepad) {\n      return target.set(0, 0);\n    }\n    if (gamepad.mapping === 'xr-standard') {\n      // See: https://github.com/donmccurdy/aframe-extras/issues/307\n      switch (index) {\n        case Joystick.MOVEMENT: return target.set(gamepad.axes[2], gamepad.axes[3]);\n        case Joystick.ROTATION: return target.set(gamepad.axes[2], 0);\n      }\n    } else {\n      switch (index) {\n        case Joystick.MOVEMENT: return target.set(gamepad.axes[0], gamepad.axes[1]);\n        case Joystick.ROTATION: return target.set(gamepad.axes[2], gamepad.axes[3]);\n      }\n    }\n    throw new Error('Unexpected joystick index \"%d\".', index);\n  },\n\n  /**\n   * Returns the state of the dpad as a THREE.Vector2.\n   * @param {THREE.Vector2} target\n   * @return {THREE.Vector2}\n   */\n  getDpad: function (target) {\n    const gamepad = this.getGamepad(Hand.LEFT);\n    if (!gamepad) {\n      return target.set(0, 0);\n    }\n    if (!gamepad.buttons[GamepadButton.DPAD_RIGHT]) {\n      return target.set(0, 0);\n    }\n    return target.set(\n      (gamepad.buttons[GamepadButton.DPAD_RIGHT].pressed ? 1 : 0)\n      + (gamepad.buttons[GamepadButton.DPAD_LEFT].pressed ? -1 : 0),\n      (gamepad.buttons[GamepadButton.DPAD_UP].pressed ? -1 : 0)\n      + (gamepad.buttons[GamepadButton.DPAD_DOWN].pressed ? 1 : 0)\n    );\n  },\n\n  /**\n   * Returns true if the gamepad is currently connected to the system.\n   * @return {boolean}\n   */\n  isConnected: function () {\n    const gamepad = this.getGamepad(Hand.LEFT);\n    return !!(gamepad && gamepad.connected);\n  },\n\n  /**\n   * Returns a string containing some information about the controller. Result\n   * may vary across browsers, for a given controller.\n   * @return {string}\n   */\n  getID: function () {\n    return this.getGamepad(Hand.LEFT).id;\n  }\n});\n","require('./checkpoint-controls');\nrequire('./gamepad-controls');\nrequire('./keyboard-controls');\nrequire('./touch-controls');\nrequire('./movement-controls');\nrequire('./trackpad-controls');\nrequire('./nipple-controls');\n","/* global AFRAME, THREE */\n/* eslint-disable no-prototype-builtins */\nrequire('../../lib/keyboard.polyfill');\n\nconst PROXY_FLAG = '__keyboard-controls-proxy';\n\nconst KeyboardEvent = window.KeyboardEvent;\n\n/**\n * Keyboard Controls component.\n *\n * Stripped-down version of: https://github.com/donmccurdy/aframe-keyboard-controls\n *\n * Bind keyboard events to components, or control your entities with the WASD keys.\n *\n * Why use KeyboardEvent.code? \"This is set to a string representing the key that was pressed to\n * generate the KeyboardEvent, without taking the current keyboard layout (e.g., QWERTY vs.\n * Dvorak), locale (e.g., English vs. French), or any modifier keys into account. This is useful\n * when you care about which physical key was pressed, rather thanwhich character it corresponds\n * to. For example, if you’re a writing a game, you might want a certain set of keys to move the\n * player in different directions, and that mapping should ideally be independent of keyboard\n * layout. See: https://developers.google.com/web/updates/2016/04/keyboardevent-keys-codes\n *\n * @namespace wasd-controls\n * keys the entity moves and if you release it will stop. Easing simulates friction.\n * to the entity when pressing the keys.\n * @param {bool} [enabled=true] - To completely enable or disable the controls\n */\nmodule.exports = AFRAME.registerComponent('keyboard-controls', {\n  schema: {\n    enabled:           { default: true },\n    debug:             { default: false }\n  },\n\n  init: function () {\n    this.dVelocity = new THREE.Vector3();\n    this.localKeys = {};\n    this.listeners = {\n      keydown: this.onKeyDown.bind(this),\n      keyup: this.onKeyUp.bind(this),\n      blur: this.onBlur.bind(this),\n      onContextMenu: this.onContextMenu.bind(this),\n    };\n  },\n\n  /*******************************************************************\n  * Movement\n  */\n\n  isVelocityActive: function () {\n    return this.data.enabled && !!Object.keys(this.getKeys()).length;\n  },\n\n  getVelocityDelta: function () {\n    const data = this.data;\n    const keys = this.getKeys();\n\n    this.dVelocity.set(0, 0, 0);\n    if (data.enabled) {\n      if (keys.KeyW || keys.ArrowUp)    { this.dVelocity.z -= 1; }\n      if (keys.KeyA || keys.ArrowLeft)  { this.dVelocity.x -= 1; }\n      if (keys.KeyS || keys.ArrowDown)  { this.dVelocity.z += 1; }\n      if (keys.KeyD || keys.ArrowRight) { this.dVelocity.x += 1; }\n\n      // Move faster when the shift key is down.\n      if (keys.ShiftLeft) { this.dVelocity = this.dVelocity.multiplyScalar(2); }\n    }\n\n    return this.dVelocity.clone();\n  },\n\n  /*******************************************************************\n  * Events\n  */\n\n  play: function () {\n    this.attachEventListeners();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n  },\n\n  attachEventListeners: function () {\n    window.addEventListener(\"contextmenu\", this.listeners.onContextMenu, false);\n    window.addEventListener(\"keydown\", this.listeners.keydown, false);\n    window.addEventListener(\"keyup\", this.listeners.keyup, false);\n    window.addEventListener(\"blur\", this.listeners.blur, false);\n  },\n\n  onContextMenu: function () {\n    for (const code in this.localKeys) {\n      if (this.localKeys.hasOwnProperty(code)) {\n        delete this.localKeys[code];\n      }\n    }\n  },\n\n  removeEventListeners: function () {\n    window.removeEventListener('keydown', this.listeners.keydown);\n    window.removeEventListener('keyup', this.listeners.keyup);\n    window.removeEventListener('blur', this.listeners.blur);\n  },\n\n  onKeyDown: function (event) {\n    if (AFRAME.utils.shouldCaptureKeyEvent(event)) {\n      this.localKeys[event.code] = true;\n      this.emit(event);\n    }\n  },\n\n  onKeyUp: function (event) {\n    if (AFRAME.utils.shouldCaptureKeyEvent(event)) {\n      delete this.localKeys[event.code];\n      this.emit(event);\n    }\n  },\n\n  onBlur: function () {\n    for (const code in this.localKeys) {\n      if (this.localKeys.hasOwnProperty(code)) {\n        delete this.localKeys[code];\n      }\n    }\n  },\n\n  emit: function (event) {\n    // TODO - keydown only initially?\n    // TODO - where the f is the spacebar\n\n    // Emit original event.\n    if (PROXY_FLAG in event) {\n      // TODO - Method never triggered.\n      this.el.emit(event.type, event);\n    }\n\n    // Emit convenience event, identifying key.\n    this.el.emit(event.type + ':' + event.code, new KeyboardEvent(event.type, event));\n    if (this.data.debug) console.log(event.type + ':' + event.code);\n  },\n\n  /*******************************************************************\n  * Accessors\n  */\n\n  isPressed: function (code) {\n    return code in this.getKeys();\n  },\n\n  getKeys: function () {\n    if (this.isProxied()) {\n      return this.el.sceneEl.components['proxy-controls'].getKeyboard();\n    }\n    return this.localKeys;\n  },\n\n  isProxied: function () {\n    const proxyControls = this.el.sceneEl.components['proxy-controls'];\n    return proxyControls && proxyControls.isConnected();\n  }\n\n});\n","/**\n * Movement Controls\n *\n * @author Don McCurdy <dm@donmccurdy.com>\n */\n\nconst COMPONENT_SUFFIX = '-controls';\nconst MAX_DELTA = 0.2; // ms\nconst EPS = 10e-6;\nconst MOVED = 'moved';\n\nmodule.exports = AFRAME.registerComponent('movement-controls', {\n\n  /*******************************************************************\n   * Schema\n   */\n\n  dependencies: ['rotation'],\n\n  schema: {\n    enabled:            { default: true },\n    controls:           { default: ['gamepad', 'trackpad', 'keyboard', 'touch'] },\n    speed:              { default: 0.3, min: 0 },\n    fly:                { default: false },\n    constrainToNavMesh: { default: false },\n    camera:             { default: '[movement-controls] [camera]', type: 'selector' }\n  },\n\n  /*******************************************************************\n   * Lifecycle\n   */\n\n  init: function () {\n    const el = this.el;\n    if (!this.data.camera) {\n      this.data.camera = el.querySelector('[camera]');\n    }\n    this.velocityCtrl = null;\n\n    this.velocity = new THREE.Vector3();\n    this.heading = new THREE.Quaternion();\n    this.eventDetail = {};\n\n    // Navigation\n    this.navGroup = null;\n    this.navNode = null;\n\n    if (el.sceneEl.hasLoaded) {\n      this.injectControls();\n    } else {\n      el.sceneEl.addEventListener('loaded', this.injectControls.bind(this));\n    }\n  },\n\n  update: function (prevData) {\n    const el = this.el;\n    const data = this.data;\n    const nav = el.sceneEl.systems.nav;\n    if (el.sceneEl.hasLoaded) {\n      this.injectControls();\n    }\n    if (nav && data.constrainToNavMesh !== prevData.constrainToNavMesh) {\n      data.constrainToNavMesh\n        ? nav.addAgent(this)\n        : nav.removeAgent(this);\n    }\n    if (data.enabled !== prevData.enabled) {\n      // Propagate the enabled change to all controls\n      for (let i = 0; i < data.controls.length; i++) {\n        const name = data.controls[i] + COMPONENT_SUFFIX;\n        this.el.setAttribute(name, { enabled: this.data.enabled });\n      }\n    }\n  },\n\n  injectControls: function () {\n    const data = this.data;\n\n    for (let i = 0; i < data.controls.length; i++) {\n      const name = data.controls[i] + COMPONENT_SUFFIX;\n      this.el.setAttribute(name, { enabled: this.data.enabled });\n    }\n  },\n\n  updateNavLocation: function () {\n    this.navGroup = null;\n    this.navNode = null;\n  },\n\n  /*******************************************************************\n   * Tick\n   */\n\n  tick: (function () {\n    const start = new THREE.Vector3();\n    const end = new THREE.Vector3();\n    const clampedEnd = new THREE.Vector3();\n\n    return function (t, dt) {\n      if (!dt) return;\n\n      const el = this.el;\n      const data = this.data;\n\n      if (!data.enabled) return;\n\n      this.updateVelocityCtrl();\n      const velocityCtrl = this.velocityCtrl;\n      const velocity = this.velocity;\n\n      if (!velocityCtrl) return;\n\n      // Update velocity. If FPS is too low, reset.\n      if (dt / 1000 > MAX_DELTA) {\n        velocity.set(0, 0, 0);\n      } else {\n        this.updateVelocity(dt);\n      }\n\n      if (data.constrainToNavMesh\n          && velocityCtrl.isNavMeshConstrained !== false) {\n\n        if (velocity.lengthSq() < EPS) return;\n\n        start.copy(el.object3D.position);\n        end\n          .copy(velocity)\n          .multiplyScalar(dt / 1000)\n          .add(start);\n\n        const nav = el.sceneEl.systems.nav;\n        this.navGroup = this.navGroup === null ? nav.getGroup(start) : this.navGroup;\n        this.navNode = this.navNode || nav.getNode(start, this.navGroup);\n        this.navNode = nav.clampStep(start, end, this.navGroup, this.navNode, clampedEnd);\n        el.object3D.position.copy(clampedEnd);\n      } else if (el.hasAttribute('velocity')) {\n        el.setAttribute('velocity', velocity);\n      } else {\n        el.object3D.position.x += velocity.x * dt / 1000;\n        el.object3D.position.y += velocity.y * dt / 1000;\n        el.object3D.position.z += velocity.z * dt / 1000;\n      }\n\n    };\n  }()),\n\n  /*******************************************************************\n   * Movement\n   */\n\n  updateVelocityCtrl: function () {\n    const data = this.data;\n    if (data.enabled) {\n      for (let i = 0, l = data.controls.length; i < l; i++) {\n        const control = this.el.components[data.controls[i] + COMPONENT_SUFFIX];\n        if (control && control.isVelocityActive()) {\n          this.velocityCtrl = control;\n          return;\n        }\n      }\n      this.velocityCtrl = null;\n    }\n  },\n\n  updateVelocity: (function () {\n    const vector2 = new THREE.Vector2();\n    const quaternion = new THREE.Quaternion();\n\n    return function (dt) {\n      let dVelocity;\n      const el = this.el;\n      const control = this.velocityCtrl;\n      const velocity = this.velocity;\n      const data = this.data;\n\n      if (control) {\n        if (control.getVelocityDelta) {\n          dVelocity = control.getVelocityDelta(dt);\n        } else if (control.getVelocity) {\n          velocity.copy(control.getVelocity());\n          return;\n        } else if (control.getPositionDelta) {\n          velocity.copy(control.getPositionDelta(dt).multiplyScalar(1000 / dt));\n          return;\n        } else {\n          throw new Error('Incompatible movement controls: ', control);\n        }\n      }\n\n      if (el.hasAttribute('velocity') && !data.constrainToNavMesh) {\n        velocity.copy(this.el.getAttribute('velocity'));\n      }\n\n      if (dVelocity && data.enabled) {\n        const cameraEl = data.camera;\n\n        // Rotate to heading\n        quaternion.copy(cameraEl.object3D.quaternion);\n        quaternion.premultiply(el.object3D.quaternion);\n        dVelocity.applyQuaternion(quaternion);\n\n        const factor = dVelocity.length();\n        if (data.fly) {\n          velocity.copy(dVelocity);\n          velocity.multiplyScalar(this.data.speed * 16.66667);\n        } else {\n          vector2.set(dVelocity.x, dVelocity.z);\n          vector2.setLength(factor * this.data.speed * 16.66667);\n          velocity.x = vector2.x;\n          velocity.y = 0;\n          velocity.z = vector2.y;\n        }\n        if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {\n          this.eventDetail.velocity = velocity;\n          this.el.emit(MOVED, this.eventDetail);\n        }\n      }\n    };\n\n  }())\n});\n","/* global AFRAME, THREE */\nimport nipplejs from \"nipplejs\";\n\nAFRAME.registerComponent(\"nipple-controls\", {\n  schema: {\n    enabled: { default: true },\n    mode: { default: \"dynamic\", oneOf: [\"static\", \"semi\", \"dynamic\"] },\n    rotationSensitivity: { default: 1.0 },\n    moveJoystickEnabled: { default: true },\n    lookJoystickEnabled: { default: true },\n    sideMargin: { default: \"30px\" },\n    bottomMargin: { default: \"70px\" },\n    moveJoystickPosition: { default: \"left\", oneOf: [\"left\", \"right\"] },\n    lookJoystickPosition: { default: \"right\", oneOf: [\"left\", \"right\"] },\n  },\n\n  init() {\n    this.dVelocity = new THREE.Vector3();\n    this.lookVector = new THREE.Vector2();\n    const lookControls = this.el.querySelector(\"[look-controls]\").components[\"look-controls\"];\n    this.pitchObject = lookControls.pitchObject;\n    this.yawObject = lookControls.yawObject;\n    this.rigRotation = this.el.object3D.rotation;\n    this.moveData = undefined;\n    this.lookData = undefined;\n    this.moving = false;\n    this.rotating = false;\n  },\n\n  update(oldData) {\n    if (\n      this.data.moveJoystickPosition !== oldData.moveJoystickPosition ||\n      this.data.sideMargin !== oldData.sideMargin ||\n      this.data.bottomMargin !== oldData.bottomMargin ||\n      this.data.mode !== oldData.mode\n    ) {\n      this.removeMoveJoystick();\n    }\n    if (\n      this.data.lookJoystickPosition !== oldData.lookJoystickPosition ||\n      this.data.sideMargin !== oldData.sideMargin ||\n      this.data.bottomMargin !== oldData.bottomMargin ||\n      this.data.mode !== oldData.mode\n    ) {\n      this.removeLookJoystick();\n    }\n    if (this.data.enabled && this.data.moveJoystickEnabled) {\n      this.createMoveJoystick();\n    } else {\n      this.removeMoveJoystick();\n    }\n    if (this.data.enabled && this.data.lookJoystickEnabled) {\n      this.createLookJoystick();\n    } else {\n      this.removeLookJoystick();\n    }\n  },\n\n  pause() {\n    this.moving = false;\n    this.rotating = false;\n  },\n\n  remove() {\n    this.removeMoveJoystick();\n    this.removeLookJoystick();\n  },\n\n  isVelocityActive() {\n    return this.data.enabled && this.moving;\n  },\n\n  getVelocityDelta() {\n    this.dVelocity.set(0, 0, 0);\n    if (this.isVelocityActive()) {\n      const force = this.moveData.force < 1 ? this.moveData.force : 1;\n      const angle = this.moveData.angle.radian;\n      const x = Math.cos(angle) * force;\n      const z = -Math.sin(angle) * force;\n      this.dVelocity.set(x, 0, z);\n    }\n    return this.dVelocity; // We don't do a clone() here, the Vector3 will be modified by the calling code but that's fine.\n  },\n\n  isRotationActive() {\n    return this.data.enabled && this.rotating;\n  },\n\n  updateRotation(dt) {\n    if (!this.isRotationActive()) return;\n\n    const force = this.lookData.force < 1 ? this.lookData.force : 1;\n    const angle = this.lookData.angle.radian;\n    const lookVector = this.lookVector;\n    lookVector.x = Math.cos(angle) * force;\n    lookVector.y = Math.sin(angle) * force;\n    lookVector.multiplyScalar((this.data.rotationSensitivity * dt) / 1000);\n\n    this.yawObject.rotation.y -= lookVector.x;\n    let x = this.pitchObject.rotation.x + lookVector.y;\n    x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, x));\n    this.pitchObject.rotation.x = x;\n  },\n\n  tick: function (t, dt) {\n    this.updateRotation(dt);\n  },\n\n  initLeftZone() {\n    const leftZone = document.createElement(\"div\");\n    leftZone.setAttribute(\"id\", \"joystickLeftZone\");\n    leftZone.setAttribute(\n      \"style\",\n      `position:absolute;${this.data.moveJoystickPosition}:${this.data.sideMargin};bottom:${this.data.bottomMargin};z-index:1`\n    );\n    document.body.appendChild(leftZone);\n    this.leftZone = leftZone;\n  },\n\n  initRightZone() {\n    const rightZone = document.createElement(\"div\");\n    rightZone.setAttribute(\"id\", \"joystickRightZone\");\n    rightZone.setAttribute(\n      \"style\",\n      `position:absolute;${this.data.lookJoystickPosition}:${this.data.sideMargin};bottom:${this.data.bottomMargin};z-index:1`\n    );\n    document.body.appendChild(rightZone);\n    this.rightZone = rightZone;\n  },\n\n  createMoveJoystick() {\n    if (this.moveJoystick) return;\n    this.initLeftZone();\n    const options = {\n      mode: this.data.mode,\n      zone: this.leftZone,\n      color: \"white\",\n      fadeTime: 0,\n    };\n    this.leftZone.style.width = \"100px\";\n    if (this.data.mode === \"static\") {\n      this.leftZone.style.height = \"100px\";\n      options.position = { left: \"50%\", bottom: \"50%\" };\n    } else {\n      this.leftZone.style.height = \"400px\";\n    }\n\n    this.moveJoystick = nipplejs.create(options);\n    this.moveJoystick.on(\"move\", (evt, data) => {\n      this.moveData = data;\n      this.moving = true;\n    });\n    this.moveJoystick.on(\"end\", (evt, data) => {\n      this.moving = false;\n    });\n  },\n\n  createLookJoystick() {\n    if (this.lookJoystick) return;\n    this.initRightZone();\n    const options = {\n      mode: this.data.mode,\n      zone: this.rightZone,\n      color: \"white\",\n      fadeTime: 0,\n    };\n    this.rightZone.style.width = \"100px\";\n    if (this.data.mode === \"static\") {\n      this.rightZone.style.height = \"100px\";\n      options.position = { left: \"50%\", bottom: \"50%\" };\n    } else {\n      this.rightZone.style.height = \"400px\";\n    }\n\n    this.lookJoystick = nipplejs.create(options);\n    this.lookJoystick.on(\"move\", (evt, data) => {\n      this.lookData = data;\n      this.rotating = true;\n    });\n    this.lookJoystick.on(\"end\", (evt, data) => {\n      this.rotating = false;\n    });\n  },\n\n  removeMoveJoystick() {\n    if (this.moveJoystick) {\n      this.moveJoystick.destroy();\n      this.moveJoystick = undefined;\n    }\n\n    this.moveData = undefined;\n\n    if (this.leftZone && this.leftZone.parentNode) {\n      this.leftZone.remove();\n      this.leftZone = undefined;\n    }\n  },\n\n  removeLookJoystick() {\n    if (this.lookJoystick) {\n      this.lookJoystick.destroy();\n      this.lookJoystick = undefined;\n    }\n\n    this.lookData = undefined;\n\n    if (this.rightZone && this.rightZone.parentNode) {\n      this.rightZone.remove();\n      this.rightZone = undefined;\n    }\n  },\n});\n","/**\n * Touch-to-move-forward controls for mobile.\n */\nmodule.exports = AFRAME.registerComponent('touch-controls', {\n  schema: {\n    enabled: { default: true },\n    reverseEnabled: { default: true }\n  },\n\n  init: function () {\n    this.dVelocity = new THREE.Vector3();\n    this.bindMethods();\n    this.direction = 0;\n  },\n\n  play: function () {\n    this.addEventListeners();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n    this.dVelocity.set(0, 0, 0);\n  },\n\n  remove: function () {\n    this.pause();\n  },\n\n  addEventListeners: function () {\n    const sceneEl = this.el.sceneEl;\n    const canvasEl = sceneEl.canvas;\n\n    if (!canvasEl) {\n      sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));\n      return;\n    }\n\n    canvasEl.addEventListener('touchstart', this.onTouchStart, {passive: true});\n    canvasEl.addEventListener('touchend', this.onTouchEnd, {passive: true});\n    const vrModeUI = sceneEl.getAttribute('vr-mode-ui');\n    if (vrModeUI && vrModeUI.cardboardModeEnabled) {\n      sceneEl.addEventListener('enter-vr', this.onEnterVR);\n    }\n  },\n\n  removeEventListeners: function () {\n    const canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;\n    if (!canvasEl) { return; }\n\n    canvasEl.removeEventListener('touchstart', this.onTouchStart);\n    canvasEl.removeEventListener('touchend', this.onTouchEnd);\n    this.el.sceneEl.removeEventListener('enter-vr', this.onEnterVR)\n  },\n\n  isVelocityActive: function () {\n    return this.data.enabled && !!this.direction;\n  },\n\n  getVelocityDelta: function () {\n    this.dVelocity.z = this.direction;\n    return this.dVelocity.clone();\n  },\n\n  bindMethods: function () {\n    this.onTouchStart = this.onTouchStart.bind(this);\n    this.onTouchEnd = this.onTouchEnd.bind(this);\n    this.onEnterVR = this.onEnterVR.bind(this);\n  },\n\n  onTouchStart: function (e) {\n    this.direction = -1;\n    if (this.data.reverseEnabled && e.touches && e.touches.length === 2) {\n      this.direction = 1;\n    }\n    e.preventDefault();\n  },\n\n  onTouchEnd: function (e) {\n    this.direction = 0;\n    e.preventDefault();\n  },\n\n  onEnterVR: function () {\n    // This is to make the Cardboard button on Chrome Android working\n    const xrSession = this.el.sceneEl.xrSession;\n    if (!xrSession) { return; }\n    xrSession.addEventListener('selectstart', this.onTouchStart);\n    xrSession.addEventListener('selectend', this.onTouchEnd);\n  }\n});\n","/**\n * 3dof (Gear VR, Daydream) controls for mobile.\n */\nmodule.exports = AFRAME.registerComponent('trackpad-controls', {\n  schema: {\n    enabled: { default: true },\n    enableNegX: { default: true },\n    enablePosX: { default: true },\n    enableNegZ: { default: true },\n    enablePosZ: { default: true },\n    mode: { default: 'touch', oneOf: ['swipe', 'touch', 'press'] }\n\n  },\n\n  init: function () {\n    this.dVelocity = new THREE.Vector3();\n    this.zVel      = 0;\n    this.xVel      = 0;\n    this.bindMethods();\n  },\n\n  play: function () {\n    this.addEventListeners();\n  },\n\n  pause: function () {\n    this.removeEventListeners();\n    this.dVelocity.set(0, 0, 0);\n  },\n\n  remove: function () {\n    this.pause();\n  },\n\n  addEventListeners: function () {\n    const data = this.data;\n    const sceneEl = this.el.sceneEl;\n\n    sceneEl.addEventListener('axismove', this.onAxisMove);\n\n    switch (data.mode) {\n      case 'swipe':\n      case 'touch':\n        sceneEl.addEventListener('trackpadtouchstart', this.onTouchStart);\n        sceneEl.addEventListener('trackpadtouchend', this.onTouchEnd);\n        break;\n\n      case 'press':\n        sceneEl.addEventListener('trackpaddown', this.onTouchStart);\n        sceneEl.addEventListener('trackpadup', this.onTouchEnd);\n        break;\n    }\n\n  },\n\n  removeEventListeners: function () {\n    const sceneEl = this.el.sceneEl;\n\n    sceneEl.removeEventListener('axismove', this.onAxisMove);\n    sceneEl.removeEventListener('trackpadtouchstart', this.onTouchStart);\n    sceneEl.removeEventListener('trackpadtouchend', this.onTouchEnd);\n    sceneEl.removeEventListener('trackpaddown', this.onTouchStart);\n    sceneEl.removeEventListener('trackpadup', this.onTouchEnd);\n  },\n\n  isVelocityActive: function () {\n    return this.data.enabled && this.isMoving;\n  },\n\n  getVelocityDelta: function () {\n    this.dVelocity.z = this.isMoving ? -this.zVel : 1;\n    this.dVelocity.x = this.isMoving ? this.xVel : 1;\n    return this.dVelocity.clone();\n  },\n\n  bindMethods: function () {\n    this.onTouchStart = this.onTouchStart.bind(this);\n    this.onTouchEnd = this.onTouchEnd.bind(this);\n    this.onAxisMove = this.onAxisMove.bind(this);\n  },\n\n  onTouchStart: function (e) {\n    switch(this.data.mode){\n      case 'swipe':\n        this.canRecordAxis = true;\n        this.startingAxisData = [];\n        break;\n      case 'touch':\n        this.isMoving = true;\n        break;\n      case 'press':\n        this.isMoving = true;\n        break;\n    }\n\n    e.preventDefault();\n  },\n\n  onTouchEnd: function (e) {\n    if(this.data.mode == 'swipe') {\n        this.startingAxisData = [];\n    }\n\n    this.isMoving = false;\n    e.preventDefault();\n  },\n\n  onAxisMove: function(e){\n    switch (this.data.mode) {\n      case 'swipe':\n        return this.handleSwipeAxis(e);\n      case 'touch':\n      case 'press':\n        return this.handleTouchAxis(e);\n    }\n  },\n\n  handleSwipeAxis: function(e) {\n    const data = this.data;\n    const axisData = e.detail.axis;\n\n    if(this.startingAxisData.length === 0 && this.canRecordAxis){\n      this.canRecordAxis = false;\n      this.startingAxisData[0] = axisData[0];\n      this.startingAxisData[1] = axisData[1];\n    }\n\n    if(this.startingAxisData.length > 0){\n      let velX = 0;\n      let velZ = 0;\n\n      if (data.enableNegX && axisData[0] < this.startingAxisData[0]) {\n        velX = -1;\n      }\n\n      if (data.enablePosX && axisData[0] > this.startingAxisData[0]) {\n        velX = 1;\n      }\n\n      if (data.enablePosZ && axisData[1] > this.startingAxisData[1]) {\n        velZ = -1;\n      }\n\n      if (data.enableNegZ && axisData[1] < this.startingAxisData[1]) {\n        velZ = 1;\n      }\n\n      const absChangeZ  = Math.abs(this.startingAxisData[1] - axisData[1]);\n      const absChangeX  = Math.abs(this.startingAxisData[0] - axisData[0]);\n\n      if (absChangeX > absChangeZ) {\n        this.zVel = 0;\n        this.xVel = velX;\n        this.isMoving = true;\n      } else {\n        this.xVel = 0;\n        this.zVel = velZ;\n        this.isMoving = true;\n      }\n\n    }\n  },\n\n  handleTouchAxis: function(e) {\n    const data = this.data;\n    const axisData = e.detail.axis;\n\n    let velX = 0;\n    let velZ = 0;\n\n    if (data.enableNegX && axisData[0] < 0) {\n      velX = -1;\n    }\n\n    if (data.enablePosX && axisData[0] > 0) {\n      velX = 1;\n    }\n\n    if (data.enablePosZ && axisData[1] > 0) {\n      velZ = -1;\n    }\n\n    if (data.enableNegZ && axisData[1] < 0) {\n      velZ = 1;\n    }\n\n    if (Math.abs(axisData[0]) > Math.abs(axisData[1])) {\n      this.zVel = 0;\n      this.xVel = velX;\n    } else {\n      this.xVel = 0;\n      this.zVel = velZ;\n    }\n\n  }\n\n});\n\n","const LoopMode = {\n  once: THREE.LoopOnce,\n  repeat: THREE.LoopRepeat,\n  pingpong: THREE.LoopPingPong\n};\n\n/**\n * animation-mixer\n *\n * Player for animation clips. Intended to be compatible with any model format that supports\n * skeletal or morph animations through THREE.AnimationMixer.\n * See: https://threejs.org/docs/?q=animation#Reference/Animation/AnimationMixer\n */\nmodule.exports = AFRAME.registerComponent('animation-mixer', {\n  schema: {\n    clip: { default: '*' },\n    useRegExp: {default: false},\n    duration: { default: 0 },\n    clampWhenFinished: { default: false, type: 'boolean' },\n    crossFadeDuration: { default: 0 },\n    loop: { default: 'repeat', oneOf: Object.keys(LoopMode) },\n    repetitions: { default: Infinity, min: 0 },\n    timeScale: { default: 1 },\n    startAt: { default: 0 }\n  },\n\n  init: function () {\n    /** @type {THREE.Mesh} */\n    this.model = null;\n    /** @type {THREE.AnimationMixer} */\n    this.mixer = null;\n    /** @type {Array<THREE.AnimationAction>} */\n    this.activeActions = [];\n\n    const model = this.el.getObject3D('mesh');\n\n    if (model) {\n      this.load(model);\n    } else {\n      this.el.addEventListener('model-loaded', (e) => {\n        this.load(e.detail.model);\n      });\n    }\n  },\n\n  load: function (model) {\n    const el = this.el;\n    this.model = model;\n    this.mixer = new THREE.AnimationMixer(model);\n    this.mixer.addEventListener('loop', (e) => {\n      el.emit('animation-loop', { action: e.action, loopDelta: e.loopDelta });\n    });\n    this.mixer.addEventListener('finished', (e) => {\n      el.emit('animation-finished', { action: e.action, direction: e.direction });\n    });\n    if (this.data.clip) this.update({});\n  },\n\n  remove: function () {\n    if (this.mixer) this.mixer.stopAllAction();\n  },\n\n  update: function (prevData) {\n    if (!prevData) return;\n\n    const data = this.data;\n    const changes = AFRAME.utils.diff(data, prevData);\n\n    // If selected clips have changed, restart animation.\n    if ('clip' in changes) {\n      this.stopAction();\n      if (data.clip) this.playAction();\n      return;\n    }\n\n    // Otherwise, modify running actions.\n    this.activeActions.forEach((action) => {\n      if ('duration' in changes && data.duration) {\n        action.setDuration(data.duration);\n      }\n      if ('clampWhenFinished' in changes) {\n        action.clampWhenFinished = data.clampWhenFinished;\n      }\n      if ('loop' in changes || 'repetitions' in changes) {\n        action.setLoop(LoopMode[data.loop], data.repetitions);\n      }\n      if ('timeScale' in changes) {\n        action.setEffectiveTimeScale(data.timeScale);\n      }\n    });\n  },\n\n  stopAction: function () {\n    const data = this.data;\n    for (let i = 0; i < this.activeActions.length; i++) {\n      data.crossFadeDuration\n        ? this.activeActions[i].fadeOut(data.crossFadeDuration)\n        : this.activeActions[i].stop();\n    }\n    this.activeActions.length = 0;\n  },\n\n  playAction: function () {\n    if (!this.mixer) return;\n\n    const model = this.model,\n      data = this.data,\n      clips = model.animations || (model.geometry || {}).animations || [];\n\n    if (!clips.length) return;\n\n    const re = data.useRegExp ? data.clip : wildcardToRegExp(data.clip);\n\n    for (let clip, i = 0; (clip = clips[i]); i++) {\n      if (clip.name.match(re)) {\n        const action = this.mixer.clipAction(clip, model);\n\n        action.enabled = true;\n        action.clampWhenFinished = data.clampWhenFinished;\n        if (data.duration) action.setDuration(data.duration);\n        if (data.timeScale !== 1) action.setEffectiveTimeScale(data.timeScale);\n        // animation-mixer.startAt and AnimationAction.startAt have very different meanings.\n        // animation-mixer.startAt indicates which frame in the animation to start at, in msecs.\n        // AnimationAction.startAt indicates when to start the animation (from the 1st frame),\n        // measured in global mixer time, in seconds.\n        action.startAt(this.mixer.time - data.startAt / 1000);\n        action\n          .setLoop(LoopMode[data.loop], data.repetitions)\n          .fadeIn(data.crossFadeDuration)\n          .play();\n        this.activeActions.push(action);\n      }\n    }\n  },\n\n  tick: function (t, dt) {\n    if (this.mixer && !isNaN(dt)) this.mixer.update(dt / 1000);\n  }\n});\n\n/**\n * Creates a RegExp from the given string, converting asterisks to .* expressions,\n * and escaping all other characters.\n */\nfunction wildcardToRegExp(s) {\n  return new RegExp('^' + s.split(/\\*+/).map(regExpEscape).join('.*') + '$');\n}\n\n/**\n * RegExp-escapes all characters in the given string.\n */\nfunction regExpEscape(s) {\n  return s.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&');\n}\n","import { ColladaLoader } from 'three/addons/loaders/ColladaLoader.js';\nTHREE.ColladaLoader = ColladaLoader;\n\n/**\n * collada-model-legacy\n *\n * Loader for COLLADA (.dae) format.\n */\nAFRAME.registerComponent('collada-model-legacy', {\n  schema: {type: 'asset'},\n\n  init: function () {\n    this.model = null;\n    this.loader = new THREE.ColladaLoader();\n  },\n\n  update: function () {\n    var self = this;\n    var el = this.el;\n    var src = this.data;\n    var rendererSystem = this.el.sceneEl.systems.renderer;\n\n    if (!src) { return; }\n\n    this.remove();\n\n    this.loader.load(src, function (colladaModel) {\n      self.model = colladaModel.scene;\n      self.model.traverse(function (object) {\n        if (object.isMesh) {\n          var material = object.material;\n          if (material.color) rendererSystem.applyColorCorrection(material.color);\n          if (material.map) rendererSystem.applyColorCorrection(material.map);\n          if (material.emissive) rendererSystem.applyColorCorrection(material.emissive);\n          if (material.emissiveMap) rendererSystem.applyColorCorrection(material.emissiveMap);\n        }\n      });\n      el.setObject3D('mesh', self.model);\n      el.emit('model-loaded', {format: 'collada', model: self.model});\n    });\n  },\n\n  remove: function () {\n    if (!this.model) { return; }\n    this.el.removeObject3D('mesh');\n  }\n});\n","import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';\nTHREE.FBXLoader = FBXLoader;\n\n/**\n * fbx-model\n *\n * Loader for FBX format.\n */\nAFRAME.registerComponent('fbx-model', {\n  schema: {\n    src:         { type: 'asset' },\n    crossorigin: { default: '' }\n  },\n\n  init: function () {\n    this.model = null;\n  },\n\n  update: function () {\n    const data = this.data;\n    if (!data.src) return;\n\n    this.remove();\n    const loader = new THREE.FBXLoader();\n    if (data.crossorigin) loader.setCrossOrigin(data.crossorigin);\n    loader.load(data.src, this.load.bind(this));\n  },\n\n  load: function (model) {\n    this.model = model;\n    this.el.setObject3D('mesh', model);\n    this.el.emit('model-loaded', {format: 'fbx', model: model});\n  },\n\n  remove: function () {\n    if (this.model) this.el.removeObject3D('mesh');\n  }\n});\n","const fetchScript = require('../../lib/fetch-script')();\n\nconst LOADER_SRC = 'https://cdn.jsdelivr.net/gh/mrdoob/three.js@r86/examples/js/loaders/GLTFLoader.js';\n\nconst loadLoader = (function () {\n  let promise;\n  return function () {\n    promise = promise || fetchScript(LOADER_SRC);\n    return promise;\n  };\n}());\n\n/**\n * Legacy loader for glTF 1.0 models.\n * Asynchronously loads THREE.GLTFLoader from jsdelivr.\n */\nmodule.exports = AFRAME.registerComponent('gltf-model-legacy', {\n  schema: {type: 'model'},\n\n  init: function () {\n    this.model = null;\n    this.loader = null;\n    this.loaderPromise = loadLoader().then(() => {\n      this.loader = new THREE.GLTFLoader();\n      this.loader.setCrossOrigin('Anonymous');\n    });\n  },\n\n  update: function () {\n    const self = this;\n    const el = this.el;\n    const src = this.data;\n\n    if (!src) { return; }\n\n    this.remove();\n\n    this.loaderPromise.then(() => {\n      this.loader.load(src, function gltfLoaded (gltfModel) {\n        self.model = gltfModel.scene;\n        self.model.animations = gltfModel.animations;\n        el.setObject3D('mesh', self.model);\n        el.emit('model-loaded', {format: 'gltf', model: self.model});\n      });\n    });\n  },\n\n  remove: function () {\n    if (!this.model) { return; }\n    this.el.removeObject3D('mesh');\n  }\n});\n","require('./animation-mixer');\nrequire('./collada-model-legacy');\nrequire('./fbx-model');\nrequire('./gltf-model-legacy');\nrequire('./object-model');\n","/**\n * object-model\n *\n * Loader for THREE.js JSON format. Somewhat confusingly, there are two different THREE.js formats,\n * both having the .json extension. This loader supports only THREE.ObjectLoader, which typically\n * includes multiple meshes or an entire scene.\n *\n * Check the console for errors, if in doubt. You may need to use `json-model` or\n * `blend-character-model` for some .js and .json files.\n *\n * See: https://clara.io/learn/user-guide/data_exchange/threejs_export\n */\nmodule.exports = AFRAME.registerComponent('object-model', {\n  schema: {\n    src:         { type: 'asset' },\n    crossorigin: { default: '' }\n  },\n\n  init: function () {\n    this.model = null;\n  },\n\n  update: function () {\n    let loader;\n    const data = this.data;\n    if (!data.src) return;\n\n    this.remove();\n    loader = new THREE.ObjectLoader();\n    if (data.crossorigin) loader.setCrossOrigin(data.crossorigin);\n    loader.load(data.src, (object) => {\n\n      // Enable skinning, if applicable.\n      object.traverse((o) => {\n        if (o instanceof THREE.SkinnedMesh && o.material) {\n          o.material.skinning = !!((o.geometry && o.geometry.bones) || []).length;\n        }\n      });\n\n      this.load(object);\n    });\n  },\n\n  load: function (model) {\n    this.model = model;\n    this.el.setObject3D('mesh', model);\n    this.el.emit('model-loaded', {format: 'json', model: model});\n  },\n\n  remove: function () {\n    if (this.model) this.el.removeObject3D('mesh');\n  }\n});\n","module.exports = AFRAME.registerComponent('checkpoint', {\n  schema: {\n    offset: {default: {x: 0, y: 0, z: 0}, type: 'vec3'}\n  },\n\n  init: function () {\n    this.active = false;\n    this.targetEl = null;\n    this.fire = this.fire.bind(this);\n    this.offset = new THREE.Vector3();\n  },\n\n  update: function () {\n    this.offset.copy(this.data.offset);\n  },\n\n  play: function () { this.el.addEventListener('click', this.fire); },\n  pause: function () { this.el.removeEventListener('click', this.fire); },\n  remove: function () { this.pause(); },\n\n  fire: function () {\n    const targetEl = this.el.sceneEl.querySelector('[checkpoint-controls]');\n    if (!targetEl) {\n      throw new Error('No `checkpoint-controls` component found.');\n    }\n    targetEl.components['checkpoint-controls'].setCheckpoint(this.el);\n  },\n\n  getOffset: function () {\n    return this.offset.copy(this.data.offset);\n  }\n});\n","/**\n * @param  {Array<THREE.Material>|THREE.Material} material\n * @return {Array<THREE.Material>}\n */\nfunction ensureMaterialArray (material) {\n  if (!material) {\n    return [];\n  } else if (Array.isArray(material)) {\n    return material;\n  } else if (material.materials) {\n    return material.materials;\n  } else {\n    return [material];\n  }\n}\n\n/**\n * @param  {THREE.Object3D} mesh\n * @param  {Array<string>} materialNames\n * @param  {THREE.Texture} envMap\n * @param  {number} reflectivity  [description]\n */\nfunction applyEnvMap (mesh, materialNames, envMap, reflectivity) {\n  if (!mesh) return;\n\n  materialNames = materialNames || [];\n\n  mesh.traverse((node) => {\n\n    if (!node.isMesh) return;\n\n    const meshMaterials = ensureMaterialArray(node.material);\n\n    meshMaterials.forEach((material) => {\n\n      if (material && !('envMap' in material)) return;\n      if (materialNames.length && materialNames.indexOf(material.name) === -1) return;\n\n      material.envMap = envMap;\n      material.reflectivity = reflectivity;\n      material.needsUpdate = true;\n\n    });\n\n  });\n}\n\n/**\n * Specifies an envMap on an entity, without replacing any existing material\n * properties.\n */\nmodule.exports = AFRAME.registerComponent('cube-env-map', {\n  multiple: true,\n\n  schema: {\n    path: {default: ''},\n    extension: {default: 'jpg', oneOf: ['jpg', 'png']},\n    enableBackground: {default: false},\n    reflectivity: {default: 1, min: 0, max: 1},\n    materials: {default: []}\n  },\n\n  init: function () {\n    const data = this.data;\n\n    this.texture = new THREE.CubeTextureLoader().load([\n      data.path + 'posx.' + data.extension, data.path + 'negx.' + data.extension,\n      data.path + 'posy.' + data.extension, data.path + 'negy.' + data.extension,\n      data.path + 'posz.' + data.extension, data.path + 'negz.' + data.extension\n    ]);\n    this.texture.format = THREE.RGBAFormat;\n\n    this.object3dsetHandler = () => {\n      const mesh = this.el.getObject3D('mesh');\n      const data = this.data;\n      applyEnvMap(mesh, data.materials, this.texture, data.reflectivity);\n    };\n\n    this.object3dsetHandler();\n    this.el.addEventListener('object3dset', this.object3dsetHandler);\n    \n  },\n\n  update: function (oldData) {\n    const data = this.data;\n    const mesh = this.el.getObject3D('mesh');\n\n    let addedMaterialNames = [];\n    let removedMaterialNames = [];\n\n    if (data.materials.length) {\n      if (oldData.materials) {\n        addedMaterialNames = data.materials.filter((name) => !oldData.materials.includes(name));\n        removedMaterialNames = oldData.materials.filter((name) => !data.materials.includes(name));\n      } else {\n        addedMaterialNames = data.materials;\n      }\n    }\n    if (addedMaterialNames.length) {\n      applyEnvMap(mesh, addedMaterialNames, this.texture, data.reflectivity);\n    }\n    if (removedMaterialNames.length) {\n      applyEnvMap(mesh, removedMaterialNames, null, 1);\n    }\n\n    if (oldData.materials && data.reflectivity !== oldData.reflectivity) {\n      const maintainedMaterialNames = data.materials\n        .filter((name) => oldData.materials.includes(name));\n      if (maintainedMaterialNames.length) {\n        applyEnvMap(mesh, maintainedMaterialNames, this.texture, data.reflectivity);\n      }\n    }\n\n    if (this.data.enableBackground && !oldData.enableBackground) {\n      this.setBackground(this.texture);\n    } else if (!this.data.enableBackground && oldData.enableBackground) {\n      this.setBackground(null);\n    }\n  },\n\n  remove: function () {\n    this.el.removeEventListener('object3dset', this.object3dsetHandler);\n    const mesh = this.el.getObject3D('mesh');\n    const data = this.data;\n\n    applyEnvMap(mesh, data.materials, null, 1);\n    if (data.enableBackground) this.setBackground(null);\n  },\n\n  setBackground: function (texture) {\n    this.el.sceneEl.object3D.background = texture;\n  }\n});","/* global CANNON */\n\n/**\n * Based on aframe/examples/showcase/tracked-controls.\n *\n * Handles events coming from the hand-controls.\n * Determines if the entity is grabbed or released.\n * Updates its position to move along the controller.\n */\nmodule.exports = AFRAME.registerComponent('grab', {\n  init: function () {\n    this.system = this.el.sceneEl.systems.physics;\n\n    this.GRABBED_STATE = 'grabbed';\n\n    this.grabbing = false;\n    this.hitEl =      /** @type {AFRAME.Element}    */ null;\n    this.physics =    /** @type {AFRAME.System}     */ this.el.sceneEl.systems.physics;\n    this.constraint = /** @type {CANNON.Constraint} */ null;\n\n    // Bind event handlers\n    this.onHit = this.onHit.bind(this);\n    this.onGripOpen = this.onGripOpen.bind(this);\n    this.onGripClose = this.onGripClose.bind(this);\n  },\n\n  play: function () {\n    const el = this.el;\n    el.addEventListener('hit', this.onHit);\n    el.addEventListener('gripdown', this.onGripClose);\n    el.addEventListener('gripup', this.onGripOpen);\n    el.addEventListener('trackpaddown', this.onGripClose);\n    el.addEventListener('trackpadup', this.onGripOpen);\n    el.addEventListener('triggerdown', this.onGripClose);\n    el.addEventListener('triggerup', this.onGripOpen);\n  },\n\n  pause: function () {\n    const el = this.el;\n    el.removeEventListener('hit', this.onHit);\n    el.removeEventListener('gripdown', this.onGripClose);\n    el.removeEventListener('gripup', this.onGripOpen);\n    el.removeEventListener('trackpaddown', this.onGripClose);\n    el.removeEventListener('trackpadup', this.onGripOpen);\n    el.removeEventListener('triggerdown', this.onGripClose);\n    el.removeEventListener('triggerup', this.onGripOpen);\n  },\n\n  onGripClose: function () {\n    this.grabbing = true;\n  },\n\n  onGripOpen: function () {\n    const hitEl = this.hitEl;\n    this.grabbing = false;\n    if (!hitEl) { return; }\n    hitEl.removeState(this.GRABBED_STATE);\n    this.hitEl = undefined;\n    this.system.removeConstraint(this.constraint);\n    this.constraint = null;\n  },\n\n  onHit: function (evt) {\n    const hitEl = evt.detail.el;\n    // If the element is already grabbed (it could be grabbed by another controller).\n    // If the hand is not grabbing the element does not stick.\n    // If we're already grabbing something you can't grab again.\n    if (hitEl.is(this.GRABBED_STATE) || !this.grabbing || this.hitEl) { return; }\n    hitEl.addState(this.GRABBED_STATE);\n    this.hitEl = hitEl;\n    this.constraint = new CANNON.LockConstraint(this.el.body, hitEl.body);\n    this.system.addConstraint(this.constraint);\n  }\n});\n","require('./checkpoint');\nrequire('./cube-env-map');\nrequire('./grab');\nrequire('./normal-material');\nrequire('./sphere-collider');\n","/**\n * Recursively applies a MeshNormalMaterial to the entity, such that\n * face colors are determined by their orientation. Helpful for\n * debugging geometry\n */\nmodule.exports = AFRAME.registerComponent('normal-material', {\n  init: function () {\n    this.material = new THREE.MeshNormalMaterial({flatShading: true});\n    this.applyMaterial = this.applyMaterial.bind(this);\n    this.el.addEventListener('object3dset', this.applyMaterial);\n    this.applyMaterial();\n  },\n\n  remove: function () {\n    this.el.removeEventListener('object3dset', this.applyMaterial);\n  },\n\n  applyMaterial: function () {\n    this.el.object3D.traverse((node) => {\n      if (node.isMesh) node.material = this.material;\n    });\n  }\n});\n","/**\n * Based on aframe/examples/showcase/tracked-controls.\n *\n * Implement bounding sphere collision detection for entities with a mesh.\n * Sets the specified state on the intersected entities.\n *\n * @property {string} objects - Selector of the entities to test for collision.\n * @property {string} state - State to set on collided entities.\n *\n */\nmodule.exports = AFRAME.registerComponent('sphere-collider', {\n  schema: {\n    enabled: {default: true},\n    interval: {default: 80},\n    objects: {default: ''},\n    state: {default: 'collided'},\n    radius: {default: 0.05},\n    watch: {default: true}\n  },\n\n  init: function () {\n    /** @type {MutationObserver} */\n    this.observer = null;\n    /** @type {Array<Element>} Elements to watch for collisions. */\n    this.els = [];\n    /** @type {Array<Element>} Elements currently in collision state. */\n    this.collisions = [];\n    this.prevCheckTime = undefined;\n\n    this.eventDetail = {};\n    this.handleHit = this.handleHit.bind(this);\n    this.handleHitEnd = this.handleHitEnd.bind(this);\n  },\n\n  play: function () {\n    const sceneEl = this.el.sceneEl;\n\n    if (this.data.watch) {\n      this.observer = new MutationObserver(this.update.bind(this, null));\n      this.observer.observe(sceneEl, {childList: true, subtree: true});\n    }\n  },\n\n  pause: function () {\n    if (this.observer) {\n      this.observer.disconnect();\n      this.observer = null;\n    }\n  },\n\n  /**\n   * Update list of entities to test for collision.\n   */\n  update: function () {\n    const data = this.data;\n    let objectEls;\n\n    // Push entities into list of els to intersect.\n    if (data.objects) {\n      objectEls = this.el.sceneEl.querySelectorAll(data.objects);\n    } else {\n      // If objects not defined, intersect with everything.\n      objectEls = this.el.sceneEl.children;\n    }\n    // Convert from NodeList to Array\n    this.els = Array.prototype.slice.call(objectEls);\n  },\n\n  tick: (function () {\n    const position = new THREE.Vector3(),\n        meshPosition = new THREE.Vector3(),\n        colliderScale = new THREE.Vector3(),\n        size = new THREE.Vector3(),\n        box = new THREE.Box3(),\n        collisions = [],\n        distanceMap = new Map();\n    return function (time) {\n      if (!this.data.enabled) { return; }\n\n      // Only check for intersection if interval time has passed.\n      const prevCheckTime = this.prevCheckTime;\n      if (prevCheckTime && (time - prevCheckTime < this.data.interval)) { return; }\n      // Update check time.\n      this.prevCheckTime = time;\n\n      const el = this.el,\n          data = this.data,\n          mesh = el.getObject3D('mesh');\n      let colliderRadius;\n\n      if (!mesh) { return; }\n\n      collisions.length = 0;\n      distanceMap.clear();\n      el.object3D.getWorldPosition(position);\n      el.object3D.getWorldScale(colliderScale);\n      colliderRadius = data.radius * scaleFactor(colliderScale);\n      // Update collision list.\n      this.els.forEach(intersect);\n\n      // Emit events and add collision states, in order of distance.\n      collisions\n        .sort((a, b) => distanceMap.get(a) > distanceMap.get(b) ? 1 : -1)\n        .forEach(this.handleHit);\n\n      // Remove collision state from other elements.\n      this.collisions\n        .filter((el) => !distanceMap.has(el))\n        .forEach(this.handleHitEnd);\n\n      // Store new collisions\n      copyArray(this.collisions, collisions);\n\n      // Bounding sphere collision detection\n      function intersect (el) {\n        let radius, mesh, distance, extent;\n\n        if (!el.isEntity) { return; }\n\n        mesh = el.getObject3D('mesh');\n\n        if (!mesh) { return; }\n\n        box.setFromObject(mesh).getSize(size);\n        extent = Math.max(size.x, size.y, size.z) / 2;\n        radius = Math.sqrt(2 * extent * extent);\n        box.getCenter(meshPosition);\n\n        if (!radius) { return; }\n\n        distance = position.distanceTo(meshPosition);\n        if (distance < radius + colliderRadius) {\n          collisions.push(el);\n          distanceMap.set(el, distance);\n        }\n      }\n      // use max of scale factors to maintain bounding sphere collision\n      function scaleFactor (scaleVec) {\n        return Math.max(scaleVec.x, scaleVec.y, scaleVec.z);\n      }\n    };\n  })(),\n\n  handleHit: function (targetEl) {\n    targetEl.emit('hit');\n    targetEl.addState(this.data.state);\n    this.eventDetail.el = targetEl;\n    this.el.emit('hit', this.eventDetail);\n  },\n  handleHitEnd: function (targetEl) {\n    targetEl.emit('hitend');\n    targetEl.removeState(this.data.state);\n    this.eventDetail.el = targetEl;\n    this.el.emit('hitend', this.eventDetail);\n  }\n});\n\nfunction copyArray (dest, source) {\n  dest.length = 0;\n  for (let i = 0; i < source.length; i++) { dest[i] = source[i]; }\n}\n","require('./nav-mesh');\nrequire('./nav-agent');\nrequire('./system');\n","module.exports = AFRAME.registerComponent('nav-agent', {\n  schema: {\n    destination: {type: 'vec3'},\n    active: {default: false},\n    speed: {default: 2}\n  },\n  init: function () {\n    this.system = this.el.sceneEl.systems.nav;\n    this.system.addAgent(this);\n    this.group = null;\n    this.path = [];\n    this.raycaster = new THREE.Raycaster();\n  },\n  remove: function () {\n    this.system.removeAgent(this);\n  },\n  update: function () {\n    this.path.length = 0;\n  },\n  updateNavLocation: function () {\n    this.group = null;\n    this.path = [];\n  },\n  tick: (function () {\n    const vDest = new THREE.Vector3();\n    const vDelta = new THREE.Vector3();\n    const vNext = new THREE.Vector3();\n\n    return function (t, dt) {\n      const el = this.el;\n      const data = this.data;\n      const raycaster = this.raycaster;\n      const speed = data.speed * dt / 1000;\n\n      if (!data.active) return;\n\n      // Use PatrolJS pathfinding system to get shortest path to target.\n      if (!this.path.length) {\n        const position = this.el.object3D.position;\n        this.group = this.group || this.system.getGroup(position);\n        this.path = this.system.getPath(position, vDest.copy(data.destination), this.group) || [];\n        el.emit('navigation-start');\n      }\n\n      // If no path is found, exit.\n      if (!this.path.length) {\n        console.warn('[nav] Unable to find path to %o.', data.destination);\n        this.el.setAttribute('nav-agent', {active: false});\n        el.emit('navigation-end');\n        return;\n      }\n\n      // Current segment is a vector from current position to next waypoint.\n      const vCurrent = el.object3D.position;\n      const vWaypoint = this.path[0];\n      vDelta.subVectors(vWaypoint, vCurrent);\n\n      const distance = vDelta.length();\n      let gazeTarget;\n\n      if (distance < speed) {\n        // If <1 step from current waypoint, discard it and move toward next.\n        this.path.shift();\n\n        // After discarding the last waypoint, exit pathfinding.\n        if (!this.path.length) {\n          this.el.setAttribute('nav-agent', {active: false});\n          el.emit('navigation-end');\n          return;\n        }\n\n        vNext.copy(vCurrent);\n        gazeTarget = this.path[0];\n      } else {\n        // If still far away from next waypoint, find next position for\n        // the current frame.\n        vNext.copy(vDelta.setLength(speed)).add(vCurrent);\n        gazeTarget = vWaypoint;\n      }\n\n      // Look at the next waypoint.\n      gazeTarget.y = vCurrent.y;\n      el.object3D.lookAt(gazeTarget);\n\n      // Raycast against the nav mesh, to keep the agent moving along the\n      // ground, not traveling in a straight line from higher to lower waypoints.\n      raycaster.ray.origin.copy(vNext);\n      raycaster.ray.origin.y += 1.5;\n      raycaster.ray.direction = {x:0, y:-1, z:0};\n      const intersections = raycaster.intersectObject(this.system.getNavMesh());\n\n      if (!intersections.length) {\n        // Raycasting failed. Step toward the waypoint and hope for the best.\n        vCurrent.copy(vNext);\n      } else {\n        // Re-project next position onto nav mesh.\n        vDelta.subVectors(intersections[0].point, vCurrent);\n        vCurrent.add(vDelta.setLength(speed));\n      }\n\n    };\n  }())\n});\n","/**\n * nav-mesh\n *\n * Waits for a mesh to be loaded on the current entity, then sets it as the\n * nav mesh in the pathfinding system.\n */\nmodule.exports = AFRAME.registerComponent('nav-mesh', {\n  schema: {\n    nodeName: {type: 'string'}\n  },\n\n  init: function () {\n    this.system = this.el.sceneEl.systems.nav;\n    this.hasLoadedNavMesh = false;\n    this.nodeName = this.data.nodeName;\n    this.el.addEventListener('object3dset', this.loadNavMesh.bind(this));\n  },\n\n  play: function () {\n    if (!this.hasLoadedNavMesh) this.loadNavMesh();\n  },\n\n  loadNavMesh: function () {\n    var self = this;\n    const object = this.el.getObject3D('mesh');\n    const scene = this.el.sceneEl.object3D;\n\n    if (!object) return;\n\n    let navMesh;\n    object.traverse((node) => {\n      if (node.isMesh &&\n          (!self.nodeName || node.name === self.nodeName)) navMesh = node;\n    });\n\n    if (!navMesh) return;\n\n    const navMeshGeometry = navMesh.geometry.clone();\n    navMesh.updateWorldMatrix(true, false);\n    navMeshGeometry.applyMatrix4(navMesh.matrixWorld);\n    this.system.setNavMeshGeometry(navMeshGeometry);\n    this.hasLoadedNavMesh = true;\n  }\n});\n","const { Pathfinding } = require('three-pathfinding');\n\nconst pathfinder = new Pathfinding();\nconst ZONE = 'level';\n\n/**\n * nav\n *\n * Pathfinding system, using PatrolJS.\n */\nmodule.exports = AFRAME.registerSystem('nav', {\n  init: function () {\n    this.navMesh = null;\n    this.agents = new Set();\n  },\n\n  /**\n   * @param {THREE.Geometry} geometry\n   */\n  setNavMeshGeometry: function (geometry) {\n    this.navMesh = new THREE.Mesh(geometry);\n    pathfinder.setZoneData(ZONE, Pathfinding.createZone(geometry));\n    Array.from(this.agents).forEach((agent) => agent.updateNavLocation());\n  },\n\n  /**\n   * @return {THREE.Mesh}\n   */\n  getNavMesh: function () {\n    return this.navMesh;\n  },\n\n  /**\n   * @param {NavAgent} ctrl\n   */\n  addAgent: function (ctrl) {\n    this.agents.add(ctrl);\n  },\n\n  /**\n   * @param {NavAgent} ctrl\n   */\n  removeAgent: function (ctrl) {\n    this.agents.delete(ctrl);\n  },\n\n  /**\n   * @param  {THREE.Vector3} start\n   * @param  {THREE.Vector3} end\n   * @param  {number} groupID\n   * @return {Array<THREE.Vector3>}\n   */\n  getPath: function (start, end, groupID) {\n    return this.navMesh\n      ? pathfinder.findPath(start, end, ZONE, groupID)\n      : null;\n  },\n\n  /**\n   * @param {THREE.Vector3} position\n   * @return {number}\n   */\n  getGroup: function (position) {\n    return this.navMesh\n      ? pathfinder.getGroup(ZONE, position)\n      : null;\n  },\n\n  /**\n   * @param  {THREE.Vector3} position\n   * @param  {number} groupID\n   * @return {Node}\n   */\n  getNode: function (position, groupID) {\n    return this.navMesh\n      ? pathfinder.getClosestNode(position, ZONE, groupID, true)\n      : null;\n  },\n\n  /**\n   * @param  {THREE.Vector3} start Starting position.\n   * @param  {THREE.Vector3} end Desired ending position.\n   * @param  {number} groupID\n   * @param  {Node} node\n   * @param  {THREE.Vector3} endTarget (Output) Adjusted step end position.\n   * @return {Node} Current node, after step is taken.\n   */\n  clampStep: function (start, end, groupID, node, endTarget) {\n    if (!this.navMesh) {\n      endTarget.copy(end);\n      return null;\n    } else if (!node) {\n      endTarget.copy(end);\n      return this.getNode(end, groupID);\n    }\n    return pathfinder.clampStep(start, end, node, ZONE, groupID, endTarget);\n  }\n});\n","/**\n * Flat grid.\n *\n * Defaults to 75x75.\n */\nmodule.exports = AFRAME.registerPrimitive('a-grid', {\n  defaultComponents: {\n    geometry: {\n      primitive: 'plane',\n      width: 75,\n      height: 75\n    },\n    rotation: {x: -90, y: 0, z: 0},\n    material: {\n      src: 'url(https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v1.16.3/assets/grid.png)',\n      repeat: '75 75'\n    }\n  },\n  mappings: {\n    width: 'geometry.width',\n    height: 'geometry.height',\n    src: 'material.src'\n  }\n});\n","/**\n * Flat-shaded ocean primitive.\n *\n * Based on a Codrops tutorial:\n * http://tympanus.net/codrops/2016/04/26/the-aviator-animating-basic-3d-scene-threejs/\n */\nmodule.exports.Primitive = AFRAME.registerPrimitive('a-ocean', {\n  defaultComponents: {\n    ocean: {},\n    rotation: {x: -90, y: 0, z: 0}\n  },\n  mappings: {\n    width: 'ocean.width',\n    depth: 'ocean.depth',\n    density: 'ocean.density',\n    amplitude: 'ocean.amplitude',\n    amplitudeVariance: 'ocean.amplitudeVariance',\n    speed: 'ocean.speed',\n    speedVariance: 'ocean.speedVariance',\n    color: 'ocean.color',\n    opacity: 'ocean.opacity'\n  }\n});\n\nmodule.exports.Component = AFRAME.registerComponent('ocean', {\n  schema: {\n    // Dimensions of the ocean area.\n    width: {default: 10, min: 0},\n    depth: {default: 10, min: 0},\n\n    // Density of waves.\n    density: {default: 10},\n\n    // Wave amplitude and variance.\n    amplitude: {default: 0.1},\n    amplitudeVariance: {default: 0.3},\n\n    // Wave speed and variance.\n    speed: {default: 1},\n    speedVariance: {default: 2},\n\n    // Material.\n    color: {default: '#7AD2F7', type: 'color'},\n    opacity: {default: 0.8}\n  },\n\n  /**\n   * Use play() instead of init(), because component mappings – unavailable as dependencies – are\n   * not guaranteed to have parsed when this component is initialized.\n   */\n  play: function () {\n    const el = this.el;\n    const data = this.data;\n    let material = el.components.material;\n\n    const geometry = new THREE.PlaneGeometry(data.width, data.depth, data.density, data.density);\n    this.waves = [];\n    const posAttribute = geometry.getAttribute('position');\n    for (let i = 0; i < posAttribute.count; i++) {\n      this.waves.push({\n        z: posAttribute.getZ(i),\n        ang: Math.random() * Math.PI * 2,\n        amp: data.amplitude + Math.random() * data.amplitudeVariance,\n        speed: (data.speed + Math.random() * data.speedVariance) / 1000 // radians / frame\n      });\n    }\n\n    if (!material) {\n      material = {};\n      material.material = new THREE.MeshPhongMaterial({\n        color: data.color,\n        transparent: data.opacity < 1,\n        opacity: data.opacity,\n        flatShading: true,\n      });\n    }\n\n    this.mesh = new THREE.Mesh(geometry, material.material);\n    el.setObject3D('mesh', this.mesh);\n  },\n\n  remove: function () {\n    this.el.removeObject3D('mesh');\n  },\n\n  tick: function (t, dt) {\n    if (!dt) return;\n\n    const posAttribute = this.mesh.geometry.getAttribute('position');\n    for (let i = 0; i < posAttribute.count; i++){\n      const vprops = this.waves[i];\n      const value = vprops.z + Math.sin(vprops.ang) * vprops.amp;\n      posAttribute.setZ(i, value);\n      vprops.ang += vprops.speed * dt;\n    }\n    posAttribute.needsUpdate = true;\n  }\n});\n","/**\n * Tube following a custom path.\n *\n * Usage:\n *\n * ```html\n * <a-tube path=\"5 0 5, 5 0 -5, -5 0 -5\" radius=\"0.5\"></a-tube>\n * ```\n */\nmodule.exports.Primitive = AFRAME.registerPrimitive('a-tube', {\n  defaultComponents: {\n    tube:           {},\n  },\n  mappings: {\n    path:           'tube.path',\n    segments:       'tube.segments',\n    radius:         'tube.radius',\n    'radial-segments': 'tube.radialSegments',\n    closed:         'tube.closed'\n  }\n});\n\nmodule.exports.Component = AFRAME.registerComponent('tube', {\n  schema: {\n    path:           {default: []},\n    segments:       {default: 64},\n    radius:         {default: 1},\n    radialSegments: {default: 8},\n    closed:         {default: false}\n  },\n\n  init: function () {\n    const el = this.el,\n        data = this.data;\n    let material = el.components.material;\n\n    if (!data.path.length) {\n      console.error('[a-tube] `path` property expected but not found.');\n      return;\n    }\n\n    const curve = new THREE.CatmullRomCurve3(data.path.map(function (point) {\n      point = point.split(' ');\n      return new THREE.Vector3(Number(point[0]), Number(point[1]), Number(point[2]));\n    }));\n    const geometry = new THREE.TubeGeometry(\n      curve, data.segments, data.radius, data.radialSegments, data.closed\n    );\n\n    if (!material) {\n      material = {};\n      material.material = new THREE.MeshPhongMaterial();\n    }\n\n    this.mesh = new THREE.Mesh(geometry, material.material);\n    this.el.setObject3D('mesh', this.mesh);\n  },\n\n  update: function (prevData) {\n    if (!Object.keys(prevData).length) return;\n\n    this.remove();\n    this.init();\n  },\n\n  remove: function () {\n    if (this.mesh) this.el.removeObject3D('mesh');\n  }\n});\n","require('./a-grid');\nrequire('./a-ocean');\nrequire('./a-tube');\n","module.exports = __WEBPACK_EXTERNAL_MODULE_three__;","import {\n\tCurve,\n\tVector3,\n\tVector4\n} from 'three';\nimport * as NURBSUtils from '../curves/NURBSUtils.js';\n\n/**\n * NURBS curve object\n *\n * Derives from Curve, overriding getPoint and getTangent.\n *\n * Implementation is based on (x, y [, z=0 [, w=1]]) control points with w=weight.\n *\n **/\n\nclass NURBSCurve extends Curve {\n\n\tconstructor(\n\t\tdegree,\n\t\tknots /* array of reals */,\n\t\tcontrolPoints /* array of Vector(2|3|4) */,\n\t\tstartKnot /* index in knots */,\n\t\tendKnot /* index in knots */\n\t) {\n\n\t\tsuper();\n\n\t\tthis.degree = degree;\n\t\tthis.knots = knots;\n\t\tthis.controlPoints = [];\n\t\t// Used by periodic NURBS to remove hidden spans\n\t\tthis.startKnot = startKnot || 0;\n\t\tthis.endKnot = endKnot || ( this.knots.length - 1 );\n\n\t\tfor ( let i = 0; i < controlPoints.length; ++ i ) {\n\n\t\t\t// ensure Vector4 for control points\n\t\t\tconst point = controlPoints[ i ];\n\t\t\tthis.controlPoints[ i ] = new Vector4( point.x, point.y, point.z, point.w );\n\n\t\t}\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst u = this.knots[ this.startKnot ] + t * ( this.knots[ this.endKnot ] - this.knots[ this.startKnot ] ); // linear mapping t->u\n\n\t\t// following results in (wx, wy, wz, w) homogeneous point\n\t\tconst hpoint = NURBSUtils.calcBSplinePoint( this.degree, this.knots, this.controlPoints, u );\n\n\t\tif ( hpoint.w !== 1.0 ) {\n\n\t\t\t// project to 3D space: (wx, wy, wz, w) -> (x, y, z, 1)\n\t\t\thpoint.divideScalar( hpoint.w );\n\n\t\t}\n\n\t\treturn point.set( hpoint.x, hpoint.y, hpoint.z );\n\n\t}\n\n\tgetTangent( t, optionalTarget = new Vector3() ) {\n\n\t\tconst tangent = optionalTarget;\n\n\t\tconst u = this.knots[ 0 ] + t * ( this.knots[ this.knots.length - 1 ] - this.knots[ 0 ] );\n\t\tconst ders = NURBSUtils.calcNURBSDerivatives( this.degree, this.knots, this.controlPoints, u, 1 );\n\t\ttangent.copy( ders[ 1 ] ).normalize();\n\n\t\treturn tangent;\n\n\t}\n\n}\n\nexport { NURBSCurve };\n","import {\n\tVector3,\n\tVector4\n} from 'three';\n\n/**\n * NURBS utils\n *\n * See NURBSCurve and NURBSSurface.\n **/\n\n\n/**************************************************************\n *\tNURBS Utils\n **************************************************************/\n\n/*\nFinds knot vector span.\n\np : degree\nu : parametric value\nU : knot vector\n\nreturns the span\n*/\nfunction findSpan( p, u, U ) {\n\n\tconst n = U.length - p - 1;\n\n\tif ( u >= U[ n ] ) {\n\n\t\treturn n - 1;\n\n\t}\n\n\tif ( u <= U[ p ] ) {\n\n\t\treturn p;\n\n\t}\n\n\tlet low = p;\n\tlet high = n;\n\tlet mid = Math.floor( ( low + high ) / 2 );\n\n\twhile ( u < U[ mid ] || u >= U[ mid + 1 ] ) {\n\n\t\tif ( u < U[ mid ] ) {\n\n\t\t\thigh = mid;\n\n\t\t} else {\n\n\t\t\tlow = mid;\n\n\t\t}\n\n\t\tmid = Math.floor( ( low + high ) / 2 );\n\n\t}\n\n\treturn mid;\n\n}\n\n\n/*\nCalculate basis functions. See The NURBS Book, page 70, algorithm A2.2\n\nspan : span in which u lies\nu    : parametric point\np    : degree\nU    : knot vector\n\nreturns array[p+1] with basis functions values.\n*/\nfunction calcBasisFunctions( span, u, p, U ) {\n\n\tconst N = [];\n\tconst left = [];\n\tconst right = [];\n\tN[ 0 ] = 1.0;\n\n\tfor ( let j = 1; j <= p; ++ j ) {\n\n\t\tleft[ j ] = u - U[ span + 1 - j ];\n\t\tright[ j ] = U[ span + j ] - u;\n\n\t\tlet saved = 0.0;\n\n\t\tfor ( let r = 0; r < j; ++ r ) {\n\n\t\t\tconst rv = right[ r + 1 ];\n\t\t\tconst lv = left[ j - r ];\n\t\t\tconst temp = N[ r ] / ( rv + lv );\n\t\t\tN[ r ] = saved + rv * temp;\n\t\t\tsaved = lv * temp;\n\n\t\t}\n\n\t\tN[ j ] = saved;\n\n\t}\n\n\treturn N;\n\n}\n\n\n/*\nCalculate B-Spline curve points. See The NURBS Book, page 82, algorithm A3.1.\n\np : degree of B-Spline\nU : knot vector\nP : control points (x, y, z, w)\nu : parametric point\n\nreturns point for given u\n*/\nfunction calcBSplinePoint( p, U, P, u ) {\n\n\tconst span = findSpan( p, u, U );\n\tconst N = calcBasisFunctions( span, u, p, U );\n\tconst C = new Vector4( 0, 0, 0, 0 );\n\n\tfor ( let j = 0; j <= p; ++ j ) {\n\n\t\tconst point = P[ span - p + j ];\n\t\tconst Nj = N[ j ];\n\t\tconst wNj = point.w * Nj;\n\t\tC.x += point.x * wNj;\n\t\tC.y += point.y * wNj;\n\t\tC.z += point.z * wNj;\n\t\tC.w += point.w * Nj;\n\n\t}\n\n\treturn C;\n\n}\n\n\n/*\nCalculate basis functions derivatives. See The NURBS Book, page 72, algorithm A2.3.\n\nspan : span in which u lies\nu    : parametric point\np    : degree\nn    : number of derivatives to calculate\nU    : knot vector\n\nreturns array[n+1][p+1] with basis functions derivatives\n*/\nfunction calcBasisFunctionDerivatives( span, u, p, n, U ) {\n\n\tconst zeroArr = [];\n\tfor ( let i = 0; i <= p; ++ i )\n\t\tzeroArr[ i ] = 0.0;\n\n\tconst ders = [];\n\n\tfor ( let i = 0; i <= n; ++ i )\n\t\tders[ i ] = zeroArr.slice( 0 );\n\n\tconst ndu = [];\n\n\tfor ( let i = 0; i <= p; ++ i )\n\t\tndu[ i ] = zeroArr.slice( 0 );\n\n\tndu[ 0 ][ 0 ] = 1.0;\n\n\tconst left = zeroArr.slice( 0 );\n\tconst right = zeroArr.slice( 0 );\n\n\tfor ( let j = 1; j <= p; ++ j ) {\n\n\t\tleft[ j ] = u - U[ span + 1 - j ];\n\t\tright[ j ] = U[ span + j ] - u;\n\n\t\tlet saved = 0.0;\n\n\t\tfor ( let r = 0; r < j; ++ r ) {\n\n\t\t\tconst rv = right[ r + 1 ];\n\t\t\tconst lv = left[ j - r ];\n\t\t\tndu[ j ][ r ] = rv + lv;\n\n\t\t\tconst temp = ndu[ r ][ j - 1 ] / ndu[ j ][ r ];\n\t\t\tndu[ r ][ j ] = saved + rv * temp;\n\t\t\tsaved = lv * temp;\n\n\t\t}\n\n\t\tndu[ j ][ j ] = saved;\n\n\t}\n\n\tfor ( let j = 0; j <= p; ++ j ) {\n\n\t\tders[ 0 ][ j ] = ndu[ j ][ p ];\n\n\t}\n\n\tfor ( let r = 0; r <= p; ++ r ) {\n\n\t\tlet s1 = 0;\n\t\tlet s2 = 1;\n\n\t\tconst a = [];\n\t\tfor ( let i = 0; i <= p; ++ i ) {\n\n\t\t\ta[ i ] = zeroArr.slice( 0 );\n\n\t\t}\n\n\t\ta[ 0 ][ 0 ] = 1.0;\n\n\t\tfor ( let k = 1; k <= n; ++ k ) {\n\n\t\t\tlet d = 0.0;\n\t\t\tconst rk = r - k;\n\t\t\tconst pk = p - k;\n\n\t\t\tif ( r >= k ) {\n\n\t\t\t\ta[ s2 ][ 0 ] = a[ s1 ][ 0 ] / ndu[ pk + 1 ][ rk ];\n\t\t\t\td = a[ s2 ][ 0 ] * ndu[ rk ][ pk ];\n\n\t\t\t}\n\n\t\t\tconst j1 = ( rk >= - 1 ) ? 1 : - rk;\n\t\t\tconst j2 = ( r - 1 <= pk ) ? k - 1 : p - r;\n\n\t\t\tfor ( let j = j1; j <= j2; ++ j ) {\n\n\t\t\t\ta[ s2 ][ j ] = ( a[ s1 ][ j ] - a[ s1 ][ j - 1 ] ) / ndu[ pk + 1 ][ rk + j ];\n\t\t\t\td += a[ s2 ][ j ] * ndu[ rk + j ][ pk ];\n\n\t\t\t}\n\n\t\t\tif ( r <= pk ) {\n\n\t\t\t\ta[ s2 ][ k ] = - a[ s1 ][ k - 1 ] / ndu[ pk + 1 ][ r ];\n\t\t\t\td += a[ s2 ][ k ] * ndu[ r ][ pk ];\n\n\t\t\t}\n\n\t\t\tders[ k ][ r ] = d;\n\n\t\t\tconst j = s1;\n\t\t\ts1 = s2;\n\t\t\ts2 = j;\n\n\t\t}\n\n\t}\n\n\tlet r = p;\n\n\tfor ( let k = 1; k <= n; ++ k ) {\n\n\t\tfor ( let j = 0; j <= p; ++ j ) {\n\n\t\t\tders[ k ][ j ] *= r;\n\n\t\t}\n\n\t\tr *= p - k;\n\n\t}\n\n\treturn ders;\n\n}\n\n\n/*\n\tCalculate derivatives of a B-Spline. See The NURBS Book, page 93, algorithm A3.2.\n\n\tp  : degree\n\tU  : knot vector\n\tP  : control points\n\tu  : Parametric points\n\tnd : number of derivatives\n\n\treturns array[d+1] with derivatives\n\t*/\nfunction calcBSplineDerivatives( p, U, P, u, nd ) {\n\n\tconst du = nd < p ? nd : p;\n\tconst CK = [];\n\tconst span = findSpan( p, u, U );\n\tconst nders = calcBasisFunctionDerivatives( span, u, p, du, U );\n\tconst Pw = [];\n\n\tfor ( let i = 0; i < P.length; ++ i ) {\n\n\t\tconst point = P[ i ].clone();\n\t\tconst w = point.w;\n\n\t\tpoint.x *= w;\n\t\tpoint.y *= w;\n\t\tpoint.z *= w;\n\n\t\tPw[ i ] = point;\n\n\t}\n\n\tfor ( let k = 0; k <= du; ++ k ) {\n\n\t\tconst point = Pw[ span - p ].clone().multiplyScalar( nders[ k ][ 0 ] );\n\n\t\tfor ( let j = 1; j <= p; ++ j ) {\n\n\t\t\tpoint.add( Pw[ span - p + j ].clone().multiplyScalar( nders[ k ][ j ] ) );\n\n\t\t}\n\n\t\tCK[ k ] = point;\n\n\t}\n\n\tfor ( let k = du + 1; k <= nd + 1; ++ k ) {\n\n\t\tCK[ k ] = new Vector4( 0, 0, 0 );\n\n\t}\n\n\treturn CK;\n\n}\n\n\n/*\nCalculate \"K over I\"\n\nreturns k!/(i!(k-i)!)\n*/\nfunction calcKoverI( k, i ) {\n\n\tlet nom = 1;\n\n\tfor ( let j = 2; j <= k; ++ j ) {\n\n\t\tnom *= j;\n\n\t}\n\n\tlet denom = 1;\n\n\tfor ( let j = 2; j <= i; ++ j ) {\n\n\t\tdenom *= j;\n\n\t}\n\n\tfor ( let j = 2; j <= k - i; ++ j ) {\n\n\t\tdenom *= j;\n\n\t}\n\n\treturn nom / denom;\n\n}\n\n\n/*\nCalculate derivatives (0-nd) of rational curve. See The NURBS Book, page 127, algorithm A4.2.\n\nPders : result of function calcBSplineDerivatives\n\nreturns array with derivatives for rational curve.\n*/\nfunction calcRationalCurveDerivatives( Pders ) {\n\n\tconst nd = Pders.length;\n\tconst Aders = [];\n\tconst wders = [];\n\n\tfor ( let i = 0; i < nd; ++ i ) {\n\n\t\tconst point = Pders[ i ];\n\t\tAders[ i ] = new Vector3( point.x, point.y, point.z );\n\t\twders[ i ] = point.w;\n\n\t}\n\n\tconst CK = [];\n\n\tfor ( let k = 0; k < nd; ++ k ) {\n\n\t\tconst v = Aders[ k ].clone();\n\n\t\tfor ( let i = 1; i <= k; ++ i ) {\n\n\t\t\tv.sub( CK[ k - i ].clone().multiplyScalar( calcKoverI( k, i ) * wders[ i ] ) );\n\n\t\t}\n\n\t\tCK[ k ] = v.divideScalar( wders[ 0 ] );\n\n\t}\n\n\treturn CK;\n\n}\n\n\n/*\nCalculate NURBS curve derivatives. See The NURBS Book, page 127, algorithm A4.2.\n\np  : degree\nU  : knot vector\nP  : control points in homogeneous space\nu  : parametric points\nnd : number of derivatives\n\nreturns array with derivatives.\n*/\nfunction calcNURBSDerivatives( p, U, P, u, nd ) {\n\n\tconst Pders = calcBSplineDerivatives( p, U, P, u, nd );\n\treturn calcRationalCurveDerivatives( Pders );\n\n}\n\n\n/*\nCalculate rational B-Spline surface point. See The NURBS Book, page 134, algorithm A4.3.\n\np, q : degrees of B-Spline surface\nU, V : knot vectors\nP    : control points (x, y, z, w)\nu, v : parametric values\n\nreturns point for given (u, v)\n*/\nfunction calcSurfacePoint( p, q, U, V, P, u, v, target ) {\n\n\tconst uspan = findSpan( p, u, U );\n\tconst vspan = findSpan( q, v, V );\n\tconst Nu = calcBasisFunctions( uspan, u, p, U );\n\tconst Nv = calcBasisFunctions( vspan, v, q, V );\n\tconst temp = [];\n\n\tfor ( let l = 0; l <= q; ++ l ) {\n\n\t\ttemp[ l ] = new Vector4( 0, 0, 0, 0 );\n\t\tfor ( let k = 0; k <= p; ++ k ) {\n\n\t\t\tconst point = P[ uspan - p + k ][ vspan - q + l ].clone();\n\t\t\tconst w = point.w;\n\t\t\tpoint.x *= w;\n\t\t\tpoint.y *= w;\n\t\t\tpoint.z *= w;\n\t\t\ttemp[ l ].add( point.multiplyScalar( Nu[ k ] ) );\n\n\t\t}\n\n\t}\n\n\tconst Sw = new Vector4( 0, 0, 0, 0 );\n\tfor ( let l = 0; l <= q; ++ l ) {\n\n\t\tSw.add( temp[ l ].multiplyScalar( Nv[ l ] ) );\n\n\t}\n\n\tSw.divideScalar( Sw.w );\n\ttarget.set( Sw.x, Sw.y, Sw.z );\n\n}\n\n/*\nCalculate rational B-Spline volume point. See The NURBS Book, page 134, algorithm A4.3.\n\np, q, r   : degrees of B-Splinevolume\nU, V, W   : knot vectors\nP         : control points (x, y, z, w)\nu, v, w   : parametric values\n\nreturns point for given (u, v, w)\n*/\nfunction calcVolumePoint( p, q, r, U, V, W, P, u, v, w, target ) {\n\n\tconst uspan = findSpan( p, u, U );\n\tconst vspan = findSpan( q, v, V );\n\tconst wspan = findSpan( r, w, W );\n\tconst Nu = calcBasisFunctions( uspan, u, p, U );\n\tconst Nv = calcBasisFunctions( vspan, v, q, V );\n\tconst Nw = calcBasisFunctions( wspan, w, r, W );\n\tconst temp = [];\n\n\tfor ( let m = 0; m <= r; ++ m ) {\n\n\t\ttemp[ m ] = [];\n\n\t\tfor ( let l = 0; l <= q; ++ l ) {\n\n\t\t\ttemp[ m ][ l ] = new Vector4( 0, 0, 0, 0 );\n\t\t\tfor ( let k = 0; k <= p; ++ k ) {\n\n\t\t\t\tconst point = P[ uspan - p + k ][ vspan - q + l ][ wspan - r + m ].clone();\n\t\t\t\tconst w = point.w;\n\t\t\t\tpoint.x *= w;\n\t\t\t\tpoint.y *= w;\n\t\t\t\tpoint.z *= w;\n\t\t\t\ttemp[ m ][ l ].add( point.multiplyScalar( Nu[ k ] ) );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\tconst Sw = new Vector4( 0, 0, 0, 0 );\n\tfor ( let m = 0; m <= r; ++ m ) {\n\t\tfor ( let l = 0; l <= q; ++ l ) {\n\n\t\t\tSw.add( temp[ m ][ l ].multiplyScalar( Nw[ m ] ).multiplyScalar( Nv[ l ] ) );\n\n\t\t}\n\t}\n\n\tSw.divideScalar( Sw.w );\n\ttarget.set( Sw.x, Sw.y, Sw.z );\n\n}\n\n\nexport {\n\tfindSpan,\n\tcalcBasisFunctions,\n\tcalcBSplinePoint,\n\tcalcBasisFunctionDerivatives,\n\tcalcBSplineDerivatives,\n\tcalcKoverI,\n\tcalcRationalCurveDerivatives,\n\tcalcNURBSDerivatives,\n\tcalcSurfacePoint,\n\tcalcVolumePoint,\n};\n","/*!\nfflate - fast JavaScript compression/decompression\n<https://101arrowz.github.io/fflate>\nLicensed under MIT. https://github.com/101arrowz/fflate/blob/master/LICENSE\nversion 0.8.2\n*/\n\n// DEFLATE is a complex format; to read this code, you should probably check the RFC first:\n// https://tools.ietf.org/html/rfc1951\n// You may also wish to take a look at the guide I made about this program:\n// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad\n// Some of the following code is similar to that of UZIP.js:\n// https://github.com/photopea/UZIP.js\n// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size.\n// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint\n// is better for memory in most engines (I *think*).\nvar ch2 = {};\nvar wk = (function (c, id, msg, transfer, cb) {\n    var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([\n        c + ';addEventListener(\"error\",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})'\n    ], { type: 'text/javascript' }))));\n    w.onmessage = function (e) {\n        var d = e.data, ed = d.$e$;\n        if (ed) {\n            var err = new Error(ed[0]);\n            err['code'] = ed[1];\n            err.stack = ed[2];\n            cb(err, null);\n        }\n        else\n            cb(null, d);\n    };\n    w.postMessage(msg, transfer);\n    return w;\n});\n\n// aliases for shorter compressed code (most minifers don't do this)\nvar u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array;\n// fixed length extra bits\nvar fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]);\n// fixed distance extra bits\nvar fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]);\n// code length index map\nvar clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);\n// get base, reverse index map from extra bits\nvar freb = function (eb, start) {\n    var b = new u16(31);\n    for (var i = 0; i < 31; ++i) {\n        b[i] = start += 1 << eb[i - 1];\n    }\n    // numbers here are at max 18 bits\n    var r = new i32(b[30]);\n    for (var i = 1; i < 30; ++i) {\n        for (var j = b[i]; j < b[i + 1]; ++j) {\n            r[j] = ((j - b[i]) << 5) | i;\n        }\n    }\n    return { b: b, r: r };\n};\nvar _a = freb(fleb, 2), fl = _a.b, revfl = _a.r;\n// we can ignore the fact that the other numbers are wrong; they never happen anyway\nfl[28] = 258, revfl[258] = 28;\nvar _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r;\n// map of value to reverse (assuming 16 bits)\nvar rev = new u16(32768);\nfor (var i = 0; i < 32768; ++i) {\n    // reverse table algorithm from SO\n    var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1);\n    x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2);\n    x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4);\n    rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1;\n}\n// create huffman tree from u8 \"map\": index -> code length for code index\n// mb (max bits) must be at most 15\n// TODO: optimize/split up?\nvar hMap = (function (cd, mb, r) {\n    var s = cd.length;\n    // index\n    var i = 0;\n    // u16 \"map\": index -> # of codes with bit length = index\n    var l = new u16(mb);\n    // length of cd must be 288 (total # of codes)\n    for (; i < s; ++i) {\n        if (cd[i])\n            ++l[cd[i] - 1];\n    }\n    // u16 \"map\": index -> minimum code for bit length = index\n    var le = new u16(mb);\n    for (i = 1; i < mb; ++i) {\n        le[i] = (le[i - 1] + l[i - 1]) << 1;\n    }\n    var co;\n    if (r) {\n        // u16 \"map\": index -> number of actual bits, symbol for code\n        co = new u16(1 << mb);\n        // bits to remove for reverser\n        var rvb = 15 - mb;\n        for (i = 0; i < s; ++i) {\n            // ignore 0 lengths\n            if (cd[i]) {\n                // num encoding both symbol and bits read\n                var sv = (i << 4) | cd[i];\n                // free bits\n                var r_1 = mb - cd[i];\n                // start value\n                var v = le[cd[i] - 1]++ << r_1;\n                // m is end value\n                for (var m = v | ((1 << r_1) - 1); v <= m; ++v) {\n                    // every 16 bit value starting with the code yields the same result\n                    co[rev[v] >> rvb] = sv;\n                }\n            }\n        }\n    }\n    else {\n        co = new u16(s);\n        for (i = 0; i < s; ++i) {\n            if (cd[i]) {\n                co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]);\n            }\n        }\n    }\n    return co;\n});\n// fixed length tree\nvar flt = new u8(288);\nfor (var i = 0; i < 144; ++i)\n    flt[i] = 8;\nfor (var i = 144; i < 256; ++i)\n    flt[i] = 9;\nfor (var i = 256; i < 280; ++i)\n    flt[i] = 7;\nfor (var i = 280; i < 288; ++i)\n    flt[i] = 8;\n// fixed distance tree\nvar fdt = new u8(32);\nfor (var i = 0; i < 32; ++i)\n    fdt[i] = 5;\n// fixed length map\nvar flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1);\n// fixed distance map\nvar fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1);\n// find max of array\nvar max = function (a) {\n    var m = a[0];\n    for (var i = 1; i < a.length; ++i) {\n        if (a[i] > m)\n            m = a[i];\n    }\n    return m;\n};\n// read d, starting at bit p and mask with m\nvar bits = function (d, p, m) {\n    var o = (p / 8) | 0;\n    return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m;\n};\n// read d, starting at bit p continuing for at least 16 bits\nvar bits16 = function (d, p) {\n    var o = (p / 8) | 0;\n    return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7));\n};\n// get end of byte\nvar shft = function (p) { return ((p + 7) / 8) | 0; };\n// typed array slice - allows garbage collector to free original reference,\n// while being more compatible than .slice\nvar slc = function (v, s, e) {\n    if (s == null || s < 0)\n        s = 0;\n    if (e == null || e > v.length)\n        e = v.length;\n    // can't use .constructor in case user-supplied\n    return new u8(v.subarray(s, e));\n};\n/**\n * Codes for errors generated within this library\n */\nexport var FlateErrorCode = {\n    UnexpectedEOF: 0,\n    InvalidBlockType: 1,\n    InvalidLengthLiteral: 2,\n    InvalidDistance: 3,\n    StreamFinished: 4,\n    NoStreamHandler: 5,\n    InvalidHeader: 6,\n    NoCallback: 7,\n    InvalidUTF8: 8,\n    ExtraFieldTooLong: 9,\n    InvalidDate: 10,\n    FilenameTooLong: 11,\n    StreamFinishing: 12,\n    InvalidZipData: 13,\n    UnknownCompressionMethod: 14\n};\n// error codes\nvar ec = [\n    'unexpected EOF',\n    'invalid block type',\n    'invalid length/literal',\n    'invalid distance',\n    'stream finished',\n    'no stream handler',\n    ,\n    'no callback',\n    'invalid UTF-8 data',\n    'extra field too long',\n    'date not in range 1980-2099',\n    'filename too long',\n    'stream finishing',\n    'invalid zip data'\n    // determined by unknown compression method\n];\n;\nvar err = function (ind, msg, nt) {\n    var e = new Error(msg || ec[ind]);\n    e.code = ind;\n    if (Error.captureStackTrace)\n        Error.captureStackTrace(e, err);\n    if (!nt)\n        throw e;\n    return e;\n};\n// expands raw DEFLATE data\nvar inflt = function (dat, st, buf, dict) {\n    // source length       dict length\n    var sl = dat.length, dl = dict ? dict.length : 0;\n    if (!sl || st.f && !st.l)\n        return buf || new u8(0);\n    var noBuf = !buf;\n    // have to estimate size\n    var resize = noBuf || st.i != 2;\n    // no state\n    var noSt = st.i;\n    // Assumes roughly 33% compression ratio average\n    if (noBuf)\n        buf = new u8(sl * 3);\n    // ensure buffer can fit at least l elements\n    var cbuf = function (l) {\n        var bl = buf.length;\n        // need to increase size to fit\n        if (l > bl) {\n            // Double or set to necessary, whichever is greater\n            var nbuf = new u8(Math.max(bl * 2, l));\n            nbuf.set(buf);\n            buf = nbuf;\n        }\n    };\n    //  last chunk         bitpos           bytes\n    var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;\n    // total bits\n    var tbts = sl * 8;\n    do {\n        if (!lm) {\n            // BFINAL - this is only 1 when last chunk is next\n            final = bits(dat, pos, 1);\n            // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman\n            var type = bits(dat, pos + 1, 3);\n            pos += 3;\n            if (!type) {\n                // go to end of byte boundary\n                var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l;\n                if (t > sl) {\n                    if (noSt)\n                        err(0);\n                    break;\n                }\n                // ensure size\n                if (resize)\n                    cbuf(bt + l);\n                // Copy over uncompressed data\n                buf.set(dat.subarray(s, t), bt);\n                // Get new bitpos, update byte count\n                st.b = bt += l, st.p = pos = t * 8, st.f = final;\n                continue;\n            }\n            else if (type == 1)\n                lm = flrm, dm = fdrm, lbt = 9, dbt = 5;\n            else if (type == 2) {\n                //  literal                            lengths\n                var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;\n                var tl = hLit + bits(dat, pos + 5, 31) + 1;\n                pos += 14;\n                // length+distance tree\n                var ldt = new u8(tl);\n                // code length tree\n                var clt = new u8(19);\n                for (var i = 0; i < hcLen; ++i) {\n                    // use index map to get real code\n                    clt[clim[i]] = bits(dat, pos + i * 3, 7);\n                }\n                pos += hcLen * 3;\n                // code lengths bits\n                var clb = max(clt), clbmsk = (1 << clb) - 1;\n                // code lengths map\n                var clm = hMap(clt, clb, 1);\n                for (var i = 0; i < tl;) {\n                    var r = clm[bits(dat, pos, clbmsk)];\n                    // bits read\n                    pos += r & 15;\n                    // symbol\n                    var s = r >> 4;\n                    // code length to copy\n                    if (s < 16) {\n                        ldt[i++] = s;\n                    }\n                    else {\n                        //  copy   count\n                        var c = 0, n = 0;\n                        if (s == 16)\n                            n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];\n                        else if (s == 17)\n                            n = 3 + bits(dat, pos, 7), pos += 3;\n                        else if (s == 18)\n                            n = 11 + bits(dat, pos, 127), pos += 7;\n                        while (n--)\n                            ldt[i++] = c;\n                    }\n                }\n                //    length tree                 distance tree\n                var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);\n                // max length bits\n                lbt = max(lt);\n                // max dist bits\n                dbt = max(dt);\n                lm = hMap(lt, lbt, 1);\n                dm = hMap(dt, dbt, 1);\n            }\n            else\n                err(1);\n            if (pos > tbts) {\n                if (noSt)\n                    err(0);\n                break;\n            }\n        }\n        // Make sure the buffer can hold this + the largest possible addition\n        // Maximum chunk size (practically, theoretically infinite) is 2^17\n        if (resize)\n            cbuf(bt + 131072);\n        var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;\n        var lpos = pos;\n        for (;; lpos = pos) {\n            // bits read, code\n            var c = lm[bits16(dat, pos) & lms], sym = c >> 4;\n            pos += c & 15;\n            if (pos > tbts) {\n                if (noSt)\n                    err(0);\n                break;\n            }\n            if (!c)\n                err(2);\n            if (sym < 256)\n                buf[bt++] = sym;\n            else if (sym == 256) {\n                lpos = pos, lm = null;\n                break;\n            }\n            else {\n                var add = sym - 254;\n                // no extra bits needed if less\n                if (sym > 264) {\n                    // index\n                    var i = sym - 257, b = fleb[i];\n                    add = bits(dat, pos, (1 << b) - 1) + fl[i];\n                    pos += b;\n                }\n                // dist\n                var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;\n                if (!d)\n                    err(3);\n                pos += d & 15;\n                var dt = fd[dsym];\n                if (dsym > 3) {\n                    var b = fdeb[dsym];\n                    dt += bits16(dat, pos) & (1 << b) - 1, pos += b;\n                }\n                if (pos > tbts) {\n                    if (noSt)\n                        err(0);\n                    break;\n                }\n                if (resize)\n                    cbuf(bt + 131072);\n                var end = bt + add;\n                if (bt < dt) {\n                    var shift = dl - dt, dend = Math.min(dt, end);\n                    if (shift + bt < 0)\n                        err(3);\n                    for (; bt < dend; ++bt)\n                        buf[bt] = dict[shift + bt];\n                }\n                for (; bt < end; ++bt)\n                    buf[bt] = buf[bt - dt];\n            }\n        }\n        st.l = lm, st.p = lpos, st.b = bt, st.f = final;\n        if (lm)\n            final = 1, st.m = lbt, st.d = dm, st.n = dbt;\n    } while (!final);\n    // don't reallocate for streams or user buffers\n    return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);\n};\n// starting at p, write the minimum number of bits that can hold v to d\nvar wbits = function (d, p, v) {\n    v <<= p & 7;\n    var o = (p / 8) | 0;\n    d[o] |= v;\n    d[o + 1] |= v >> 8;\n};\n// starting at p, write the minimum number of bits (>8) that can hold v to d\nvar wbits16 = function (d, p, v) {\n    v <<= p & 7;\n    var o = (p / 8) | 0;\n    d[o] |= v;\n    d[o + 1] |= v >> 8;\n    d[o + 2] |= v >> 16;\n};\n// creates code lengths from a frequency table\nvar hTree = function (d, mb) {\n    // Need extra info to make a tree\n    var t = [];\n    for (var i = 0; i < d.length; ++i) {\n        if (d[i])\n            t.push({ s: i, f: d[i] });\n    }\n    var s = t.length;\n    var t2 = t.slice();\n    if (!s)\n        return { t: et, l: 0 };\n    if (s == 1) {\n        var v = new u8(t[0].s + 1);\n        v[t[0].s] = 1;\n        return { t: v, l: 1 };\n    }\n    t.sort(function (a, b) { return a.f - b.f; });\n    // after i2 reaches last ind, will be stopped\n    // freq must be greater than largest possible number of symbols\n    t.push({ s: -1, f: 25001 });\n    var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;\n    t[0] = { s: -1, f: l.f + r.f, l: l, r: r };\n    // efficient algorithm from UZIP.js\n    // i0 is lookbehind, i2 is lookahead - after processing two low-freq\n    // symbols that combined have high freq, will start processing i2 (high-freq,\n    // non-composite) symbols instead\n    // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/\n    while (i1 != s - 1) {\n        l = t[t[i0].f < t[i2].f ? i0++ : i2++];\n        r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];\n        t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r };\n    }\n    var maxSym = t2[0].s;\n    for (var i = 1; i < s; ++i) {\n        if (t2[i].s > maxSym)\n            maxSym = t2[i].s;\n    }\n    // code lengths\n    var tr = new u16(maxSym + 1);\n    // max bits in tree\n    var mbt = ln(t[i1 - 1], tr, 0);\n    if (mbt > mb) {\n        // more algorithms from UZIP.js\n        // TODO: find out how this code works (debt)\n        //  ind    debt\n        var i = 0, dt = 0;\n        //    left            cost\n        var lft = mbt - mb, cst = 1 << lft;\n        t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; });\n        for (; i < s; ++i) {\n            var i2_1 = t2[i].s;\n            if (tr[i2_1] > mb) {\n                dt += cst - (1 << (mbt - tr[i2_1]));\n                tr[i2_1] = mb;\n            }\n            else\n                break;\n        }\n        dt >>= lft;\n        while (dt > 0) {\n            var i2_2 = t2[i].s;\n            if (tr[i2_2] < mb)\n                dt -= 1 << (mb - tr[i2_2]++ - 1);\n            else\n                ++i;\n        }\n        for (; i >= 0 && dt; --i) {\n            var i2_3 = t2[i].s;\n            if (tr[i2_3] == mb) {\n                --tr[i2_3];\n                ++dt;\n            }\n        }\n        mbt = mb;\n    }\n    return { t: new u8(tr), l: mbt };\n};\n// get the max length and assign length codes\nvar ln = function (n, l, d) {\n    return n.s == -1\n        ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1))\n        : (l[n.s] = d);\n};\n// length codes generation\nvar lc = function (c) {\n    var s = c.length;\n    // Note that the semicolon was intentional\n    while (s && !c[--s])\n        ;\n    var cl = new u16(++s);\n    //  ind      num         streak\n    var cli = 0, cln = c[0], cls = 1;\n    var w = function (v) { cl[cli++] = v; };\n    for (var i = 1; i <= s; ++i) {\n        if (c[i] == cln && i != s)\n            ++cls;\n        else {\n            if (!cln && cls > 2) {\n                for (; cls > 138; cls -= 138)\n                    w(32754);\n                if (cls > 2) {\n                    w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305);\n                    cls = 0;\n                }\n            }\n            else if (cls > 3) {\n                w(cln), --cls;\n                for (; cls > 6; cls -= 6)\n                    w(8304);\n                if (cls > 2)\n                    w(((cls - 3) << 5) | 8208), cls = 0;\n            }\n            while (cls--)\n                w(cln);\n            cls = 1;\n            cln = c[i];\n        }\n    }\n    return { c: cl.subarray(0, cli), n: s };\n};\n// calculate the length of output from tree, code lengths\nvar clen = function (cf, cl) {\n    var l = 0;\n    for (var i = 0; i < cl.length; ++i)\n        l += cf[i] * cl[i];\n    return l;\n};\n// writes a fixed block\n// returns the new bit pos\nvar wfblk = function (out, pos, dat) {\n    // no need to write 00 as type: TypedArray defaults to 0\n    var s = dat.length;\n    var o = shft(pos + 2);\n    out[o] = s & 255;\n    out[o + 1] = s >> 8;\n    out[o + 2] = out[o] ^ 255;\n    out[o + 3] = out[o + 1] ^ 255;\n    for (var i = 0; i < s; ++i)\n        out[o + i + 4] = dat[i];\n    return (o + 4 + s) * 8;\n};\n// writes a block\nvar wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) {\n    wbits(out, p++, final);\n    ++lf[256];\n    var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l;\n    var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l;\n    var _c = lc(dlt), lclt = _c.c, nlc = _c.n;\n    var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;\n    var lcfreq = new u16(19);\n    for (var i = 0; i < lclt.length; ++i)\n        ++lcfreq[lclt[i] & 31];\n    for (var i = 0; i < lcdt.length; ++i)\n        ++lcfreq[lcdt[i] & 31];\n    var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;\n    var nlcc = 19;\n    for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)\n        ;\n    var flen = (bl + 5) << 3;\n    var ftlen = clen(lf, flt) + clen(df, fdt) + eb;\n    var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];\n    if (bs >= 0 && flen <= ftlen && flen <= dtlen)\n        return wfblk(out, p, dat.subarray(bs, bs + bl));\n    var lm, ll, dm, dl;\n    wbits(out, p, 1 + (dtlen < ftlen)), p += 2;\n    if (dtlen < ftlen) {\n        lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;\n        var llm = hMap(lct, mlcb, 0);\n        wbits(out, p, nlc - 257);\n        wbits(out, p + 5, ndc - 1);\n        wbits(out, p + 10, nlcc - 4);\n        p += 14;\n        for (var i = 0; i < nlcc; ++i)\n            wbits(out, p + 3 * i, lct[clim[i]]);\n        p += 3 * nlcc;\n        var lcts = [lclt, lcdt];\n        for (var it = 0; it < 2; ++it) {\n            var clct = lcts[it];\n            for (var i = 0; i < clct.length; ++i) {\n                var len = clct[i] & 31;\n                wbits(out, p, llm[len]), p += lct[len];\n                if (len > 15)\n                    wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12;\n            }\n        }\n    }\n    else {\n        lm = flm, ll = flt, dm = fdm, dl = fdt;\n    }\n    for (var i = 0; i < li; ++i) {\n        var sym = syms[i];\n        if (sym > 255) {\n            var len = (sym >> 18) & 31;\n            wbits16(out, p, lm[len + 257]), p += ll[len + 257];\n            if (len > 7)\n                wbits(out, p, (sym >> 23) & 31), p += fleb[len];\n            var dst = sym & 31;\n            wbits16(out, p, dm[dst]), p += dl[dst];\n            if (dst > 3)\n                wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst];\n        }\n        else {\n            wbits16(out, p, lm[sym]), p += ll[sym];\n        }\n    }\n    wbits16(out, p, lm[256]);\n    return p + ll[256];\n};\n// deflate options (nice << 13) | chain\nvar deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);\n// empty\nvar et = /*#__PURE__*/ new u8(0);\n// compresses data into a raw DEFLATE buffer\nvar dflt = function (dat, lvl, plvl, pre, post, st) {\n    var s = st.z || dat.length;\n    var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post);\n    // writing to this writes to the output buffer\n    var w = o.subarray(pre, o.length - post);\n    var lst = st.l;\n    var pos = (st.r || 0) & 7;\n    if (lvl) {\n        if (pos)\n            w[0] = st.r >> 3;\n        var opt = deo[lvl - 1];\n        var n = opt >> 13, c = opt & 8191;\n        var msk_1 = (1 << plvl) - 1;\n        //    prev 2-byte val map    curr 2-byte val map\n        var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);\n        var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;\n        var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; };\n        // 24576 is an arbitrary number of maximum symbols per block\n        // 424 buffer for last block\n        var syms = new i32(25000);\n        // length/literal freq   distance freq\n        var lf = new u16(288), df = new u16(32);\n        //  l/lcnt  exbits  index          l/lind  waitdx          blkpos\n        var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;\n        for (; i + 2 < s; ++i) {\n            // hash value\n            var hv = hsh(i);\n            // index mod 32768    previous index mod\n            var imod = i & 32767, pimod = head[hv];\n            prev[imod] = pimod;\n            head[hv] = imod;\n            // We always should modify head and prev, but only add symbols if\n            // this data is not yet processed (\"wait\" for wait index)\n            if (wi <= i) {\n                // bytes remaining\n                var rem = s - i;\n                if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) {\n                    pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);\n                    li = lc_1 = eb = 0, bs = i;\n                    for (var j = 0; j < 286; ++j)\n                        lf[j] = 0;\n                    for (var j = 0; j < 30; ++j)\n                        df[j] = 0;\n                }\n                //  len    dist   chain\n                var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;\n                if (rem > 2 && hv == hsh(i - dif)) {\n                    var maxn = Math.min(n, rem) - 1;\n                    var maxd = Math.min(32767, i);\n                    // max possible length\n                    // not capped at dif because decompressors implement \"rolling\" index population\n                    var ml = Math.min(258, rem);\n                    while (dif <= maxd && --ch_1 && imod != pimod) {\n                        if (dat[i + l] == dat[i + l - dif]) {\n                            var nl = 0;\n                            for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)\n                                ;\n                            if (nl > l) {\n                                l = nl, d = dif;\n                                // break out early when we reach \"nice\" (we are satisfied enough)\n                                if (nl > maxn)\n                                    break;\n                                // now, find the rarest 2-byte sequence within this\n                                // length of literals and search for that instead.\n                                // Much faster than just using the start\n                                var mmd = Math.min(dif, nl - 2);\n                                var md = 0;\n                                for (var j = 0; j < mmd; ++j) {\n                                    var ti = i - dif + j & 32767;\n                                    var pti = prev[ti];\n                                    var cd = ti - pti & 32767;\n                                    if (cd > md)\n                                        md = cd, pimod = ti;\n                                }\n                            }\n                        }\n                        // check the previous match\n                        imod = pimod, pimod = prev[imod];\n                        dif += imod - pimod & 32767;\n                    }\n                }\n                // d will be nonzero only when a match was found\n                if (d) {\n                    // store both dist and len data in one int32\n                    // Make sure this is recognized as a len/dist with 28th bit (2^28)\n                    syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d];\n                    var lin = revfl[l] & 31, din = revfd[d] & 31;\n                    eb += fleb[lin] + fdeb[din];\n                    ++lf[257 + lin];\n                    ++df[din];\n                    wi = i + l;\n                    ++lc_1;\n                }\n                else {\n                    syms[li++] = dat[i];\n                    ++lf[dat[i]];\n                }\n            }\n        }\n        for (i = Math.max(i, wi); i < s; ++i) {\n            syms[li++] = dat[i];\n            ++lf[dat[i]];\n        }\n        pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);\n        if (!lst) {\n            st.r = (pos & 7) | w[(pos / 8) | 0] << 3;\n            // shft(pos) now 1 less if pos & 7 != 0\n            pos -= 7;\n            st.h = head, st.p = prev, st.i = i, st.w = wi;\n        }\n    }\n    else {\n        for (var i = st.w || 0; i < s + lst; i += 65535) {\n            // end\n            var e = i + 65535;\n            if (e >= s) {\n                // write final block\n                w[(pos / 8) | 0] = lst;\n                e = s;\n            }\n            pos = wfblk(w, pos + 1, dat.subarray(i, e));\n        }\n        st.i = s;\n    }\n    return slc(o, 0, pre + shft(pos) + post);\n};\n// CRC32 table\nvar crct = /*#__PURE__*/ (function () {\n    var t = new Int32Array(256);\n    for (var i = 0; i < 256; ++i) {\n        var c = i, k = 9;\n        while (--k)\n            c = ((c & 1) && -306674912) ^ (c >>> 1);\n        t[i] = c;\n    }\n    return t;\n})();\n// CRC32\nvar crc = function () {\n    var c = -1;\n    return {\n        p: function (d) {\n            // closures have awful performance\n            var cr = c;\n            for (var i = 0; i < d.length; ++i)\n                cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8);\n            c = cr;\n        },\n        d: function () { return ~c; }\n    };\n};\n// Adler32\nvar adler = function () {\n    var a = 1, b = 0;\n    return {\n        p: function (d) {\n            // closures have awful performance\n            var n = a, m = b;\n            var l = d.length | 0;\n            for (var i = 0; i != l;) {\n                var e = Math.min(i + 2655, l);\n                for (; i < e; ++i)\n                    m += n += d[i];\n                n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16);\n            }\n            a = n, b = m;\n        },\n        d: function () {\n            a %= 65521, b %= 65521;\n            return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8);\n        }\n    };\n};\n;\n// deflate with opts\nvar dopt = function (dat, opt, pre, post, st) {\n    if (!st) {\n        st = { l: 1 };\n        if (opt.dictionary) {\n            var dict = opt.dictionary.subarray(-32768);\n            var newDat = new u8(dict.length + dat.length);\n            newDat.set(dict);\n            newDat.set(dat, dict.length);\n            dat = newDat;\n            st.w = dict.length;\n        }\n    }\n    return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st);\n};\n// Walmart object spread\nvar mrg = function (a, b) {\n    var o = {};\n    for (var k in a)\n        o[k] = a[k];\n    for (var k in b)\n        o[k] = b[k];\n    return o;\n};\n// worker clone\n// This is possibly the craziest part of the entire codebase, despite how simple it may seem.\n// The only parameter to this function is a closure that returns an array of variables outside of the function scope.\n// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization.\n// We will return an object mapping of true variable name to value (basically, the current scope as a JS object).\n// The reason we can't just use the original variable names is minifiers mangling the toplevel scope.\n// This took me three weeks to figure out how to do.\nvar wcln = function (fn, fnStr, td) {\n    var dt = fn();\n    var st = fn.toString();\n    var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\\s+/g, '').split(',');\n    for (var i = 0; i < dt.length; ++i) {\n        var v = dt[i], k = ks[i];\n        if (typeof v == 'function') {\n            fnStr += ';' + k + '=';\n            var st_1 = v.toString();\n            if (v.prototype) {\n                // for global objects\n                if (st_1.indexOf('[native code]') != -1) {\n                    var spInd = st_1.indexOf(' ', 8) + 1;\n                    fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd));\n                }\n                else {\n                    fnStr += st_1;\n                    for (var t in v.prototype)\n                        fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString();\n                }\n            }\n            else\n                fnStr += st_1;\n        }\n        else\n            td[k] = v;\n    }\n    return fnStr;\n};\nvar ch = [];\n// clone bufs\nvar cbfs = function (v) {\n    var tl = [];\n    for (var k in v) {\n        if (v[k].buffer) {\n            tl.push((v[k] = new v[k].constructor(v[k])).buffer);\n        }\n    }\n    return tl;\n};\n// use a worker to execute code\nvar wrkr = function (fns, init, id, cb) {\n    if (!ch[id]) {\n        var fnStr = '', td_1 = {}, m = fns.length - 1;\n        for (var i = 0; i < m; ++i)\n            fnStr = wcln(fns[i], fnStr, td_1);\n        ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 };\n    }\n    var td = mrg({}, ch[id].e);\n    return wk(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb);\n};\n// base async inflate fn\nvar bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; };\nvar bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; };\n// gzip extra\nvar gze = function () { return [gzh, gzhl, wbytes, crc, crct]; };\n// gunzip extra\nvar guze = function () { return [gzs, gzl]; };\n// zlib extra\nvar zle = function () { return [zlh, wbytes, adler]; };\n// unzlib extra\nvar zule = function () { return [zls]; };\n// post buf\nvar pbf = function (msg) { return postMessage(msg, [msg.buffer]); };\n// get opts\nvar gopt = function (o) { return o && {\n    out: o.size && new u8(o.size),\n    dictionary: o.dictionary\n}; };\n// async helper\nvar cbify = function (dat, opts, fns, init, id, cb) {\n    var w = wrkr(fns, init, id, function (err, dat) {\n        w.terminate();\n        cb(err, dat);\n    });\n    w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []);\n    return function () { w.terminate(); };\n};\n// auto stream\nvar astrm = function (strm) {\n    strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); };\n    return function (ev) {\n        if (ev.data.length) {\n            strm.push(ev.data[0], ev.data[1]);\n            postMessage([ev.data[0].length]);\n        }\n        else\n            strm.flush();\n    };\n};\n// async stream attach\nvar astrmify = function (fns, strm, opts, init, id, flush, ext) {\n    var t;\n    var w = wrkr(fns, init, id, function (err, dat) {\n        if (err)\n            w.terminate(), strm.ondata.call(strm, err);\n        else if (!Array.isArray(dat))\n            ext(dat);\n        else if (dat.length == 1) {\n            strm.queuedSize -= dat[0];\n            if (strm.ondrain)\n                strm.ondrain(dat[0]);\n        }\n        else {\n            if (dat[1])\n                w.terminate();\n            strm.ondata.call(strm, err, dat[0], dat[1]);\n        }\n    });\n    w.postMessage(opts);\n    strm.queuedSize = 0;\n    strm.push = function (d, f) {\n        if (!strm.ondata)\n            err(5);\n        if (t)\n            strm.ondata(err(4, 0, 1), null, !!f);\n        strm.queuedSize += d.length;\n        w.postMessage([d, t = f], [d.buffer]);\n    };\n    strm.terminate = function () { w.terminate(); };\n    if (flush) {\n        strm.flush = function () { w.postMessage([]); };\n    }\n};\n// read 2 bytes\nvar b2 = function (d, b) { return d[b] | (d[b + 1] << 8); };\n// read 4 bytes\nvar b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; };\nvar b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); };\n// write bytes\nvar wbytes = function (d, b, v) {\n    for (; v; ++b)\n        d[b] = v, v >>>= 8;\n};\n// gzip header\nvar gzh = function (c, o) {\n    var fn = o.filename;\n    c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix\n    if (o.mtime != 0)\n        wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000));\n    if (fn) {\n        c[3] = 8;\n        for (var i = 0; i <= fn.length; ++i)\n            c[i + 10] = fn.charCodeAt(i);\n    }\n};\n// gzip footer: -8 to -4 = CRC, -4 to -0 is length\n// gzip start\nvar gzs = function (d) {\n    if (d[0] != 31 || d[1] != 139 || d[2] != 8)\n        err(6, 'invalid gzip data');\n    var flg = d[3];\n    var st = 10;\n    if (flg & 4)\n        st += (d[10] | d[11] << 8) + 2;\n    for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++])\n        ;\n    return st + (flg & 2);\n};\n// gzip length\nvar gzl = function (d) {\n    var l = d.length;\n    return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;\n};\n// gzip header length\nvar gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); };\n// zlib header\nvar zlh = function (c, o) {\n    var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2;\n    c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32);\n    c[1] |= 31 - ((c[0] << 8) | c[1]) % 31;\n    if (o.dictionary) {\n        var h = adler();\n        h.p(o.dictionary);\n        wbytes(c, 2, h.d());\n    }\n};\n// zlib start\nvar zls = function (d, dict) {\n    if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31))\n        err(6, 'invalid zlib data');\n    if ((d[1] >> 5 & 1) == +!dict)\n        err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary');\n    return (d[1] >> 3 & 4) + 2;\n};\nfunction StrmOpt(opts, cb) {\n    if (typeof opts == 'function')\n        cb = opts, opts = {};\n    this.ondata = cb;\n    return opts;\n}\n/**\n * Streaming DEFLATE compression\n */\nvar Deflate = /*#__PURE__*/ (function () {\n    function Deflate(opts, cb) {\n        if (typeof opts == 'function')\n            cb = opts, opts = {};\n        this.ondata = cb;\n        this.o = opts || {};\n        this.s = { l: 0, i: 32768, w: 32768, z: 32768 };\n        // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev\n        // 98304 = 32768 (lookback) + 65536 (common chunk size)\n        this.b = new u8(98304);\n        if (this.o.dictionary) {\n            var dict = this.o.dictionary.subarray(-32768);\n            this.b.set(dict, 32768 - dict.length);\n            this.s.i = 32768 - dict.length;\n        }\n    }\n    Deflate.prototype.p = function (c, f) {\n        this.ondata(dopt(c, this.o, 0, 0, this.s), f);\n    };\n    /**\n     * Pushes a chunk to be deflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Deflate.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        if (this.s.l)\n            err(4);\n        var endLen = chunk.length + this.s.z;\n        if (endLen > this.b.length) {\n            if (endLen > 2 * this.b.length - 32768) {\n                var newBuf = new u8(endLen & -32768);\n                newBuf.set(this.b.subarray(0, this.s.z));\n                this.b = newBuf;\n            }\n            var split = this.b.length - this.s.z;\n            this.b.set(chunk.subarray(0, split), this.s.z);\n            this.s.z = this.b.length;\n            this.p(this.b, false);\n            this.b.set(this.b.subarray(-32768));\n            this.b.set(chunk.subarray(split), 32768);\n            this.s.z = chunk.length - split + 32768;\n            this.s.i = 32766, this.s.w = 32768;\n        }\n        else {\n            this.b.set(chunk, this.s.z);\n            this.s.z += chunk.length;\n        }\n        this.s.l = final & 1;\n        if (this.s.z > this.s.w + 8191 || final) {\n            this.p(this.b, final || false);\n            this.s.w = this.s.i, this.s.i -= 2;\n        }\n    };\n    /**\n     * Flushes buffered uncompressed data. Useful to immediately retrieve the\n     * deflated output for small inputs.\n     */\n    Deflate.prototype.flush = function () {\n        if (!this.ondata)\n            err(5);\n        if (this.s.l)\n            err(4);\n        this.p(this.b, false);\n        this.s.w = this.s.i, this.s.i -= 2;\n    };\n    return Deflate;\n}());\nexport { Deflate };\n/**\n * Asynchronous streaming DEFLATE compression\n */\nvar AsyncDeflate = /*#__PURE__*/ (function () {\n    function AsyncDeflate(opts, cb) {\n        astrmify([\n            bDflt,\n            function () { return [astrm, Deflate]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Deflate(ev.data);\n            onmessage = astrm(strm);\n        }, 6, 1);\n    }\n    return AsyncDeflate;\n}());\nexport { AsyncDeflate };\nexport function deflate(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bDflt,\n    ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb);\n}\n/**\n * Compresses data with DEFLATE without any wrapper\n * @param data The data to compress\n * @param opts The compression options\n * @returns The deflated version of the data\n */\nexport function deflateSync(data, opts) {\n    return dopt(data, opts || {}, 0, 0);\n}\n/**\n * Streaming DEFLATE decompression\n */\nvar Inflate = /*#__PURE__*/ (function () {\n    function Inflate(opts, cb) {\n        // no StrmOpt here to avoid adding to workerizer\n        if (typeof opts == 'function')\n            cb = opts, opts = {};\n        this.ondata = cb;\n        var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768);\n        this.s = { i: 0, b: dict ? dict.length : 0 };\n        this.o = new u8(32768);\n        this.p = new u8(0);\n        if (dict)\n            this.o.set(dict);\n    }\n    Inflate.prototype.e = function (c) {\n        if (!this.ondata)\n            err(5);\n        if (this.d)\n            err(4);\n        if (!this.p.length)\n            this.p = c;\n        else if (c.length) {\n            var n = new u8(this.p.length + c.length);\n            n.set(this.p), n.set(c, this.p.length), this.p = n;\n        }\n    };\n    Inflate.prototype.c = function (final) {\n        this.s.i = +(this.d = final || false);\n        var bts = this.s.b;\n        var dt = inflt(this.p, this.s, this.o);\n        this.ondata(slc(dt, bts, this.s.b), this.d);\n        this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length;\n        this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7;\n    };\n    /**\n     * Pushes a chunk to be inflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the final chunk\n     */\n    Inflate.prototype.push = function (chunk, final) {\n        this.e(chunk), this.c(final);\n    };\n    return Inflate;\n}());\nexport { Inflate };\n/**\n * Asynchronous streaming DEFLATE decompression\n */\nvar AsyncInflate = /*#__PURE__*/ (function () {\n    function AsyncInflate(opts, cb) {\n        astrmify([\n            bInflt,\n            function () { return [astrm, Inflate]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Inflate(ev.data);\n            onmessage = astrm(strm);\n        }, 7, 0);\n    }\n    return AsyncInflate;\n}());\nexport { AsyncInflate };\nexport function inflate(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bInflt\n    ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb);\n}\n/**\n * Expands DEFLATE data with no wrapper\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function inflateSync(data, opts) {\n    return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);\n}\n// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize.\n/**\n * Streaming GZIP compression\n */\nvar Gzip = /*#__PURE__*/ (function () {\n    function Gzip(opts, cb) {\n        this.c = crc();\n        this.l = 0;\n        this.v = 1;\n        Deflate.call(this, opts, cb);\n    }\n    /**\n     * Pushes a chunk to be GZIPped\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Gzip.prototype.push = function (chunk, final) {\n        this.c.p(chunk);\n        this.l += chunk.length;\n        Deflate.prototype.push.call(this, chunk, final);\n    };\n    Gzip.prototype.p = function (c, f) {\n        var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s);\n        if (this.v)\n            gzh(raw, this.o), this.v = 0;\n        if (f)\n            wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l);\n        this.ondata(raw, f);\n    };\n    /**\n     * Flushes buffered uncompressed data. Useful to immediately retrieve the\n     * GZIPped output for small inputs.\n     */\n    Gzip.prototype.flush = function () {\n        Deflate.prototype.flush.call(this);\n    };\n    return Gzip;\n}());\nexport { Gzip };\n/**\n * Asynchronous streaming GZIP compression\n */\nvar AsyncGzip = /*#__PURE__*/ (function () {\n    function AsyncGzip(opts, cb) {\n        astrmify([\n            bDflt,\n            gze,\n            function () { return [astrm, Deflate, Gzip]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Gzip(ev.data);\n            onmessage = astrm(strm);\n        }, 8, 1);\n    }\n    return AsyncGzip;\n}());\nexport { AsyncGzip };\nexport function gzip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bDflt,\n        gze,\n        function () { return [gzipSync]; }\n    ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb);\n}\n/**\n * Compresses data with GZIP\n * @param data The data to compress\n * @param opts The compression options\n * @returns The gzipped version of the data\n */\nexport function gzipSync(data, opts) {\n    if (!opts)\n        opts = {};\n    var c = crc(), l = data.length;\n    c.p(data);\n    var d = dopt(data, opts, gzhl(opts), 8), s = d.length;\n    return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;\n}\n/**\n * Streaming single or multi-member GZIP decompression\n */\nvar Gunzip = /*#__PURE__*/ (function () {\n    function Gunzip(opts, cb) {\n        this.v = 1;\n        this.r = 0;\n        Inflate.call(this, opts, cb);\n    }\n    /**\n     * Pushes a chunk to be GUNZIPped\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Gunzip.prototype.push = function (chunk, final) {\n        Inflate.prototype.e.call(this, chunk);\n        this.r += chunk.length;\n        if (this.v) {\n            var p = this.p.subarray(this.v - 1);\n            var s = p.length > 3 ? gzs(p) : 4;\n            if (s > p.length) {\n                if (!final)\n                    return;\n            }\n            else if (this.v > 1 && this.onmember) {\n                this.onmember(this.r - p.length);\n            }\n            this.p = p.subarray(s), this.v = 0;\n        }\n        // necessary to prevent TS from using the closure value\n        // This allows for workerization to function correctly\n        Inflate.prototype.c.call(this, final);\n        // process concatenated GZIP\n        if (this.s.f && !this.s.l && !final) {\n            this.v = shft(this.s.p) + 9;\n            this.s = { i: 0 };\n            this.o = new u8(0);\n            this.push(new u8(0), final);\n        }\n    };\n    return Gunzip;\n}());\nexport { Gunzip };\n/**\n * Asynchronous streaming single or multi-member GZIP decompression\n */\nvar AsyncGunzip = /*#__PURE__*/ (function () {\n    function AsyncGunzip(opts, cb) {\n        var _this = this;\n        astrmify([\n            bInflt,\n            guze,\n            function () { return [astrm, Inflate, Gunzip]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Gunzip(ev.data);\n            strm.onmember = function (offset) { return postMessage(offset); };\n            onmessage = astrm(strm);\n        }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); });\n    }\n    return AsyncGunzip;\n}());\nexport { AsyncGunzip };\nexport function gunzip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bInflt,\n        guze,\n        function () { return [gunzipSync]; }\n    ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb);\n}\n/**\n * Expands GZIP data\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function gunzipSync(data, opts) {\n    var st = gzs(data);\n    if (st + 8 > data.length)\n        err(6, 'invalid gzip data');\n    return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);\n}\n/**\n * Streaming Zlib compression\n */\nvar Zlib = /*#__PURE__*/ (function () {\n    function Zlib(opts, cb) {\n        this.c = adler();\n        this.v = 1;\n        Deflate.call(this, opts, cb);\n    }\n    /**\n     * Pushes a chunk to be zlibbed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Zlib.prototype.push = function (chunk, final) {\n        this.c.p(chunk);\n        Deflate.prototype.push.call(this, chunk, final);\n    };\n    Zlib.prototype.p = function (c, f) {\n        var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s);\n        if (this.v)\n            zlh(raw, this.o), this.v = 0;\n        if (f)\n            wbytes(raw, raw.length - 4, this.c.d());\n        this.ondata(raw, f);\n    };\n    /**\n     * Flushes buffered uncompressed data. Useful to immediately retrieve the\n     * zlibbed output for small inputs.\n     */\n    Zlib.prototype.flush = function () {\n        Deflate.prototype.flush.call(this);\n    };\n    return Zlib;\n}());\nexport { Zlib };\n/**\n * Asynchronous streaming Zlib compression\n */\nvar AsyncZlib = /*#__PURE__*/ (function () {\n    function AsyncZlib(opts, cb) {\n        astrmify([\n            bDflt,\n            zle,\n            function () { return [astrm, Deflate, Zlib]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Zlib(ev.data);\n            onmessage = astrm(strm);\n        }, 10, 1);\n    }\n    return AsyncZlib;\n}());\nexport { AsyncZlib };\nexport function zlib(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bDflt,\n        zle,\n        function () { return [zlibSync]; }\n    ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb);\n}\n/**\n * Compress data with Zlib\n * @param data The data to compress\n * @param opts The compression options\n * @returns The zlib-compressed version of the data\n */\nexport function zlibSync(data, opts) {\n    if (!opts)\n        opts = {};\n    var a = adler();\n    a.p(data);\n    var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4);\n    return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d;\n}\n/**\n * Streaming Zlib decompression\n */\nvar Unzlib = /*#__PURE__*/ (function () {\n    function Unzlib(opts, cb) {\n        Inflate.call(this, opts, cb);\n        this.v = opts && opts.dictionary ? 2 : 1;\n    }\n    /**\n     * Pushes a chunk to be unzlibbed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Unzlib.prototype.push = function (chunk, final) {\n        Inflate.prototype.e.call(this, chunk);\n        if (this.v) {\n            if (this.p.length < 6 && !final)\n                return;\n            this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0;\n        }\n        if (final) {\n            if (this.p.length < 4)\n                err(6, 'invalid zlib data');\n            this.p = this.p.subarray(0, -4);\n        }\n        // necessary to prevent TS from using the closure value\n        // This allows for workerization to function correctly\n        Inflate.prototype.c.call(this, final);\n    };\n    return Unzlib;\n}());\nexport { Unzlib };\n/**\n * Asynchronous streaming Zlib decompression\n */\nvar AsyncUnzlib = /*#__PURE__*/ (function () {\n    function AsyncUnzlib(opts, cb) {\n        astrmify([\n            bInflt,\n            zule,\n            function () { return [astrm, Inflate, Unzlib]; }\n        ], this, StrmOpt.call(this, opts, cb), function (ev) {\n            var strm = new Unzlib(ev.data);\n            onmessage = astrm(strm);\n        }, 11, 0);\n    }\n    return AsyncUnzlib;\n}());\nexport { AsyncUnzlib };\nexport function unzlib(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return cbify(data, opts, [\n        bInflt,\n        zule,\n        function () { return [unzlibSync]; }\n    ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb);\n}\n/**\n * Expands Zlib data\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function unzlibSync(data, opts) {\n    return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary);\n}\n// Default algorithm for compression (used because having a known output size allows faster decompression)\nexport { gzip as compress, AsyncGzip as AsyncCompress };\nexport { gzipSync as compressSync, Gzip as Compress };\n/**\n * Streaming GZIP, Zlib, or raw DEFLATE decompression\n */\nvar Decompress = /*#__PURE__*/ (function () {\n    function Decompress(opts, cb) {\n        this.o = StrmOpt.call(this, opts, cb) || {};\n        this.G = Gunzip;\n        this.I = Inflate;\n        this.Z = Unzlib;\n    }\n    // init substream\n    // overriden by AsyncDecompress\n    Decompress.prototype.i = function () {\n        var _this = this;\n        this.s.ondata = function (dat, final) {\n            _this.ondata(dat, final);\n        };\n    };\n    /**\n     * Pushes a chunk to be decompressed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Decompress.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        if (!this.s) {\n            if (this.p && this.p.length) {\n                var n = new u8(this.p.length + chunk.length);\n                n.set(this.p), n.set(chunk, this.p.length);\n            }\n            else\n                this.p = chunk;\n            if (this.p.length > 2) {\n                this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8)\n                    ? new this.G(this.o)\n                    : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31))\n                        ? new this.I(this.o)\n                        : new this.Z(this.o);\n                this.i();\n                this.s.push(this.p, final);\n                this.p = null;\n            }\n        }\n        else\n            this.s.push(chunk, final);\n    };\n    return Decompress;\n}());\nexport { Decompress };\n/**\n * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression\n */\nvar AsyncDecompress = /*#__PURE__*/ (function () {\n    function AsyncDecompress(opts, cb) {\n        Decompress.call(this, opts, cb);\n        this.queuedSize = 0;\n        this.G = AsyncGunzip;\n        this.I = AsyncInflate;\n        this.Z = AsyncUnzlib;\n    }\n    AsyncDecompress.prototype.i = function () {\n        var _this = this;\n        this.s.ondata = function (err, dat, final) {\n            _this.ondata(err, dat, final);\n        };\n        this.s.ondrain = function (size) {\n            _this.queuedSize -= size;\n            if (_this.ondrain)\n                _this.ondrain(size);\n        };\n    };\n    /**\n     * Pushes a chunk to be decompressed\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    AsyncDecompress.prototype.push = function (chunk, final) {\n        this.queuedSize += chunk.length;\n        Decompress.prototype.push.call(this, chunk, final);\n    };\n    return AsyncDecompress;\n}());\nexport { AsyncDecompress };\nexport function decompress(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    return (data[0] == 31 && data[1] == 139 && data[2] == 8)\n        ? gunzip(data, opts, cb)\n        : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\n            ? inflate(data, opts, cb)\n            : unzlib(data, opts, cb);\n}\n/**\n * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function decompressSync(data, opts) {\n    return (data[0] == 31 && data[1] == 139 && data[2] == 8)\n        ? gunzipSync(data, opts)\n        : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\n            ? inflateSync(data, opts)\n            : unzlibSync(data, opts);\n}\n// flatten a directory structure\nvar fltn = function (d, p, t, o) {\n    for (var k in d) {\n        var val = d[k], n = p + k, op = o;\n        if (Array.isArray(val))\n            op = mrg(o, val[1]), val = val[0];\n        if (val instanceof u8)\n            t[n] = [val, op];\n        else {\n            t[n += '/'] = [new u8(0), op];\n            fltn(val, n, t, o);\n        }\n    }\n};\n// text encoder\nvar te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder();\n// text decoder\nvar td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder();\n// text decoder stream\nvar tds = 0;\ntry {\n    td.decode(et, { stream: true });\n    tds = 1;\n}\ncatch (e) { }\n// decode UTF8\nvar dutf8 = function (d) {\n    for (var r = '', i = 0;;) {\n        var c = d[i++];\n        var eb = (c > 127) + (c > 223) + (c > 239);\n        if (i + eb > d.length)\n            return { s: r, r: slc(d, i - 1) };\n        if (!eb)\n            r += String.fromCharCode(c);\n        else if (eb == 3) {\n            c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536,\n                r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023));\n        }\n        else if (eb & 1)\n            r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63));\n        else\n            r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63));\n    }\n};\n/**\n * Streaming UTF-8 decoding\n */\nvar DecodeUTF8 = /*#__PURE__*/ (function () {\n    /**\n     * Creates a UTF-8 decoding stream\n     * @param cb The callback to call whenever data is decoded\n     */\n    function DecodeUTF8(cb) {\n        this.ondata = cb;\n        if (tds)\n            this.t = new TextDecoder();\n        else\n            this.p = et;\n    }\n    /**\n     * Pushes a chunk to be decoded from UTF-8 binary\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    DecodeUTF8.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        final = !!final;\n        if (this.t) {\n            this.ondata(this.t.decode(chunk, { stream: true }), final);\n            if (final) {\n                if (this.t.decode().length)\n                    err(8);\n                this.t = null;\n            }\n            return;\n        }\n        if (!this.p)\n            err(4);\n        var dat = new u8(this.p.length + chunk.length);\n        dat.set(this.p);\n        dat.set(chunk, this.p.length);\n        var _a = dutf8(dat), s = _a.s, r = _a.r;\n        if (final) {\n            if (r.length)\n                err(8);\n            this.p = null;\n        }\n        else\n            this.p = r;\n        this.ondata(s, final);\n    };\n    return DecodeUTF8;\n}());\nexport { DecodeUTF8 };\n/**\n * Streaming UTF-8 encoding\n */\nvar EncodeUTF8 = /*#__PURE__*/ (function () {\n    /**\n     * Creates a UTF-8 decoding stream\n     * @param cb The callback to call whenever data is encoded\n     */\n    function EncodeUTF8(cb) {\n        this.ondata = cb;\n    }\n    /**\n     * Pushes a chunk to be encoded to UTF-8\n     * @param chunk The string data to push\n     * @param final Whether this is the last chunk\n     */\n    EncodeUTF8.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        if (this.d)\n            err(4);\n        this.ondata(strToU8(chunk), this.d = final || false);\n    };\n    return EncodeUTF8;\n}());\nexport { EncodeUTF8 };\n/**\n * Converts a string into a Uint8Array for use with compression/decompression methods\n * @param str The string to encode\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\n *               not need to be true unless decoding a binary string.\n * @returns The string encoded in UTF-8/Latin-1 binary\n */\nexport function strToU8(str, latin1) {\n    if (latin1) {\n        var ar_1 = new u8(str.length);\n        for (var i = 0; i < str.length; ++i)\n            ar_1[i] = str.charCodeAt(i);\n        return ar_1;\n    }\n    if (te)\n        return te.encode(str);\n    var l = str.length;\n    var ar = new u8(str.length + (str.length >> 1));\n    var ai = 0;\n    var w = function (v) { ar[ai++] = v; };\n    for (var i = 0; i < l; ++i) {\n        if (ai + 5 > ar.length) {\n            var n = new u8(ai + 8 + ((l - i) << 1));\n            n.set(ar);\n            ar = n;\n        }\n        var c = str.charCodeAt(i);\n        if (c < 128 || latin1)\n            w(c);\n        else if (c < 2048)\n            w(192 | (c >> 6)), w(128 | (c & 63));\n        else if (c > 55295 && c < 57344)\n            c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023),\n                w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\n        else\n            w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\n    }\n    return slc(ar, 0, ai);\n}\n/**\n * Converts a Uint8Array to a string\n * @param dat The data to decode to string\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\n *               not need to be true unless encoding to binary string.\n * @returns The original UTF-8/Latin-1 string\n */\nexport function strFromU8(dat, latin1) {\n    if (latin1) {\n        var r = '';\n        for (var i = 0; i < dat.length; i += 16384)\n            r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));\n        return r;\n    }\n    else if (td) {\n        return td.decode(dat);\n    }\n    else {\n        var _a = dutf8(dat), s = _a.s, r = _a.r;\n        if (r.length)\n            err(8);\n        return s;\n    }\n}\n;\n// deflate bit flag\nvar dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; };\n// skip local zip header\nvar slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); };\n// read zip header\nvar zh = function (d, b, z) {\n    var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);\n    var _a = z && bs == 4294967295 ? z64e(d, es) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a[0], su = _a[1], off = _a[2];\n    return [b2(d, b + 10), sc, su, fn, es + b2(d, b + 30) + b2(d, b + 32), off];\n};\n// read zip64 extra field\nvar z64e = function (d, b) {\n    for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))\n        ;\n    return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];\n};\n// extra field length\nvar exfl = function (ex) {\n    var le = 0;\n    if (ex) {\n        for (var k in ex) {\n            var l = ex[k].length;\n            if (l > 65535)\n                err(9);\n            le += l + 4;\n        }\n    }\n    return le;\n};\n// write zip header\nvar wzh = function (d, b, f, fn, u, c, ce, co) {\n    var fl = fn.length, ex = f.extra, col = co && co.length;\n    var exl = exfl(ex);\n    wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4;\n    if (ce != null)\n        d[b++] = 20, d[b++] = f.os;\n    d[b] = 20, b += 2; // spec compliance? what's that?\n    d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8;\n    d[b++] = f.compression & 255, d[b++] = f.compression >> 8;\n    var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;\n    if (y < 0 || y > 119)\n        err(10);\n    wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4;\n    if (c != -1) {\n        wbytes(d, b, f.crc);\n        wbytes(d, b + 4, c < 0 ? -c - 2 : c);\n        wbytes(d, b + 8, f.size);\n    }\n    wbytes(d, b + 12, fl);\n    wbytes(d, b + 14, exl), b += 16;\n    if (ce != null) {\n        wbytes(d, b, col);\n        wbytes(d, b + 6, f.attrs);\n        wbytes(d, b + 10, ce), b += 14;\n    }\n    d.set(fn, b);\n    b += fl;\n    if (exl) {\n        for (var k in ex) {\n            var exf = ex[k], l = exf.length;\n            wbytes(d, b, +k);\n            wbytes(d, b + 2, l);\n            d.set(exf, b + 4), b += 4 + l;\n        }\n    }\n    if (col)\n        d.set(co, b), b += col;\n    return b;\n};\n// write zip footer (end of central directory)\nvar wzf = function (o, b, c, d, e) {\n    wbytes(o, b, 0x6054B50); // skip disk\n    wbytes(o, b + 8, c);\n    wbytes(o, b + 10, c);\n    wbytes(o, b + 12, d);\n    wbytes(o, b + 16, e);\n};\n/**\n * A pass-through stream to keep data uncompressed in a ZIP archive.\n */\nvar ZipPassThrough = /*#__PURE__*/ (function () {\n    /**\n     * Creates a pass-through stream that can be added to ZIP archives\n     * @param filename The filename to associate with this data stream\n     */\n    function ZipPassThrough(filename) {\n        this.filename = filename;\n        this.c = crc();\n        this.size = 0;\n        this.compression = 0;\n    }\n    /**\n     * Processes a chunk and pushes to the output stream. You can override this\n     * method in a subclass for custom behavior, but by default this passes\n     * the data through. You must call this.ondata(err, chunk, final) at some\n     * point in this method.\n     * @param chunk The chunk to process\n     * @param final Whether this is the last chunk\n     */\n    ZipPassThrough.prototype.process = function (chunk, final) {\n        this.ondata(null, chunk, final);\n    };\n    /**\n     * Pushes a chunk to be added. If you are subclassing this with a custom\n     * compression algorithm, note that you must push data from the source\n     * file only, pre-compression.\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    ZipPassThrough.prototype.push = function (chunk, final) {\n        if (!this.ondata)\n            err(5);\n        this.c.p(chunk);\n        this.size += chunk.length;\n        if (final)\n            this.crc = this.c.d();\n        this.process(chunk, final || false);\n    };\n    return ZipPassThrough;\n}());\nexport { ZipPassThrough };\n// I don't extend because TypeScript extension adds 1kB of runtime bloat\n/**\n * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate\n * for better performance\n */\nvar ZipDeflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates a DEFLATE stream that can be added to ZIP archives\n     * @param filename The filename to associate with this data stream\n     * @param opts The compression options\n     */\n    function ZipDeflate(filename, opts) {\n        var _this = this;\n        if (!opts)\n            opts = {};\n        ZipPassThrough.call(this, filename);\n        this.d = new Deflate(opts, function (dat, final) {\n            _this.ondata(null, dat, final);\n        });\n        this.compression = 8;\n        this.flag = dbf(opts.level);\n    }\n    ZipDeflate.prototype.process = function (chunk, final) {\n        try {\n            this.d.push(chunk, final);\n        }\n        catch (e) {\n            this.ondata(e, null, final);\n        }\n    };\n    /**\n     * Pushes a chunk to be deflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    ZipDeflate.prototype.push = function (chunk, final) {\n        ZipPassThrough.prototype.push.call(this, chunk, final);\n    };\n    return ZipDeflate;\n}());\nexport { ZipDeflate };\n/**\n * Asynchronous streaming DEFLATE compression for ZIP archives\n */\nvar AsyncZipDeflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates an asynchronous DEFLATE stream that can be added to ZIP archives\n     * @param filename The filename to associate with this data stream\n     * @param opts The compression options\n     */\n    function AsyncZipDeflate(filename, opts) {\n        var _this = this;\n        if (!opts)\n            opts = {};\n        ZipPassThrough.call(this, filename);\n        this.d = new AsyncDeflate(opts, function (err, dat, final) {\n            _this.ondata(err, dat, final);\n        });\n        this.compression = 8;\n        this.flag = dbf(opts.level);\n        this.terminate = this.d.terminate;\n    }\n    AsyncZipDeflate.prototype.process = function (chunk, final) {\n        this.d.push(chunk, final);\n    };\n    /**\n     * Pushes a chunk to be deflated\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    AsyncZipDeflate.prototype.push = function (chunk, final) {\n        ZipPassThrough.prototype.push.call(this, chunk, final);\n    };\n    return AsyncZipDeflate;\n}());\nexport { AsyncZipDeflate };\n// TODO: Better tree shaking\n/**\n * A zippable archive to which files can incrementally be added\n */\nvar Zip = /*#__PURE__*/ (function () {\n    /**\n     * Creates an empty ZIP archive to which files can be added\n     * @param cb The callback to call whenever data for the generated ZIP archive\n     *           is available\n     */\n    function Zip(cb) {\n        this.ondata = cb;\n        this.u = [];\n        this.d = 1;\n    }\n    /**\n     * Adds a file to the ZIP archive\n     * @param file The file stream to add\n     */\n    Zip.prototype.add = function (file) {\n        var _this = this;\n        if (!this.ondata)\n            err(5);\n        // finishing or finished\n        if (this.d & 2)\n            this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false);\n        else {\n            var f = strToU8(file.filename), fl_1 = f.length;\n            var com = file.comment, o = com && strToU8(com);\n            var u = fl_1 != file.filename.length || (o && (com.length != o.length));\n            var hl_1 = fl_1 + exfl(file.extra) + 30;\n            if (fl_1 > 65535)\n                this.ondata(err(11, 0, 1), null, false);\n            var header = new u8(hl_1);\n            wzh(header, 0, file, f, u, -1);\n            var chks_1 = [header];\n            var pAll_1 = function () {\n                for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) {\n                    var chk = chks_2[_i];\n                    _this.ondata(null, chk, false);\n                }\n                chks_1 = [];\n            };\n            var tr_1 = this.d;\n            this.d = 0;\n            var ind_1 = this.u.length;\n            var uf_1 = mrg(file, {\n                f: f,\n                u: u,\n                o: o,\n                t: function () {\n                    if (file.terminate)\n                        file.terminate();\n                },\n                r: function () {\n                    pAll_1();\n                    if (tr_1) {\n                        var nxt = _this.u[ind_1 + 1];\n                        if (nxt)\n                            nxt.r();\n                        else\n                            _this.d = 1;\n                    }\n                    tr_1 = 1;\n                }\n            });\n            var cl_1 = 0;\n            file.ondata = function (err, dat, final) {\n                if (err) {\n                    _this.ondata(err, dat, final);\n                    _this.terminate();\n                }\n                else {\n                    cl_1 += dat.length;\n                    chks_1.push(dat);\n                    if (final) {\n                        var dd = new u8(16);\n                        wbytes(dd, 0, 0x8074B50);\n                        wbytes(dd, 4, file.crc);\n                        wbytes(dd, 8, cl_1);\n                        wbytes(dd, 12, file.size);\n                        chks_1.push(dd);\n                        uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size;\n                        if (tr_1)\n                            uf_1.r();\n                        tr_1 = 1;\n                    }\n                    else if (tr_1)\n                        pAll_1();\n                }\n            };\n            this.u.push(uf_1);\n        }\n    };\n    /**\n     * Ends the process of adding files and prepares to emit the final chunks.\n     * This *must* be called after adding all desired files for the resulting\n     * ZIP file to work properly.\n     */\n    Zip.prototype.end = function () {\n        var _this = this;\n        if (this.d & 2) {\n            this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true);\n            return;\n        }\n        if (this.d)\n            this.e();\n        else\n            this.u.push({\n                r: function () {\n                    if (!(_this.d & 1))\n                        return;\n                    _this.u.splice(-1, 1);\n                    _this.e();\n                },\n                t: function () { }\n            });\n        this.d = 3;\n    };\n    Zip.prototype.e = function () {\n        var bt = 0, l = 0, tl = 0;\n        for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\n            var f = _a[_i];\n            tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0);\n        }\n        var out = new u8(tl + 22);\n        for (var _b = 0, _c = this.u; _b < _c.length; _b++) {\n            var f = _c[_b];\n            wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o);\n            bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b;\n        }\n        wzf(out, bt, this.u.length, tl, l);\n        this.ondata(null, out, true);\n        this.d = 2;\n    };\n    /**\n     * A method to terminate any internal workers used by the stream. Subsequent\n     * calls to add() will fail.\n     */\n    Zip.prototype.terminate = function () {\n        for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\n            var f = _a[_i];\n            f.t();\n        }\n        this.d = 2;\n    };\n    return Zip;\n}());\nexport { Zip };\nexport function zip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    var r = {};\n    fltn(data, '', r, opts);\n    var k = Object.keys(r);\n    var lft = k.length, o = 0, tot = 0;\n    var slft = lft, files = new Array(lft);\n    var term = [];\n    var tAll = function () {\n        for (var i = 0; i < term.length; ++i)\n            term[i]();\n    };\n    var cbd = function (a, b) {\n        mt(function () { cb(a, b); });\n    };\n    mt(function () { cbd = cb; });\n    var cbf = function () {\n        var out = new u8(tot + 22), oe = o, cdl = tot - o;\n        tot = 0;\n        for (var i = 0; i < slft; ++i) {\n            var f = files[i];\n            try {\n                var l = f.c.length;\n                wzh(out, tot, f, f.f, f.u, l);\n                var badd = 30 + f.f.length + exfl(f.extra);\n                var loc = tot + badd;\n                out.set(f.c, loc);\n                wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l;\n            }\n            catch (e) {\n                return cbd(e, null);\n            }\n        }\n        wzf(out, o, files.length, cdl, oe);\n        cbd(null, out);\n    };\n    if (!lft)\n        cbf();\n    var _loop_1 = function (i) {\n        var fn = k[i];\n        var _a = r[fn], file = _a[0], p = _a[1];\n        var c = crc(), size = file.length;\n        c.p(file);\n        var f = strToU8(fn), s = f.length;\n        var com = p.comment, m = com && strToU8(com), ms = m && m.length;\n        var exl = exfl(p.extra);\n        var compression = p.level == 0 ? 0 : 8;\n        var cbl = function (e, d) {\n            if (e) {\n                tAll();\n                cbd(e, null);\n            }\n            else {\n                var l = d.length;\n                files[i] = mrg(p, {\n                    size: size,\n                    crc: c.d(),\n                    c: d,\n                    f: f,\n                    m: m,\n                    u: s != fn.length || (m && (com.length != ms)),\n                    compression: compression\n                });\n                o += 30 + s + exl + l;\n                tot += 76 + 2 * (s + exl) + (ms || 0) + l;\n                if (!--lft)\n                    cbf();\n            }\n        };\n        if (s > 65535)\n            cbl(err(11, 0, 1), null);\n        if (!compression)\n            cbl(null, file);\n        else if (size < 160000) {\n            try {\n                cbl(null, deflateSync(file, p));\n            }\n            catch (e) {\n                cbl(e, null);\n            }\n        }\n        else\n            term.push(deflate(file, p, cbl));\n    };\n    // Cannot use lft because it can decrease\n    for (var i = 0; i < slft; ++i) {\n        _loop_1(i);\n    }\n    return tAll;\n}\n/**\n * Synchronously creates a ZIP file. Prefer using `zip` for better performance\n * with more than one file.\n * @param data The directory structure for the ZIP archive\n * @param opts The main options, merged with per-file options\n * @returns The generated ZIP archive\n */\nexport function zipSync(data, opts) {\n    if (!opts)\n        opts = {};\n    var r = {};\n    var files = [];\n    fltn(data, '', r, opts);\n    var o = 0;\n    var tot = 0;\n    for (var fn in r) {\n        var _a = r[fn], file = _a[0], p = _a[1];\n        var compression = p.level == 0 ? 0 : 8;\n        var f = strToU8(fn), s = f.length;\n        var com = p.comment, m = com && strToU8(com), ms = m && m.length;\n        var exl = exfl(p.extra);\n        if (s > 65535)\n            err(11);\n        var d = compression ? deflateSync(file, p) : file, l = d.length;\n        var c = crc();\n        c.p(file);\n        files.push(mrg(p, {\n            size: file.length,\n            crc: c.d(),\n            c: d,\n            f: f,\n            m: m,\n            u: s != fn.length || (m && (com.length != ms)),\n            o: o,\n            compression: compression\n        }));\n        o += 30 + s + exl + l;\n        tot += 76 + 2 * (s + exl) + (ms || 0) + l;\n    }\n    var out = new u8(tot + 22), oe = o, cdl = tot - o;\n    for (var i = 0; i < files.length; ++i) {\n        var f = files[i];\n        wzh(out, f.o, f, f.f, f.u, f.c.length);\n        var badd = 30 + f.f.length + exfl(f.extra);\n        out.set(f.c, f.o + badd);\n        wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);\n    }\n    wzf(out, o, files.length, cdl, oe);\n    return out;\n}\n/**\n * Streaming pass-through decompression for ZIP archives\n */\nvar UnzipPassThrough = /*#__PURE__*/ (function () {\n    function UnzipPassThrough() {\n    }\n    UnzipPassThrough.prototype.push = function (data, final) {\n        this.ondata(null, data, final);\n    };\n    UnzipPassThrough.compression = 0;\n    return UnzipPassThrough;\n}());\nexport { UnzipPassThrough };\n/**\n * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for\n * better performance.\n */\nvar UnzipInflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates a DEFLATE decompression that can be used in ZIP archives\n     */\n    function UnzipInflate() {\n        var _this = this;\n        this.i = new Inflate(function (dat, final) {\n            _this.ondata(null, dat, final);\n        });\n    }\n    UnzipInflate.prototype.push = function (data, final) {\n        try {\n            this.i.push(data, final);\n        }\n        catch (e) {\n            this.ondata(e, null, final);\n        }\n    };\n    UnzipInflate.compression = 8;\n    return UnzipInflate;\n}());\nexport { UnzipInflate };\n/**\n * Asynchronous streaming DEFLATE decompression for ZIP archives\n */\nvar AsyncUnzipInflate = /*#__PURE__*/ (function () {\n    /**\n     * Creates a DEFLATE decompression that can be used in ZIP archives\n     */\n    function AsyncUnzipInflate(_, sz) {\n        var _this = this;\n        if (sz < 320000) {\n            this.i = new Inflate(function (dat, final) {\n                _this.ondata(null, dat, final);\n            });\n        }\n        else {\n            this.i = new AsyncInflate(function (err, dat, final) {\n                _this.ondata(err, dat, final);\n            });\n            this.terminate = this.i.terminate;\n        }\n    }\n    AsyncUnzipInflate.prototype.push = function (data, final) {\n        if (this.i.terminate)\n            data = slc(data, 0);\n        this.i.push(data, final);\n    };\n    AsyncUnzipInflate.compression = 8;\n    return AsyncUnzipInflate;\n}());\nexport { AsyncUnzipInflate };\n/**\n * A ZIP archive decompression stream that emits files as they are discovered\n */\nvar Unzip = /*#__PURE__*/ (function () {\n    /**\n     * Creates a ZIP decompression stream\n     * @param cb The callback to call whenever a file in the ZIP archive is found\n     */\n    function Unzip(cb) {\n        this.onfile = cb;\n        this.k = [];\n        this.o = {\n            0: UnzipPassThrough\n        };\n        this.p = et;\n    }\n    /**\n     * Pushes a chunk to be unzipped\n     * @param chunk The chunk to push\n     * @param final Whether this is the last chunk\n     */\n    Unzip.prototype.push = function (chunk, final) {\n        var _this = this;\n        if (!this.onfile)\n            err(5);\n        if (!this.p)\n            err(4);\n        if (this.c > 0) {\n            var len = Math.min(this.c, chunk.length);\n            var toAdd = chunk.subarray(0, len);\n            this.c -= len;\n            if (this.d)\n                this.d.push(toAdd, !this.c);\n            else\n                this.k[0].push(toAdd);\n            chunk = chunk.subarray(len);\n            if (chunk.length)\n                return this.push(chunk, final);\n        }\n        else {\n            var f = 0, i = 0, is = void 0, buf = void 0;\n            if (!this.p.length)\n                buf = chunk;\n            else if (!chunk.length)\n                buf = this.p;\n            else {\n                buf = new u8(this.p.length + chunk.length);\n                buf.set(this.p), buf.set(chunk, this.p.length);\n            }\n            var l = buf.length, oc = this.c, add = oc && this.d;\n            var _loop_2 = function () {\n                var _a;\n                var sig = b4(buf, i);\n                if (sig == 0x4034B50) {\n                    f = 1, is = i;\n                    this_1.d = null;\n                    this_1.c = 0;\n                    var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28);\n                    if (l > i + 30 + fnl + es) {\n                        var chks_3 = [];\n                        this_1.k.unshift(chks_3);\n                        f = 2;\n                        var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);\n                        var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);\n                        if (sc_1 == 4294967295) {\n                            _a = dd ? [-2] : z64e(buf, i), sc_1 = _a[0], su_1 = _a[1];\n                        }\n                        else if (dd)\n                            sc_1 = -1;\n                        i += es;\n                        this_1.c = sc_1;\n                        var d_1;\n                        var file_1 = {\n                            name: fn_1,\n                            compression: cmp_1,\n                            start: function () {\n                                if (!file_1.ondata)\n                                    err(5);\n                                if (!sc_1)\n                                    file_1.ondata(null, et, true);\n                                else {\n                                    var ctr = _this.o[cmp_1];\n                                    if (!ctr)\n                                        file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false);\n                                    d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1);\n                                    d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); };\n                                    for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) {\n                                        var dat = chks_4[_i];\n                                        d_1.push(dat, false);\n                                    }\n                                    if (_this.k[0] == chks_3 && _this.c)\n                                        _this.d = d_1;\n                                    else\n                                        d_1.push(et, true);\n                                }\n                            },\n                            terminate: function () {\n                                if (d_1 && d_1.terminate)\n                                    d_1.terminate();\n                            }\n                        };\n                        if (sc_1 >= 0)\n                            file_1.size = sc_1, file_1.originalSize = su_1;\n                        this_1.onfile(file_1);\n                    }\n                    return \"break\";\n                }\n                else if (oc) {\n                    if (sig == 0x8074B50) {\n                        is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0;\n                        return \"break\";\n                    }\n                    else if (sig == 0x2014B50) {\n                        is = i -= 4, f = 3, this_1.c = 0;\n                        return \"break\";\n                    }\n                }\n            };\n            var this_1 = this;\n            for (; i < l - 4; ++i) {\n                var state_1 = _loop_2();\n                if (state_1 === \"break\")\n                    break;\n            }\n            this.p = et;\n            if (oc < 0) {\n                var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i);\n                if (add)\n                    add.push(dat, !!f);\n                else\n                    this.k[+(f == 2)].push(dat);\n            }\n            if (f & 2)\n                return this.push(buf.subarray(i), final);\n            this.p = buf.subarray(i);\n        }\n        if (final) {\n            if (this.c)\n                err(13);\n            this.p = null;\n        }\n    };\n    /**\n     * Registers a decoder with the stream, allowing for files compressed with\n     * the compression type provided to be expanded correctly\n     * @param decoder The decoder constructor\n     */\n    Unzip.prototype.register = function (decoder) {\n        this.o[decoder.compression] = decoder;\n    };\n    return Unzip;\n}());\nexport { Unzip };\nvar mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); };\nexport function unzip(data, opts, cb) {\n    if (!cb)\n        cb = opts, opts = {};\n    if (typeof cb != 'function')\n        err(7);\n    var term = [];\n    var tAll = function () {\n        for (var i = 0; i < term.length; ++i)\n            term[i]();\n    };\n    var files = {};\n    var cbd = function (a, b) {\n        mt(function () { cb(a, b); });\n    };\n    mt(function () { cbd = cb; });\n    var e = data.length - 22;\n    for (; b4(data, e) != 0x6054B50; --e) {\n        if (!e || data.length - e > 65558) {\n            cbd(err(13, 0, 1), null);\n            return tAll;\n        }\n    }\n    ;\n    var lft = b2(data, e + 8);\n    if (lft) {\n        var c = lft;\n        var o = b4(data, e + 16);\n        var z = o == 4294967295 || c == 65535;\n        if (z) {\n            var ze = b4(data, e - 12);\n            z = b4(data, ze) == 0x6064B50;\n            if (z) {\n                c = lft = b4(data, ze + 32);\n                o = b4(data, ze + 48);\n            }\n        }\n        var fltr = opts && opts.filter;\n        var _loop_3 = function (i) {\n            var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\n            o = no;\n            var cbl = function (e, d) {\n                if (e) {\n                    tAll();\n                    cbd(e, null);\n                }\n                else {\n                    if (d)\n                        files[fn] = d;\n                    if (!--lft)\n                        cbd(null, files);\n                }\n            };\n            if (!fltr || fltr({\n                name: fn,\n                size: sc,\n                originalSize: su,\n                compression: c_1\n            })) {\n                if (!c_1)\n                    cbl(null, slc(data, b, b + sc));\n                else if (c_1 == 8) {\n                    var infl = data.subarray(b, b + sc);\n                    // Synchronously decompress under 512KB, or barely-compressed data\n                    if (su < 524288 || sc > 0.8 * su) {\n                        try {\n                            cbl(null, inflateSync(infl, { out: new u8(su) }));\n                        }\n                        catch (e) {\n                            cbl(e, null);\n                        }\n                    }\n                    else\n                        term.push(inflate(infl, { size: su }, cbl));\n                }\n                else\n                    cbl(err(14, 'unknown compression type ' + c_1, 1), null);\n            }\n            else\n                cbl(null, null);\n        };\n        for (var i = 0; i < c; ++i) {\n            _loop_3(i);\n        }\n    }\n    else\n        cbd(null, {});\n    return tAll;\n}\n/**\n * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better\n * performance with more than one file.\n * @param data The raw compressed ZIP file\n * @param opts The ZIP extraction options\n * @returns The decompressed files\n */\nexport function unzipSync(data, opts) {\n    var files = {};\n    var e = data.length - 22;\n    for (; b4(data, e) != 0x6054B50; --e) {\n        if (!e || data.length - e > 65558)\n            err(13);\n    }\n    ;\n    var c = b2(data, e + 8);\n    if (!c)\n        return {};\n    var o = b4(data, e + 16);\n    var z = o == 4294967295 || c == 65535;\n    if (z) {\n        var ze = b4(data, e - 12);\n        z = b4(data, ze) == 0x6064B50;\n        if (z) {\n            c = b4(data, ze + 32);\n            o = b4(data, ze + 48);\n        }\n    }\n    var fltr = opts && opts.filter;\n    for (var i = 0; i < c; ++i) {\n        var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\n        o = no;\n        if (!fltr || fltr({\n            name: fn,\n            size: sc,\n            originalSize: su,\n            compression: c_2\n        })) {\n            if (!c_2)\n                files[fn] = slc(data, b, b + sc);\n            else if (c_2 == 8)\n                files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });\n            else\n                err(14, 'unknown compression type ' + c_2);\n        }\n    }\n    return files;\n}\n","import {\n\tAmbientLight,\n\tAnimationClip,\n\tBone,\n\tBufferGeometry,\n\tClampToEdgeWrapping,\n\tColor,\n\tDirectionalLight,\n\tDoubleSide,\n\tFileLoader,\n\tFloat32BufferAttribute,\n\tFrontSide,\n\tGroup,\n\tLine,\n\tLineBasicMaterial,\n\tLineSegments,\n\tLoader,\n\tLoaderUtils,\n\tMathUtils,\n\tMatrix4,\n\tMesh,\n\tMeshBasicMaterial,\n\tMeshLambertMaterial,\n\tMeshPhongMaterial,\n\tOrthographicCamera,\n\tPerspectiveCamera,\n\tPointLight,\n\tQuaternion,\n\tQuaternionKeyframeTrack,\n\tRepeatWrapping,\n\tScene,\n\tSkeleton,\n\tSkinnedMesh,\n\tSpotLight,\n\tTextureLoader,\n\tVector2,\n\tVector3,\n\tVectorKeyframeTrack,\n\tSRGBColorSpace\n} from 'three';\nimport { TGALoader } from '../loaders/TGALoader.js';\n\nclass ColladaLoader extends Loader {\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst path = ( scope.path === '' ) ? LoaderUtils.extractUrlBase( url ) : scope.path;\n\n\t\tconst loader = new FileLoader( scope.manager );\n\t\tloader.setPath( scope.path );\n\t\tloader.setRequestHeader( scope.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( text, path ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( text, path ) {\n\n\t\tfunction getElementsByTagName( xml, name ) {\n\n\t\t\t// Non recursive xml.getElementsByTagName() ...\n\n\t\t\tconst array = [];\n\t\t\tconst childNodes = xml.childNodes;\n\n\t\t\tfor ( let i = 0, l = childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = childNodes[ i ];\n\n\t\t\t\tif ( child.nodeName === name ) {\n\n\t\t\t\t\tarray.push( child );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn array;\n\n\t\t}\n\n\t\tfunction parseStrings( text ) {\n\n\t\t\tif ( text.length === 0 ) return [];\n\n\t\t\tconst parts = text.trim().split( /\\s+/ );\n\t\t\tconst array = new Array( parts.length );\n\n\t\t\tfor ( let i = 0, l = parts.length; i < l; i ++ ) {\n\n\t\t\t\tarray[ i ] = parts[ i ];\n\n\t\t\t}\n\n\t\t\treturn array;\n\n\t\t}\n\n\t\tfunction parseFloats( text ) {\n\n\t\t\tif ( text.length === 0 ) return [];\n\n\t\t\tconst parts = text.trim().split( /\\s+/ );\n\t\t\tconst array = new Array( parts.length );\n\n\t\t\tfor ( let i = 0, l = parts.length; i < l; i ++ ) {\n\n\t\t\t\tarray[ i ] = parseFloat( parts[ i ] );\n\n\t\t\t}\n\n\t\t\treturn array;\n\n\t\t}\n\n\t\tfunction parseInts( text ) {\n\n\t\t\tif ( text.length === 0 ) return [];\n\n\t\t\tconst parts = text.trim().split( /\\s+/ );\n\t\t\tconst array = new Array( parts.length );\n\n\t\t\tfor ( let i = 0, l = parts.length; i < l; i ++ ) {\n\n\t\t\t\tarray[ i ] = parseInt( parts[ i ] );\n\n\t\t\t}\n\n\t\t\treturn array;\n\n\t\t}\n\n\t\tfunction parseId( text ) {\n\n\t\t\treturn text.substring( 1 );\n\n\t\t}\n\n\t\tfunction generateId() {\n\n\t\t\treturn 'three_default_' + ( count ++ );\n\n\t\t}\n\n\t\tfunction isEmpty( object ) {\n\n\t\t\treturn Object.keys( object ).length === 0;\n\n\t\t}\n\n\t\t// asset\n\n\t\tfunction parseAsset( xml ) {\n\n\t\t\treturn {\n\t\t\t\tunit: parseAssetUnit( getElementsByTagName( xml, 'unit' )[ 0 ] ),\n\t\t\t\tupAxis: parseAssetUpAxis( getElementsByTagName( xml, 'up_axis' )[ 0 ] )\n\t\t\t};\n\n\t\t}\n\n\t\tfunction parseAssetUnit( xml ) {\n\n\t\t\tif ( ( xml !== undefined ) && ( xml.hasAttribute( 'meter' ) === true ) ) {\n\n\t\t\t\treturn parseFloat( xml.getAttribute( 'meter' ) );\n\n\t\t\t} else {\n\n\t\t\t\treturn 1; // default 1 meter\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseAssetUpAxis( xml ) {\n\n\t\t\treturn xml !== undefined ? xml.textContent : 'Y_UP';\n\n\t\t}\n\n\t\t// library\n\n\t\tfunction parseLibrary( xml, libraryName, nodeName, parser ) {\n\n\t\t\tconst library = getElementsByTagName( xml, libraryName )[ 0 ];\n\n\t\t\tif ( library !== undefined ) {\n\n\t\t\t\tconst elements = getElementsByTagName( library, nodeName );\n\n\t\t\t\tfor ( let i = 0; i < elements.length; i ++ ) {\n\n\t\t\t\t\tparser( elements[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction buildLibrary( data, builder ) {\n\n\t\t\tfor ( const name in data ) {\n\n\t\t\t\tconst object = data[ name ];\n\t\t\t\tobject.build = builder( data[ name ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// get\n\n\t\tfunction getBuild( data, builder ) {\n\n\t\t\tif ( data.build !== undefined ) return data.build;\n\n\t\t\tdata.build = builder( data );\n\n\t\t\treturn data.build;\n\n\t\t}\n\n\t\t// animation\n\n\t\tfunction parseAnimation( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tsources: {},\n\t\t\t\tsamplers: {},\n\t\t\t\tchannels: {}\n\t\t\t};\n\n\t\t\tlet hasChildren = false;\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tlet id;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'source':\n\t\t\t\t\t\tid = child.getAttribute( 'id' );\n\t\t\t\t\t\tdata.sources[ id ] = parseSource( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'sampler':\n\t\t\t\t\t\tid = child.getAttribute( 'id' );\n\t\t\t\t\t\tdata.samplers[ id ] = parseAnimationSampler( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'channel':\n\t\t\t\t\t\tid = child.getAttribute( 'target' );\n\t\t\t\t\t\tdata.channels[ id ] = parseAnimationChannel( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'animation':\n\t\t\t\t\t\t// hierarchy of related animations\n\t\t\t\t\t\tparseAnimation( child );\n\t\t\t\t\t\thasChildren = true;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tconsole.log( child );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( hasChildren === false ) {\n\n\t\t\t\t// since 'id' attributes can be optional, it's necessary to generate a UUID for unqiue assignment\n\n\t\t\t\tlibrary.animations[ xml.getAttribute( 'id' ) || MathUtils.generateUUID() ] = data;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseAnimationSampler( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tinputs: {},\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'input':\n\t\t\t\t\t\tconst id = parseId( child.getAttribute( 'source' ) );\n\t\t\t\t\t\tconst semantic = child.getAttribute( 'semantic' );\n\t\t\t\t\t\tdata.inputs[ semantic ] = id;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseAnimationChannel( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tconst target = xml.getAttribute( 'target' );\n\n\t\t\t// parsing SID Addressing Syntax\n\n\t\t\tlet parts = target.split( '/' );\n\n\t\t\tconst id = parts.shift();\n\t\t\tlet sid = parts.shift();\n\n\t\t\t// check selection syntax\n\n\t\t\tconst arraySyntax = ( sid.indexOf( '(' ) !== - 1 );\n\t\t\tconst memberSyntax = ( sid.indexOf( '.' ) !== - 1 );\n\n\t\t\tif ( memberSyntax ) {\n\n\t\t\t\t//  member selection access\n\n\t\t\t\tparts = sid.split( '.' );\n\t\t\t\tsid = parts.shift();\n\t\t\t\tdata.member = parts.shift();\n\n\t\t\t} else if ( arraySyntax ) {\n\n\t\t\t\t// array-access syntax. can be used to express fields in one-dimensional vectors or two-dimensional matrices.\n\n\t\t\t\tconst indices = sid.split( '(' );\n\t\t\t\tsid = indices.shift();\n\n\t\t\t\tfor ( let i = 0; i < indices.length; i ++ ) {\n\n\t\t\t\t\tindices[ i ] = parseInt( indices[ i ].replace( /\\)/, '' ) );\n\n\t\t\t\t}\n\n\t\t\t\tdata.indices = indices;\n\n\t\t\t}\n\n\t\t\tdata.id = id;\n\t\t\tdata.sid = sid;\n\n\t\t\tdata.arraySyntax = arraySyntax;\n\t\t\tdata.memberSyntax = memberSyntax;\n\n\t\t\tdata.sampler = parseId( xml.getAttribute( 'source' ) );\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction buildAnimation( data ) {\n\n\t\t\tconst tracks = [];\n\n\t\t\tconst channels = data.channels;\n\t\t\tconst samplers = data.samplers;\n\t\t\tconst sources = data.sources;\n\n\t\t\tfor ( const target in channels ) {\n\n\t\t\t\tif ( channels.hasOwnProperty( target ) ) {\n\n\t\t\t\t\tconst channel = channels[ target ];\n\t\t\t\t\tconst sampler = samplers[ channel.sampler ];\n\n\t\t\t\t\tconst inputId = sampler.inputs.INPUT;\n\t\t\t\t\tconst outputId = sampler.inputs.OUTPUT;\n\n\t\t\t\t\tconst inputSource = sources[ inputId ];\n\t\t\t\t\tconst outputSource = sources[ outputId ];\n\n\t\t\t\t\tconst animation = buildAnimationChannel( channel, inputSource, outputSource );\n\n\t\t\t\t\tcreateKeyframeTracks( animation, tracks );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn tracks;\n\n\t\t}\n\n\t\tfunction getAnimation( id ) {\n\n\t\t\treturn getBuild( library.animations[ id ], buildAnimation );\n\n\t\t}\n\n\t\tfunction buildAnimationChannel( channel, inputSource, outputSource ) {\n\n\t\t\tconst node = library.nodes[ channel.id ];\n\t\t\tconst object3D = getNode( node.id );\n\n\t\t\tconst transform = node.transforms[ channel.sid ];\n\t\t\tconst defaultMatrix = node.matrix.clone().transpose();\n\n\t\t\tlet time, stride;\n\t\t\tlet i, il, j, jl;\n\n\t\t\tconst data = {};\n\n\t\t\t// the collada spec allows the animation of data in various ways.\n\t\t\t// depending on the transform type (matrix, translate, rotate, scale), we execute different logic\n\n\t\t\tswitch ( transform ) {\n\n\t\t\t\tcase 'matrix':\n\n\t\t\t\t\tfor ( i = 0, il = inputSource.array.length; i < il; i ++ ) {\n\n\t\t\t\t\t\ttime = inputSource.array[ i ];\n\t\t\t\t\t\tstride = i * outputSource.stride;\n\n\t\t\t\t\t\tif ( data[ time ] === undefined ) data[ time ] = {};\n\n\t\t\t\t\t\tif ( channel.arraySyntax === true ) {\n\n\t\t\t\t\t\t\tconst value = outputSource.array[ stride ];\n\t\t\t\t\t\t\tconst index = channel.indices[ 0 ] + 4 * channel.indices[ 1 ];\n\n\t\t\t\t\t\t\tdata[ time ][ index ] = value;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tfor ( j = 0, jl = outputSource.stride; j < jl; j ++ ) {\n\n\t\t\t\t\t\t\t\tdata[ time ][ j ] = outputSource.array[ stride + j ];\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'translate':\n\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Animation transform type \"%s\" not yet implemented.', transform );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'rotate':\n\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Animation transform type \"%s\" not yet implemented.', transform );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'scale':\n\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Animation transform type \"%s\" not yet implemented.', transform );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tconst keyframes = prepareAnimationData( data, defaultMatrix );\n\n\t\t\tconst animation = {\n\t\t\t\tname: object3D.uuid,\n\t\t\t\tkeyframes: keyframes\n\t\t\t};\n\n\t\t\treturn animation;\n\n\t\t}\n\n\t\tfunction prepareAnimationData( data, defaultMatrix ) {\n\n\t\t\tconst keyframes = [];\n\n\t\t\t// transfer data into a sortable array\n\n\t\t\tfor ( const time in data ) {\n\n\t\t\t\tkeyframes.push( { time: parseFloat( time ), value: data[ time ] } );\n\n\t\t\t}\n\n\t\t\t// ensure keyframes are sorted by time\n\n\t\t\tkeyframes.sort( ascending );\n\n\t\t\t// now we clean up all animation data, so we can use them for keyframe tracks\n\n\t\t\tfor ( let i = 0; i < 16; i ++ ) {\n\n\t\t\t\ttransformAnimationData( keyframes, i, defaultMatrix.elements[ i ] );\n\n\t\t\t}\n\n\t\t\treturn keyframes;\n\n\t\t\t// array sort function\n\n\t\t\tfunction ascending( a, b ) {\n\n\t\t\t\treturn a.time - b.time;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst position = new Vector3();\n\t\tconst scale = new Vector3();\n\t\tconst quaternion = new Quaternion();\n\n\t\tfunction createKeyframeTracks( animation, tracks ) {\n\n\t\t\tconst keyframes = animation.keyframes;\n\t\t\tconst name = animation.name;\n\n\t\t\tconst times = [];\n\t\t\tconst positionData = [];\n\t\t\tconst quaternionData = [];\n\t\t\tconst scaleData = [];\n\n\t\t\tfor ( let i = 0, l = keyframes.length; i < l; i ++ ) {\n\n\t\t\t\tconst keyframe = keyframes[ i ];\n\n\t\t\t\tconst time = keyframe.time;\n\t\t\t\tconst value = keyframe.value;\n\n\t\t\t\tmatrix.fromArray( value ).transpose();\n\t\t\t\tmatrix.decompose( position, quaternion, scale );\n\n\t\t\t\ttimes.push( time );\n\t\t\t\tpositionData.push( position.x, position.y, position.z );\n\t\t\t\tquaternionData.push( quaternion.x, quaternion.y, quaternion.z, quaternion.w );\n\t\t\t\tscaleData.push( scale.x, scale.y, scale.z );\n\n\t\t\t}\n\n\t\t\tif ( positionData.length > 0 ) tracks.push( new VectorKeyframeTrack( name + '.position', times, positionData ) );\n\t\t\tif ( quaternionData.length > 0 ) tracks.push( new QuaternionKeyframeTrack( name + '.quaternion', times, quaternionData ) );\n\t\t\tif ( scaleData.length > 0 ) tracks.push( new VectorKeyframeTrack( name + '.scale', times, scaleData ) );\n\n\t\t\treturn tracks;\n\n\t\t}\n\n\t\tfunction transformAnimationData( keyframes, property, defaultValue ) {\n\n\t\t\tlet keyframe;\n\n\t\t\tlet empty = true;\n\t\t\tlet i, l;\n\n\t\t\t// check, if values of a property are missing in our keyframes\n\n\t\t\tfor ( i = 0, l = keyframes.length; i < l; i ++ ) {\n\n\t\t\t\tkeyframe = keyframes[ i ];\n\n\t\t\t\tif ( keyframe.value[ property ] === undefined ) {\n\n\t\t\t\t\tkeyframe.value[ property ] = null; // mark as missing\n\n\t\t\t\t} else {\n\n\t\t\t\t\tempty = false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( empty === true ) {\n\n\t\t\t\t// no values at all, so we set a default value\n\n\t\t\t\tfor ( i = 0, l = keyframes.length; i < l; i ++ ) {\n\n\t\t\t\t\tkeyframe = keyframes[ i ];\n\n\t\t\t\t\tkeyframe.value[ property ] = defaultValue;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// filling gaps\n\n\t\t\t\tcreateMissingKeyframes( keyframes, property );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction createMissingKeyframes( keyframes, property ) {\n\n\t\t\tlet prev, next;\n\n\t\t\tfor ( let i = 0, l = keyframes.length; i < l; i ++ ) {\n\n\t\t\t\tconst keyframe = keyframes[ i ];\n\n\t\t\t\tif ( keyframe.value[ property ] === null ) {\n\n\t\t\t\t\tprev = getPrev( keyframes, i, property );\n\t\t\t\t\tnext = getNext( keyframes, i, property );\n\n\t\t\t\t\tif ( prev === null ) {\n\n\t\t\t\t\t\tkeyframe.value[ property ] = next.value[ property ];\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( next === null ) {\n\n\t\t\t\t\t\tkeyframe.value[ property ] = prev.value[ property ];\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tinterpolate( keyframe, prev, next, property );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getPrev( keyframes, i, property ) {\n\n\t\t\twhile ( i >= 0 ) {\n\n\t\t\t\tconst keyframe = keyframes[ i ];\n\n\t\t\t\tif ( keyframe.value[ property ] !== null ) return keyframe;\n\n\t\t\t\ti --;\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tfunction getNext( keyframes, i, property ) {\n\n\t\t\twhile ( i < keyframes.length ) {\n\n\t\t\t\tconst keyframe = keyframes[ i ];\n\n\t\t\t\tif ( keyframe.value[ property ] !== null ) return keyframe;\n\n\t\t\t\ti ++;\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tfunction interpolate( key, prev, next, property ) {\n\n\t\t\tif ( ( next.time - prev.time ) === 0 ) {\n\n\t\t\t\tkey.value[ property ] = prev.value[ property ];\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tkey.value[ property ] = ( ( key.time - prev.time ) * ( next.value[ property ] - prev.value[ property ] ) / ( next.time - prev.time ) ) + prev.value[ property ];\n\n\t\t}\n\n\t\t// animation clips\n\n\t\tfunction parseAnimationClip( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'id' ) || 'default',\n\t\t\t\tstart: parseFloat( xml.getAttribute( 'start' ) || 0 ),\n\t\t\t\tend: parseFloat( xml.getAttribute( 'end' ) || 0 ),\n\t\t\t\tanimations: []\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'instance_animation':\n\t\t\t\t\t\tdata.animations.push( parseId( child.getAttribute( 'url' ) ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.clips[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction buildAnimationClip( data ) {\n\n\t\t\tconst tracks = [];\n\n\t\t\tconst name = data.name;\n\t\t\tconst duration = ( data.end - data.start ) || - 1;\n\t\t\tconst animations = data.animations;\n\n\t\t\tfor ( let i = 0, il = animations.length; i < il; i ++ ) {\n\n\t\t\t\tconst animationTracks = getAnimation( animations[ i ] );\n\n\t\t\t\tfor ( let j = 0, jl = animationTracks.length; j < jl; j ++ ) {\n\n\t\t\t\t\ttracks.push( animationTracks[ j ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn new AnimationClip( name, duration, tracks );\n\n\t\t}\n\n\t\tfunction getAnimationClip( id ) {\n\n\t\t\treturn getBuild( library.clips[ id ], buildAnimationClip );\n\n\t\t}\n\n\t\t// controller\n\n\t\tfunction parseController( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'skin':\n\t\t\t\t\t\t// there is exactly one skin per controller\n\t\t\t\t\t\tdata.id = parseId( child.getAttribute( 'source' ) );\n\t\t\t\t\t\tdata.skin = parseSkin( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'morph':\n\t\t\t\t\t\tdata.id = parseId( child.getAttribute( 'source' ) );\n\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Morph target animation not supported yet.' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.controllers[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction parseSkin( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tsources: {}\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'bind_shape_matrix':\n\t\t\t\t\t\tdata.bindShapeMatrix = parseFloats( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'source':\n\t\t\t\t\t\tconst id = child.getAttribute( 'id' );\n\t\t\t\t\t\tdata.sources[ id ] = parseSource( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'joints':\n\t\t\t\t\t\tdata.joints = parseJoints( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'vertex_weights':\n\t\t\t\t\t\tdata.vertexWeights = parseVertexWeights( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseJoints( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tinputs: {}\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'input':\n\t\t\t\t\t\tconst semantic = child.getAttribute( 'semantic' );\n\t\t\t\t\t\tconst id = parseId( child.getAttribute( 'source' ) );\n\t\t\t\t\t\tdata.inputs[ semantic ] = id;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseVertexWeights( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tinputs: {}\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'input':\n\t\t\t\t\t\tconst semantic = child.getAttribute( 'semantic' );\n\t\t\t\t\t\tconst id = parseId( child.getAttribute( 'source' ) );\n\t\t\t\t\t\tconst offset = parseInt( child.getAttribute( 'offset' ) );\n\t\t\t\t\t\tdata.inputs[ semantic ] = { id: id, offset: offset };\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'vcount':\n\t\t\t\t\t\tdata.vcount = parseInts( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'v':\n\t\t\t\t\t\tdata.v = parseInts( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction buildController( data ) {\n\n\t\t\tconst build = {\n\t\t\t\tid: data.id\n\t\t\t};\n\n\t\t\tconst geometry = library.geometries[ build.id ];\n\n\t\t\tif ( data.skin !== undefined ) {\n\n\t\t\t\tbuild.skin = buildSkin( data.skin );\n\n\t\t\t\t// we enhance the 'sources' property of the corresponding geometry with our skin data\n\n\t\t\t\tgeometry.sources.skinIndices = build.skin.indices;\n\t\t\t\tgeometry.sources.skinWeights = build.skin.weights;\n\n\t\t\t}\n\n\t\t\treturn build;\n\n\t\t}\n\n\t\tfunction buildSkin( data ) {\n\n\t\t\tconst BONE_LIMIT = 4;\n\n\t\t\tconst build = {\n\t\t\t\tjoints: [], // this must be an array to preserve the joint order\n\t\t\t\tindices: {\n\t\t\t\t\tarray: [],\n\t\t\t\t\tstride: BONE_LIMIT\n\t\t\t\t},\n\t\t\t\tweights: {\n\t\t\t\t\tarray: [],\n\t\t\t\t\tstride: BONE_LIMIT\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tconst sources = data.sources;\n\t\t\tconst vertexWeights = data.vertexWeights;\n\n\t\t\tconst vcount = vertexWeights.vcount;\n\t\t\tconst v = vertexWeights.v;\n\t\t\tconst jointOffset = vertexWeights.inputs.JOINT.offset;\n\t\t\tconst weightOffset = vertexWeights.inputs.WEIGHT.offset;\n\n\t\t\tconst jointSource = data.sources[ data.joints.inputs.JOINT ];\n\t\t\tconst inverseSource = data.sources[ data.joints.inputs.INV_BIND_MATRIX ];\n\n\t\t\tconst weights = sources[ vertexWeights.inputs.WEIGHT.id ].array;\n\t\t\tlet stride = 0;\n\n\t\t\tlet i, j, l;\n\n\t\t\t// process skin data for each vertex\n\n\t\t\tfor ( i = 0, l = vcount.length; i < l; i ++ ) {\n\n\t\t\t\tconst jointCount = vcount[ i ]; // this is the amount of joints that affect a single vertex\n\t\t\t\tconst vertexSkinData = [];\n\n\t\t\t\tfor ( j = 0; j < jointCount; j ++ ) {\n\n\t\t\t\t\tconst skinIndex = v[ stride + jointOffset ];\n\t\t\t\t\tconst weightId = v[ stride + weightOffset ];\n\t\t\t\t\tconst skinWeight = weights[ weightId ];\n\n\t\t\t\t\tvertexSkinData.push( { index: skinIndex, weight: skinWeight } );\n\n\t\t\t\t\tstride += 2;\n\n\t\t\t\t}\n\n\t\t\t\t// we sort the joints in descending order based on the weights.\n\t\t\t\t// this ensures, we only procced the most important joints of the vertex\n\n\t\t\t\tvertexSkinData.sort( descending );\n\n\t\t\t\t// now we provide for each vertex a set of four index and weight values.\n\t\t\t\t// the order of the skin data matches the order of vertices\n\n\t\t\t\tfor ( j = 0; j < BONE_LIMIT; j ++ ) {\n\n\t\t\t\t\tconst d = vertexSkinData[ j ];\n\n\t\t\t\t\tif ( d !== undefined ) {\n\n\t\t\t\t\t\tbuild.indices.array.push( d.index );\n\t\t\t\t\t\tbuild.weights.array.push( d.weight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tbuild.indices.array.push( 0 );\n\t\t\t\t\t\tbuild.weights.array.push( 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// setup bind matrix\n\n\t\t\tif ( data.bindShapeMatrix ) {\n\n\t\t\t\tbuild.bindMatrix = new Matrix4().fromArray( data.bindShapeMatrix ).transpose();\n\n\t\t\t} else {\n\n\t\t\t\tbuild.bindMatrix = new Matrix4().identity();\n\n\t\t\t}\n\n\t\t\t// process bones and inverse bind matrix data\n\n\t\t\tfor ( i = 0, l = jointSource.array.length; i < l; i ++ ) {\n\n\t\t\t\tconst name = jointSource.array[ i ];\n\t\t\t\tconst boneInverse = new Matrix4().fromArray( inverseSource.array, i * inverseSource.stride ).transpose();\n\n\t\t\t\tbuild.joints.push( { name: name, boneInverse: boneInverse } );\n\n\t\t\t}\n\n\t\t\treturn build;\n\n\t\t\t// array sort function\n\n\t\t\tfunction descending( a, b ) {\n\n\t\t\t\treturn b.weight - a.weight;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getController( id ) {\n\n\t\t\treturn getBuild( library.controllers[ id ], buildController );\n\n\t\t}\n\n\t\t// image\n\n\t\tfunction parseImage( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tinit_from: getElementsByTagName( xml, 'init_from' )[ 0 ].textContent\n\t\t\t};\n\n\t\t\tlibrary.images[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction buildImage( data ) {\n\n\t\t\tif ( data.build !== undefined ) return data.build;\n\n\t\t\treturn data.init_from;\n\n\t\t}\n\n\t\tfunction getImage( id ) {\n\n\t\t\tconst data = library.images[ id ];\n\n\t\t\tif ( data !== undefined ) {\n\n\t\t\t\treturn getBuild( data, buildImage );\n\n\t\t\t}\n\n\t\t\tconsole.warn( 'THREE.ColladaLoader: Couldn\\'t find image with ID:', id );\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// effect\n\n\t\tfunction parseEffect( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'profile_COMMON':\n\t\t\t\t\t\tdata.profile = parseEffectProfileCOMMON( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.effects[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction parseEffectProfileCOMMON( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tsurfaces: {},\n\t\t\t\tsamplers: {}\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'newparam':\n\t\t\t\t\t\tparseEffectNewparam( child, data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'technique':\n\t\t\t\t\t\tdata.technique = parseEffectTechnique( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'extra':\n\t\t\t\t\t\tdata.extra = parseEffectExtra( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectNewparam( xml, data ) {\n\n\t\t\tconst sid = xml.getAttribute( 'sid' );\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'surface':\n\t\t\t\t\t\tdata.surfaces[ sid ] = parseEffectSurface( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'sampler2D':\n\t\t\t\t\t\tdata.samplers[ sid ] = parseEffectSampler( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseEffectSurface( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'init_from':\n\t\t\t\t\t\tdata.init_from = child.textContent;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectSampler( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'source':\n\t\t\t\t\t\tdata.source = child.textContent;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectTechnique( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'constant':\n\t\t\t\t\tcase 'lambert':\n\t\t\t\t\tcase 'blinn':\n\t\t\t\t\tcase 'phong':\n\t\t\t\t\t\tdata.type = child.nodeName;\n\t\t\t\t\t\tdata.parameters = parseEffectParameters( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'extra':\n\t\t\t\t\t\tdata.extra = parseEffectExtra( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectParameters( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'emission':\n\t\t\t\t\tcase 'diffuse':\n\t\t\t\t\tcase 'specular':\n\t\t\t\t\tcase 'bump':\n\t\t\t\t\tcase 'ambient':\n\t\t\t\t\tcase 'shininess':\n\t\t\t\t\tcase 'transparency':\n\t\t\t\t\t\tdata[ child.nodeName ] = parseEffectParameter( child );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'transparent':\n\t\t\t\t\t\tdata[ child.nodeName ] = {\n\t\t\t\t\t\t\topaque: child.hasAttribute( 'opaque' ) ? child.getAttribute( 'opaque' ) : 'A_ONE',\n\t\t\t\t\t\t\tdata: parseEffectParameter( child )\n\t\t\t\t\t\t};\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectParameter( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'color':\n\t\t\t\t\t\tdata[ child.nodeName ] = parseFloats( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'float':\n\t\t\t\t\t\tdata[ child.nodeName ] = parseFloat( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'texture':\n\t\t\t\t\t\tdata[ child.nodeName ] = { id: child.getAttribute( 'texture' ), extra: parseEffectParameterTexture( child ) };\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectParameterTexture( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\ttechnique: {}\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'extra':\n\t\t\t\t\t\tparseEffectParameterTextureExtra( child, data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectParameterTextureExtra( xml, data ) {\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'technique':\n\t\t\t\t\t\tparseEffectParameterTextureExtraTechnique( child, data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseEffectParameterTextureExtraTechnique( xml, data ) {\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'repeatU':\n\t\t\t\t\tcase 'repeatV':\n\t\t\t\t\tcase 'offsetU':\n\t\t\t\t\tcase 'offsetV':\n\t\t\t\t\t\tdata.technique[ child.nodeName ] = parseFloat( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'wrapU':\n\t\t\t\t\tcase 'wrapV':\n\n\t\t\t\t\t\t// some files have values for wrapU/wrapV which become NaN via parseInt\n\n\t\t\t\t\t\tif ( child.textContent.toUpperCase() === 'TRUE' ) {\n\n\t\t\t\t\t\t\tdata.technique[ child.nodeName ] = 1;\n\n\t\t\t\t\t\t} else if ( child.textContent.toUpperCase() === 'FALSE' ) {\n\n\t\t\t\t\t\t\tdata.technique[ child.nodeName ] = 0;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tdata.technique[ child.nodeName ] = parseInt( child.textContent );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'bump':\n\t\t\t\t\t\tdata[ child.nodeName ] = parseEffectExtraTechniqueBump( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseEffectExtra( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'technique':\n\t\t\t\t\t\tdata.technique = parseEffectExtraTechnique( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectExtraTechnique( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'double_sided':\n\t\t\t\t\t\tdata[ child.nodeName ] = parseInt( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'bump':\n\t\t\t\t\t\tdata[ child.nodeName ] = parseEffectExtraTechniqueBump( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseEffectExtraTechniqueBump( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'texture':\n\t\t\t\t\t\tdata[ child.nodeName ] = { id: child.getAttribute( 'texture' ), texcoord: child.getAttribute( 'texcoord' ), extra: parseEffectParameterTexture( child ) };\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction buildEffect( data ) {\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction getEffect( id ) {\n\n\t\t\treturn getBuild( library.effects[ id ], buildEffect );\n\n\t\t}\n\n\t\t// material\n\n\t\tfunction parseMaterial( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'name' )\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'instance_effect':\n\t\t\t\t\t\tdata.url = parseId( child.getAttribute( 'url' ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.materials[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction getTextureLoader( image ) {\n\n\t\t\tlet loader;\n\n\t\t\tlet extension = image.slice( ( image.lastIndexOf( '.' ) - 1 >>> 0 ) + 2 ); // http://www.jstips.co/en/javascript/get-file-extension/\n\t\t\textension = extension.toLowerCase();\n\n\t\t\tswitch ( extension ) {\n\n\t\t\t\tcase 'tga':\n\t\t\t\t\tloader = tgaLoader;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tloader = textureLoader;\n\n\t\t\t}\n\n\t\t\treturn loader;\n\n\t\t}\n\n\t\tfunction buildMaterial( data ) {\n\n\t\t\tconst effect = getEffect( data.url );\n\t\t\tconst technique = effect.profile.technique;\n\n\t\t\tlet material;\n\n\t\t\tswitch ( technique.type ) {\n\n\t\t\t\tcase 'phong':\n\t\t\t\tcase 'blinn':\n\t\t\t\t\tmaterial = new MeshPhongMaterial();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'lambert':\n\t\t\t\t\tmaterial = new MeshLambertMaterial();\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tmaterial = new MeshBasicMaterial();\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tmaterial.name = data.name || '';\n\n\t\t\tfunction getTexture( textureObject, colorSpace = null ) {\n\n\t\t\t\tconst sampler = effect.profile.samplers[ textureObject.id ];\n\t\t\t\tlet image = null;\n\n\t\t\t\t// get image\n\n\t\t\t\tif ( sampler !== undefined ) {\n\n\t\t\t\t\tconst surface = effect.profile.surfaces[ sampler.source ];\n\t\t\t\t\timage = getImage( surface.init_from );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Undefined sampler. Access image directly (see #12530).' );\n\t\t\t\t\timage = getImage( textureObject.id );\n\n\t\t\t\t}\n\n\t\t\t\t// create texture if image is avaiable\n\n\t\t\t\tif ( image !== null ) {\n\n\t\t\t\t\tconst loader = getTextureLoader( image );\n\n\t\t\t\t\tif ( loader !== undefined ) {\n\n\t\t\t\t\t\tconst texture = loader.load( image );\n\n\t\t\t\t\t\tconst extra = textureObject.extra;\n\n\t\t\t\t\t\tif ( extra !== undefined && extra.technique !== undefined && isEmpty( extra.technique ) === false ) {\n\n\t\t\t\t\t\t\tconst technique = extra.technique;\n\n\t\t\t\t\t\t\ttexture.wrapS = technique.wrapU ? RepeatWrapping : ClampToEdgeWrapping;\n\t\t\t\t\t\t\ttexture.wrapT = technique.wrapV ? RepeatWrapping : ClampToEdgeWrapping;\n\n\t\t\t\t\t\t\ttexture.offset.set( technique.offsetU || 0, technique.offsetV || 0 );\n\t\t\t\t\t\t\ttexture.repeat.set( technique.repeatU || 1, technique.repeatV || 1 );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\ttexture.wrapS = RepeatWrapping;\n\t\t\t\t\t\t\ttexture.wrapT = RepeatWrapping;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( colorSpace !== null ) {\n\n\t\t\t\t\t\t\ttexture.colorSpace = colorSpace;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn texture;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Loader for texture %s not found.', image );\n\n\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Couldn\\'t create texture with ID:', textureObject.id );\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst parameters = technique.parameters;\n\n\t\t\tfor ( const key in parameters ) {\n\n\t\t\t\tconst parameter = parameters[ key ];\n\n\t\t\t\tswitch ( key ) {\n\n\t\t\t\t\tcase 'diffuse':\n\t\t\t\t\t\tif ( parameter.color ) material.color.fromArray( parameter.color );\n\t\t\t\t\t\tif ( parameter.texture ) material.map = getTexture( parameter.texture, SRGBColorSpace );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'specular':\n\t\t\t\t\t\tif ( parameter.color && material.specular ) material.specular.fromArray( parameter.color );\n\t\t\t\t\t\tif ( parameter.texture ) material.specularMap = getTexture( parameter.texture );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'bump':\n\t\t\t\t\t\tif ( parameter.texture ) material.normalMap = getTexture( parameter.texture );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'ambient':\n\t\t\t\t\t\tif ( parameter.texture ) material.lightMap = getTexture( parameter.texture, SRGBColorSpace );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'shininess':\n\t\t\t\t\t\tif ( parameter.float && material.shininess ) material.shininess = parameter.float;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'emission':\n\t\t\t\t\t\tif ( parameter.color && material.emissive ) material.emissive.fromArray( parameter.color );\n\t\t\t\t\t\tif ( parameter.texture ) material.emissiveMap = getTexture( parameter.texture, SRGBColorSpace );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tmaterial.color.convertSRGBToLinear();\n\t\t\tif ( material.specular ) material.specular.convertSRGBToLinear();\n\t\t\tif ( material.emissive ) material.emissive.convertSRGBToLinear();\n\n\t\t\t//\n\n\t\t\tlet transparent = parameters[ 'transparent' ];\n\t\t\tlet transparency = parameters[ 'transparency' ];\n\n\t\t\t// <transparency> does not exist but <transparent>\n\n\t\t\tif ( transparency === undefined && transparent ) {\n\n\t\t\t\ttransparency = {\n\t\t\t\t\tfloat: 1\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\t// <transparent> does not exist but <transparency>\n\n\t\t\tif ( transparent === undefined && transparency ) {\n\n\t\t\t\ttransparent = {\n\t\t\t\t\topaque: 'A_ONE',\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tcolor: [ 1, 1, 1, 1 ]\n\t\t\t\t\t} };\n\n\t\t\t}\n\n\t\t\tif ( transparent && transparency ) {\n\n\t\t\t\t// handle case if a texture exists but no color\n\n\t\t\t\tif ( transparent.data.texture ) {\n\n\t\t\t\t\t// we do not set an alpha map (see #13792)\n\n\t\t\t\t\tmaterial.transparent = true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst color = transparent.data.color;\n\n\t\t\t\t\tswitch ( transparent.opaque ) {\n\n\t\t\t\t\t\tcase 'A_ONE':\n\t\t\t\t\t\t\tmaterial.opacity = color[ 3 ] * transparency.float;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'RGB_ZERO':\n\t\t\t\t\t\t\tmaterial.opacity = 1 - ( color[ 0 ] * transparency.float );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'A_ZERO':\n\t\t\t\t\t\t\tmaterial.opacity = 1 - ( color[ 3 ] * transparency.float );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'RGB_ONE':\n\t\t\t\t\t\t\tmaterial.opacity = color[ 0 ] * transparency.float;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Invalid opaque type \"%s\" of transparent tag.', transparent.opaque );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( material.opacity < 1 ) material.transparent = true;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//\n\n\n\t\t\tif ( technique.extra !== undefined && technique.extra.technique !== undefined ) {\n\n\t\t\t\tconst techniques = technique.extra.technique;\n\n\t\t\t\tfor ( const k in techniques ) {\n\n\t\t\t\t\tconst v = techniques[ k ];\n\n\t\t\t\t\tswitch ( k ) {\n\n\t\t\t\t\t\tcase 'double_sided':\n\t\t\t\t\t\t\tmaterial.side = ( v === 1 ? DoubleSide : FrontSide );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'bump':\n\t\t\t\t\t\t\tmaterial.normalMap = getTexture( v.texture );\n\t\t\t\t\t\t\tmaterial.normalScale = new Vector2( 1, 1 );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn material;\n\n\t\t}\n\n\t\tfunction getMaterial( id ) {\n\n\t\t\treturn getBuild( library.materials[ id ], buildMaterial );\n\n\t\t}\n\n\t\t// camera\n\n\t\tfunction parseCamera( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'name' )\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'optics':\n\t\t\t\t\t\tdata.optics = parseCameraOptics( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.cameras[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction parseCameraOptics( xml ) {\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'technique_common':\n\t\t\t\t\t\treturn parseCameraTechnique( child );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn {};\n\n\t\t}\n\n\t\tfunction parseCameraTechnique( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'perspective':\n\t\t\t\t\tcase 'orthographic':\n\n\t\t\t\t\t\tdata.technique = child.nodeName;\n\t\t\t\t\t\tdata.parameters = parseCameraParameters( child );\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseCameraParameters( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'xfov':\n\t\t\t\t\tcase 'yfov':\n\t\t\t\t\tcase 'xmag':\n\t\t\t\t\tcase 'ymag':\n\t\t\t\t\tcase 'znear':\n\t\t\t\t\tcase 'zfar':\n\t\t\t\t\tcase 'aspect_ratio':\n\t\t\t\t\t\tdata[ child.nodeName ] = parseFloat( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction buildCamera( data ) {\n\n\t\t\tlet camera;\n\n\t\t\tswitch ( data.optics.technique ) {\n\n\t\t\t\tcase 'perspective':\n\t\t\t\t\tcamera = new PerspectiveCamera(\n\t\t\t\t\t\tdata.optics.parameters.yfov,\n\t\t\t\t\t\tdata.optics.parameters.aspect_ratio,\n\t\t\t\t\t\tdata.optics.parameters.znear,\n\t\t\t\t\t\tdata.optics.parameters.zfar\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'orthographic':\n\t\t\t\t\tlet ymag = data.optics.parameters.ymag;\n\t\t\t\t\tlet xmag = data.optics.parameters.xmag;\n\t\t\t\t\tconst aspectRatio = data.optics.parameters.aspect_ratio;\n\n\t\t\t\t\txmag = ( xmag === undefined ) ? ( ymag * aspectRatio ) : xmag;\n\t\t\t\t\tymag = ( ymag === undefined ) ? ( xmag / aspectRatio ) : ymag;\n\n\t\t\t\t\txmag *= 0.5;\n\t\t\t\t\tymag *= 0.5;\n\n\t\t\t\t\tcamera = new OrthographicCamera(\n\t\t\t\t\t\t- xmag, xmag, ymag, - ymag, // left, right, top, bottom\n\t\t\t\t\t\tdata.optics.parameters.znear,\n\t\t\t\t\t\tdata.optics.parameters.zfar\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tcamera = new PerspectiveCamera();\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tcamera.name = data.name || '';\n\n\t\t\treturn camera;\n\n\t\t}\n\n\t\tfunction getCamera( id ) {\n\n\t\t\tconst data = library.cameras[ id ];\n\n\t\t\tif ( data !== undefined ) {\n\n\t\t\t\treturn getBuild( data, buildCamera );\n\n\t\t\t}\n\n\t\t\tconsole.warn( 'THREE.ColladaLoader: Couldn\\'t find camera with ID:', id );\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// light\n\n\t\tfunction parseLight( xml ) {\n\n\t\t\tlet data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'technique_common':\n\t\t\t\t\t\tdata = parseLightTechnique( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.lights[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction parseLightTechnique( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'directional':\n\t\t\t\t\tcase 'point':\n\t\t\t\t\tcase 'spot':\n\t\t\t\t\tcase 'ambient':\n\n\t\t\t\t\t\tdata.technique = child.nodeName;\n\t\t\t\t\t\tdata.parameters = parseLightParameters( child );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseLightParameters( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'color':\n\t\t\t\t\t\tconst array = parseFloats( child.textContent );\n\t\t\t\t\t\tdata.color = new Color().fromArray( array ).convertSRGBToLinear();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'falloff_angle':\n\t\t\t\t\t\tdata.falloffAngle = parseFloat( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'quadratic_attenuation':\n\t\t\t\t\t\tconst f = parseFloat( child.textContent );\n\t\t\t\t\t\tdata.distance = f ? Math.sqrt( 1 / f ) : 0;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction buildLight( data ) {\n\n\t\t\tlet light;\n\n\t\t\tswitch ( data.technique ) {\n\n\t\t\t\tcase 'directional':\n\t\t\t\t\tlight = new DirectionalLight();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'point':\n\t\t\t\t\tlight = new PointLight();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'spot':\n\t\t\t\t\tlight = new SpotLight();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ambient':\n\t\t\t\t\tlight = new AmbientLight();\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( data.parameters.color ) light.color.copy( data.parameters.color );\n\t\t\tif ( data.parameters.distance ) light.distance = data.parameters.distance;\n\n\t\t\treturn light;\n\n\t\t}\n\n\t\tfunction getLight( id ) {\n\n\t\t\tconst data = library.lights[ id ];\n\n\t\t\tif ( data !== undefined ) {\n\n\t\t\t\treturn getBuild( data, buildLight );\n\n\t\t\t}\n\n\t\t\tconsole.warn( 'THREE.ColladaLoader: Couldn\\'t find light with ID:', id );\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// geometry\n\n\t\tfunction parseGeometry( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'name' ),\n\t\t\t\tsources: {},\n\t\t\t\tvertices: {},\n\t\t\t\tprimitives: []\n\t\t\t};\n\n\t\t\tconst mesh = getElementsByTagName( xml, 'mesh' )[ 0 ];\n\n\t\t\t// the following tags inside geometry are not supported yet (see https://github.com/mrdoob/three.js/pull/12606): convex_mesh, spline, brep\n\t\t\tif ( mesh === undefined ) return;\n\n\t\t\tfor ( let i = 0; i < mesh.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = mesh.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tconst id = child.getAttribute( 'id' );\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'source':\n\t\t\t\t\t\tdata.sources[ id ] = parseSource( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'vertices':\n\t\t\t\t\t\t// data.sources[ id ] = data.sources[ parseId( getElementsByTagName( child, 'input' )[ 0 ].getAttribute( 'source' ) ) ];\n\t\t\t\t\t\tdata.vertices = parseGeometryVertices( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'polygons':\n\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Unsupported primitive type: ', child.nodeName );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'lines':\n\t\t\t\t\tcase 'linestrips':\n\t\t\t\t\tcase 'polylist':\n\t\t\t\t\tcase 'triangles':\n\t\t\t\t\t\tdata.primitives.push( parseGeometryPrimitive( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tconsole.log( child );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.geometries[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction parseSource( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tarray: [],\n\t\t\t\tstride: 3\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'float_array':\n\t\t\t\t\t\tdata.array = parseFloats( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'Name_array':\n\t\t\t\t\t\tdata.array = parseStrings( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'technique_common':\n\t\t\t\t\t\tconst accessor = getElementsByTagName( child, 'accessor' )[ 0 ];\n\n\t\t\t\t\t\tif ( accessor !== undefined ) {\n\n\t\t\t\t\t\t\tdata.stride = parseInt( accessor.getAttribute( 'stride' ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseGeometryVertices( xml ) {\n\n\t\t\tconst data = {};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tdata[ child.getAttribute( 'semantic' ) ] = parseId( child.getAttribute( 'source' ) );\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseGeometryPrimitive( xml ) {\n\n\t\t\tconst primitive = {\n\t\t\t\ttype: xml.nodeName,\n\t\t\t\tmaterial: xml.getAttribute( 'material' ),\n\t\t\t\tcount: parseInt( xml.getAttribute( 'count' ) ),\n\t\t\t\tinputs: {},\n\t\t\t\tstride: 0,\n\t\t\t\thasUV: false\n\t\t\t};\n\n\t\t\tfor ( let i = 0, l = xml.childNodes.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'input':\n\t\t\t\t\t\tconst id = parseId( child.getAttribute( 'source' ) );\n\t\t\t\t\t\tconst semantic = child.getAttribute( 'semantic' );\n\t\t\t\t\t\tconst offset = parseInt( child.getAttribute( 'offset' ) );\n\t\t\t\t\t\tconst set = parseInt( child.getAttribute( 'set' ) );\n\t\t\t\t\t\tconst inputname = ( set > 0 ? semantic + set : semantic );\n\t\t\t\t\t\tprimitive.inputs[ inputname ] = { id: id, offset: offset };\n\t\t\t\t\t\tprimitive.stride = Math.max( primitive.stride, offset + 1 );\n\t\t\t\t\t\tif ( semantic === 'TEXCOORD' ) primitive.hasUV = true;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'vcount':\n\t\t\t\t\t\tprimitive.vcount = parseInts( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'p':\n\t\t\t\t\t\tprimitive.p = parseInts( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn primitive;\n\n\t\t}\n\n\t\tfunction groupPrimitives( primitives ) {\n\n\t\t\tconst build = {};\n\n\t\t\tfor ( let i = 0; i < primitives.length; i ++ ) {\n\n\t\t\t\tconst primitive = primitives[ i ];\n\n\t\t\t\tif ( build[ primitive.type ] === undefined ) build[ primitive.type ] = [];\n\n\t\t\t\tbuild[ primitive.type ].push( primitive );\n\n\t\t\t}\n\n\t\t\treturn build;\n\n\t\t}\n\n\t\tfunction checkUVCoordinates( primitives ) {\n\n\t\t\tlet count = 0;\n\n\t\t\tfor ( let i = 0, l = primitives.length; i < l; i ++ ) {\n\n\t\t\t\tconst primitive = primitives[ i ];\n\n\t\t\t\tif ( primitive.hasUV === true ) {\n\n\t\t\t\t\tcount ++;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( count > 0 && count < primitives.length ) {\n\n\t\t\t\tprimitives.uvsNeedsFix = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction buildGeometry( data ) {\n\n\t\t\tconst build = {};\n\n\t\t\tconst sources = data.sources;\n\t\t\tconst vertices = data.vertices;\n\t\t\tconst primitives = data.primitives;\n\n\t\t\tif ( primitives.length === 0 ) return {};\n\n\t\t\t// our goal is to create one buffer geometry for a single type of primitives\n\t\t\t// first, we group all primitives by their type\n\n\t\t\tconst groupedPrimitives = groupPrimitives( primitives );\n\n\t\t\tfor ( const type in groupedPrimitives ) {\n\n\t\t\t\tconst primitiveType = groupedPrimitives[ type ];\n\n\t\t\t\t// second, ensure consistent uv coordinates for each type of primitives (polylist,triangles or lines)\n\n\t\t\t\tcheckUVCoordinates( primitiveType );\n\n\t\t\t\t// third, create a buffer geometry for each type of primitives\n\n\t\t\t\tbuild[ type ] = buildGeometryType( primitiveType, sources, vertices );\n\n\t\t\t}\n\n\t\t\treturn build;\n\n\t\t}\n\n\t\tfunction buildGeometryType( primitives, sources, vertices ) {\n\n\t\t\tconst build = {};\n\n\t\t\tconst position = { array: [], stride: 0 };\n\t\t\tconst normal = { array: [], stride: 0 };\n\t\t\tconst uv = { array: [], stride: 0 };\n\t\t\tconst uv1 = { array: [], stride: 0 };\n\t\t\tconst color = { array: [], stride: 0 };\n\n\t\t\tconst skinIndex = { array: [], stride: 4 };\n\t\t\tconst skinWeight = { array: [], stride: 4 };\n\n\t\t\tconst geometry = new BufferGeometry();\n\n\t\t\tconst materialKeys = [];\n\n\t\t\tlet start = 0;\n\n\t\t\tfor ( let p = 0; p < primitives.length; p ++ ) {\n\n\t\t\t\tconst primitive = primitives[ p ];\n\t\t\t\tconst inputs = primitive.inputs;\n\n\t\t\t\t// groups\n\n\t\t\t\tlet count = 0;\n\n\t\t\t\tswitch ( primitive.type ) {\n\n\t\t\t\t\tcase 'lines':\n\t\t\t\t\tcase 'linestrips':\n\t\t\t\t\t\tcount = primitive.count * 2;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'triangles':\n\t\t\t\t\t\tcount = primitive.count * 3;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'polylist':\n\n\t\t\t\t\t\tfor ( let g = 0; g < primitive.count; g ++ ) {\n\n\t\t\t\t\t\t\tconst vc = primitive.vcount[ g ];\n\n\t\t\t\t\t\t\tswitch ( vc ) {\n\n\t\t\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\t\t\tcount += 3; // single triangle\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 4:\n\t\t\t\t\t\t\t\t\tcount += 6; // quad, subdivided into two triangles\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tcount += ( vc - 2 ) * 3; // polylist with more than four vertices\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Unknow primitive type:', primitive.type );\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.addGroup( start, count, p );\n\t\t\t\tstart += count;\n\n\t\t\t\t// material\n\n\t\t\t\tif ( primitive.material ) {\n\n\t\t\t\t\tmaterialKeys.push( primitive.material );\n\n\t\t\t\t}\n\n\t\t\t\t// geometry data\n\n\t\t\t\tfor ( const name in inputs ) {\n\n\t\t\t\t\tconst input = inputs[ name ];\n\n\t\t\t\t\tswitch ( name )\t{\n\n\t\t\t\t\t\tcase 'VERTEX':\n\t\t\t\t\t\t\tfor ( const key in vertices ) {\n\n\t\t\t\t\t\t\t\tconst id = vertices[ key ];\n\n\t\t\t\t\t\t\t\tswitch ( key ) {\n\n\t\t\t\t\t\t\t\t\tcase 'POSITION':\n\t\t\t\t\t\t\t\t\t\tconst prevLength = position.array.length;\n\t\t\t\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ id ], input.offset, position.array );\n\t\t\t\t\t\t\t\t\t\tposition.stride = sources[ id ].stride;\n\n\t\t\t\t\t\t\t\t\t\tif ( sources.skinWeights && sources.skinIndices ) {\n\n\t\t\t\t\t\t\t\t\t\t\tbuildGeometryData( primitive, sources.skinIndices, input.offset, skinIndex.array );\n\t\t\t\t\t\t\t\t\t\t\tbuildGeometryData( primitive, sources.skinWeights, input.offset, skinWeight.array );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// see #3803\n\n\t\t\t\t\t\t\t\t\t\tif ( primitive.hasUV === false && primitives.uvsNeedsFix === true ) {\n\n\t\t\t\t\t\t\t\t\t\t\tconst count = ( position.array.length - prevLength ) / position.stride;\n\n\t\t\t\t\t\t\t\t\t\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\t// fill missing uv coordinates\n\n\t\t\t\t\t\t\t\t\t\t\t\tuv.array.push( 0, 0 );\n\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'NORMAL':\n\t\t\t\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ id ], input.offset, normal.array );\n\t\t\t\t\t\t\t\t\t\tnormal.stride = sources[ id ].stride;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'COLOR':\n\t\t\t\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ id ], input.offset, color.array );\n\t\t\t\t\t\t\t\t\t\tcolor.stride = sources[ id ].stride;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'TEXCOORD':\n\t\t\t\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ id ], input.offset, uv.array );\n\t\t\t\t\t\t\t\t\t\tuv.stride = sources[ id ].stride;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tcase 'TEXCOORD1':\n\t\t\t\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ id ], input.offset, uv1.array );\n\t\t\t\t\t\t\t\t\t\tuv.stride = sources[ id ].stride;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Semantic \"%s\" not handled in geometry build process.', key );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'NORMAL':\n\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ input.id ], input.offset, normal.array );\n\t\t\t\t\t\t\tnormal.stride = sources[ input.id ].stride;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'COLOR':\n\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ input.id ], input.offset, color.array, true );\n\t\t\t\t\t\t\tcolor.stride = sources[ input.id ].stride;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'TEXCOORD':\n\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ input.id ], input.offset, uv.array );\n\t\t\t\t\t\t\tuv.stride = sources[ input.id ].stride;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'TEXCOORD1':\n\t\t\t\t\t\t\tbuildGeometryData( primitive, sources[ input.id ], input.offset, uv1.array );\n\t\t\t\t\t\t\tuv1.stride = sources[ input.id ].stride;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// build geometry\n\n\t\t\tif ( position.array.length > 0 ) geometry.setAttribute( 'position', new Float32BufferAttribute( position.array, position.stride ) );\n\t\t\tif ( normal.array.length > 0 ) geometry.setAttribute( 'normal', new Float32BufferAttribute( normal.array, normal.stride ) );\n\t\t\tif ( color.array.length > 0 ) geometry.setAttribute( 'color', new Float32BufferAttribute( color.array, color.stride ) );\n\t\t\tif ( uv.array.length > 0 ) geometry.setAttribute( 'uv', new Float32BufferAttribute( uv.array, uv.stride ) );\n\t\t\tif ( uv1.array.length > 0 ) geometry.setAttribute( 'uv1', new Float32BufferAttribute( uv1.array, uv1.stride ) );\n\n\t\t\tif ( skinIndex.array.length > 0 ) geometry.setAttribute( 'skinIndex', new Float32BufferAttribute( skinIndex.array, skinIndex.stride ) );\n\t\t\tif ( skinWeight.array.length > 0 ) geometry.setAttribute( 'skinWeight', new Float32BufferAttribute( skinWeight.array, skinWeight.stride ) );\n\n\t\t\tbuild.data = geometry;\n\t\t\tbuild.type = primitives[ 0 ].type;\n\t\t\tbuild.materialKeys = materialKeys;\n\n\t\t\treturn build;\n\n\t\t}\n\n\t\tfunction buildGeometryData( primitive, source, offset, array, isColor = false ) {\n\n\t\t\tconst indices = primitive.p;\n\t\t\tconst stride = primitive.stride;\n\t\t\tconst vcount = primitive.vcount;\n\n\t\t\tfunction pushVector( i ) {\n\n\t\t\t\tlet index = indices[ i + offset ] * sourceStride;\n\t\t\t\tconst length = index + sourceStride;\n\n\t\t\t\tfor ( ; index < length; index ++ ) {\n\n\t\t\t\t\tarray.push( sourceArray[ index ] );\n\n\t\t\t\t}\n\n\t\t\t\tif ( isColor ) {\n\n\t\t\t\t\t// convert the vertex colors from srgb to linear if present\n\t\t\t\t\tconst startIndex = array.length - sourceStride - 1;\n\t\t\t\t\ttempColor.setRGB(\n\t\t\t\t\t\tarray[ startIndex + 0 ],\n\t\t\t\t\t\tarray[ startIndex + 1 ],\n\t\t\t\t\t\tarray[ startIndex + 2 ]\n\t\t\t\t\t).convertSRGBToLinear();\n\n\t\t\t\t\tarray[ startIndex + 0 ] = tempColor.r;\n\t\t\t\t\tarray[ startIndex + 1 ] = tempColor.g;\n\t\t\t\t\tarray[ startIndex + 2 ] = tempColor.b;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst sourceArray = source.array;\n\t\t\tconst sourceStride = source.stride;\n\n\t\t\tif ( primitive.vcount !== undefined ) {\n\n\t\t\t\tlet index = 0;\n\n\t\t\t\tfor ( let i = 0, l = vcount.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst count = vcount[ i ];\n\n\t\t\t\t\tif ( count === 4 ) {\n\n\t\t\t\t\t\tconst a = index + stride * 0;\n\t\t\t\t\t\tconst b = index + stride * 1;\n\t\t\t\t\t\tconst c = index + stride * 2;\n\t\t\t\t\t\tconst d = index + stride * 3;\n\n\t\t\t\t\t\tpushVector( a ); pushVector( b ); pushVector( d );\n\t\t\t\t\t\tpushVector( b ); pushVector( c ); pushVector( d );\n\n\t\t\t\t\t} else if ( count === 3 ) {\n\n\t\t\t\t\t\tconst a = index + stride * 0;\n\t\t\t\t\t\tconst b = index + stride * 1;\n\t\t\t\t\t\tconst c = index + stride * 2;\n\n\t\t\t\t\t\tpushVector( a ); pushVector( b ); pushVector( c );\n\n\t\t\t\t\t} else if ( count > 4 ) {\n\n\t\t\t\t\t\tfor ( let k = 1, kl = ( count - 2 ); k <= kl; k ++ ) {\n\n\t\t\t\t\t\t\tconst a = index + stride * 0;\n\t\t\t\t\t\t\tconst b = index + stride * k;\n\t\t\t\t\t\t\tconst c = index + stride * ( k + 1 );\n\n\t\t\t\t\t\t\tpushVector( a ); pushVector( b ); pushVector( c );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tindex += stride * count;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tfor ( let i = 0, l = indices.length; i < l; i += stride ) {\n\n\t\t\t\t\tpushVector( i );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getGeometry( id ) {\n\n\t\t\treturn getBuild( library.geometries[ id ], buildGeometry );\n\n\t\t}\n\n\t\t// kinematics\n\n\t\tfunction parseKinematicsModel( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'name' ) || '',\n\t\t\t\tjoints: {},\n\t\t\t\tlinks: []\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'technique_common':\n\t\t\t\t\t\tparseKinematicsTechniqueCommon( child, data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.kinematicsModels[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction buildKinematicsModel( data ) {\n\n\t\t\tif ( data.build !== undefined ) return data.build;\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction getKinematicsModel( id ) {\n\n\t\t\treturn getBuild( library.kinematicsModels[ id ], buildKinematicsModel );\n\n\t\t}\n\n\t\tfunction parseKinematicsTechniqueCommon( xml, data ) {\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'joint':\n\t\t\t\t\t\tdata.joints[ child.getAttribute( 'sid' ) ] = parseKinematicsJoint( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'link':\n\t\t\t\t\t\tdata.links.push( parseKinematicsLink( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parseKinematicsJoint( xml ) {\n\n\t\t\tlet data;\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'prismatic':\n\t\t\t\t\tcase 'revolute':\n\t\t\t\t\t\tdata = parseKinematicsJointParameter( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseKinematicsJointParameter( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tsid: xml.getAttribute( 'sid' ),\n\t\t\t\tname: xml.getAttribute( 'name' ) || '',\n\t\t\t\taxis: new Vector3(),\n\t\t\t\tlimits: {\n\t\t\t\t\tmin: 0,\n\t\t\t\t\tmax: 0\n\t\t\t\t},\n\t\t\t\ttype: xml.nodeName,\n\t\t\t\tstatic: false,\n\t\t\t\tzeroPosition: 0,\n\t\t\t\tmiddlePosition: 0\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'axis':\n\t\t\t\t\t\tconst array = parseFloats( child.textContent );\n\t\t\t\t\t\tdata.axis.fromArray( array );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'limits':\n\t\t\t\t\t\tconst max = child.getElementsByTagName( 'max' )[ 0 ];\n\t\t\t\t\t\tconst min = child.getElementsByTagName( 'min' )[ 0 ];\n\n\t\t\t\t\t\tdata.limits.max = parseFloat( max.textContent );\n\t\t\t\t\t\tdata.limits.min = parseFloat( min.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// if min is equal to or greater than max, consider the joint static\n\n\t\t\tif ( data.limits.min >= data.limits.max ) {\n\n\t\t\t\tdata.static = true;\n\n\t\t\t}\n\n\t\t\t// calculate middle position\n\n\t\t\tdata.middlePosition = ( data.limits.min + data.limits.max ) / 2.0;\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseKinematicsLink( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tsid: xml.getAttribute( 'sid' ),\n\t\t\t\tname: xml.getAttribute( 'name' ) || '',\n\t\t\t\tattachments: [],\n\t\t\t\ttransforms: []\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'attachment_full':\n\t\t\t\t\t\tdata.attachments.push( parseKinematicsAttachment( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'matrix':\n\t\t\t\t\tcase 'translate':\n\t\t\t\t\tcase 'rotate':\n\t\t\t\t\t\tdata.transforms.push( parseKinematicsTransform( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseKinematicsAttachment( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tjoint: xml.getAttribute( 'joint' ).split( '/' ).pop(),\n\t\t\t\ttransforms: [],\n\t\t\t\tlinks: []\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'link':\n\t\t\t\t\t\tdata.links.push( parseKinematicsLink( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'matrix':\n\t\t\t\t\tcase 'translate':\n\t\t\t\t\tcase 'rotate':\n\t\t\t\t\t\tdata.transforms.push( parseKinematicsTransform( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseKinematicsTransform( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\ttype: xml.nodeName\n\t\t\t};\n\n\t\t\tconst array = parseFloats( xml.textContent );\n\n\t\t\tswitch ( data.type ) {\n\n\t\t\t\tcase 'matrix':\n\t\t\t\t\tdata.obj = new Matrix4();\n\t\t\t\t\tdata.obj.fromArray( array ).transpose();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'translate':\n\t\t\t\t\tdata.obj = new Vector3();\n\t\t\t\t\tdata.obj.fromArray( array );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'rotate':\n\t\t\t\t\tdata.obj = new Vector3();\n\t\t\t\t\tdata.obj.fromArray( array );\n\t\t\t\t\tdata.angle = MathUtils.degToRad( array[ 3 ] );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\t// physics\n\n\t\tfunction parsePhysicsModel( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'name' ) || '',\n\t\t\t\trigidBodies: {}\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'rigid_body':\n\t\t\t\t\t\tdata.rigidBodies[ child.getAttribute( 'name' ) ] = {};\n\t\t\t\t\t\tparsePhysicsRigidBody( child, data.rigidBodies[ child.getAttribute( 'name' ) ] );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.physicsModels[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction parsePhysicsRigidBody( xml, data ) {\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'technique_common':\n\t\t\t\t\t\tparsePhysicsTechniqueCommon( child, data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction parsePhysicsTechniqueCommon( xml, data ) {\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'inertia':\n\t\t\t\t\t\tdata.inertia = parseFloats( child.textContent );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'mass':\n\t\t\t\t\t\tdata.mass = parseFloats( child.textContent )[ 0 ];\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// scene\n\n\t\tfunction parseKinematicsScene( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tbindJointAxis: []\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'bind_joint_axis':\n\t\t\t\t\t\tdata.bindJointAxis.push( parseKinematicsBindJointAxis( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tlibrary.kinematicsScenes[ parseId( xml.getAttribute( 'url' ) ) ] = data;\n\n\t\t}\n\n\t\tfunction parseKinematicsBindJointAxis( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\ttarget: xml.getAttribute( 'target' ).split( '/' ).pop()\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'axis':\n\t\t\t\t\t\tconst param = child.getElementsByTagName( 'param' )[ 0 ];\n\t\t\t\t\t\tdata.axis = param.textContent;\n\t\t\t\t\t\tconst tmpJointIndex = data.axis.split( 'inst_' ).pop().split( 'axis' )[ 0 ];\n\t\t\t\t\t\tdata.jointIndex = tmpJointIndex.substring( 0, tmpJointIndex.length - 1 );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction buildKinematicsScene( data ) {\n\n\t\t\tif ( data.build !== undefined ) return data.build;\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction getKinematicsScene( id ) {\n\n\t\t\treturn getBuild( library.kinematicsScenes[ id ], buildKinematicsScene );\n\n\t\t}\n\n\t\tfunction setupKinematics() {\n\n\t\t\tconst kinematicsModelId = Object.keys( library.kinematicsModels )[ 0 ];\n\t\t\tconst kinematicsSceneId = Object.keys( library.kinematicsScenes )[ 0 ];\n\t\t\tconst visualSceneId = Object.keys( library.visualScenes )[ 0 ];\n\n\t\t\tif ( kinematicsModelId === undefined || kinematicsSceneId === undefined ) return;\n\n\t\t\tconst kinematicsModel = getKinematicsModel( kinematicsModelId );\n\t\t\tconst kinematicsScene = getKinematicsScene( kinematicsSceneId );\n\t\t\tconst visualScene = getVisualScene( visualSceneId );\n\n\t\t\tconst bindJointAxis = kinematicsScene.bindJointAxis;\n\t\t\tconst jointMap = {};\n\n\t\t\tfor ( let i = 0, l = bindJointAxis.length; i < l; i ++ ) {\n\n\t\t\t\tconst axis = bindJointAxis[ i ];\n\n\t\t\t\t// the result of the following query is an element of type 'translate', 'rotate','scale' or 'matrix'\n\n\t\t\t\tconst targetElement = collada.querySelector( '[sid=\"' + axis.target + '\"]' );\n\n\t\t\t\tif ( targetElement ) {\n\n\t\t\t\t\t// get the parent of the transform element\n\n\t\t\t\t\tconst parentVisualElement = targetElement.parentElement;\n\n\t\t\t\t\t// connect the joint of the kinematics model with the element in the visual scene\n\n\t\t\t\t\tconnect( axis.jointIndex, parentVisualElement );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction connect( jointIndex, visualElement ) {\n\n\t\t\t\tconst visualElementName = visualElement.getAttribute( 'name' );\n\t\t\t\tconst joint = kinematicsModel.joints[ jointIndex ];\n\n\t\t\t\tvisualScene.traverse( function ( object ) {\n\n\t\t\t\t\tif ( object.name === visualElementName ) {\n\n\t\t\t\t\t\tjointMap[ jointIndex ] = {\n\t\t\t\t\t\t\tobject: object,\n\t\t\t\t\t\t\ttransforms: buildTransformList( visualElement ),\n\t\t\t\t\t\t\tjoint: joint,\n\t\t\t\t\t\t\tposition: joint.zeroPosition\n\t\t\t\t\t\t};\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tconst m0 = new Matrix4();\n\n\t\t\tkinematics = {\n\n\t\t\t\tjoints: kinematicsModel && kinematicsModel.joints,\n\n\t\t\t\tgetJointValue: function ( jointIndex ) {\n\n\t\t\t\t\tconst jointData = jointMap[ jointIndex ];\n\n\t\t\t\t\tif ( jointData ) {\n\n\t\t\t\t\t\treturn jointData.position;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' doesn\\'t exist.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\tsetJointValue: function ( jointIndex, value ) {\n\n\t\t\t\t\tconst jointData = jointMap[ jointIndex ];\n\n\t\t\t\t\tif ( jointData ) {\n\n\t\t\t\t\t\tconst joint = jointData.joint;\n\n\t\t\t\t\t\tif ( value > joint.limits.max || value < joint.limits.min ) {\n\n\t\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ').' );\n\n\t\t\t\t\t\t} else if ( joint.static ) {\n\n\t\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Joint ' + jointIndex + ' is static.' );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tconst object = jointData.object;\n\t\t\t\t\t\t\tconst axis = joint.axis;\n\t\t\t\t\t\t\tconst transforms = jointData.transforms;\n\n\t\t\t\t\t\t\tmatrix.identity();\n\n\t\t\t\t\t\t\t// each update, we have to apply all transforms in the correct order\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < transforms.length; i ++ ) {\n\n\t\t\t\t\t\t\t\tconst transform = transforms[ i ];\n\n\t\t\t\t\t\t\t\t// if there is a connection of the transform node with a joint, apply the joint value\n\n\t\t\t\t\t\t\t\tif ( transform.sid && transform.sid.indexOf( jointIndex ) !== - 1 ) {\n\n\t\t\t\t\t\t\t\t\tswitch ( joint.type ) {\n\n\t\t\t\t\t\t\t\t\t\tcase 'revolute':\n\t\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m0.makeRotationAxis( axis, MathUtils.degToRad( value ) ) );\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t\tcase 'prismatic':\n\t\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m0.makeTranslation( axis.x * value, axis.y * value, axis.z * value ) );\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Unknown joint type: ' + joint.type );\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tswitch ( transform.type ) {\n\n\t\t\t\t\t\t\t\t\t\tcase 'matrix':\n\t\t\t\t\t\t\t\t\t\t\tmatrix.multiply( transform.obj );\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t\tcase 'translate':\n\t\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m0.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) );\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t\tcase 'scale':\n\t\t\t\t\t\t\t\t\t\t\tmatrix.scale( transform.obj );\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t\tcase 'rotate':\n\t\t\t\t\t\t\t\t\t\t\tmatrix.multiply( m0.makeRotationAxis( transform.obj, transform.angle ) );\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tobject.matrix.copy( matrix );\n\t\t\t\t\t\t\tobject.matrix.decompose( object.position, object.quaternion, object.scale );\n\n\t\t\t\t\t\t\tjointMap[ jointIndex ].position = value;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.log( 'THREE.ColladaLoader: ' + jointIndex + ' does not exist.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}\n\n\t\tfunction buildTransformList( node ) {\n\n\t\t\tconst transforms = [];\n\n\t\t\tconst xml = collada.querySelector( '[id=\"' + node.id + '\"]' );\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tlet array, vector;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'matrix':\n\t\t\t\t\t\tarray = parseFloats( child.textContent );\n\t\t\t\t\t\tconst matrix = new Matrix4().fromArray( array ).transpose();\n\t\t\t\t\t\ttransforms.push( {\n\t\t\t\t\t\t\tsid: child.getAttribute( 'sid' ),\n\t\t\t\t\t\t\ttype: child.nodeName,\n\t\t\t\t\t\t\tobj: matrix\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'translate':\n\t\t\t\t\tcase 'scale':\n\t\t\t\t\t\tarray = parseFloats( child.textContent );\n\t\t\t\t\t\tvector = new Vector3().fromArray( array );\n\t\t\t\t\t\ttransforms.push( {\n\t\t\t\t\t\t\tsid: child.getAttribute( 'sid' ),\n\t\t\t\t\t\t\ttype: child.nodeName,\n\t\t\t\t\t\t\tobj: vector\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'rotate':\n\t\t\t\t\t\tarray = parseFloats( child.textContent );\n\t\t\t\t\t\tvector = new Vector3().fromArray( array );\n\t\t\t\t\t\tconst angle = MathUtils.degToRad( array[ 3 ] );\n\t\t\t\t\t\ttransforms.push( {\n\t\t\t\t\t\t\tsid: child.getAttribute( 'sid' ),\n\t\t\t\t\t\t\ttype: child.nodeName,\n\t\t\t\t\t\t\tobj: vector,\n\t\t\t\t\t\t\tangle: angle\n\t\t\t\t\t\t} );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn transforms;\n\n\t\t}\n\n\t\t// nodes\n\n\t\tfunction prepareNodes( xml ) {\n\n\t\t\tconst elements = xml.getElementsByTagName( 'node' );\n\n\t\t\t// ensure all node elements have id attributes\n\n\t\t\tfor ( let i = 0; i < elements.length; i ++ ) {\n\n\t\t\t\tconst element = elements[ i ];\n\n\t\t\t\tif ( element.hasAttribute( 'id' ) === false ) {\n\n\t\t\t\t\telement.setAttribute( 'id', generateId() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst matrix = new Matrix4();\n\t\tconst vector = new Vector3();\n\n\t\tfunction parseNode( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'name' ) || '',\n\t\t\t\ttype: xml.getAttribute( 'type' ),\n\t\t\t\tid: xml.getAttribute( 'id' ),\n\t\t\t\tsid: xml.getAttribute( 'sid' ),\n\t\t\t\tmatrix: new Matrix4(),\n\t\t\t\tnodes: [],\n\t\t\t\tinstanceCameras: [],\n\t\t\t\tinstanceControllers: [],\n\t\t\t\tinstanceLights: [],\n\t\t\t\tinstanceGeometries: [],\n\t\t\t\tinstanceNodes: [],\n\t\t\t\ttransforms: {}\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tif ( child.nodeType !== 1 ) continue;\n\n\t\t\t\tlet array;\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'node':\n\t\t\t\t\t\tdata.nodes.push( child.getAttribute( 'id' ) );\n\t\t\t\t\t\tparseNode( child );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'instance_camera':\n\t\t\t\t\t\tdata.instanceCameras.push( parseId( child.getAttribute( 'url' ) ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'instance_controller':\n\t\t\t\t\t\tdata.instanceControllers.push( parseNodeInstance( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'instance_light':\n\t\t\t\t\t\tdata.instanceLights.push( parseId( child.getAttribute( 'url' ) ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'instance_geometry':\n\t\t\t\t\t\tdata.instanceGeometries.push( parseNodeInstance( child ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'instance_node':\n\t\t\t\t\t\tdata.instanceNodes.push( parseId( child.getAttribute( 'url' ) ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'matrix':\n\t\t\t\t\t\tarray = parseFloats( child.textContent );\n\t\t\t\t\t\tdata.matrix.multiply( matrix.fromArray( array ).transpose() );\n\t\t\t\t\t\tdata.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'translate':\n\t\t\t\t\t\tarray = parseFloats( child.textContent );\n\t\t\t\t\t\tvector.fromArray( array );\n\t\t\t\t\t\tdata.matrix.multiply( matrix.makeTranslation( vector.x, vector.y, vector.z ) );\n\t\t\t\t\t\tdata.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'rotate':\n\t\t\t\t\t\tarray = parseFloats( child.textContent );\n\t\t\t\t\t\tconst angle = MathUtils.degToRad( array[ 3 ] );\n\t\t\t\t\t\tdata.matrix.multiply( matrix.makeRotationAxis( vector.fromArray( array ), angle ) );\n\t\t\t\t\t\tdata.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'scale':\n\t\t\t\t\t\tarray = parseFloats( child.textContent );\n\t\t\t\t\t\tdata.matrix.scale( vector.fromArray( array ) );\n\t\t\t\t\t\tdata.transforms[ child.getAttribute( 'sid' ) ] = child.nodeName;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'extra':\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tconsole.log( child );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( hasNode( data.id ) ) {\n\n\t\t\t\tconsole.warn( 'THREE.ColladaLoader: There is already a node with ID %s. Exclude current node from further processing.', data.id );\n\n\t\t\t} else {\n\n\t\t\t\tlibrary.nodes[ data.id ] = data;\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction parseNodeInstance( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tid: parseId( xml.getAttribute( 'url' ) ),\n\t\t\t\tmaterials: {},\n\t\t\t\tskeletons: []\n\t\t\t};\n\n\t\t\tfor ( let i = 0; i < xml.childNodes.length; i ++ ) {\n\n\t\t\t\tconst child = xml.childNodes[ i ];\n\n\t\t\t\tswitch ( child.nodeName ) {\n\n\t\t\t\t\tcase 'bind_material':\n\t\t\t\t\t\tconst instances = child.getElementsByTagName( 'instance_material' );\n\n\t\t\t\t\t\tfor ( let j = 0; j < instances.length; j ++ ) {\n\n\t\t\t\t\t\t\tconst instance = instances[ j ];\n\t\t\t\t\t\t\tconst symbol = instance.getAttribute( 'symbol' );\n\t\t\t\t\t\t\tconst target = instance.getAttribute( 'target' );\n\n\t\t\t\t\t\t\tdata.materials[ symbol ] = parseId( target );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'skeleton':\n\t\t\t\t\t\tdata.skeletons.push( parseId( child.textContent ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\tfunction buildSkeleton( skeletons, joints ) {\n\n\t\t\tconst boneData = [];\n\t\t\tconst sortedBoneData = [];\n\n\t\t\tlet i, j, data;\n\n\t\t\t// a skeleton can have multiple root bones. collada expresses this\n\t\t\t// situtation with multiple \"skeleton\" tags per controller instance\n\n\t\t\tfor ( i = 0; i < skeletons.length; i ++ ) {\n\n\t\t\t\tconst skeleton = skeletons[ i ];\n\n\t\t\t\tlet root;\n\n\t\t\t\tif ( hasNode( skeleton ) ) {\n\n\t\t\t\t\troot = getNode( skeleton );\n\t\t\t\t\tbuildBoneHierarchy( root, joints, boneData );\n\n\t\t\t\t} else if ( hasVisualScene( skeleton ) ) {\n\n\t\t\t\t\t// handle case where the skeleton refers to the visual scene (#13335)\n\n\t\t\t\t\tconst visualScene = library.visualScenes[ skeleton ];\n\t\t\t\t\tconst children = visualScene.children;\n\n\t\t\t\t\tfor ( let j = 0; j < children.length; j ++ ) {\n\n\t\t\t\t\t\tconst child = children[ j ];\n\n\t\t\t\t\t\tif ( child.type === 'JOINT' ) {\n\n\t\t\t\t\t\t\tconst root = getNode( child.id );\n\t\t\t\t\t\t\tbuildBoneHierarchy( root, joints, boneData );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( 'THREE.ColladaLoader: Unable to find root bone of skeleton with ID:', skeleton );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// sort bone data (the order is defined in the corresponding controller)\n\n\t\t\tfor ( i = 0; i < joints.length; i ++ ) {\n\n\t\t\t\tfor ( j = 0; j < boneData.length; j ++ ) {\n\n\t\t\t\t\tdata = boneData[ j ];\n\n\t\t\t\t\tif ( data.bone.name === joints[ i ].name ) {\n\n\t\t\t\t\t\tsortedBoneData[ i ] = data;\n\t\t\t\t\t\tdata.processed = true;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add unprocessed bone data at the end of the list\n\n\t\t\tfor ( i = 0; i < boneData.length; i ++ ) {\n\n\t\t\t\tdata = boneData[ i ];\n\n\t\t\t\tif ( data.processed === false ) {\n\n\t\t\t\t\tsortedBoneData.push( data );\n\t\t\t\t\tdata.processed = true;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// setup arrays for skeleton creation\n\n\t\t\tconst bones = [];\n\t\t\tconst boneInverses = [];\n\n\t\t\tfor ( i = 0; i < sortedBoneData.length; i ++ ) {\n\n\t\t\t\tdata = sortedBoneData[ i ];\n\n\t\t\t\tbones.push( data.bone );\n\t\t\t\tboneInverses.push( data.boneInverse );\n\n\t\t\t}\n\n\t\t\treturn new Skeleton( bones, boneInverses );\n\n\t\t}\n\n\t\tfunction buildBoneHierarchy( root, joints, boneData ) {\n\n\t\t\t// setup bone data from visual scene\n\n\t\t\troot.traverse( function ( object ) {\n\n\t\t\t\tif ( object.isBone === true ) {\n\n\t\t\t\t\tlet boneInverse;\n\n\t\t\t\t\t// retrieve the boneInverse from the controller data\n\n\t\t\t\t\tfor ( let i = 0; i < joints.length; i ++ ) {\n\n\t\t\t\t\t\tconst joint = joints[ i ];\n\n\t\t\t\t\t\tif ( joint.name === object.name ) {\n\n\t\t\t\t\t\t\tboneInverse = joint.boneInverse;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( boneInverse === undefined ) {\n\n\t\t\t\t\t\t// Unfortunately, there can be joints in the visual scene that are not part of the\n\t\t\t\t\t\t// corresponding controller. In this case, we have to create a dummy boneInverse matrix\n\t\t\t\t\t\t// for the respective bone. This bone won't affect any vertices, because there are no skin indices\n\t\t\t\t\t\t// and weights defined for it. But we still have to add the bone to the sorted bone list in order to\n\t\t\t\t\t\t// ensure a correct animation of the model.\n\n\t\t\t\t\t\tboneInverse = new Matrix4();\n\n\t\t\t\t\t}\n\n\t\t\t\t\tboneData.push( { bone: object, boneInverse: boneInverse, processed: false } );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t\tfunction buildNode( data ) {\n\n\t\t\tconst objects = [];\n\n\t\t\tconst matrix = data.matrix;\n\t\t\tconst nodes = data.nodes;\n\t\t\tconst type = data.type;\n\t\t\tconst instanceCameras = data.instanceCameras;\n\t\t\tconst instanceControllers = data.instanceControllers;\n\t\t\tconst instanceLights = data.instanceLights;\n\t\t\tconst instanceGeometries = data.instanceGeometries;\n\t\t\tconst instanceNodes = data.instanceNodes;\n\n\t\t\t// nodes\n\n\t\t\tfor ( let i = 0, l = nodes.length; i < l; i ++ ) {\n\n\t\t\t\tobjects.push( getNode( nodes[ i ] ) );\n\n\t\t\t}\n\n\t\t\t// instance cameras\n\n\t\t\tfor ( let i = 0, l = instanceCameras.length; i < l; i ++ ) {\n\n\t\t\t\tconst instanceCamera = getCamera( instanceCameras[ i ] );\n\n\t\t\t\tif ( instanceCamera !== null ) {\n\n\t\t\t\t\tobjects.push( instanceCamera.clone() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// instance controllers\n\n\t\t\tfor ( let i = 0, l = instanceControllers.length; i < l; i ++ ) {\n\n\t\t\t\tconst instance = instanceControllers[ i ];\n\t\t\t\tconst controller = getController( instance.id );\n\t\t\t\tconst geometries = getGeometry( controller.id );\n\t\t\t\tconst newObjects = buildObjects( geometries, instance.materials );\n\n\t\t\t\tconst skeletons = instance.skeletons;\n\t\t\t\tconst joints = controller.skin.joints;\n\n\t\t\t\tconst skeleton = buildSkeleton( skeletons, joints );\n\n\t\t\t\tfor ( let j = 0, jl = newObjects.length; j < jl; j ++ ) {\n\n\t\t\t\t\tconst object = newObjects[ j ];\n\n\t\t\t\t\tif ( object.isSkinnedMesh ) {\n\n\t\t\t\t\t\tobject.bind( skeleton, controller.skin.bindMatrix );\n\t\t\t\t\t\tobject.normalizeSkinWeights();\n\n\t\t\t\t\t}\n\n\t\t\t\t\tobjects.push( object );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// instance lights\n\n\t\t\tfor ( let i = 0, l = instanceLights.length; i < l; i ++ ) {\n\n\t\t\t\tconst instanceLight = getLight( instanceLights[ i ] );\n\n\t\t\t\tif ( instanceLight !== null ) {\n\n\t\t\t\t\tobjects.push( instanceLight.clone() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// instance geometries\n\n\t\t\tfor ( let i = 0, l = instanceGeometries.length; i < l; i ++ ) {\n\n\t\t\t\tconst instance = instanceGeometries[ i ];\n\n\t\t\t\t// a single geometry instance in collada can lead to multiple object3Ds.\n\t\t\t\t// this is the case when primitives are combined like triangles and lines\n\n\t\t\t\tconst geometries = getGeometry( instance.id );\n\t\t\t\tconst newObjects = buildObjects( geometries, instance.materials );\n\n\t\t\t\tfor ( let j = 0, jl = newObjects.length; j < jl; j ++ ) {\n\n\t\t\t\t\tobjects.push( newObjects[ j ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// instance nodes\n\n\t\t\tfor ( let i = 0, l = instanceNodes.length; i < l; i ++ ) {\n\n\t\t\t\tobjects.push( getNode( instanceNodes[ i ] ).clone() );\n\n\t\t\t}\n\n\t\t\tlet object;\n\n\t\t\tif ( nodes.length === 0 && objects.length === 1 ) {\n\n\t\t\t\tobject = objects[ 0 ];\n\n\t\t\t} else {\n\n\t\t\t\tobject = ( type === 'JOINT' ) ? new Bone() : new Group();\n\n\t\t\t\tfor ( let i = 0; i < objects.length; i ++ ) {\n\n\t\t\t\t\tobject.add( objects[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tobject.name = ( type === 'JOINT' ) ? data.sid : data.name;\n\t\t\tobject.matrix.copy( matrix );\n\t\t\tobject.matrix.decompose( object.position, object.quaternion, object.scale );\n\n\t\t\treturn object;\n\n\t\t}\n\n\t\tconst fallbackMaterial = new MeshBasicMaterial( {\n\t\t\tname: Loader.DEFAULT_MATERIAL_NAME,\n\t\t\tcolor: 0xff00ff\n\t\t} );\n\n\t\tfunction resolveMaterialBinding( keys, instanceMaterials ) {\n\n\t\t\tconst materials = [];\n\n\t\t\tfor ( let i = 0, l = keys.length; i < l; i ++ ) {\n\n\t\t\t\tconst id = instanceMaterials[ keys[ i ] ];\n\n\t\t\t\tif ( id === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Material with key %s not found. Apply fallback material.', keys[ i ] );\n\t\t\t\t\tmaterials.push( fallbackMaterial );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tmaterials.push( getMaterial( id ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn materials;\n\n\t\t}\n\n\t\tfunction buildObjects( geometries, instanceMaterials ) {\n\n\t\t\tconst objects = [];\n\n\t\t\tfor ( const type in geometries ) {\n\n\t\t\t\tconst geometry = geometries[ type ];\n\n\t\t\t\tconst materials = resolveMaterialBinding( geometry.materialKeys, instanceMaterials );\n\n\t\t\t\t// handle case if no materials are defined\n\n\t\t\t\tif ( materials.length === 0 ) {\n\n\t\t\t\t\tif ( type === 'lines' || type === 'linestrips' ) {\n\n\t\t\t\t\t\tmaterials.push( new LineBasicMaterial() );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tmaterials.push( new MeshPhongMaterial() );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// Collada allows to use phong and lambert materials with lines. Replacing these cases with LineBasicMaterial.\n\n\t\t\t\tif ( type === 'lines' || type === 'linestrips' ) {\n\n\t\t\t\t\tfor ( let i = 0, l = materials.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tconst material = materials[ i ];\n\n\t\t\t\t\t\tif ( material.isMeshPhongMaterial === true || material.isMeshLambertMaterial === true ) {\n\n\t\t\t\t\t\t\tconst lineMaterial = new LineBasicMaterial();\n\n\t\t\t\t\t\t\t// copy compatible properties\n\n\t\t\t\t\t\t\tlineMaterial.color.copy( material.color );\n\t\t\t\t\t\t\tlineMaterial.opacity = material.opacity;\n\t\t\t\t\t\t\tlineMaterial.transparent = material.transparent;\n\n\t\t\t\t\t\t\t// replace material\n\n\t\t\t\t\t\t\tmaterials[ i ] = lineMaterial;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// regard skinning\n\n\t\t\t\tconst skinning = ( geometry.data.attributes.skinIndex !== undefined );\n\n\t\t\t\t// choose between a single or multi materials (material array)\n\n\t\t\t\tconst material = ( materials.length === 1 ) ? materials[ 0 ] : materials;\n\n\t\t\t\t// now create a specific 3D object\n\n\t\t\t\tlet object;\n\n\t\t\t\tswitch ( type ) {\n\n\t\t\t\t\tcase 'lines':\n\t\t\t\t\t\tobject = new LineSegments( geometry.data, material );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'linestrips':\n\t\t\t\t\t\tobject = new Line( geometry.data, material );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'triangles':\n\t\t\t\t\tcase 'polylist':\n\t\t\t\t\t\tif ( skinning ) {\n\n\t\t\t\t\t\t\tobject = new SkinnedMesh( geometry.data, material );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tobject = new Mesh( geometry.data, material );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tobjects.push( object );\n\n\t\t\t}\n\n\t\t\treturn objects;\n\n\t\t}\n\n\t\tfunction hasNode( id ) {\n\n\t\t\treturn library.nodes[ id ] !== undefined;\n\n\t\t}\n\n\t\tfunction getNode( id ) {\n\n\t\t\treturn getBuild( library.nodes[ id ], buildNode );\n\n\t\t}\n\n\t\t// visual scenes\n\n\t\tfunction parseVisualScene( xml ) {\n\n\t\t\tconst data = {\n\t\t\t\tname: xml.getAttribute( 'name' ),\n\t\t\t\tchildren: []\n\t\t\t};\n\n\t\t\tprepareNodes( xml );\n\n\t\t\tconst elements = getElementsByTagName( xml, 'node' );\n\n\t\t\tfor ( let i = 0; i < elements.length; i ++ ) {\n\n\t\t\t\tdata.children.push( parseNode( elements[ i ] ) );\n\n\t\t\t}\n\n\t\t\tlibrary.visualScenes[ xml.getAttribute( 'id' ) ] = data;\n\n\t\t}\n\n\t\tfunction buildVisualScene( data ) {\n\n\t\t\tconst group = new Group();\n\t\t\tgroup.name = data.name;\n\n\t\t\tconst children = data.children;\n\n\t\t\tfor ( let i = 0; i < children.length; i ++ ) {\n\n\t\t\t\tconst child = children[ i ];\n\n\t\t\t\tgroup.add( getNode( child.id ) );\n\n\t\t\t}\n\n\t\t\treturn group;\n\n\t\t}\n\n\t\tfunction hasVisualScene( id ) {\n\n\t\t\treturn library.visualScenes[ id ] !== undefined;\n\n\t\t}\n\n\t\tfunction getVisualScene( id ) {\n\n\t\t\treturn getBuild( library.visualScenes[ id ], buildVisualScene );\n\n\t\t}\n\n\t\t// scenes\n\n\t\tfunction parseScene( xml ) {\n\n\t\t\tconst instance = getElementsByTagName( xml, 'instance_visual_scene' )[ 0 ];\n\t\t\treturn getVisualScene( parseId( instance.getAttribute( 'url' ) ) );\n\n\t\t}\n\n\t\tfunction setupAnimations() {\n\n\t\t\tconst clips = library.clips;\n\n\t\t\tif ( isEmpty( clips ) === true ) {\n\n\t\t\t\tif ( isEmpty( library.animations ) === false ) {\n\n\t\t\t\t\t// if there are animations but no clips, we create a default clip for playback\n\n\t\t\t\t\tconst tracks = [];\n\n\t\t\t\t\tfor ( const id in library.animations ) {\n\n\t\t\t\t\t\tconst animationTracks = getAnimation( id );\n\n\t\t\t\t\t\tfor ( let i = 0, l = animationTracks.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\ttracks.push( animationTracks[ i ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tanimations.push( new AnimationClip( 'default', - 1, tracks ) );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tfor ( const id in clips ) {\n\n\t\t\t\t\tanimations.push( getAnimationClip( id ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// convert the parser error element into text with each child elements text\n\t\t// separated by new lines.\n\n\t\tfunction parserErrorToText( parserError ) {\n\n\t\t\tlet result = '';\n\t\t\tconst stack = [ parserError ];\n\n\t\t\twhile ( stack.length ) {\n\n\t\t\t\tconst node = stack.shift();\n\n\t\t\t\tif ( node.nodeType === Node.TEXT_NODE ) {\n\n\t\t\t\t\tresult += node.textContent;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tresult += '\\n';\n\t\t\t\t\tstack.push.apply( stack, node.childNodes );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn result.trim();\n\n\t\t}\n\n\t\tif ( text.length === 0 ) {\n\n\t\t\treturn { scene: new Scene() };\n\n\t\t}\n\n\t\tconst xml = new DOMParser().parseFromString( text, 'application/xml' );\n\n\t\tconst collada = getElementsByTagName( xml, 'COLLADA' )[ 0 ];\n\n\t\tconst parserError = xml.getElementsByTagName( 'parsererror' )[ 0 ];\n\t\tif ( parserError !== undefined ) {\n\n\t\t\t// Chrome will return parser error with a div in it\n\n\t\t\tconst errorElement = getElementsByTagName( parserError, 'div' )[ 0 ];\n\t\t\tlet errorText;\n\n\t\t\tif ( errorElement ) {\n\n\t\t\t\terrorText = errorElement.textContent;\n\n\t\t\t} else {\n\n\t\t\t\terrorText = parserErrorToText( parserError );\n\n\t\t\t}\n\n\t\t\tconsole.error( 'THREE.ColladaLoader: Failed to parse collada file.\\n', errorText );\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// metadata\n\n\t\tconst version = collada.getAttribute( 'version' );\n\t\tconsole.debug( 'THREE.ColladaLoader: File version', version );\n\n\t\tconst asset = parseAsset( getElementsByTagName( collada, 'asset' )[ 0 ] );\n\t\tconst textureLoader = new TextureLoader( this.manager );\n\t\ttextureLoader.setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );\n\n\t\tlet tgaLoader;\n\n\t\tif ( TGALoader ) {\n\n\t\t\ttgaLoader = new TGALoader( this.manager );\n\t\t\ttgaLoader.setPath( this.resourcePath || path );\n\n\t\t}\n\n\t\t//\n\n\t\tconst tempColor = new Color();\n\t\tconst animations = [];\n\t\tlet kinematics = {};\n\t\tlet count = 0;\n\n\t\t//\n\n\t\tconst library = {\n\t\t\tanimations: {},\n\t\t\tclips: {},\n\t\t\tcontrollers: {},\n\t\t\timages: {},\n\t\t\teffects: {},\n\t\t\tmaterials: {},\n\t\t\tcameras: {},\n\t\t\tlights: {},\n\t\t\tgeometries: {},\n\t\t\tnodes: {},\n\t\t\tvisualScenes: {},\n\t\t\tkinematicsModels: {},\n\t\t\tphysicsModels: {},\n\t\t\tkinematicsScenes: {}\n\t\t};\n\n\t\tparseLibrary( collada, 'library_animations', 'animation', parseAnimation );\n\t\tparseLibrary( collada, 'library_animation_clips', 'animation_clip', parseAnimationClip );\n\t\tparseLibrary( collada, 'library_controllers', 'controller', parseController );\n\t\tparseLibrary( collada, 'library_images', 'image', parseImage );\n\t\tparseLibrary( collada, 'library_effects', 'effect', parseEffect );\n\t\tparseLibrary( collada, 'library_materials', 'material', parseMaterial );\n\t\tparseLibrary( collada, 'library_cameras', 'camera', parseCamera );\n\t\tparseLibrary( collada, 'library_lights', 'light', parseLight );\n\t\tparseLibrary( collada, 'library_geometries', 'geometry', parseGeometry );\n\t\tparseLibrary( collada, 'library_nodes', 'node', parseNode );\n\t\tparseLibrary( collada, 'library_visual_scenes', 'visual_scene', parseVisualScene );\n\t\tparseLibrary( collada, 'library_kinematics_models', 'kinematics_model', parseKinematicsModel );\n\t\tparseLibrary( collada, 'library_physics_models', 'physics_model', parsePhysicsModel );\n\t\tparseLibrary( collada, 'scene', 'instance_kinematics_scene', parseKinematicsScene );\n\n\t\tbuildLibrary( library.animations, buildAnimation );\n\t\tbuildLibrary( library.clips, buildAnimationClip );\n\t\tbuildLibrary( library.controllers, buildController );\n\t\tbuildLibrary( library.images, buildImage );\n\t\tbuildLibrary( library.effects, buildEffect );\n\t\tbuildLibrary( library.materials, buildMaterial );\n\t\tbuildLibrary( library.cameras, buildCamera );\n\t\tbuildLibrary( library.lights, buildLight );\n\t\tbuildLibrary( library.geometries, buildGeometry );\n\t\tbuildLibrary( library.visualScenes, buildVisualScene );\n\n\t\tsetupAnimations();\n\t\tsetupKinematics();\n\n\t\tconst scene = parseScene( getElementsByTagName( collada, 'scene' )[ 0 ] );\n\t\tscene.animations = animations;\n\n\t\tif ( asset.upAxis === 'Z_UP' ) {\n\n\t\t\tconsole.warn( 'THREE.ColladaLoader: You are loading an asset with a Z-UP coordinate system. The loader just rotates the asset to transform it into Y-UP. The vertex data are not converted, see #24289.' );\n\t\t\tscene.rotation.set( - Math.PI / 2, 0, 0 );\n\n\t\t}\n\n\t\tscene.scale.multiplyScalar( asset.unit );\n\n\t\treturn {\n\t\t\tget animations() {\n\n\t\t\t\tconsole.warn( 'THREE.ColladaLoader: Please access animations over scene.animations now.' );\n\t\t\t\treturn animations;\n\n\t\t\t},\n\t\t\tkinematics: kinematics,\n\t\t\tlibrary: library,\n\t\t\tscene: scene\n\t\t};\n\n\t}\n\n}\n\nexport { ColladaLoader };\n","import {\n\tAmbientLight,\n\tAnimationClip,\n\tBone,\n\tBufferGeometry,\n\tClampToEdgeWrapping,\n\tColor,\n\tDirectionalLight,\n\tEquirectangularReflectionMapping,\n\tEuler,\n\tFileLoader,\n\tFloat32BufferAttribute,\n\tGroup,\n\tLine,\n\tLineBasicMaterial,\n\tLoader,\n\tLoaderUtils,\n\tMathUtils,\n\tMatrix3,\n\tMatrix4,\n\tMesh,\n\tMeshLambertMaterial,\n\tMeshPhongMaterial,\n\tNumberKeyframeTrack,\n\tObject3D,\n\tOrthographicCamera,\n\tPerspectiveCamera,\n\tPointLight,\n\tPropertyBinding,\n\tQuaternion,\n\tQuaternionKeyframeTrack,\n\tRepeatWrapping,\n\tSkeleton,\n\tSkinnedMesh,\n\tSpotLight,\n\tTexture,\n\tTextureLoader,\n\tUint16BufferAttribute,\n\tVector2,\n\tVector3,\n\tVector4,\n\tVectorKeyframeTrack,\n\tSRGBColorSpace,\n\tShapeUtils\n} from 'three';\nimport * as fflate from '../libs/fflate.module.js';\nimport { NURBSCurve } from '../curves/NURBSCurve.js';\n\n/**\n * Loader loads FBX file and generates Group representing FBX scene.\n * Requires FBX file to be >= 7.0 and in ASCII or >= 6400 in Binary format\n * Versions lower than this may load but will probably have errors\n *\n * Needs Support:\n *  Morph normals / blend shape normals\n *\n * FBX format references:\n * \thttps://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_index_html (C++ SDK reference)\n *\n * Binary format specification:\n *\thttps://code.blender.org/2013/08/fbx-binary-file-format-specification/\n */\n\n\nlet fbxTree;\nlet connections;\nlet sceneGraph;\n\nclass FBXLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst path = ( scope.path === '' ) ? LoaderUtils.extractUrlBase( url ) : scope.path;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( scope.path );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.setRequestHeader( scope.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\n\t\tloader.load( url, function ( buffer ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( buffer, path ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( FBXBuffer, path ) {\n\n\t\tif ( isFbxFormatBinary( FBXBuffer ) ) {\n\n\t\t\tfbxTree = new BinaryParser().parse( FBXBuffer );\n\n\t\t} else {\n\n\t\t\tconst FBXText = convertArrayBufferToString( FBXBuffer );\n\n\t\t\tif ( ! isFbxFormatASCII( FBXText ) ) {\n\n\t\t\t\tthrow new Error( 'THREE.FBXLoader: Unknown format.' );\n\n\t\t\t}\n\n\t\t\tif ( getFbxVersion( FBXText ) < 7000 ) {\n\n\t\t\t\tthrow new Error( 'THREE.FBXLoader: FBX version not supported, FileVersion: ' + getFbxVersion( FBXText ) );\n\n\t\t\t}\n\n\t\t\tfbxTree = new TextParser().parse( FBXText );\n\n\t\t}\n\n\t\t// console.log( fbxTree );\n\n\t\tconst textureLoader = new TextureLoader( this.manager ).setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );\n\n\t\treturn new FBXTreeParser( textureLoader, this.manager ).parse( fbxTree );\n\n\t}\n\n}\n\n// Parse the FBXTree object returned by the BinaryParser or TextParser and return a Group\nclass FBXTreeParser {\n\n\tconstructor( textureLoader, manager ) {\n\n\t\tthis.textureLoader = textureLoader;\n\t\tthis.manager = manager;\n\n\t}\n\n\tparse() {\n\n\t\tconnections = this.parseConnections();\n\n\t\tconst images = this.parseImages();\n\t\tconst textures = this.parseTextures( images );\n\t\tconst materials = this.parseMaterials( textures );\n\t\tconst deformers = this.parseDeformers();\n\t\tconst geometryMap = new GeometryParser().parse( deformers );\n\n\t\tthis.parseScene( deformers, geometryMap, materials );\n\n\t\treturn sceneGraph;\n\n\t}\n\n\t// Parses FBXTree.Connections which holds parent-child connections between objects (e.g. material -> texture, model->geometry )\n\t// and details the connection type\n\tparseConnections() {\n\n\t\tconst connectionMap = new Map();\n\n\t\tif ( 'Connections' in fbxTree ) {\n\n\t\t\tconst rawConnections = fbxTree.Connections.connections;\n\n\t\t\trawConnections.forEach( function ( rawConnection ) {\n\n\t\t\t\tconst fromID = rawConnection[ 0 ];\n\t\t\t\tconst toID = rawConnection[ 1 ];\n\t\t\t\tconst relationship = rawConnection[ 2 ];\n\n\t\t\t\tif ( ! connectionMap.has( fromID ) ) {\n\n\t\t\t\t\tconnectionMap.set( fromID, {\n\t\t\t\t\t\tparents: [],\n\t\t\t\t\t\tchildren: []\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t\tconst parentRelationship = { ID: toID, relationship: relationship };\n\t\t\t\tconnectionMap.get( fromID ).parents.push( parentRelationship );\n\n\t\t\t\tif ( ! connectionMap.has( toID ) ) {\n\n\t\t\t\t\tconnectionMap.set( toID, {\n\t\t\t\t\t\tparents: [],\n\t\t\t\t\t\tchildren: []\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t\tconst childRelationship = { ID: fromID, relationship: relationship };\n\t\t\t\tconnectionMap.get( toID ).children.push( childRelationship );\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn connectionMap;\n\n\t}\n\n\t// Parse FBXTree.Objects.Video for embedded image data\n\t// These images are connected to textures in FBXTree.Objects.Textures\n\t// via FBXTree.Connections.\n\tparseImages() {\n\n\t\tconst images = {};\n\t\tconst blobs = {};\n\n\t\tif ( 'Video' in fbxTree.Objects ) {\n\n\t\t\tconst videoNodes = fbxTree.Objects.Video;\n\n\t\t\tfor ( const nodeID in videoNodes ) {\n\n\t\t\t\tconst videoNode = videoNodes[ nodeID ];\n\n\t\t\t\tconst id = parseInt( nodeID );\n\n\t\t\t\timages[ id ] = videoNode.RelativeFilename || videoNode.Filename;\n\n\t\t\t\t// raw image data is in videoNode.Content\n\t\t\t\tif ( 'Content' in videoNode ) {\n\n\t\t\t\t\tconst arrayBufferContent = ( videoNode.Content instanceof ArrayBuffer ) && ( videoNode.Content.byteLength > 0 );\n\t\t\t\t\tconst base64Content = ( typeof videoNode.Content === 'string' ) && ( videoNode.Content !== '' );\n\n\t\t\t\t\tif ( arrayBufferContent || base64Content ) {\n\n\t\t\t\t\t\tconst image = this.parseImage( videoNodes[ nodeID ] );\n\n\t\t\t\t\t\tblobs[ videoNode.RelativeFilename || videoNode.Filename ] = image;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( const id in images ) {\n\n\t\t\tconst filename = images[ id ];\n\n\t\t\tif ( blobs[ filename ] !== undefined ) images[ id ] = blobs[ filename ];\n\t\t\telse images[ id ] = images[ id ].split( '\\\\' ).pop();\n\n\t\t}\n\n\t\treturn images;\n\n\t}\n\n\t// Parse embedded image data in FBXTree.Video.Content\n\tparseImage( videoNode ) {\n\n\t\tconst content = videoNode.Content;\n\t\tconst fileName = videoNode.RelativeFilename || videoNode.Filename;\n\t\tconst extension = fileName.slice( fileName.lastIndexOf( '.' ) + 1 ).toLowerCase();\n\n\t\tlet type;\n\n\t\tswitch ( extension ) {\n\n\t\t\tcase 'bmp':\n\n\t\t\t\ttype = 'image/bmp';\n\t\t\t\tbreak;\n\n\t\t\tcase 'jpg':\n\t\t\tcase 'jpeg':\n\n\t\t\t\ttype = 'image/jpeg';\n\t\t\t\tbreak;\n\n\t\t\tcase 'png':\n\n\t\t\t\ttype = 'image/png';\n\t\t\t\tbreak;\n\n\t\t\tcase 'tif':\n\n\t\t\t\ttype = 'image/tiff';\n\t\t\t\tbreak;\n\n\t\t\tcase 'tga':\n\n\t\t\t\tif ( this.manager.getHandler( '.tga' ) === null ) {\n\n\t\t\t\t\tconsole.warn( 'FBXLoader: TGA loader not found, skipping ', fileName );\n\n\t\t\t\t}\n\n\t\t\t\ttype = 'image/tga';\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tconsole.warn( 'FBXLoader: Image type \"' + extension + '\" is not supported.' );\n\t\t\t\treturn;\n\n\t\t}\n\n\t\tif ( typeof content === 'string' ) { // ASCII format\n\n\t\t\treturn 'data:' + type + ';base64,' + content;\n\n\t\t} else { // Binary Format\n\n\t\t\tconst array = new Uint8Array( content );\n\t\t\treturn window.URL.createObjectURL( new Blob( [ array ], { type: type } ) );\n\n\t\t}\n\n\t}\n\n\t// Parse nodes in FBXTree.Objects.Texture\n\t// These contain details such as UV scaling, cropping, rotation etc and are connected\n\t// to images in FBXTree.Objects.Video\n\tparseTextures( images ) {\n\n\t\tconst textureMap = new Map();\n\n\t\tif ( 'Texture' in fbxTree.Objects ) {\n\n\t\t\tconst textureNodes = fbxTree.Objects.Texture;\n\t\t\tfor ( const nodeID in textureNodes ) {\n\n\t\t\t\tconst texture = this.parseTexture( textureNodes[ nodeID ], images );\n\t\t\t\ttextureMap.set( parseInt( nodeID ), texture );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn textureMap;\n\n\t}\n\n\t// Parse individual node in FBXTree.Objects.Texture\n\tparseTexture( textureNode, images ) {\n\n\t\tconst texture = this.loadTexture( textureNode, images );\n\n\t\ttexture.ID = textureNode.id;\n\n\t\ttexture.name = textureNode.attrName;\n\n\t\tconst wrapModeU = textureNode.WrapModeU;\n\t\tconst wrapModeV = textureNode.WrapModeV;\n\n\t\tconst valueU = wrapModeU !== undefined ? wrapModeU.value : 0;\n\t\tconst valueV = wrapModeV !== undefined ? wrapModeV.value : 0;\n\n\t\t// http://download.autodesk.com/us/fbx/SDKdocs/FBX_SDK_Help/files/fbxsdkref/class_k_fbx_texture.html#889640e63e2e681259ea81061b85143a\n\t\t// 0: repeat(default), 1: clamp\n\n\t\ttexture.wrapS = valueU === 0 ? RepeatWrapping : ClampToEdgeWrapping;\n\t\ttexture.wrapT = valueV === 0 ? RepeatWrapping : ClampToEdgeWrapping;\n\n\t\tif ( 'Scaling' in textureNode ) {\n\n\t\t\tconst values = textureNode.Scaling.value;\n\n\t\t\ttexture.repeat.x = values[ 0 ];\n\t\t\ttexture.repeat.y = values[ 1 ];\n\n\t\t}\n\n\t\tif ( 'Translation' in textureNode ) {\n\n\t\t\tconst values = textureNode.Translation.value;\n\n\t\t\ttexture.offset.x = values[ 0 ];\n\t\t\ttexture.offset.y = values[ 1 ];\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\t// load a texture specified as a blob or data URI, or via an external URL using TextureLoader\n\tloadTexture( textureNode, images ) {\n\n\t\tlet fileName;\n\n\t\tconst currentPath = this.textureLoader.path;\n\n\t\tconst children = connections.get( textureNode.id ).children;\n\n\t\tif ( children !== undefined && children.length > 0 && images[ children[ 0 ].ID ] !== undefined ) {\n\n\t\t\tfileName = images[ children[ 0 ].ID ];\n\n\t\t\tif ( fileName.indexOf( 'blob:' ) === 0 || fileName.indexOf( 'data:' ) === 0 ) {\n\n\t\t\t\tthis.textureLoader.setPath( undefined );\n\n\t\t\t}\n\n\t\t}\n\n\t\tlet texture;\n\n\t\tconst extension = textureNode.FileName.slice( - 3 ).toLowerCase();\n\n\t\tif ( extension === 'tga' ) {\n\n\t\t\tconst loader = this.manager.getHandler( '.tga' );\n\n\t\t\tif ( loader === null ) {\n\n\t\t\t\tconsole.warn( 'FBXLoader: TGA loader not found, creating placeholder texture for', textureNode.RelativeFilename );\n\t\t\t\ttexture = new Texture();\n\n\t\t\t} else {\n\n\t\t\t\tloader.setPath( this.textureLoader.path );\n\t\t\t\ttexture = loader.load( fileName );\n\n\t\t\t}\n\n\t\t} else if ( extension === 'dds' ) {\n\n\t\t\tconst loader = this.manager.getHandler( '.dds' );\n\n\t\t\tif ( loader === null ) {\n\n\t\t\t\tconsole.warn( 'FBXLoader: DDS loader not found, creating placeholder texture for', textureNode.RelativeFilename );\n\t\t\t\ttexture = new Texture();\n\n\t\t\t} else {\n\n\t\t\t\tloader.setPath( this.textureLoader.path );\n\t\t\t\ttexture = loader.load( fileName );\n\n\t\t\t}\n\n\t\t} else if ( extension === 'psd' ) {\n\n\t\t\tconsole.warn( 'FBXLoader: PSD textures are not supported, creating placeholder texture for', textureNode.RelativeFilename );\n\t\t\ttexture = new Texture();\n\n\t\t} else {\n\n\t\t\ttexture = this.textureLoader.load( fileName );\n\n\t\t}\n\n\t\tthis.textureLoader.setPath( currentPath );\n\n\t\treturn texture;\n\n\t}\n\n\t// Parse nodes in FBXTree.Objects.Material\n\tparseMaterials( textureMap ) {\n\n\t\tconst materialMap = new Map();\n\n\t\tif ( 'Material' in fbxTree.Objects ) {\n\n\t\t\tconst materialNodes = fbxTree.Objects.Material;\n\n\t\t\tfor ( const nodeID in materialNodes ) {\n\n\t\t\t\tconst material = this.parseMaterial( materialNodes[ nodeID ], textureMap );\n\n\t\t\t\tif ( material !== null ) materialMap.set( parseInt( nodeID ), material );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn materialMap;\n\n\t}\n\n\t// Parse single node in FBXTree.Objects.Material\n\t// Materials are connected to texture maps in FBXTree.Objects.Textures\n\t// FBX format currently only supports Lambert and Phong shading models\n\tparseMaterial( materialNode, textureMap ) {\n\n\t\tconst ID = materialNode.id;\n\t\tconst name = materialNode.attrName;\n\t\tlet type = materialNode.ShadingModel;\n\n\t\t// Case where FBX wraps shading model in property object.\n\t\tif ( typeof type === 'object' ) {\n\n\t\t\ttype = type.value;\n\n\t\t}\n\n\t\t// Ignore unused materials which don't have any connections.\n\t\tif ( ! connections.has( ID ) ) return null;\n\n\t\tconst parameters = this.parseParameters( materialNode, textureMap, ID );\n\n\t\tlet material;\n\n\t\tswitch ( type.toLowerCase() ) {\n\n\t\t\tcase 'phong':\n\t\t\t\tmaterial = new MeshPhongMaterial();\n\t\t\t\tbreak;\n\t\t\tcase 'lambert':\n\t\t\t\tmaterial = new MeshLambertMaterial();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tconsole.warn( 'THREE.FBXLoader: unknown material type \"%s\". Defaulting to MeshPhongMaterial.', type );\n\t\t\t\tmaterial = new MeshPhongMaterial();\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tmaterial.setValues( parameters );\n\t\tmaterial.name = name;\n\n\t\treturn material;\n\n\t}\n\n\t// Parse FBX material and return parameters suitable for a three.js material\n\t// Also parse the texture map and return any textures associated with the material\n\tparseParameters( materialNode, textureMap, ID ) {\n\n\t\tconst parameters = {};\n\n\t\tif ( materialNode.BumpFactor ) {\n\n\t\t\tparameters.bumpScale = materialNode.BumpFactor.value;\n\n\t\t}\n\n\t\tif ( materialNode.Diffuse ) {\n\n\t\t\tparameters.color = new Color().fromArray( materialNode.Diffuse.value ).convertSRGBToLinear();\n\n\t\t} else if ( materialNode.DiffuseColor && ( materialNode.DiffuseColor.type === 'Color' || materialNode.DiffuseColor.type === 'ColorRGB' ) ) {\n\n\t\t\t// The blender exporter exports diffuse here instead of in materialNode.Diffuse\n\t\t\tparameters.color = new Color().fromArray( materialNode.DiffuseColor.value ).convertSRGBToLinear();\n\n\t\t}\n\n\t\tif ( materialNode.DisplacementFactor ) {\n\n\t\t\tparameters.displacementScale = materialNode.DisplacementFactor.value;\n\n\t\t}\n\n\t\tif ( materialNode.Emissive ) {\n\n\t\t\tparameters.emissive = new Color().fromArray( materialNode.Emissive.value ).convertSRGBToLinear();\n\n\t\t} else if ( materialNode.EmissiveColor && ( materialNode.EmissiveColor.type === 'Color' || materialNode.EmissiveColor.type === 'ColorRGB' ) ) {\n\n\t\t\t// The blender exporter exports emissive color here instead of in materialNode.Emissive\n\t\t\tparameters.emissive = new Color().fromArray( materialNode.EmissiveColor.value ).convertSRGBToLinear();\n\n\t\t}\n\n\t\tif ( materialNode.EmissiveFactor ) {\n\n\t\t\tparameters.emissiveIntensity = parseFloat( materialNode.EmissiveFactor.value );\n\n\t\t}\n\n\t\tif ( materialNode.Opacity ) {\n\n\t\t\tparameters.opacity = parseFloat( materialNode.Opacity.value );\n\n\t\t}\n\n\t\tif ( parameters.opacity < 1.0 ) {\n\n\t\t\tparameters.transparent = true;\n\n\t\t}\n\n\t\tif ( materialNode.ReflectionFactor ) {\n\n\t\t\tparameters.reflectivity = materialNode.ReflectionFactor.value;\n\n\t\t}\n\n\t\tif ( materialNode.Shininess ) {\n\n\t\t\tparameters.shininess = materialNode.Shininess.value;\n\n\t\t}\n\n\t\tif ( materialNode.Specular ) {\n\n\t\t\tparameters.specular = new Color().fromArray( materialNode.Specular.value ).convertSRGBToLinear();\n\n\t\t} else if ( materialNode.SpecularColor && materialNode.SpecularColor.type === 'Color' ) {\n\n\t\t\t// The blender exporter exports specular color here instead of in materialNode.Specular\n\t\t\tparameters.specular = new Color().fromArray( materialNode.SpecularColor.value ).convertSRGBToLinear();\n\n\t\t}\n\n\t\tconst scope = this;\n\t\tconnections.get( ID ).children.forEach( function ( child ) {\n\n\t\t\tconst type = child.relationship;\n\n\t\t\tswitch ( type ) {\n\n\t\t\t\tcase 'Bump':\n\t\t\t\t\tparameters.bumpMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'Maya|TEX_ao_map':\n\t\t\t\t\tparameters.aoMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'DiffuseColor':\n\t\t\t\tcase 'Maya|TEX_color_map':\n\t\t\t\t\tparameters.map = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tif ( parameters.map !== undefined ) {\n\n\t\t\t\t\t\tparameters.map.colorSpace = SRGBColorSpace;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'DisplacementColor':\n\t\t\t\t\tparameters.displacementMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'EmissiveColor':\n\t\t\t\t\tparameters.emissiveMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tif ( parameters.emissiveMap !== undefined ) {\n\n\t\t\t\t\t\tparameters.emissiveMap.colorSpace = SRGBColorSpace;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'NormalMap':\n\t\t\t\tcase 'Maya|TEX_normal_map':\n\t\t\t\t\tparameters.normalMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'ReflectionColor':\n\t\t\t\t\tparameters.envMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tif ( parameters.envMap !== undefined ) {\n\n\t\t\t\t\t\tparameters.envMap.mapping = EquirectangularReflectionMapping;\n\t\t\t\t\t\tparameters.envMap.colorSpace = SRGBColorSpace;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SpecularColor':\n\t\t\t\t\tparameters.specularMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tif ( parameters.specularMap !== undefined ) {\n\n\t\t\t\t\t\tparameters.specularMap.colorSpace = SRGBColorSpace;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'TransparentColor':\n\t\t\t\tcase 'TransparencyFactor':\n\t\t\t\t\tparameters.alphaMap = scope.getTexture( textureMap, child.ID );\n\t\t\t\t\tparameters.transparent = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'AmbientColor':\n\t\t\t\tcase 'ShininessExponent': // AKA glossiness map\n\t\t\t\tcase 'SpecularFactor': // AKA specularLevel\n\t\t\t\tcase 'VectorDisplacementColor': // NOTE: Seems to be a copy of DisplacementColor\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.warn( 'THREE.FBXLoader: %s map is not supported in three.js, skipping texture.', type );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t} );\n\n\t\treturn parameters;\n\n\t}\n\n\t// get a texture from the textureMap for use by a material.\n\tgetTexture( textureMap, id ) {\n\n\t\t// if the texture is a layered texture, just use the first layer and issue a warning\n\t\tif ( 'LayeredTexture' in fbxTree.Objects && id in fbxTree.Objects.LayeredTexture ) {\n\n\t\t\tconsole.warn( 'THREE.FBXLoader: layered textures are not supported in three.js. Discarding all but first layer.' );\n\t\t\tid = connections.get( id ).children[ 0 ].ID;\n\n\t\t}\n\n\t\treturn textureMap.get( id );\n\n\t}\n\n\t// Parse nodes in FBXTree.Objects.Deformer\n\t// Deformer node can contain skinning or Vertex Cache animation data, however only skinning is supported here\n\t// Generates map of Skeleton-like objects for use later when generating and binding skeletons.\n\tparseDeformers() {\n\n\t\tconst skeletons = {};\n\t\tconst morphTargets = {};\n\n\t\tif ( 'Deformer' in fbxTree.Objects ) {\n\n\t\t\tconst DeformerNodes = fbxTree.Objects.Deformer;\n\n\t\t\tfor ( const nodeID in DeformerNodes ) {\n\n\t\t\t\tconst deformerNode = DeformerNodes[ nodeID ];\n\n\t\t\t\tconst relationships = connections.get( parseInt( nodeID ) );\n\n\t\t\t\tif ( deformerNode.attrType === 'Skin' ) {\n\n\t\t\t\t\tconst skeleton = this.parseSkeleton( relationships, DeformerNodes );\n\t\t\t\t\tskeleton.ID = nodeID;\n\n\t\t\t\t\tif ( relationships.parents.length > 1 ) console.warn( 'THREE.FBXLoader: skeleton attached to more than one geometry is not supported.' );\n\t\t\t\t\tskeleton.geometryID = relationships.parents[ 0 ].ID;\n\n\t\t\t\t\tskeletons[ nodeID ] = skeleton;\n\n\t\t\t\t} else if ( deformerNode.attrType === 'BlendShape' ) {\n\n\t\t\t\t\tconst morphTarget = {\n\t\t\t\t\t\tid: nodeID,\n\t\t\t\t\t};\n\n\t\t\t\t\tmorphTarget.rawTargets = this.parseMorphTargets( relationships, DeformerNodes );\n\t\t\t\t\tmorphTarget.id = nodeID;\n\n\t\t\t\t\tif ( relationships.parents.length > 1 ) console.warn( 'THREE.FBXLoader: morph target attached to more than one geometry is not supported.' );\n\n\t\t\t\t\tmorphTargets[ nodeID ] = morphTarget;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\n\t\t\tskeletons: skeletons,\n\t\t\tmorphTargets: morphTargets,\n\n\t\t};\n\n\t}\n\n\t// Parse single nodes in FBXTree.Objects.Deformer\n\t// The top level skeleton node has type 'Skin' and sub nodes have type 'Cluster'\n\t// Each skin node represents a skeleton and each cluster node represents a bone\n\tparseSkeleton( relationships, deformerNodes ) {\n\n\t\tconst rawBones = [];\n\n\t\trelationships.children.forEach( function ( child ) {\n\n\t\t\tconst boneNode = deformerNodes[ child.ID ];\n\n\t\t\tif ( boneNode.attrType !== 'Cluster' ) return;\n\n\t\t\tconst rawBone = {\n\n\t\t\t\tID: child.ID,\n\t\t\t\tindices: [],\n\t\t\t\tweights: [],\n\t\t\t\ttransformLink: new Matrix4().fromArray( boneNode.TransformLink.a ),\n\t\t\t\t// transform: new Matrix4().fromArray( boneNode.Transform.a ),\n\t\t\t\t// linkMode: boneNode.Mode,\n\n\t\t\t};\n\n\t\t\tif ( 'Indexes' in boneNode ) {\n\n\t\t\t\trawBone.indices = boneNode.Indexes.a;\n\t\t\t\trawBone.weights = boneNode.Weights.a;\n\n\t\t\t}\n\n\t\t\trawBones.push( rawBone );\n\n\t\t} );\n\n\t\treturn {\n\n\t\t\trawBones: rawBones,\n\t\t\tbones: []\n\n\t\t};\n\n\t}\n\n\t// The top level morph deformer node has type \"BlendShape\" and sub nodes have type \"BlendShapeChannel\"\n\tparseMorphTargets( relationships, deformerNodes ) {\n\n\t\tconst rawMorphTargets = [];\n\n\t\tfor ( let i = 0; i < relationships.children.length; i ++ ) {\n\n\t\t\tconst child = relationships.children[ i ];\n\n\t\t\tconst morphTargetNode = deformerNodes[ child.ID ];\n\n\t\t\tconst rawMorphTarget = {\n\n\t\t\t\tname: morphTargetNode.attrName,\n\t\t\t\tinitialWeight: morphTargetNode.DeformPercent,\n\t\t\t\tid: morphTargetNode.id,\n\t\t\t\tfullWeights: morphTargetNode.FullWeights.a\n\n\t\t\t};\n\n\t\t\tif ( morphTargetNode.attrType !== 'BlendShapeChannel' ) return;\n\n\t\t\trawMorphTarget.geoID = connections.get( parseInt( child.ID ) ).children.filter( function ( child ) {\n\n\t\t\t\treturn child.relationship === undefined;\n\n\t\t\t} )[ 0 ].ID;\n\n\t\t\trawMorphTargets.push( rawMorphTarget );\n\n\t\t}\n\n\t\treturn rawMorphTargets;\n\n\t}\n\n\t// create the main Group() to be returned by the loader\n\tparseScene( deformers, geometryMap, materialMap ) {\n\n\t\tsceneGraph = new Group();\n\n\t\tconst modelMap = this.parseModels( deformers.skeletons, geometryMap, materialMap );\n\n\t\tconst modelNodes = fbxTree.Objects.Model;\n\n\t\tconst scope = this;\n\t\tmodelMap.forEach( function ( model ) {\n\n\t\t\tconst modelNode = modelNodes[ model.ID ];\n\t\t\tscope.setLookAtProperties( model, modelNode );\n\n\t\t\tconst parentConnections = connections.get( model.ID ).parents;\n\n\t\t\tparentConnections.forEach( function ( connection ) {\n\n\t\t\t\tconst parent = modelMap.get( connection.ID );\n\t\t\t\tif ( parent !== undefined ) parent.add( model );\n\n\t\t\t} );\n\n\t\t\tif ( model.parent === null ) {\n\n\t\t\t\tsceneGraph.add( model );\n\n\t\t\t}\n\n\n\t\t} );\n\n\t\tthis.bindSkeleton( deformers.skeletons, geometryMap, modelMap );\n\n\t\tthis.addGlobalSceneSettings();\n\n\t\tsceneGraph.traverse( function ( node ) {\n\n\t\t\tif ( node.userData.transformData ) {\n\n\t\t\t\tif ( node.parent ) {\n\n\t\t\t\t\tnode.userData.transformData.parentMatrix = node.parent.matrix;\n\t\t\t\t\tnode.userData.transformData.parentMatrixWorld = node.parent.matrixWorld;\n\n\t\t\t\t}\n\n\t\t\t\tconst transform = generateTransform( node.userData.transformData );\n\n\t\t\t\tnode.applyMatrix4( transform );\n\t\t\t\tnode.updateWorldMatrix();\n\n\t\t\t}\n\n\t\t} );\n\n\t\tconst animations = new AnimationParser().parse();\n\n\t\t// if all the models where already combined in a single group, just return that\n\t\tif ( sceneGraph.children.length === 1 && sceneGraph.children[ 0 ].isGroup ) {\n\n\t\t\tsceneGraph.children[ 0 ].animations = animations;\n\t\t\tsceneGraph = sceneGraph.children[ 0 ];\n\n\t\t}\n\n\t\tsceneGraph.animations = animations;\n\n\t}\n\n\t// parse nodes in FBXTree.Objects.Model\n\tparseModels( skeletons, geometryMap, materialMap ) {\n\n\t\tconst modelMap = new Map();\n\t\tconst modelNodes = fbxTree.Objects.Model;\n\n\t\tfor ( const nodeID in modelNodes ) {\n\n\t\t\tconst id = parseInt( nodeID );\n\t\t\tconst node = modelNodes[ nodeID ];\n\t\t\tconst relationships = connections.get( id );\n\n\t\t\tlet model = this.buildSkeleton( relationships, skeletons, id, node.attrName );\n\n\t\t\tif ( ! model ) {\n\n\t\t\t\tswitch ( node.attrType ) {\n\n\t\t\t\t\tcase 'Camera':\n\t\t\t\t\t\tmodel = this.createCamera( relationships );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'Light':\n\t\t\t\t\t\tmodel = this.createLight( relationships );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'Mesh':\n\t\t\t\t\t\tmodel = this.createMesh( relationships, geometryMap, materialMap );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'NurbsCurve':\n\t\t\t\t\t\tmodel = this.createCurve( relationships, geometryMap );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'LimbNode':\n\t\t\t\t\tcase 'Root':\n\t\t\t\t\t\tmodel = new Bone();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'Null':\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tmodel = new Group();\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tmodel.name = node.attrName ? PropertyBinding.sanitizeNodeName( node.attrName ) : '';\n\t\t\t\tmodel.userData.originalName = node.attrName;\n\n\t\t\t\tmodel.ID = id;\n\n\t\t\t}\n\n\t\t\tthis.getTransformData( model, node );\n\t\t\tmodelMap.set( id, model );\n\n\t\t}\n\n\t\treturn modelMap;\n\n\t}\n\n\tbuildSkeleton( relationships, skeletons, id, name ) {\n\n\t\tlet bone = null;\n\n\t\trelationships.parents.forEach( function ( parent ) {\n\n\t\t\tfor ( const ID in skeletons ) {\n\n\t\t\t\tconst skeleton = skeletons[ ID ];\n\n\t\t\t\tskeleton.rawBones.forEach( function ( rawBone, i ) {\n\n\t\t\t\t\tif ( rawBone.ID === parent.ID ) {\n\n\t\t\t\t\t\tconst subBone = bone;\n\t\t\t\t\t\tbone = new Bone();\n\n\t\t\t\t\t\tbone.matrixWorld.copy( rawBone.transformLink );\n\n\t\t\t\t\t\t// set name and id here - otherwise in cases where \"subBone\" is created it will not have a name / id\n\n\t\t\t\t\t\tbone.name = name ? PropertyBinding.sanitizeNodeName( name ) : '';\n\t\t\t\t\t\tbone.userData.originalName = name;\n\t\t\t\t\t\tbone.ID = id;\n\n\t\t\t\t\t\tskeleton.bones[ i ] = bone;\n\n\t\t\t\t\t\t// In cases where a bone is shared between multiple meshes\n\t\t\t\t\t\t// duplicate the bone here and and it as a child of the first bone\n\t\t\t\t\t\tif ( subBone !== null ) {\n\n\t\t\t\t\t\t\tbone.add( subBone );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t} );\n\n\t\treturn bone;\n\n\t}\n\n\t// create a PerspectiveCamera or OrthographicCamera\n\tcreateCamera( relationships ) {\n\n\t\tlet model;\n\t\tlet cameraAttribute;\n\n\t\trelationships.children.forEach( function ( child ) {\n\n\t\t\tconst attr = fbxTree.Objects.NodeAttribute[ child.ID ];\n\n\t\t\tif ( attr !== undefined ) {\n\n\t\t\t\tcameraAttribute = attr;\n\n\t\t\t}\n\n\t\t} );\n\n\t\tif ( cameraAttribute === undefined ) {\n\n\t\t\tmodel = new Object3D();\n\n\t\t} else {\n\n\t\t\tlet type = 0;\n\t\t\tif ( cameraAttribute.CameraProjectionType !== undefined && cameraAttribute.CameraProjectionType.value === 1 ) {\n\n\t\t\t\ttype = 1;\n\n\t\t\t}\n\n\t\t\tlet nearClippingPlane = 1;\n\t\t\tif ( cameraAttribute.NearPlane !== undefined ) {\n\n\t\t\t\tnearClippingPlane = cameraAttribute.NearPlane.value / 1000;\n\n\t\t\t}\n\n\t\t\tlet farClippingPlane = 1000;\n\t\t\tif ( cameraAttribute.FarPlane !== undefined ) {\n\n\t\t\t\tfarClippingPlane = cameraAttribute.FarPlane.value / 1000;\n\n\t\t\t}\n\n\n\t\t\tlet width = window.innerWidth;\n\t\t\tlet height = window.innerHeight;\n\n\t\t\tif ( cameraAttribute.AspectWidth !== undefined && cameraAttribute.AspectHeight !== undefined ) {\n\n\t\t\t\twidth = cameraAttribute.AspectWidth.value;\n\t\t\t\theight = cameraAttribute.AspectHeight.value;\n\n\t\t\t}\n\n\t\t\tconst aspect = width / height;\n\n\t\t\tlet fov = 45;\n\t\t\tif ( cameraAttribute.FieldOfView !== undefined ) {\n\n\t\t\t\tfov = cameraAttribute.FieldOfView.value;\n\n\t\t\t}\n\n\t\t\tconst focalLength = cameraAttribute.FocalLength ? cameraAttribute.FocalLength.value : null;\n\n\t\t\tswitch ( type ) {\n\n\t\t\t\tcase 0: // Perspective\n\t\t\t\t\tmodel = new PerspectiveCamera( fov, aspect, nearClippingPlane, farClippingPlane );\n\t\t\t\t\tif ( focalLength !== null ) model.setFocalLength( focalLength );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1: // Orthographic\n\t\t\t\t\tmodel = new OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.warn( 'THREE.FBXLoader: Unknown camera type ' + type + '.' );\n\t\t\t\t\tmodel = new Object3D();\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn model;\n\n\t}\n\n\t// Create a DirectionalLight, PointLight or SpotLight\n\tcreateLight( relationships ) {\n\n\t\tlet model;\n\t\tlet lightAttribute;\n\n\t\trelationships.children.forEach( function ( child ) {\n\n\t\t\tconst attr = fbxTree.Objects.NodeAttribute[ child.ID ];\n\n\t\t\tif ( attr !== undefined ) {\n\n\t\t\t\tlightAttribute = attr;\n\n\t\t\t}\n\n\t\t} );\n\n\t\tif ( lightAttribute === undefined ) {\n\n\t\t\tmodel = new Object3D();\n\n\t\t} else {\n\n\t\t\tlet type;\n\n\t\t\t// LightType can be undefined for Point lights\n\t\t\tif ( lightAttribute.LightType === undefined ) {\n\n\t\t\t\ttype = 0;\n\n\t\t\t} else {\n\n\t\t\t\ttype = lightAttribute.LightType.value;\n\n\t\t\t}\n\n\t\t\tlet color = 0xffffff;\n\n\t\t\tif ( lightAttribute.Color !== undefined ) {\n\n\t\t\t\tcolor = new Color().fromArray( lightAttribute.Color.value ).convertSRGBToLinear();\n\n\t\t\t}\n\n\t\t\tlet intensity = ( lightAttribute.Intensity === undefined ) ? 1 : lightAttribute.Intensity.value / 100;\n\n\t\t\t// light disabled\n\t\t\tif ( lightAttribute.CastLightOnObject !== undefined && lightAttribute.CastLightOnObject.value === 0 ) {\n\n\t\t\t\tintensity = 0;\n\n\t\t\t}\n\n\t\t\tlet distance = 0;\n\t\t\tif ( lightAttribute.FarAttenuationEnd !== undefined ) {\n\n\t\t\t\tif ( lightAttribute.EnableFarAttenuation !== undefined && lightAttribute.EnableFarAttenuation.value === 0 ) {\n\n\t\t\t\t\tdistance = 0;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdistance = lightAttribute.FarAttenuationEnd.value;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// TODO: could this be calculated linearly from FarAttenuationStart to FarAttenuationEnd?\n\t\t\tconst decay = 1;\n\n\t\t\tswitch ( type ) {\n\n\t\t\t\tcase 0: // Point\n\t\t\t\t\tmodel = new PointLight( color, intensity, distance, decay );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1: // Directional\n\t\t\t\t\tmodel = new DirectionalLight( color, intensity );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2: // Spot\n\t\t\t\t\tlet angle = Math.PI / 3;\n\n\t\t\t\t\tif ( lightAttribute.InnerAngle !== undefined ) {\n\n\t\t\t\t\t\tangle = MathUtils.degToRad( lightAttribute.InnerAngle.value );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet penumbra = 0;\n\t\t\t\t\tif ( lightAttribute.OuterAngle !== undefined ) {\n\n\t\t\t\t\t\t// TODO: this is not correct - FBX calculates outer and inner angle in degrees\n\t\t\t\t\t\t// with OuterAngle > InnerAngle && OuterAngle <= Math.PI\n\t\t\t\t\t\t// while three.js uses a penumbra between (0, 1) to attenuate the inner angle\n\t\t\t\t\t\tpenumbra = MathUtils.degToRad( lightAttribute.OuterAngle.value );\n\t\t\t\t\t\tpenumbra = Math.max( penumbra, 1 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tmodel = new SpotLight( color, intensity, distance, angle, penumbra, decay );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.warn( 'THREE.FBXLoader: Unknown light type ' + lightAttribute.LightType.value + ', defaulting to a PointLight.' );\n\t\t\t\t\tmodel = new PointLight( color, intensity );\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( lightAttribute.CastShadows !== undefined && lightAttribute.CastShadows.value === 1 ) {\n\n\t\t\t\tmodel.castShadow = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn model;\n\n\t}\n\n\tcreateMesh( relationships, geometryMap, materialMap ) {\n\n\t\tlet model;\n\t\tlet geometry = null;\n\t\tlet material = null;\n\t\tconst materials = [];\n\n\t\t// get geometry and materials(s) from connections\n\t\trelationships.children.forEach( function ( child ) {\n\n\t\t\tif ( geometryMap.has( child.ID ) ) {\n\n\t\t\t\tgeometry = geometryMap.get( child.ID );\n\n\t\t\t}\n\n\t\t\tif ( materialMap.has( child.ID ) ) {\n\n\t\t\t\tmaterials.push( materialMap.get( child.ID ) );\n\n\t\t\t}\n\n\t\t} );\n\n\t\tif ( materials.length > 1 ) {\n\n\t\t\tmaterial = materials;\n\n\t\t} else if ( materials.length > 0 ) {\n\n\t\t\tmaterial = materials[ 0 ];\n\n\t\t} else {\n\n\t\t\tmaterial = new MeshPhongMaterial( {\n\t\t\t\tname: Loader.DEFAULT_MATERIAL_NAME,\n\t\t\t\tcolor: 0xcccccc\n\t\t\t} );\n\t\t\tmaterials.push( material );\n\n\t\t}\n\n\t\tif ( 'color' in geometry.attributes ) {\n\n\t\t\tmaterials.forEach( function ( material ) {\n\n\t\t\t\tmaterial.vertexColors = true;\n\n\t\t\t} );\n\n\t\t}\n\n\t\tif ( geometry.FBX_Deformer ) {\n\n\t\t\tmodel = new SkinnedMesh( geometry, material );\n\t\t\tmodel.normalizeSkinWeights();\n\n\t\t} else {\n\n\t\t\tmodel = new Mesh( geometry, material );\n\n\t\t}\n\n\t\treturn model;\n\n\t}\n\n\tcreateCurve( relationships, geometryMap ) {\n\n\t\tconst geometry = relationships.children.reduce( function ( geo, child ) {\n\n\t\t\tif ( geometryMap.has( child.ID ) ) geo = geometryMap.get( child.ID );\n\n\t\t\treturn geo;\n\n\t\t}, null );\n\n\t\t// FBX does not list materials for Nurbs lines, so we'll just put our own in here.\n\t\tconst material = new LineBasicMaterial( {\n\t\t\tname: Loader.DEFAULT_MATERIAL_NAME,\n\t\t\tcolor: 0x3300ff,\n\t\t\tlinewidth: 1\n\t\t} );\n\t\treturn new Line( geometry, material );\n\n\t}\n\n\t// parse the model node for transform data\n\tgetTransformData( model, modelNode ) {\n\n\t\tconst transformData = {};\n\n\t\tif ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );\n\n\t\tif ( 'RotationOrder' in modelNode ) transformData.eulerOrder = getEulerOrder( modelNode.RotationOrder.value );\n\t\telse transformData.eulerOrder = 'ZYX';\n\n\t\tif ( 'Lcl_Translation' in modelNode ) transformData.translation = modelNode.Lcl_Translation.value;\n\n\t\tif ( 'PreRotation' in modelNode ) transformData.preRotation = modelNode.PreRotation.value;\n\t\tif ( 'Lcl_Rotation' in modelNode ) transformData.rotation = modelNode.Lcl_Rotation.value;\n\t\tif ( 'PostRotation' in modelNode ) transformData.postRotation = modelNode.PostRotation.value;\n\n\t\tif ( 'Lcl_Scaling' in modelNode ) transformData.scale = modelNode.Lcl_Scaling.value;\n\n\t\tif ( 'ScalingOffset' in modelNode ) transformData.scalingOffset = modelNode.ScalingOffset.value;\n\t\tif ( 'ScalingPivot' in modelNode ) transformData.scalingPivot = modelNode.ScalingPivot.value;\n\n\t\tif ( 'RotationOffset' in modelNode ) transformData.rotationOffset = modelNode.RotationOffset.value;\n\t\tif ( 'RotationPivot' in modelNode ) transformData.rotationPivot = modelNode.RotationPivot.value;\n\n\t\tmodel.userData.transformData = transformData;\n\n\t}\n\n\tsetLookAtProperties( model, modelNode ) {\n\n\t\tif ( 'LookAtProperty' in modelNode ) {\n\n\t\t\tconst children = connections.get( model.ID ).children;\n\n\t\t\tchildren.forEach( function ( child ) {\n\n\t\t\t\tif ( child.relationship === 'LookAtProperty' ) {\n\n\t\t\t\t\tconst lookAtTarget = fbxTree.Objects.Model[ child.ID ];\n\n\t\t\t\t\tif ( 'Lcl_Translation' in lookAtTarget ) {\n\n\t\t\t\t\t\tconst pos = lookAtTarget.Lcl_Translation.value;\n\n\t\t\t\t\t\t// DirectionalLight, SpotLight\n\t\t\t\t\t\tif ( model.target !== undefined ) {\n\n\t\t\t\t\t\t\tmodel.target.position.fromArray( pos );\n\t\t\t\t\t\t\tsceneGraph.add( model.target );\n\n\t\t\t\t\t\t} else { // Cameras and other Object3Ds\n\n\t\t\t\t\t\t\tmodel.lookAt( new Vector3().fromArray( pos ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t}\n\n\tbindSkeleton( skeletons, geometryMap, modelMap ) {\n\n\t\tconst bindMatrices = this.parsePoseNodes();\n\n\t\tfor ( const ID in skeletons ) {\n\n\t\t\tconst skeleton = skeletons[ ID ];\n\n\t\t\tconst parents = connections.get( parseInt( skeleton.ID ) ).parents;\n\n\t\t\tparents.forEach( function ( parent ) {\n\n\t\t\t\tif ( geometryMap.has( parent.ID ) ) {\n\n\t\t\t\t\tconst geoID = parent.ID;\n\t\t\t\t\tconst geoRelationships = connections.get( geoID );\n\n\t\t\t\t\tgeoRelationships.parents.forEach( function ( geoConnParent ) {\n\n\t\t\t\t\t\tif ( modelMap.has( geoConnParent.ID ) ) {\n\n\t\t\t\t\t\t\tconst model = modelMap.get( geoConnParent.ID );\n\n\t\t\t\t\t\t\tmodel.bind( new Skeleton( skeleton.bones ), bindMatrices[ geoConnParent.ID ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t}\n\n\tparsePoseNodes() {\n\n\t\tconst bindMatrices = {};\n\n\t\tif ( 'Pose' in fbxTree.Objects ) {\n\n\t\t\tconst BindPoseNode = fbxTree.Objects.Pose;\n\n\t\t\tfor ( const nodeID in BindPoseNode ) {\n\n\t\t\t\tif ( BindPoseNode[ nodeID ].attrType === 'BindPose' && BindPoseNode[ nodeID ].NbPoseNodes > 0 ) {\n\n\t\t\t\t\tconst poseNodes = BindPoseNode[ nodeID ].PoseNode;\n\n\t\t\t\t\tif ( Array.isArray( poseNodes ) ) {\n\n\t\t\t\t\t\tposeNodes.forEach( function ( poseNode ) {\n\n\t\t\t\t\t\t\tbindMatrices[ poseNode.Node ] = new Matrix4().fromArray( poseNode.Matrix.a );\n\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tbindMatrices[ poseNodes.Node ] = new Matrix4().fromArray( poseNodes.Matrix.a );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn bindMatrices;\n\n\t}\n\n\taddGlobalSceneSettings() {\n\n\t\tif ( 'GlobalSettings' in fbxTree ) {\n\n\t\t\tif ( 'AmbientColor' in fbxTree.GlobalSettings ) {\n\n\t\t\t\t// Parse ambient color - if it's not set to black (default), create an ambient light\n\n\t\t\t\tconst ambientColor = fbxTree.GlobalSettings.AmbientColor.value;\n\t\t\t\tconst r = ambientColor[ 0 ];\n\t\t\t\tconst g = ambientColor[ 1 ];\n\t\t\t\tconst b = ambientColor[ 2 ];\n\n\t\t\t\tif ( r !== 0 || g !== 0 || b !== 0 ) {\n\n\t\t\t\t\tconst color = new Color( r, g, b ).convertSRGBToLinear();\n\t\t\t\t\tsceneGraph.add( new AmbientLight( color, 1 ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( 'UnitScaleFactor' in fbxTree.GlobalSettings ) {\n\n\t\t\t\tsceneGraph.userData.unitScaleFactor = fbxTree.GlobalSettings.UnitScaleFactor.value;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\n// parse Geometry data from FBXTree and return map of BufferGeometries\nclass GeometryParser {\n\n\tconstructor() {\n\n\t\tthis.negativeMaterialIndices = false;\n\n\t}\n\n\t// Parse nodes in FBXTree.Objects.Geometry\n\tparse( deformers ) {\n\n\t\tconst geometryMap = new Map();\n\n\t\tif ( 'Geometry' in fbxTree.Objects ) {\n\n\t\t\tconst geoNodes = fbxTree.Objects.Geometry;\n\n\t\t\tfor ( const nodeID in geoNodes ) {\n\n\t\t\t\tconst relationships = connections.get( parseInt( nodeID ) );\n\t\t\t\tconst geo = this.parseGeometry( relationships, geoNodes[ nodeID ], deformers );\n\n\t\t\t\tgeometryMap.set( parseInt( nodeID ), geo );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// report warnings\n\n\t\tif ( this.negativeMaterialIndices === true ) {\n\n\t\t\tconsole.warn( 'THREE.FBXLoader: The FBX file contains invalid (negative) material indices. The asset might not render as expected.' );\n\n\t\t}\n\n\t\treturn geometryMap;\n\n\t}\n\n\t// Parse single node in FBXTree.Objects.Geometry\n\tparseGeometry( relationships, geoNode, deformers ) {\n\n\t\tswitch ( geoNode.attrType ) {\n\n\t\t\tcase 'Mesh':\n\t\t\t\treturn this.parseMeshGeometry( relationships, geoNode, deformers );\n\t\t\t\tbreak;\n\n\t\t\tcase 'NurbsCurve':\n\t\t\t\treturn this.parseNurbsGeometry( geoNode );\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\t// Parse single node mesh geometry in FBXTree.Objects.Geometry\n\tparseMeshGeometry( relationships, geoNode, deformers ) {\n\n\t\tconst skeletons = deformers.skeletons;\n\t\tconst morphTargets = [];\n\n\t\tconst modelNodes = relationships.parents.map( function ( parent ) {\n\n\t\t\treturn fbxTree.Objects.Model[ parent.ID ];\n\n\t\t} );\n\n\t\t// don't create geometry if it is not associated with any models\n\t\tif ( modelNodes.length === 0 ) return;\n\n\t\tconst skeleton = relationships.children.reduce( function ( skeleton, child ) {\n\n\t\t\tif ( skeletons[ child.ID ] !== undefined ) skeleton = skeletons[ child.ID ];\n\n\t\t\treturn skeleton;\n\n\t\t}, null );\n\n\t\trelationships.children.forEach( function ( child ) {\n\n\t\t\tif ( deformers.morphTargets[ child.ID ] !== undefined ) {\n\n\t\t\t\tmorphTargets.push( deformers.morphTargets[ child.ID ] );\n\n\t\t\t}\n\n\t\t} );\n\n\t\t// Assume one model and get the preRotation from that\n\t\t// if there is more than one model associated with the geometry this may cause problems\n\t\tconst modelNode = modelNodes[ 0 ];\n\n\t\tconst transformData = {};\n\n\t\tif ( 'RotationOrder' in modelNode ) transformData.eulerOrder = getEulerOrder( modelNode.RotationOrder.value );\n\t\tif ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );\n\n\t\tif ( 'GeometricTranslation' in modelNode ) transformData.translation = modelNode.GeometricTranslation.value;\n\t\tif ( 'GeometricRotation' in modelNode ) transformData.rotation = modelNode.GeometricRotation.value;\n\t\tif ( 'GeometricScaling' in modelNode ) transformData.scale = modelNode.GeometricScaling.value;\n\n\t\tconst transform = generateTransform( transformData );\n\n\t\treturn this.genGeometry( geoNode, skeleton, morphTargets, transform );\n\n\t}\n\n\t// Generate a BufferGeometry from a node in FBXTree.Objects.Geometry\n\tgenGeometry( geoNode, skeleton, morphTargets, preTransform ) {\n\n\t\tconst geo = new BufferGeometry();\n\t\tif ( geoNode.attrName ) geo.name = geoNode.attrName;\n\n\t\tconst geoInfo = this.parseGeoNode( geoNode, skeleton );\n\t\tconst buffers = this.genBuffers( geoInfo );\n\n\t\tconst positionAttribute = new Float32BufferAttribute( buffers.vertex, 3 );\n\n\t\tpositionAttribute.applyMatrix4( preTransform );\n\n\t\tgeo.setAttribute( 'position', positionAttribute );\n\n\t\tif ( buffers.colors.length > 0 ) {\n\n\t\t\tgeo.setAttribute( 'color', new Float32BufferAttribute( buffers.colors, 3 ) );\n\n\t\t}\n\n\t\tif ( skeleton ) {\n\n\t\t\tgeo.setAttribute( 'skinIndex', new Uint16BufferAttribute( buffers.weightsIndices, 4 ) );\n\n\t\t\tgeo.setAttribute( 'skinWeight', new Float32BufferAttribute( buffers.vertexWeights, 4 ) );\n\n\t\t\t// used later to bind the skeleton to the model\n\t\t\tgeo.FBX_Deformer = skeleton;\n\n\t\t}\n\n\t\tif ( buffers.normal.length > 0 ) {\n\n\t\t\tconst normalMatrix = new Matrix3().getNormalMatrix( preTransform );\n\n\t\t\tconst normalAttribute = new Float32BufferAttribute( buffers.normal, 3 );\n\t\t\tnormalAttribute.applyNormalMatrix( normalMatrix );\n\n\t\t\tgeo.setAttribute( 'normal', normalAttribute );\n\n\t\t}\n\n\t\tbuffers.uvs.forEach( function ( uvBuffer, i ) {\n\n\t\t\tconst name = i === 0 ? 'uv' : `uv${ i }`;\n\n\t\t\tgeo.setAttribute( name, new Float32BufferAttribute( buffers.uvs[ i ], 2 ) );\n\n\t\t} );\n\n\t\tif ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {\n\n\t\t\t// Convert the material indices of each vertex into rendering groups on the geometry.\n\t\t\tlet prevMaterialIndex = buffers.materialIndex[ 0 ];\n\t\t\tlet startIndex = 0;\n\n\t\t\tbuffers.materialIndex.forEach( function ( currentIndex, i ) {\n\n\t\t\t\tif ( currentIndex !== prevMaterialIndex ) {\n\n\t\t\t\t\tgeo.addGroup( startIndex, i - startIndex, prevMaterialIndex );\n\n\t\t\t\t\tprevMaterialIndex = currentIndex;\n\t\t\t\t\tstartIndex = i;\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\t// the loop above doesn't add the last group, do that here.\n\t\t\tif ( geo.groups.length > 0 ) {\n\n\t\t\t\tconst lastGroup = geo.groups[ geo.groups.length - 1 ];\n\t\t\t\tconst lastIndex = lastGroup.start + lastGroup.count;\n\n\t\t\t\tif ( lastIndex !== buffers.materialIndex.length ) {\n\n\t\t\t\t\tgeo.addGroup( lastIndex, buffers.materialIndex.length - lastIndex, prevMaterialIndex );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// case where there are multiple materials but the whole geometry is only\n\t\t\t// using one of them\n\t\t\tif ( geo.groups.length === 0 ) {\n\n\t\t\t\tgeo.addGroup( 0, buffers.materialIndex.length, buffers.materialIndex[ 0 ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.addMorphTargets( geo, geoNode, morphTargets, preTransform );\n\n\t\treturn geo;\n\n\t}\n\n\tparseGeoNode( geoNode, skeleton ) {\n\n\t\tconst geoInfo = {};\n\n\t\tgeoInfo.vertexPositions = ( geoNode.Vertices !== undefined ) ? geoNode.Vertices.a : [];\n\t\tgeoInfo.vertexIndices = ( geoNode.PolygonVertexIndex !== undefined ) ? geoNode.PolygonVertexIndex.a : [];\n\n\t\tif ( geoNode.LayerElementColor ) {\n\n\t\t\tgeoInfo.color = this.parseVertexColors( geoNode.LayerElementColor[ 0 ] );\n\n\t\t}\n\n\t\tif ( geoNode.LayerElementMaterial ) {\n\n\t\t\tgeoInfo.material = this.parseMaterialIndices( geoNode.LayerElementMaterial[ 0 ] );\n\n\t\t}\n\n\t\tif ( geoNode.LayerElementNormal ) {\n\n\t\t\tgeoInfo.normal = this.parseNormals( geoNode.LayerElementNormal[ 0 ] );\n\n\t\t}\n\n\t\tif ( geoNode.LayerElementUV ) {\n\n\t\t\tgeoInfo.uv = [];\n\n\t\t\tlet i = 0;\n\t\t\twhile ( geoNode.LayerElementUV[ i ] ) {\n\n\t\t\t\tif ( geoNode.LayerElementUV[ i ].UV ) {\n\n\t\t\t\t\tgeoInfo.uv.push( this.parseUVs( geoNode.LayerElementUV[ i ] ) );\n\n\t\t\t\t}\n\n\t\t\t\ti ++;\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeoInfo.weightTable = {};\n\n\t\tif ( skeleton !== null ) {\n\n\t\t\tgeoInfo.skeleton = skeleton;\n\n\t\t\tskeleton.rawBones.forEach( function ( rawBone, i ) {\n\n\t\t\t\t// loop over the bone's vertex indices and weights\n\t\t\t\trawBone.indices.forEach( function ( index, j ) {\n\n\t\t\t\t\tif ( geoInfo.weightTable[ index ] === undefined ) geoInfo.weightTable[ index ] = [];\n\n\t\t\t\t\tgeoInfo.weightTable[ index ].push( {\n\n\t\t\t\t\t\tid: i,\n\t\t\t\t\t\tweight: rawBone.weights[ j ],\n\n\t\t\t\t\t} );\n\n\t\t\t\t} );\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn geoInfo;\n\n\t}\n\n\tgenBuffers( geoInfo ) {\n\n\t\tconst buffers = {\n\t\t\tvertex: [],\n\t\t\tnormal: [],\n\t\t\tcolors: [],\n\t\t\tuvs: [],\n\t\t\tmaterialIndex: [],\n\t\t\tvertexWeights: [],\n\t\t\tweightsIndices: [],\n\t\t};\n\n\t\tlet polygonIndex = 0;\n\t\tlet faceLength = 0;\n\t\tlet displayedWeightsWarning = false;\n\n\t\t// these will hold data for a single face\n\t\tlet facePositionIndexes = [];\n\t\tlet faceNormals = [];\n\t\tlet faceColors = [];\n\t\tlet faceUVs = [];\n\t\tlet faceWeights = [];\n\t\tlet faceWeightIndices = [];\n\n\t\tconst scope = this;\n\t\tgeoInfo.vertexIndices.forEach( function ( vertexIndex, polygonVertexIndex ) {\n\n\t\t\tlet materialIndex;\n\t\t\tlet endOfFace = false;\n\n\t\t\t// Face index and vertex index arrays are combined in a single array\n\t\t\t// A cube with quad faces looks like this:\n\t\t\t// PolygonVertexIndex: *24 {\n\t\t\t//  a: 0, 1, 3, -3, 2, 3, 5, -5, 4, 5, 7, -7, 6, 7, 1, -1, 1, 7, 5, -4, 6, 0, 2, -5\n\t\t\t//  }\n\t\t\t// Negative numbers mark the end of a face - first face here is 0, 1, 3, -3\n\t\t\t// to find index of last vertex bit shift the index: ^ - 1\n\t\t\tif ( vertexIndex < 0 ) {\n\n\t\t\t\tvertexIndex = vertexIndex ^ - 1; // equivalent to ( x * -1 ) - 1\n\t\t\t\tendOfFace = true;\n\n\t\t\t}\n\n\t\t\tlet weightIndices = [];\n\t\t\tlet weights = [];\n\n\t\t\tfacePositionIndexes.push( vertexIndex * 3, vertexIndex * 3 + 1, vertexIndex * 3 + 2 );\n\n\t\t\tif ( geoInfo.color ) {\n\n\t\t\t\tconst data = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.color );\n\n\t\t\t\tfaceColors.push( data[ 0 ], data[ 1 ], data[ 2 ] );\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.skeleton ) {\n\n\t\t\t\tif ( geoInfo.weightTable[ vertexIndex ] !== undefined ) {\n\n\t\t\t\t\tgeoInfo.weightTable[ vertexIndex ].forEach( function ( wt ) {\n\n\t\t\t\t\t\tweights.push( wt.weight );\n\t\t\t\t\t\tweightIndices.push( wt.id );\n\n\t\t\t\t\t} );\n\n\n\t\t\t\t}\n\n\t\t\t\tif ( weights.length > 4 ) {\n\n\t\t\t\t\tif ( ! displayedWeightsWarning ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.FBXLoader: Vertex has more than 4 skinning weights assigned to vertex. Deleting additional weights.' );\n\t\t\t\t\t\tdisplayedWeightsWarning = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst wIndex = [ 0, 0, 0, 0 ];\n\t\t\t\t\tconst Weight = [ 0, 0, 0, 0 ];\n\n\t\t\t\t\tweights.forEach( function ( weight, weightIndex ) {\n\n\t\t\t\t\t\tlet currentWeight = weight;\n\t\t\t\t\t\tlet currentIndex = weightIndices[ weightIndex ];\n\n\t\t\t\t\t\tWeight.forEach( function ( comparedWeight, comparedWeightIndex, comparedWeightArray ) {\n\n\t\t\t\t\t\t\tif ( currentWeight > comparedWeight ) {\n\n\t\t\t\t\t\t\t\tcomparedWeightArray[ comparedWeightIndex ] = currentWeight;\n\t\t\t\t\t\t\t\tcurrentWeight = comparedWeight;\n\n\t\t\t\t\t\t\t\tconst tmp = wIndex[ comparedWeightIndex ];\n\t\t\t\t\t\t\t\twIndex[ comparedWeightIndex ] = currentIndex;\n\t\t\t\t\t\t\t\tcurrentIndex = tmp;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t} );\n\n\t\t\t\t\tweightIndices = wIndex;\n\t\t\t\t\tweights = Weight;\n\n\t\t\t\t}\n\n\t\t\t\t// if the weight array is shorter than 4 pad with 0s\n\t\t\t\twhile ( weights.length < 4 ) {\n\n\t\t\t\t\tweights.push( 0 );\n\t\t\t\t\tweightIndices.push( 0 );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0; i < 4; ++ i ) {\n\n\t\t\t\t\tfaceWeights.push( weights[ i ] );\n\t\t\t\t\tfaceWeightIndices.push( weightIndices[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.normal ) {\n\n\t\t\t\tconst data = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.normal );\n\n\t\t\t\tfaceNormals.push( data[ 0 ], data[ 1 ], data[ 2 ] );\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {\n\n\t\t\t\tmaterialIndex = getData( polygonVertexIndex, polygonIndex, vertexIndex, geoInfo.material )[ 0 ];\n\n\t\t\t\tif ( materialIndex < 0 ) {\n\n\t\t\t\t\tscope.negativeMaterialIndices = true;\n\t\t\t\t\tmaterialIndex = 0; // fallback\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.uv ) {\n\n\t\t\t\tgeoInfo.uv.forEach( function ( uv, i ) {\n\n\t\t\t\t\tconst data = getData( polygonVertexIndex, polygonIndex, vertexIndex, uv );\n\n\t\t\t\t\tif ( faceUVs[ i ] === undefined ) {\n\n\t\t\t\t\t\tfaceUVs[ i ] = [];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfaceUVs[ i ].push( data[ 0 ] );\n\t\t\t\t\tfaceUVs[ i ].push( data[ 1 ] );\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tfaceLength ++;\n\n\t\t\tif ( endOfFace ) {\n\n\t\t\t\tscope.genFace( buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength );\n\n\t\t\t\tpolygonIndex ++;\n\t\t\t\tfaceLength = 0;\n\n\t\t\t\t// reset arrays for the next face\n\t\t\t\tfacePositionIndexes = [];\n\t\t\t\tfaceNormals = [];\n\t\t\t\tfaceColors = [];\n\t\t\t\tfaceUVs = [];\n\t\t\t\tfaceWeights = [];\n\t\t\t\tfaceWeightIndices = [];\n\n\t\t\t}\n\n\t\t} );\n\n\t\treturn buffers;\n\n\t}\n\n\t// See https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal\n\tgetNormalNewell( vertices ) {\n\n\t\tconst normal = new Vector3( 0.0, 0.0, 0.0 );\n\n\t\tfor ( let i = 0; i < vertices.length; i ++ ) {\n\n\t\t\tconst current = vertices[ i ];\n\t\t\tconst next = vertices[ ( i + 1 ) % vertices.length ];\n\n\t\t\tnormal.x += ( current.y - next.y ) * ( current.z + next.z );\n\t\t\tnormal.y += ( current.z - next.z ) * ( current.x + next.x );\n\t\t\tnormal.z += ( current.x - next.x ) * ( current.y + next.y );\n\n\t\t}\n\n\t\tnormal.normalize();\n\n\t\treturn normal;\n\n\t}\n\n\tgetNormalTangentAndBitangent( vertices ) {\n\n\t\tconst normalVector = this.getNormalNewell( vertices );\n\t\t// Avoid up being equal or almost equal to normalVector\n\t\tconst up = Math.abs( normalVector.z ) > 0.5 ? new Vector3( 0.0, 1.0, 0.0 ) : new Vector3( 0.0, 0.0, 1.0 );\n\t\tconst tangent = up.cross( normalVector ).normalize();\n\t\tconst bitangent = normalVector.clone().cross( tangent ).normalize();\n\n\t\treturn {\n\t\t\tnormal: normalVector,\n\t\t\ttangent: tangent,\n\t\t\tbitangent: bitangent\n\t\t};\n\n\t}\n\n\tflattenVertex( vertex, normalTangent, normalBitangent ) {\n\n\t\treturn new Vector2(\n\t\t\tvertex.dot( normalTangent ),\n\t\t\tvertex.dot( normalBitangent )\n\t\t);\n\n\t}\n\n\t// Generate data for a single face in a geometry. If the face is a quad then split it into 2 tris\n\tgenFace( buffers, geoInfo, facePositionIndexes, materialIndex, faceNormals, faceColors, faceUVs, faceWeights, faceWeightIndices, faceLength ) {\n\n\t\tlet triangles;\n\n\t\tif ( faceLength > 3 ) {\n\n\t\t\t// Triangulate n-gon using earcut\n\n\t\t\tconst vertices = [];\n\n\t\t\tfor ( let i = 0; i < facePositionIndexes.length; i += 3 ) {\n\n\t\t\t\tvertices.push( new Vector3(\n\t\t\t\t\tgeoInfo.vertexPositions[ facePositionIndexes[ i ] ],\n\t\t\t\t\tgeoInfo.vertexPositions[ facePositionIndexes[ i + 1 ] ],\n\t\t\t\t\tgeoInfo.vertexPositions[ facePositionIndexes[ i + 2 ] ]\n\t\t\t\t) );\n\n\t\t\t}\n\n\t\t\tconst { tangent, bitangent } = this.getNormalTangentAndBitangent( vertices );\n\t\t\tconst triangulationInput = [];\n\n\t\t\tfor ( const vertex of vertices ) {\n\n\t\t\t\ttriangulationInput.push( this.flattenVertex( vertex, tangent, bitangent ) );\n\n\t\t\t}\n\n\t\t\ttriangles = ShapeUtils.triangulateShape( triangulationInput, [] );\n\n\t\t} else {\n\n\t\t\t// Regular triangle, skip earcut triangulation step\n\t\t\ttriangles = [[ 0, 1, 2 ]];\n\n\t\t}\n\n\t\tfor ( const [ i0, i1, i2 ] of triangles ) {\n\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i0 * 3 ] ] );\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i0 * 3 + 1 ] ] );\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i0 * 3 + 2 ] ] );\n\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i1 * 3 ] ] );\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i1 * 3 + 1 ] ] );\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i1 * 3 + 2 ] ] );\n\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i2 * 3 ] ] );\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i2 * 3 + 1 ] ] );\n\t\t\tbuffers.vertex.push( geoInfo.vertexPositions[ facePositionIndexes[ i2 * 3 + 2 ] ] );\n\n\t\t\tif ( geoInfo.skeleton ) {\n\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i0 * 4 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i0 * 4 + 1 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i0 * 4 + 2 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i0 * 4 + 3 ] );\n\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i1 * 4 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i1 * 4 + 1 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i1 * 4 + 2 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i1 * 4 + 3 ] );\n\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i2 * 4 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i2 * 4 + 1 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i2 * 4 + 2 ] );\n\t\t\t\tbuffers.vertexWeights.push( faceWeights[ i2 * 4 + 3 ] );\n\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i0 * 4 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i0 * 4 + 1 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i0 * 4 + 2 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i0 * 4 + 3 ] );\n\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i1 * 4 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i1 * 4 + 1 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i1 * 4 + 2 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i1 * 4 + 3 ] );\n\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i2 * 4 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i2 * 4 + 1 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i2 * 4 + 2 ] );\n\t\t\t\tbuffers.weightsIndices.push( faceWeightIndices[ i2 * 4 + 3 ] );\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.color ) {\n\n\t\t\t\tbuffers.colors.push( faceColors[ i0 * 3 ] );\n\t\t\t\tbuffers.colors.push( faceColors[ i0 * 3 + 1 ] );\n\t\t\t\tbuffers.colors.push( faceColors[ i0 * 3 + 2 ] );\n\n\t\t\t\tbuffers.colors.push( faceColors[ i1 * 3 ] );\n\t\t\t\tbuffers.colors.push( faceColors[ i1 * 3 + 1 ] );\n\t\t\t\tbuffers.colors.push( faceColors[ i1 * 3 + 2 ] );\n\n\t\t\t\tbuffers.colors.push( faceColors[ i2 * 3 ] );\n\t\t\t\tbuffers.colors.push( faceColors[ i2 * 3 + 1 ] );\n\t\t\t\tbuffers.colors.push( faceColors[ i2 * 3 + 2 ] );\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.material && geoInfo.material.mappingType !== 'AllSame' ) {\n\n\t\t\t\tbuffers.materialIndex.push( materialIndex );\n\t\t\t\tbuffers.materialIndex.push( materialIndex );\n\t\t\t\tbuffers.materialIndex.push( materialIndex );\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.normal ) {\n\n\t\t\t\tbuffers.normal.push( faceNormals[ i0 * 3 ] );\n\t\t\t\tbuffers.normal.push( faceNormals[ i0 * 3 + 1 ] );\n\t\t\t\tbuffers.normal.push( faceNormals[ i0 * 3 + 2 ] );\n\n\t\t\t\tbuffers.normal.push( faceNormals[ i1 * 3 ] );\n\t\t\t\tbuffers.normal.push( faceNormals[ i1 * 3 + 1 ] );\n\t\t\t\tbuffers.normal.push( faceNormals[ i1 * 3 + 2 ] );\n\n\t\t\t\tbuffers.normal.push( faceNormals[ i2 * 3 ] );\n\t\t\t\tbuffers.normal.push( faceNormals[ i2 * 3 + 1 ] );\n\t\t\t\tbuffers.normal.push( faceNormals[ i2 * 3 + 2 ] );\n\n\t\t\t}\n\n\t\t\tif ( geoInfo.uv ) {\n\n\t\t\t\tgeoInfo.uv.forEach( function ( uv, j ) {\n\n\t\t\t\t\tif ( buffers.uvs[ j ] === undefined ) buffers.uvs[ j ] = [];\n\n\t\t\t\t\tbuffers.uvs[ j ].push( faceUVs[ j ][ i0 * 2 ] );\n\t\t\t\t\tbuffers.uvs[ j ].push( faceUVs[ j ][ i0 * 2 + 1 ] );\n\n\t\t\t\t\tbuffers.uvs[ j ].push( faceUVs[ j ][ i1 * 2 ] );\n\t\t\t\t\tbuffers.uvs[ j ].push( faceUVs[ j ][ i1 * 2 + 1 ] );\n\n\t\t\t\t\tbuffers.uvs[ j ].push( faceUVs[ j ][ i2 * 2 ] );\n\t\t\t\t\tbuffers.uvs[ j ].push( faceUVs[ j ][ i2 * 2 + 1 ] );\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\taddMorphTargets( parentGeo, parentGeoNode, morphTargets, preTransform ) {\n\n\t\tif ( morphTargets.length === 0 ) return;\n\n\t\tparentGeo.morphTargetsRelative = true;\n\n\t\tparentGeo.morphAttributes.position = [];\n\t\t// parentGeo.morphAttributes.normal = []; // not implemented\n\n\t\tconst scope = this;\n\t\tmorphTargets.forEach( function ( morphTarget ) {\n\n\t\t\tmorphTarget.rawTargets.forEach( function ( rawTarget ) {\n\n\t\t\t\tconst morphGeoNode = fbxTree.Objects.Geometry[ rawTarget.geoID ];\n\n\t\t\t\tif ( morphGeoNode !== undefined ) {\n\n\t\t\t\t\tscope.genMorphGeometry( parentGeo, parentGeoNode, morphGeoNode, preTransform, rawTarget.name );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t} );\n\n\t}\n\n\t// a morph geometry node is similar to a standard  node, and the node is also contained\n\t// in FBXTree.Objects.Geometry, however it can only have attributes for position, normal\n\t// and a special attribute Index defining which vertices of the original geometry are affected\n\t// Normal and position attributes only have data for the vertices that are affected by the morph\n\tgenMorphGeometry( parentGeo, parentGeoNode, morphGeoNode, preTransform, name ) {\n\n\t\tconst vertexIndices = ( parentGeoNode.PolygonVertexIndex !== undefined ) ? parentGeoNode.PolygonVertexIndex.a : [];\n\n\t\tconst morphPositionsSparse = ( morphGeoNode.Vertices !== undefined ) ? morphGeoNode.Vertices.a : [];\n\t\tconst indices = ( morphGeoNode.Indexes !== undefined ) ? morphGeoNode.Indexes.a : [];\n\n\t\tconst length = parentGeo.attributes.position.count * 3;\n\t\tconst morphPositions = new Float32Array( length );\n\n\t\tfor ( let i = 0; i < indices.length; i ++ ) {\n\n\t\t\tconst morphIndex = indices[ i ] * 3;\n\n\t\t\tmorphPositions[ morphIndex ] = morphPositionsSparse[ i * 3 ];\n\t\t\tmorphPositions[ morphIndex + 1 ] = morphPositionsSparse[ i * 3 + 1 ];\n\t\t\tmorphPositions[ morphIndex + 2 ] = morphPositionsSparse[ i * 3 + 2 ];\n\n\t\t}\n\n\t\t// TODO: add morph normal support\n\t\tconst morphGeoInfo = {\n\t\t\tvertexIndices: vertexIndices,\n\t\t\tvertexPositions: morphPositions,\n\n\t\t};\n\n\t\tconst morphBuffers = this.genBuffers( morphGeoInfo );\n\n\t\tconst positionAttribute = new Float32BufferAttribute( morphBuffers.vertex, 3 );\n\t\tpositionAttribute.name = name || morphGeoNode.attrName;\n\n\t\tpositionAttribute.applyMatrix4( preTransform );\n\n\t\tparentGeo.morphAttributes.position.push( positionAttribute );\n\n\t}\n\n\t// Parse normal from FBXTree.Objects.Geometry.LayerElementNormal if it exists\n\tparseNormals( NormalNode ) {\n\n\t\tconst mappingType = NormalNode.MappingInformationType;\n\t\tconst referenceType = NormalNode.ReferenceInformationType;\n\t\tconst buffer = NormalNode.Normals.a;\n\t\tlet indexBuffer = [];\n\t\tif ( referenceType === 'IndexToDirect' ) {\n\n\t\t\tif ( 'NormalIndex' in NormalNode ) {\n\n\t\t\t\tindexBuffer = NormalNode.NormalIndex.a;\n\n\t\t\t} else if ( 'NormalsIndex' in NormalNode ) {\n\n\t\t\t\tindexBuffer = NormalNode.NormalsIndex.a;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\tdataSize: 3,\n\t\t\tbuffer: buffer,\n\t\t\tindices: indexBuffer,\n\t\t\tmappingType: mappingType,\n\t\t\treferenceType: referenceType\n\t\t};\n\n\t}\n\n\t// Parse UVs from FBXTree.Objects.Geometry.LayerElementUV if it exists\n\tparseUVs( UVNode ) {\n\n\t\tconst mappingType = UVNode.MappingInformationType;\n\t\tconst referenceType = UVNode.ReferenceInformationType;\n\t\tconst buffer = UVNode.UV.a;\n\t\tlet indexBuffer = [];\n\t\tif ( referenceType === 'IndexToDirect' ) {\n\n\t\t\tindexBuffer = UVNode.UVIndex.a;\n\n\t\t}\n\n\t\treturn {\n\t\t\tdataSize: 2,\n\t\t\tbuffer: buffer,\n\t\t\tindices: indexBuffer,\n\t\t\tmappingType: mappingType,\n\t\t\treferenceType: referenceType\n\t\t};\n\n\t}\n\n\t// Parse Vertex Colors from FBXTree.Objects.Geometry.LayerElementColor if it exists\n\tparseVertexColors( ColorNode ) {\n\n\t\tconst mappingType = ColorNode.MappingInformationType;\n\t\tconst referenceType = ColorNode.ReferenceInformationType;\n\t\tconst buffer = ColorNode.Colors.a;\n\t\tlet indexBuffer = [];\n\t\tif ( referenceType === 'IndexToDirect' ) {\n\n\t\t\tindexBuffer = ColorNode.ColorIndex.a;\n\n\t\t}\n\n\t\tfor ( let i = 0, c = new Color(); i < buffer.length; i += 4 ) {\n\n\t\t\tc.fromArray( buffer, i ).convertSRGBToLinear().toArray( buffer, i );\n\n\t\t}\n\n\t\treturn {\n\t\t\tdataSize: 4,\n\t\t\tbuffer: buffer,\n\t\t\tindices: indexBuffer,\n\t\t\tmappingType: mappingType,\n\t\t\treferenceType: referenceType\n\t\t};\n\n\t}\n\n\t// Parse mapping and material data in FBXTree.Objects.Geometry.LayerElementMaterial if it exists\n\tparseMaterialIndices( MaterialNode ) {\n\n\t\tconst mappingType = MaterialNode.MappingInformationType;\n\t\tconst referenceType = MaterialNode.ReferenceInformationType;\n\n\t\tif ( mappingType === 'NoMappingInformation' ) {\n\n\t\t\treturn {\n\t\t\t\tdataSize: 1,\n\t\t\t\tbuffer: [ 0 ],\n\t\t\t\tindices: [ 0 ],\n\t\t\t\tmappingType: 'AllSame',\n\t\t\t\treferenceType: referenceType\n\t\t\t};\n\n\t\t}\n\n\t\tconst materialIndexBuffer = MaterialNode.Materials.a;\n\n\t\t// Since materials are stored as indices, there's a bit of a mismatch between FBX and what\n\t\t// we expect.So we create an intermediate buffer that points to the index in the buffer,\n\t\t// for conforming with the other functions we've written for other data.\n\t\tconst materialIndices = [];\n\n\t\tfor ( let i = 0; i < materialIndexBuffer.length; ++ i ) {\n\n\t\t\tmaterialIndices.push( i );\n\n\t\t}\n\n\t\treturn {\n\t\t\tdataSize: 1,\n\t\t\tbuffer: materialIndexBuffer,\n\t\t\tindices: materialIndices,\n\t\t\tmappingType: mappingType,\n\t\t\treferenceType: referenceType\n\t\t};\n\n\t}\n\n\t// Generate a NurbGeometry from a node in FBXTree.Objects.Geometry\n\tparseNurbsGeometry( geoNode ) {\n\n\t\tconst order = parseInt( geoNode.Order );\n\n\t\tif ( isNaN( order ) ) {\n\n\t\t\tconsole.error( 'THREE.FBXLoader: Invalid Order %s given for geometry ID: %s', geoNode.Order, geoNode.id );\n\t\t\treturn new BufferGeometry();\n\n\t\t}\n\n\t\tconst degree = order - 1;\n\n\t\tconst knots = geoNode.KnotVector.a;\n\t\tconst controlPoints = [];\n\t\tconst pointsValues = geoNode.Points.a;\n\n\t\tfor ( let i = 0, l = pointsValues.length; i < l; i += 4 ) {\n\n\t\t\tcontrolPoints.push( new Vector4().fromArray( pointsValues, i ) );\n\n\t\t}\n\n\t\tlet startKnot, endKnot;\n\n\t\tif ( geoNode.Form === 'Closed' ) {\n\n\t\t\tcontrolPoints.push( controlPoints[ 0 ] );\n\n\t\t} else if ( geoNode.Form === 'Periodic' ) {\n\n\t\t\tstartKnot = degree;\n\t\t\tendKnot = knots.length - 1 - startKnot;\n\n\t\t\tfor ( let i = 0; i < degree; ++ i ) {\n\n\t\t\t\tcontrolPoints.push( controlPoints[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst curve = new NURBSCurve( degree, knots, controlPoints, startKnot, endKnot );\n\t\tconst points = curve.getPoints( controlPoints.length * 12 );\n\n\t\treturn new BufferGeometry().setFromPoints( points );\n\n\t}\n\n}\n\n// parse animation data from FBXTree\nclass AnimationParser {\n\n\t// take raw animation clips and turn them into three.js animation clips\n\tparse() {\n\n\t\tconst animationClips = [];\n\n\t\tconst rawClips = this.parseClips();\n\n\t\tif ( rawClips !== undefined ) {\n\n\t\t\tfor ( const key in rawClips ) {\n\n\t\t\t\tconst rawClip = rawClips[ key ];\n\n\t\t\t\tconst clip = this.addClip( rawClip );\n\n\t\t\t\tanimationClips.push( clip );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn animationClips;\n\n\t}\n\n\tparseClips() {\n\n\t\t// since the actual transformation data is stored in FBXTree.Objects.AnimationCurve,\n\t\t// if this is undefined we can safely assume there are no animations\n\t\tif ( fbxTree.Objects.AnimationCurve === undefined ) return undefined;\n\n\t\tconst curveNodesMap = this.parseAnimationCurveNodes();\n\n\t\tthis.parseAnimationCurves( curveNodesMap );\n\n\t\tconst layersMap = this.parseAnimationLayers( curveNodesMap );\n\t\tconst rawClips = this.parseAnimStacks( layersMap );\n\n\t\treturn rawClips;\n\n\t}\n\n\t// parse nodes in FBXTree.Objects.AnimationCurveNode\n\t// each AnimationCurveNode holds data for an animation transform for a model (e.g. left arm rotation )\n\t// and is referenced by an AnimationLayer\n\tparseAnimationCurveNodes() {\n\n\t\tconst rawCurveNodes = fbxTree.Objects.AnimationCurveNode;\n\n\t\tconst curveNodesMap = new Map();\n\n\t\tfor ( const nodeID in rawCurveNodes ) {\n\n\t\t\tconst rawCurveNode = rawCurveNodes[ nodeID ];\n\n\t\t\tif ( rawCurveNode.attrName.match( /S|R|T|DeformPercent/ ) !== null ) {\n\n\t\t\t\tconst curveNode = {\n\n\t\t\t\t\tid: rawCurveNode.id,\n\t\t\t\t\tattr: rawCurveNode.attrName,\n\t\t\t\t\tcurves: {},\n\n\t\t\t\t};\n\n\t\t\t\tcurveNodesMap.set( curveNode.id, curveNode );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn curveNodesMap;\n\n\t}\n\n\t// parse nodes in FBXTree.Objects.AnimationCurve and connect them up to\n\t// previously parsed AnimationCurveNodes. Each AnimationCurve holds data for a single animated\n\t// axis ( e.g. times and values of x rotation)\n\tparseAnimationCurves( curveNodesMap ) {\n\n\t\tconst rawCurves = fbxTree.Objects.AnimationCurve;\n\n\t\t// TODO: Many values are identical up to roundoff error, but won't be optimised\n\t\t// e.g. position times: [0, 0.4, 0. 8]\n\t\t// position values: [7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.23538335023477e-7, 93.67518615722656, -0.9982695579528809, 7.235384487103147e-7, 93.67520904541016, -0.9982695579528809]\n\t\t// clearly, this should be optimised to\n\t\t// times: [0], positions [7.23538335023477e-7, 93.67518615722656, -0.9982695579528809]\n\t\t// this shows up in nearly every FBX file, and generally time array is length > 100\n\n\t\tfor ( const nodeID in rawCurves ) {\n\n\t\t\tconst animationCurve = {\n\n\t\t\t\tid: rawCurves[ nodeID ].id,\n\t\t\t\ttimes: rawCurves[ nodeID ].KeyTime.a.map( convertFBXTimeToSeconds ),\n\t\t\t\tvalues: rawCurves[ nodeID ].KeyValueFloat.a,\n\n\t\t\t};\n\n\t\t\tconst relationships = connections.get( animationCurve.id );\n\n\t\t\tif ( relationships !== undefined ) {\n\n\t\t\t\tconst animationCurveID = relationships.parents[ 0 ].ID;\n\t\t\t\tconst animationCurveRelationship = relationships.parents[ 0 ].relationship;\n\n\t\t\t\tif ( animationCurveRelationship.match( /X/ ) ) {\n\n\t\t\t\t\tcurveNodesMap.get( animationCurveID ).curves[ 'x' ] = animationCurve;\n\n\t\t\t\t} else if ( animationCurveRelationship.match( /Y/ ) ) {\n\n\t\t\t\t\tcurveNodesMap.get( animationCurveID ).curves[ 'y' ] = animationCurve;\n\n\t\t\t\t} else if ( animationCurveRelationship.match( /Z/ ) ) {\n\n\t\t\t\t\tcurveNodesMap.get( animationCurveID ).curves[ 'z' ] = animationCurve;\n\n\t\t\t\t} else if ( animationCurveRelationship.match( /DeformPercent/ ) && curveNodesMap.has( animationCurveID ) ) {\n\n\t\t\t\t\tcurveNodesMap.get( animationCurveID ).curves[ 'morph' ] = animationCurve;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// parse nodes in FBXTree.Objects.AnimationLayer. Each layers holds references\n\t// to various AnimationCurveNodes and is referenced by an AnimationStack node\n\t// note: theoretically a stack can have multiple layers, however in practice there always seems to be one per stack\n\tparseAnimationLayers( curveNodesMap ) {\n\n\t\tconst rawLayers = fbxTree.Objects.AnimationLayer;\n\n\t\tconst layersMap = new Map();\n\n\t\tfor ( const nodeID in rawLayers ) {\n\n\t\t\tconst layerCurveNodes = [];\n\n\t\t\tconst connection = connections.get( parseInt( nodeID ) );\n\n\t\t\tif ( connection !== undefined ) {\n\n\t\t\t\t// all the animationCurveNodes used in the layer\n\t\t\t\tconst children = connection.children;\n\n\t\t\t\tchildren.forEach( function ( child, i ) {\n\n\t\t\t\t\tif ( curveNodesMap.has( child.ID ) ) {\n\n\t\t\t\t\t\tconst curveNode = curveNodesMap.get( child.ID );\n\n\t\t\t\t\t\t// check that the curves are defined for at least one axis, otherwise ignore the curveNode\n\t\t\t\t\t\tif ( curveNode.curves.x !== undefined || curveNode.curves.y !== undefined || curveNode.curves.z !== undefined ) {\n\n\t\t\t\t\t\t\tif ( layerCurveNodes[ i ] === undefined ) {\n\n\t\t\t\t\t\t\t\tconst modelID = connections.get( child.ID ).parents.filter( function ( parent ) {\n\n\t\t\t\t\t\t\t\t\treturn parent.relationship !== undefined;\n\n\t\t\t\t\t\t\t\t} )[ 0 ].ID;\n\n\t\t\t\t\t\t\t\tif ( modelID !== undefined ) {\n\n\t\t\t\t\t\t\t\t\tconst rawModel = fbxTree.Objects.Model[ modelID.toString() ];\n\n\t\t\t\t\t\t\t\t\tif ( rawModel === undefined ) {\n\n\t\t\t\t\t\t\t\t\t\tconsole.warn( 'THREE.FBXLoader: Encountered a unused curve.', child );\n\t\t\t\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tconst node = {\n\n\t\t\t\t\t\t\t\t\t\tmodelName: rawModel.attrName ? PropertyBinding.sanitizeNodeName( rawModel.attrName ) : '',\n\t\t\t\t\t\t\t\t\t\tID: rawModel.id,\n\t\t\t\t\t\t\t\t\t\tinitialPosition: [ 0, 0, 0 ],\n\t\t\t\t\t\t\t\t\t\tinitialRotation: [ 0, 0, 0 ],\n\t\t\t\t\t\t\t\t\t\tinitialScale: [ 1, 1, 1 ],\n\n\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\tsceneGraph.traverse( function ( child ) {\n\n\t\t\t\t\t\t\t\t\t\tif ( child.ID === rawModel.id ) {\n\n\t\t\t\t\t\t\t\t\t\t\tnode.transform = child.matrix;\n\n\t\t\t\t\t\t\t\t\t\t\tif ( child.userData.transformData ) node.eulerOrder = child.userData.transformData.eulerOrder;\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t\t\t\tif ( ! node.transform ) node.transform = new Matrix4();\n\n\t\t\t\t\t\t\t\t\t// if the animated model is pre rotated, we'll have to apply the pre rotations to every\n\t\t\t\t\t\t\t\t\t// animation value as well\n\t\t\t\t\t\t\t\t\tif ( 'PreRotation' in rawModel ) node.preRotation = rawModel.PreRotation.value;\n\t\t\t\t\t\t\t\t\tif ( 'PostRotation' in rawModel ) node.postRotation = rawModel.PostRotation.value;\n\n\t\t\t\t\t\t\t\t\tlayerCurveNodes[ i ] = node;\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( layerCurveNodes[ i ] ) layerCurveNodes[ i ][ curveNode.attr ] = curveNode;\n\n\t\t\t\t\t\t} else if ( curveNode.curves.morph !== undefined ) {\n\n\t\t\t\t\t\t\tif ( layerCurveNodes[ i ] === undefined ) {\n\n\t\t\t\t\t\t\t\tconst deformerID = connections.get( child.ID ).parents.filter( function ( parent ) {\n\n\t\t\t\t\t\t\t\t\treturn parent.relationship !== undefined;\n\n\t\t\t\t\t\t\t\t} )[ 0 ].ID;\n\n\t\t\t\t\t\t\t\tconst morpherID = connections.get( deformerID ).parents[ 0 ].ID;\n\t\t\t\t\t\t\t\tconst geoID = connections.get( morpherID ).parents[ 0 ].ID;\n\n\t\t\t\t\t\t\t\t// assuming geometry is not used in more than one model\n\t\t\t\t\t\t\t\tconst modelID = connections.get( geoID ).parents[ 0 ].ID;\n\n\t\t\t\t\t\t\t\tconst rawModel = fbxTree.Objects.Model[ modelID ];\n\n\t\t\t\t\t\t\t\tconst node = {\n\n\t\t\t\t\t\t\t\t\tmodelName: rawModel.attrName ? PropertyBinding.sanitizeNodeName( rawModel.attrName ) : '',\n\t\t\t\t\t\t\t\t\tmorphName: fbxTree.Objects.Deformer[ deformerID ].attrName,\n\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tlayerCurveNodes[ i ] = node;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlayerCurveNodes[ i ][ curveNode.attr ] = curveNode;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t\tlayersMap.set( parseInt( nodeID ), layerCurveNodes );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn layersMap;\n\n\t}\n\n\t// parse nodes in FBXTree.Objects.AnimationStack. These are the top level node in the animation\n\t// hierarchy. Each Stack node will be used to create a AnimationClip\n\tparseAnimStacks( layersMap ) {\n\n\t\tconst rawStacks = fbxTree.Objects.AnimationStack;\n\n\t\t// connect the stacks (clips) up to the layers\n\t\tconst rawClips = {};\n\n\t\tfor ( const nodeID in rawStacks ) {\n\n\t\t\tconst children = connections.get( parseInt( nodeID ) ).children;\n\n\t\t\tif ( children.length > 1 ) {\n\n\t\t\t\t// it seems like stacks will always be associated with a single layer. But just in case there are files\n\t\t\t\t// where there are multiple layers per stack, we'll display a warning\n\t\t\t\tconsole.warn( 'THREE.FBXLoader: Encountered an animation stack with multiple layers, this is currently not supported. Ignoring subsequent layers.' );\n\n\t\t\t}\n\n\t\t\tconst layer = layersMap.get( children[ 0 ].ID );\n\n\t\t\trawClips[ nodeID ] = {\n\n\t\t\t\tname: rawStacks[ nodeID ].attrName,\n\t\t\t\tlayer: layer,\n\n\t\t\t};\n\n\t\t}\n\n\t\treturn rawClips;\n\n\t}\n\n\taddClip( rawClip ) {\n\n\t\tlet tracks = [];\n\n\t\tconst scope = this;\n\t\trawClip.layer.forEach( function ( rawTracks ) {\n\n\t\t\ttracks = tracks.concat( scope.generateTracks( rawTracks ) );\n\n\t\t} );\n\n\t\treturn new AnimationClip( rawClip.name, - 1, tracks );\n\n\t}\n\n\tgenerateTracks( rawTracks ) {\n\n\t\tconst tracks = [];\n\n\t\tlet initialPosition = new Vector3();\n\t\tlet initialScale = new Vector3();\n\n\t\tif ( rawTracks.transform ) rawTracks.transform.decompose( initialPosition, new Quaternion(), initialScale );\n\n\t\tinitialPosition = initialPosition.toArray();\n\t\tinitialScale = initialScale.toArray();\n\n\t\tif ( rawTracks.T !== undefined && Object.keys( rawTracks.T.curves ).length > 0 ) {\n\n\t\t\tconst positionTrack = this.generateVectorTrack( rawTracks.modelName, rawTracks.T.curves, initialPosition, 'position' );\n\t\t\tif ( positionTrack !== undefined ) tracks.push( positionTrack );\n\n\t\t}\n\n\t\tif ( rawTracks.R !== undefined && Object.keys( rawTracks.R.curves ).length > 0 ) {\n\n\t\t\tconst rotationTrack = this.generateRotationTrack( rawTracks.modelName, rawTracks.R.curves, rawTracks.preRotation, rawTracks.postRotation, rawTracks.eulerOrder );\n\t\t\tif ( rotationTrack !== undefined ) tracks.push( rotationTrack );\n\n\t\t}\n\n\t\tif ( rawTracks.S !== undefined && Object.keys( rawTracks.S.curves ).length > 0 ) {\n\n\t\t\tconst scaleTrack = this.generateVectorTrack( rawTracks.modelName, rawTracks.S.curves, initialScale, 'scale' );\n\t\t\tif ( scaleTrack !== undefined ) tracks.push( scaleTrack );\n\n\t\t}\n\n\t\tif ( rawTracks.DeformPercent !== undefined ) {\n\n\t\t\tconst morphTrack = this.generateMorphTrack( rawTracks );\n\t\t\tif ( morphTrack !== undefined ) tracks.push( morphTrack );\n\n\t\t}\n\n\t\treturn tracks;\n\n\t}\n\n\tgenerateVectorTrack( modelName, curves, initialValue, type ) {\n\n\t\tconst times = this.getTimesForAllAxes( curves );\n\t\tconst values = this.getKeyframeTrackValues( times, curves, initialValue );\n\n\t\treturn new VectorKeyframeTrack( modelName + '.' + type, times, values );\n\n\t}\n\n\tgenerateRotationTrack( modelName, curves, preRotation, postRotation, eulerOrder ) {\n\n\t\tlet times;\n\t\tlet values;\n\n\t\tif ( curves.x !== undefined && curves.y !== undefined && curves.z !== undefined ) {\n\n\t\t\tconst result = this.interpolateRotations( curves.x, curves.y, curves.z, eulerOrder );\n\n\t\t\ttimes = result[ 0 ];\n\t\t\tvalues = result[ 1 ];\n\n\t\t}\n\n\t\tif ( preRotation !== undefined ) {\n\n\t\t\tpreRotation = preRotation.map( MathUtils.degToRad );\n\t\t\tpreRotation.push( eulerOrder );\n\n\t\t\tpreRotation = new Euler().fromArray( preRotation );\n\t\t\tpreRotation = new Quaternion().setFromEuler( preRotation );\n\n\t\t}\n\n\t\tif ( postRotation !== undefined ) {\n\n\t\t\tpostRotation = postRotation.map( MathUtils.degToRad );\n\t\t\tpostRotation.push( eulerOrder );\n\n\t\t\tpostRotation = new Euler().fromArray( postRotation );\n\t\t\tpostRotation = new Quaternion().setFromEuler( postRotation ).invert();\n\n\t\t}\n\n\t\tconst quaternion = new Quaternion();\n\t\tconst euler = new Euler();\n\n\t\tconst quaternionValues = [];\n\n\t\tif ( ! values || ! times ) return new QuaternionKeyframeTrack( modelName + '.quaternion', [ 0 ], [ 0 ] );\n\n\t\tfor ( let i = 0; i < values.length; i += 3 ) {\n\n\t\t\teuler.set( values[ i ], values[ i + 1 ], values[ i + 2 ], eulerOrder );\n\t\t\tquaternion.setFromEuler( euler );\n\n\t\t\tif ( preRotation !== undefined ) quaternion.premultiply( preRotation );\n\t\t\tif ( postRotation !== undefined ) quaternion.multiply( postRotation );\n\n\t\t\t// Check unroll\n\t\t\tif ( i > 2 ) {\n\n\t\t\t\tconst prevQuat = new Quaternion().fromArray(\n\t\t\t\t\tquaternionValues,\n\t\t\t\t\t( ( i - 3 ) / 3 ) * 4\n\t\t\t\t);\n\n\t\t\t\tif ( prevQuat.dot( quaternion ) < 0 ) {\n\n\t\t\t\t\tquaternion.set( - quaternion.x, - quaternion.y, - quaternion.z, - quaternion.w );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tquaternion.toArray( quaternionValues, ( i / 3 ) * 4 );\n\n\t\t}\n\n\t\treturn new QuaternionKeyframeTrack( modelName + '.quaternion', times, quaternionValues );\n\n\t}\n\n\tgenerateMorphTrack( rawTracks ) {\n\n\t\tconst curves = rawTracks.DeformPercent.curves.morph;\n\t\tconst values = curves.values.map( function ( val ) {\n\n\t\t\treturn val / 100;\n\n\t\t} );\n\n\t\tconst morphNum = sceneGraph.getObjectByName( rawTracks.modelName ).morphTargetDictionary[ rawTracks.morphName ];\n\n\t\treturn new NumberKeyframeTrack( rawTracks.modelName + '.morphTargetInfluences[' + morphNum + ']', curves.times, values );\n\n\t}\n\n\t// For all animated objects, times are defined separately for each axis\n\t// Here we'll combine the times into one sorted array without duplicates\n\tgetTimesForAllAxes( curves ) {\n\n\t\tlet times = [];\n\n\t\t// first join together the times for each axis, if defined\n\t\tif ( curves.x !== undefined ) times = times.concat( curves.x.times );\n\t\tif ( curves.y !== undefined ) times = times.concat( curves.y.times );\n\t\tif ( curves.z !== undefined ) times = times.concat( curves.z.times );\n\n\t\t// then sort them\n\t\ttimes = times.sort( function ( a, b ) {\n\n\t\t\treturn a - b;\n\n\t\t} );\n\n\t\t// and remove duplicates\n\t\tif ( times.length > 1 ) {\n\n\t\t\tlet targetIndex = 1;\n\t\t\tlet lastValue = times[ 0 ];\n\t\t\tfor ( let i = 1; i < times.length; i ++ ) {\n\n\t\t\t\tconst currentValue = times[ i ];\n\t\t\t\tif ( currentValue !== lastValue ) {\n\n\t\t\t\t\ttimes[ targetIndex ] = currentValue;\n\t\t\t\t\tlastValue = currentValue;\n\t\t\t\t\ttargetIndex ++;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\ttimes = times.slice( 0, targetIndex );\n\n\t\t}\n\n\t\treturn times;\n\n\t}\n\n\tgetKeyframeTrackValues( times, curves, initialValue ) {\n\n\t\tconst prevValue = initialValue;\n\n\t\tconst values = [];\n\n\t\tlet xIndex = - 1;\n\t\tlet yIndex = - 1;\n\t\tlet zIndex = - 1;\n\n\t\ttimes.forEach( function ( time ) {\n\n\t\t\tif ( curves.x ) xIndex = curves.x.times.indexOf( time );\n\t\t\tif ( curves.y ) yIndex = curves.y.times.indexOf( time );\n\t\t\tif ( curves.z ) zIndex = curves.z.times.indexOf( time );\n\n\t\t\t// if there is an x value defined for this frame, use that\n\t\t\tif ( xIndex !== - 1 ) {\n\n\t\t\t\tconst xValue = curves.x.values[ xIndex ];\n\t\t\t\tvalues.push( xValue );\n\t\t\t\tprevValue[ 0 ] = xValue;\n\n\t\t\t} else {\n\n\t\t\t\t// otherwise use the x value from the previous frame\n\t\t\t\tvalues.push( prevValue[ 0 ] );\n\n\t\t\t}\n\n\t\t\tif ( yIndex !== - 1 ) {\n\n\t\t\t\tconst yValue = curves.y.values[ yIndex ];\n\t\t\t\tvalues.push( yValue );\n\t\t\t\tprevValue[ 1 ] = yValue;\n\n\t\t\t} else {\n\n\t\t\t\tvalues.push( prevValue[ 1 ] );\n\n\t\t\t}\n\n\t\t\tif ( zIndex !== - 1 ) {\n\n\t\t\t\tconst zValue = curves.z.values[ zIndex ];\n\t\t\t\tvalues.push( zValue );\n\t\t\t\tprevValue[ 2 ] = zValue;\n\n\t\t\t} else {\n\n\t\t\t\tvalues.push( prevValue[ 2 ] );\n\n\t\t\t}\n\n\t\t} );\n\n\t\treturn values;\n\n\t}\n\n\t// Rotations are defined as Euler angles which can have values  of any size\n\t// These will be converted to quaternions which don't support values greater than\n\t// PI, so we'll interpolate large rotations\n\tinterpolateRotations( curvex, curvey, curvez, eulerOrder ) {\n\n\t\tconst times = [];\n\t\tconst values = [];\n\n\t\t// Add first frame\n\t\ttimes.push( curvex.times[ 0 ] );\n\t\tvalues.push( MathUtils.degToRad( curvex.values[ 0 ] ) );\n\t\tvalues.push( MathUtils.degToRad( curvey.values[ 0 ] ) );\n\t\tvalues.push( MathUtils.degToRad( curvez.values[ 0 ] ) );\n\n\t\tfor ( let i = 1; i < curvex.values.length; i ++ ) {\n\n\t\t\tconst initialValue = [\n\t\t\t\tcurvex.values[ i - 1 ],\n\t\t\t\tcurvey.values[ i - 1 ],\n\t\t\t\tcurvez.values[ i - 1 ],\n\t\t\t];\n\n\t\t\tif ( isNaN( initialValue[ 0 ] ) || isNaN( initialValue[ 1 ] ) || isNaN( initialValue[ 2 ] ) ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tconst initialValueRad = initialValue.map( MathUtils.degToRad );\n\n\t\t\tconst currentValue = [\n\t\t\t\tcurvex.values[ i ],\n\t\t\t\tcurvey.values[ i ],\n\t\t\t\tcurvez.values[ i ],\n\t\t\t];\n\n\t\t\tif ( isNaN( currentValue[ 0 ] ) || isNaN( currentValue[ 1 ] ) || isNaN( currentValue[ 2 ] ) ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tconst currentValueRad = currentValue.map( MathUtils.degToRad );\n\n\t\t\tconst valuesSpan = [\n\t\t\t\tcurrentValue[ 0 ] - initialValue[ 0 ],\n\t\t\t\tcurrentValue[ 1 ] - initialValue[ 1 ],\n\t\t\t\tcurrentValue[ 2 ] - initialValue[ 2 ],\n\t\t\t];\n\n\t\t\tconst absoluteSpan = [\n\t\t\t\tMath.abs( valuesSpan[ 0 ] ),\n\t\t\t\tMath.abs( valuesSpan[ 1 ] ),\n\t\t\t\tMath.abs( valuesSpan[ 2 ] ),\n\t\t\t];\n\n\t\t\tif ( absoluteSpan[ 0 ] >= 180 || absoluteSpan[ 1 ] >= 180 || absoluteSpan[ 2 ] >= 180 ) {\n\n\t\t\t\tconst maxAbsSpan = Math.max( ...absoluteSpan );\n\n\t\t\t\tconst numSubIntervals = maxAbsSpan / 180;\n\n\t\t\t\tconst E1 = new Euler( ...initialValueRad, eulerOrder );\n\t\t\t\tconst E2 = new Euler( ...currentValueRad, eulerOrder );\n\n\t\t\t\tconst Q1 = new Quaternion().setFromEuler( E1 );\n\t\t\t\tconst Q2 = new Quaternion().setFromEuler( E2 );\n\n\t\t\t\t// Check unroll\n\t\t\t\tif ( Q1.dot( Q2 ) ) {\n\n\t\t\t\t\tQ2.set( - Q2.x, - Q2.y, - Q2.z, - Q2.w );\n\n\t\t\t\t}\n\n\t\t\t\t// Interpolate\n\t\t\t\tconst initialTime = curvex.times[ i - 1 ];\n\t\t\t\tconst timeSpan = curvex.times[ i ] - initialTime;\n\n\t\t\t\tconst Q = new Quaternion();\n\t\t\t\tconst E = new Euler();\n\t\t\t\tfor ( let t = 0; t < 1; t += 1 / numSubIntervals ) {\n\n\t\t\t\t\tQ.copy( Q1.clone().slerp( Q2.clone(), t ) );\n\n\t\t\t\t\ttimes.push( initialTime + t * timeSpan );\n\t\t\t\t\tE.setFromQuaternion( Q, eulerOrder );\n\n\t\t\t\t\tvalues.push( E.x );\n\t\t\t\t\tvalues.push( E.y );\n\t\t\t\t\tvalues.push( E.z );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\ttimes.push( curvex.times[ i ] );\n\t\t\t\tvalues.push( MathUtils.degToRad( curvex.values[ i ] ) );\n\t\t\t\tvalues.push( MathUtils.degToRad( curvey.values[ i ] ) );\n\t\t\t\tvalues.push( MathUtils.degToRad( curvez.values[ i ] ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn [ times, values ];\n\n\t}\n\n}\n\n// parse an FBX file in ASCII format\nclass TextParser {\n\n\tgetPrevNode() {\n\n\t\treturn this.nodeStack[ this.currentIndent - 2 ];\n\n\t}\n\n\tgetCurrentNode() {\n\n\t\treturn this.nodeStack[ this.currentIndent - 1 ];\n\n\t}\n\n\tgetCurrentProp() {\n\n\t\treturn this.currentProp;\n\n\t}\n\n\tpushStack( node ) {\n\n\t\tthis.nodeStack.push( node );\n\t\tthis.currentIndent += 1;\n\n\t}\n\n\tpopStack() {\n\n\t\tthis.nodeStack.pop();\n\t\tthis.currentIndent -= 1;\n\n\t}\n\n\tsetCurrentProp( val, name ) {\n\n\t\tthis.currentProp = val;\n\t\tthis.currentPropName = name;\n\n\t}\n\n\tparse( text ) {\n\n\t\tthis.currentIndent = 0;\n\n\t\tthis.allNodes = new FBXTree();\n\t\tthis.nodeStack = [];\n\t\tthis.currentProp = [];\n\t\tthis.currentPropName = '';\n\n\t\tconst scope = this;\n\n\t\tconst split = text.split( /[\\r\\n]+/ );\n\n\t\tsplit.forEach( function ( line, i ) {\n\n\t\t\tconst matchComment = line.match( /^[\\s\\t]*;/ );\n\t\t\tconst matchEmpty = line.match( /^[\\s\\t]*$/ );\n\n\t\t\tif ( matchComment || matchEmpty ) return;\n\n\t\t\tconst matchBeginning = line.match( '^\\\\t{' + scope.currentIndent + '}(\\\\w+):(.*){', '' );\n\t\t\tconst matchProperty = line.match( '^\\\\t{' + ( scope.currentIndent ) + '}(\\\\w+):[\\\\s\\\\t\\\\r\\\\n](.*)' );\n\t\t\tconst matchEnd = line.match( '^\\\\t{' + ( scope.currentIndent - 1 ) + '}}' );\n\n\t\t\tif ( matchBeginning ) {\n\n\t\t\t\tscope.parseNodeBegin( line, matchBeginning );\n\n\t\t\t} else if ( matchProperty ) {\n\n\t\t\t\tscope.parseNodeProperty( line, matchProperty, split[ ++ i ] );\n\n\t\t\t} else if ( matchEnd ) {\n\n\t\t\t\tscope.popStack();\n\n\t\t\t} else if ( line.match( /^[^\\s\\t}]/ ) ) {\n\n\t\t\t\t// large arrays are split over multiple lines terminated with a ',' character\n\t\t\t\t// if this is encountered the line needs to be joined to the previous line\n\t\t\t\tscope.parseNodePropertyContinued( line );\n\n\t\t\t}\n\n\t\t} );\n\n\t\treturn this.allNodes;\n\n\t}\n\n\tparseNodeBegin( line, property ) {\n\n\t\tconst nodeName = property[ 1 ].trim().replace( /^\"/, '' ).replace( /\"$/, '' );\n\n\t\tconst nodeAttrs = property[ 2 ].split( ',' ).map( function ( attr ) {\n\n\t\t\treturn attr.trim().replace( /^\"/, '' ).replace( /\"$/, '' );\n\n\t\t} );\n\n\t\tconst node = { name: nodeName };\n\t\tconst attrs = this.parseNodeAttr( nodeAttrs );\n\n\t\tconst currentNode = this.getCurrentNode();\n\n\t\t// a top node\n\t\tif ( this.currentIndent === 0 ) {\n\n\t\t\tthis.allNodes.add( nodeName, node );\n\n\t\t} else { // a subnode\n\n\t\t\t// if the subnode already exists, append it\n\t\t\tif ( nodeName in currentNode ) {\n\n\t\t\t\t// special case Pose needs PoseNodes as an array\n\t\t\t\tif ( nodeName === 'PoseNode' ) {\n\n\t\t\t\t\tcurrentNode.PoseNode.push( node );\n\n\t\t\t\t} else if ( currentNode[ nodeName ].id !== undefined ) {\n\n\t\t\t\t\tcurrentNode[ nodeName ] = {};\n\t\t\t\t\tcurrentNode[ nodeName ][ currentNode[ nodeName ].id ] = currentNode[ nodeName ];\n\n\t\t\t\t}\n\n\t\t\t\tif ( attrs.id !== '' ) currentNode[ nodeName ][ attrs.id ] = node;\n\n\t\t\t} else if ( typeof attrs.id === 'number' ) {\n\n\t\t\t\tcurrentNode[ nodeName ] = {};\n\t\t\t\tcurrentNode[ nodeName ][ attrs.id ] = node;\n\n\t\t\t} else if ( nodeName !== 'Properties70' ) {\n\n\t\t\t\tif ( nodeName === 'PoseNode' )\tcurrentNode[ nodeName ] = [ node ];\n\t\t\t\telse currentNode[ nodeName ] = node;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( typeof attrs.id === 'number' ) node.id = attrs.id;\n\t\tif ( attrs.name !== '' ) node.attrName = attrs.name;\n\t\tif ( attrs.type !== '' ) node.attrType = attrs.type;\n\n\t\tthis.pushStack( node );\n\n\t}\n\n\tparseNodeAttr( attrs ) {\n\n\t\tlet id = attrs[ 0 ];\n\n\t\tif ( attrs[ 0 ] !== '' ) {\n\n\t\t\tid = parseInt( attrs[ 0 ] );\n\n\t\t\tif ( isNaN( id ) ) {\n\n\t\t\t\tid = attrs[ 0 ];\n\n\t\t\t}\n\n\t\t}\n\n\t\tlet name = '', type = '';\n\n\t\tif ( attrs.length > 1 ) {\n\n\t\t\tname = attrs[ 1 ].replace( /^(\\w+)::/, '' );\n\t\t\ttype = attrs[ 2 ];\n\n\t\t}\n\n\t\treturn { id: id, name: name, type: type };\n\n\t}\n\n\tparseNodeProperty( line, property, contentLine ) {\n\n\t\tlet propName = property[ 1 ].replace( /^\"/, '' ).replace( /\"$/, '' ).trim();\n\t\tlet propValue = property[ 2 ].replace( /^\"/, '' ).replace( /\"$/, '' ).trim();\n\n\t\t// for special case: base64 image data follows \"Content: ,\" line\n\t\t//\tContent: ,\n\t\t//\t \"/9j/4RDaRXhpZgAATU0A...\"\n\t\tif ( propName === 'Content' && propValue === ',' ) {\n\n\t\t\tpropValue = contentLine.replace( /\"/g, '' ).replace( /,$/, '' ).trim();\n\n\t\t}\n\n\t\tconst currentNode = this.getCurrentNode();\n\t\tconst parentName = currentNode.name;\n\n\t\tif ( parentName === 'Properties70' ) {\n\n\t\t\tthis.parseNodeSpecialProperty( line, propName, propValue );\n\t\t\treturn;\n\n\t\t}\n\n\t\t// Connections\n\t\tif ( propName === 'C' ) {\n\n\t\t\tconst connProps = propValue.split( ',' ).slice( 1 );\n\t\t\tconst from = parseInt( connProps[ 0 ] );\n\t\t\tconst to = parseInt( connProps[ 1 ] );\n\n\t\t\tlet rest = propValue.split( ',' ).slice( 3 );\n\n\t\t\trest = rest.map( function ( elem ) {\n\n\t\t\t\treturn elem.trim().replace( /^\"/, '' );\n\n\t\t\t} );\n\n\t\t\tpropName = 'connections';\n\t\t\tpropValue = [ from, to ];\n\t\t\tappend( propValue, rest );\n\n\t\t\tif ( currentNode[ propName ] === undefined ) {\n\n\t\t\t\tcurrentNode[ propName ] = [];\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Node\n\t\tif ( propName === 'Node' ) currentNode.id = propValue;\n\n\t\t// connections\n\t\tif ( propName in currentNode && Array.isArray( currentNode[ propName ] ) ) {\n\n\t\t\tcurrentNode[ propName ].push( propValue );\n\n\t\t} else {\n\n\t\t\tif ( propName !== 'a' ) currentNode[ propName ] = propValue;\n\t\t\telse currentNode.a = propValue;\n\n\t\t}\n\n\t\tthis.setCurrentProp( currentNode, propName );\n\n\t\t// convert string to array, unless it ends in ',' in which case more will be added to it\n\t\tif ( propName === 'a' && propValue.slice( - 1 ) !== ',' ) {\n\n\t\t\tcurrentNode.a = parseNumberArray( propValue );\n\n\t\t}\n\n\t}\n\n\tparseNodePropertyContinued( line ) {\n\n\t\tconst currentNode = this.getCurrentNode();\n\n\t\tcurrentNode.a += line;\n\n\t\t// if the line doesn't end in ',' we have reached the end of the property value\n\t\t// so convert the string to an array\n\t\tif ( line.slice( - 1 ) !== ',' ) {\n\n\t\t\tcurrentNode.a = parseNumberArray( currentNode.a );\n\n\t\t}\n\n\t}\n\n\t// parse \"Property70\"\n\tparseNodeSpecialProperty( line, propName, propValue ) {\n\n\t\t// split this\n\t\t// P: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",1,1,1\n\t\t// into array like below\n\t\t// [\"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\", \"1,1,1\" ]\n\t\tconst props = propValue.split( '\",' ).map( function ( prop ) {\n\n\t\t\treturn prop.trim().replace( /^\\\"/, '' ).replace( /\\s/, '_' );\n\n\t\t} );\n\n\t\tconst innerPropName = props[ 0 ];\n\t\tconst innerPropType1 = props[ 1 ];\n\t\tconst innerPropType2 = props[ 2 ];\n\t\tconst innerPropFlag = props[ 3 ];\n\t\tlet innerPropValue = props[ 4 ];\n\n\t\t// cast values where needed, otherwise leave as strings\n\t\tswitch ( innerPropType1 ) {\n\n\t\t\tcase 'int':\n\t\t\tcase 'enum':\n\t\t\tcase 'bool':\n\t\t\tcase 'ULongLong':\n\t\t\tcase 'double':\n\t\t\tcase 'Number':\n\t\t\tcase 'FieldOfView':\n\t\t\t\tinnerPropValue = parseFloat( innerPropValue );\n\t\t\t\tbreak;\n\n\t\t\tcase 'Color':\n\t\t\tcase 'ColorRGB':\n\t\t\tcase 'Vector3D':\n\t\t\tcase 'Lcl_Translation':\n\t\t\tcase 'Lcl_Rotation':\n\t\t\tcase 'Lcl_Scaling':\n\t\t\t\tinnerPropValue = parseNumberArray( innerPropValue );\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\t// CAUTION: these props must append to parent's parent\n\t\tthis.getPrevNode()[ innerPropName ] = {\n\n\t\t\t'type': innerPropType1,\n\t\t\t'type2': innerPropType2,\n\t\t\t'flag': innerPropFlag,\n\t\t\t'value': innerPropValue\n\n\t\t};\n\n\t\tthis.setCurrentProp( this.getPrevNode(), innerPropName );\n\n\t}\n\n}\n\n// Parse an FBX file in Binary format\nclass BinaryParser {\n\n\tparse( buffer ) {\n\n\t\tconst reader = new BinaryReader( buffer );\n\t\treader.skip( 23 ); // skip magic 23 bytes\n\n\t\tconst version = reader.getUint32();\n\n\t\tif ( version < 6400 ) {\n\n\t\t\tthrow new Error( 'THREE.FBXLoader: FBX version not supported, FileVersion: ' + version );\n\n\t\t}\n\n\t\tconst allNodes = new FBXTree();\n\n\t\twhile ( ! this.endOfContent( reader ) ) {\n\n\t\t\tconst node = this.parseNode( reader, version );\n\t\t\tif ( node !== null ) allNodes.add( node.name, node );\n\n\t\t}\n\n\t\treturn allNodes;\n\n\t}\n\n\t// Check if reader has reached the end of content.\n\tendOfContent( reader ) {\n\n\t\t// footer size: 160bytes + 16-byte alignment padding\n\t\t// - 16bytes: magic\n\t\t// - padding til 16-byte alignment (at least 1byte?)\n\t\t//\t(seems like some exporters embed fixed 15 or 16bytes?)\n\t\t// - 4bytes: magic\n\t\t// - 4bytes: version\n\t\t// - 120bytes: zero\n\t\t// - 16bytes: magic\n\t\tif ( reader.size() % 16 === 0 ) {\n\n\t\t\treturn ( ( reader.getOffset() + 160 + 16 ) & ~ 0xf ) >= reader.size();\n\n\t\t} else {\n\n\t\t\treturn reader.getOffset() + 160 + 16 >= reader.size();\n\n\t\t}\n\n\t}\n\n\t// recursively parse nodes until the end of the file is reached\n\tparseNode( reader, version ) {\n\n\t\tconst node = {};\n\n\t\t// The first three data sizes depends on version.\n\t\tconst endOffset = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();\n\t\tconst numProperties = ( version >= 7500 ) ? reader.getUint64() : reader.getUint32();\n\n\t\t( version >= 7500 ) ? reader.getUint64() : reader.getUint32(); // the returned propertyListLen is not used\n\n\t\tconst nameLen = reader.getUint8();\n\t\tconst name = reader.getString( nameLen );\n\n\t\t// Regards this node as NULL-record if endOffset is zero\n\t\tif ( endOffset === 0 ) return null;\n\n\t\tconst propertyList = [];\n\n\t\tfor ( let i = 0; i < numProperties; i ++ ) {\n\n\t\t\tpropertyList.push( this.parseProperty( reader ) );\n\n\t\t}\n\n\t\t// Regards the first three elements in propertyList as id, attrName, and attrType\n\t\tconst id = propertyList.length > 0 ? propertyList[ 0 ] : '';\n\t\tconst attrName = propertyList.length > 1 ? propertyList[ 1 ] : '';\n\t\tconst attrType = propertyList.length > 2 ? propertyList[ 2 ] : '';\n\n\t\t// check if this node represents just a single property\n\t\t// like (name, 0) set or (name2, [0, 1, 2]) set of {name: 0, name2: [0, 1, 2]}\n\t\tnode.singleProperty = ( numProperties === 1 && reader.getOffset() === endOffset ) ? true : false;\n\n\t\twhile ( endOffset > reader.getOffset() ) {\n\n\t\t\tconst subNode = this.parseNode( reader, version );\n\n\t\t\tif ( subNode !== null ) this.parseSubNode( name, node, subNode );\n\n\t\t}\n\n\t\tnode.propertyList = propertyList; // raw property list used by parent\n\n\t\tif ( typeof id === 'number' ) node.id = id;\n\t\tif ( attrName !== '' ) node.attrName = attrName;\n\t\tif ( attrType !== '' ) node.attrType = attrType;\n\t\tif ( name !== '' ) node.name = name;\n\n\t\treturn node;\n\n\t}\n\n\tparseSubNode( name, node, subNode ) {\n\n\t\t// special case: child node is single property\n\t\tif ( subNode.singleProperty === true ) {\n\n\t\t\tconst value = subNode.propertyList[ 0 ];\n\n\t\t\tif ( Array.isArray( value ) ) {\n\n\t\t\t\tnode[ subNode.name ] = subNode;\n\n\t\t\t\tsubNode.a = value;\n\n\t\t\t} else {\n\n\t\t\t\tnode[ subNode.name ] = value;\n\n\t\t\t}\n\n\t\t} else if ( name === 'Connections' && subNode.name === 'C' ) {\n\n\t\t\tconst array = [];\n\n\t\t\tsubNode.propertyList.forEach( function ( property, i ) {\n\n\t\t\t\t// first Connection is FBX type (OO, OP, etc.). We'll discard these\n\t\t\t\tif ( i !== 0 ) array.push( property );\n\n\t\t\t} );\n\n\t\t\tif ( node.connections === undefined ) {\n\n\t\t\t\tnode.connections = [];\n\n\t\t\t}\n\n\t\t\tnode.connections.push( array );\n\n\t\t} else if ( subNode.name === 'Properties70' ) {\n\n\t\t\tconst keys = Object.keys( subNode );\n\n\t\t\tkeys.forEach( function ( key ) {\n\n\t\t\t\tnode[ key ] = subNode[ key ];\n\n\t\t\t} );\n\n\t\t} else if ( name === 'Properties70' && subNode.name === 'P' ) {\n\n\t\t\tlet innerPropName = subNode.propertyList[ 0 ];\n\t\t\tlet innerPropType1 = subNode.propertyList[ 1 ];\n\t\t\tconst innerPropType2 = subNode.propertyList[ 2 ];\n\t\t\tconst innerPropFlag = subNode.propertyList[ 3 ];\n\t\t\tlet innerPropValue;\n\n\t\t\tif ( innerPropName.indexOf( 'Lcl ' ) === 0 ) innerPropName = innerPropName.replace( 'Lcl ', 'Lcl_' );\n\t\t\tif ( innerPropType1.indexOf( 'Lcl ' ) === 0 ) innerPropType1 = innerPropType1.replace( 'Lcl ', 'Lcl_' );\n\n\t\t\tif ( innerPropType1 === 'Color' || innerPropType1 === 'ColorRGB' || innerPropType1 === 'Vector' || innerPropType1 === 'Vector3D' || innerPropType1.indexOf( 'Lcl_' ) === 0 ) {\n\n\t\t\t\tinnerPropValue = [\n\t\t\t\t\tsubNode.propertyList[ 4 ],\n\t\t\t\t\tsubNode.propertyList[ 5 ],\n\t\t\t\t\tsubNode.propertyList[ 6 ]\n\t\t\t\t];\n\n\t\t\t} else {\n\n\t\t\t\tinnerPropValue = subNode.propertyList[ 4 ];\n\n\t\t\t}\n\n\t\t\t// this will be copied to parent, see above\n\t\t\tnode[ innerPropName ] = {\n\n\t\t\t\t'type': innerPropType1,\n\t\t\t\t'type2': innerPropType2,\n\t\t\t\t'flag': innerPropFlag,\n\t\t\t\t'value': innerPropValue\n\n\t\t\t};\n\n\t\t} else if ( node[ subNode.name ] === undefined ) {\n\n\t\t\tif ( typeof subNode.id === 'number' ) {\n\n\t\t\t\tnode[ subNode.name ] = {};\n\t\t\t\tnode[ subNode.name ][ subNode.id ] = subNode;\n\n\t\t\t} else {\n\n\t\t\t\tnode[ subNode.name ] = subNode;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( subNode.name === 'PoseNode' ) {\n\n\t\t\t\tif ( ! Array.isArray( node[ subNode.name ] ) ) {\n\n\t\t\t\t\tnode[ subNode.name ] = [ node[ subNode.name ] ];\n\n\t\t\t\t}\n\n\t\t\t\tnode[ subNode.name ].push( subNode );\n\n\t\t\t} else if ( node[ subNode.name ][ subNode.id ] === undefined ) {\n\n\t\t\t\tnode[ subNode.name ][ subNode.id ] = subNode;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tparseProperty( reader ) {\n\n\t\tconst type = reader.getString( 1 );\n\t\tlet length;\n\n\t\tswitch ( type ) {\n\n\t\t\tcase 'C':\n\t\t\t\treturn reader.getBoolean();\n\n\t\t\tcase 'D':\n\t\t\t\treturn reader.getFloat64();\n\n\t\t\tcase 'F':\n\t\t\t\treturn reader.getFloat32();\n\n\t\t\tcase 'I':\n\t\t\t\treturn reader.getInt32();\n\n\t\t\tcase 'L':\n\t\t\t\treturn reader.getInt64();\n\n\t\t\tcase 'R':\n\t\t\t\tlength = reader.getUint32();\n\t\t\t\treturn reader.getArrayBuffer( length );\n\n\t\t\tcase 'S':\n\t\t\t\tlength = reader.getUint32();\n\t\t\t\treturn reader.getString( length );\n\n\t\t\tcase 'Y':\n\t\t\t\treturn reader.getInt16();\n\n\t\t\tcase 'b':\n\t\t\tcase 'c':\n\t\t\tcase 'd':\n\t\t\tcase 'f':\n\t\t\tcase 'i':\n\t\t\tcase 'l':\n\n\t\t\t\tconst arrayLength = reader.getUint32();\n\t\t\t\tconst encoding = reader.getUint32(); // 0: non-compressed, 1: compressed\n\t\t\t\tconst compressedLength = reader.getUint32();\n\n\t\t\t\tif ( encoding === 0 ) {\n\n\t\t\t\t\tswitch ( type ) {\n\n\t\t\t\t\t\tcase 'b':\n\t\t\t\t\t\tcase 'c':\n\t\t\t\t\t\t\treturn reader.getBooleanArray( arrayLength );\n\n\t\t\t\t\t\tcase 'd':\n\t\t\t\t\t\t\treturn reader.getFloat64Array( arrayLength );\n\n\t\t\t\t\t\tcase 'f':\n\t\t\t\t\t\t\treturn reader.getFloat32Array( arrayLength );\n\n\t\t\t\t\t\tcase 'i':\n\t\t\t\t\t\t\treturn reader.getInt32Array( arrayLength );\n\n\t\t\t\t\t\tcase 'l':\n\t\t\t\t\t\t\treturn reader.getInt64Array( arrayLength );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tconst data = fflate.unzlibSync( new Uint8Array( reader.getArrayBuffer( compressedLength ) ) );\n\t\t\t\tconst reader2 = new BinaryReader( data.buffer );\n\n\t\t\t\tswitch ( type ) {\n\n\t\t\t\t\tcase 'b':\n\t\t\t\t\tcase 'c':\n\t\t\t\t\t\treturn reader2.getBooleanArray( arrayLength );\n\n\t\t\t\t\tcase 'd':\n\t\t\t\t\t\treturn reader2.getFloat64Array( arrayLength );\n\n\t\t\t\t\tcase 'f':\n\t\t\t\t\t\treturn reader2.getFloat32Array( arrayLength );\n\n\t\t\t\t\tcase 'i':\n\t\t\t\t\t\treturn reader2.getInt32Array( arrayLength );\n\n\t\t\t\t\tcase 'l':\n\t\t\t\t\t\treturn reader2.getInt64Array( arrayLength );\n\n\t\t\t\t}\n\n\t\t\t\tbreak; // cannot happen but is required by the DeepScan\n\n\t\t\tdefault:\n\t\t\t\tthrow new Error( 'THREE.FBXLoader: Unknown property type ' + type );\n\n\t\t}\n\n\t}\n\n}\n\nclass BinaryReader {\n\n\tconstructor( buffer, littleEndian ) {\n\n\t\tthis.dv = new DataView( buffer );\n\t\tthis.offset = 0;\n\t\tthis.littleEndian = ( littleEndian !== undefined ) ? littleEndian : true;\n\t\tthis._textDecoder = new TextDecoder();\n\n\t}\n\n\tgetOffset() {\n\n\t\treturn this.offset;\n\n\t}\n\n\tsize() {\n\n\t\treturn this.dv.buffer.byteLength;\n\n\t}\n\n\tskip( length ) {\n\n\t\tthis.offset += length;\n\n\t}\n\n\t// seems like true/false representation depends on exporter.\n\t// true: 1 or 'Y'(=0x59), false: 0 or 'T'(=0x54)\n\t// then sees LSB.\n\tgetBoolean() {\n\n\t\treturn ( this.getUint8() & 1 ) === 1;\n\n\t}\n\n\tgetBooleanArray( size ) {\n\n\t\tconst a = [];\n\n\t\tfor ( let i = 0; i < size; i ++ ) {\n\n\t\t\ta.push( this.getBoolean() );\n\n\t\t}\n\n\t\treturn a;\n\n\t}\n\n\tgetUint8() {\n\n\t\tconst value = this.dv.getUint8( this.offset );\n\t\tthis.offset += 1;\n\t\treturn value;\n\n\t}\n\n\tgetInt16() {\n\n\t\tconst value = this.dv.getInt16( this.offset, this.littleEndian );\n\t\tthis.offset += 2;\n\t\treturn value;\n\n\t}\n\n\tgetInt32() {\n\n\t\tconst value = this.dv.getInt32( this.offset, this.littleEndian );\n\t\tthis.offset += 4;\n\t\treturn value;\n\n\t}\n\n\tgetInt32Array( size ) {\n\n\t\tconst a = [];\n\n\t\tfor ( let i = 0; i < size; i ++ ) {\n\n\t\t\ta.push( this.getInt32() );\n\n\t\t}\n\n\t\treturn a;\n\n\t}\n\n\tgetUint32() {\n\n\t\tconst value = this.dv.getUint32( this.offset, this.littleEndian );\n\t\tthis.offset += 4;\n\t\treturn value;\n\n\t}\n\n\t// JavaScript doesn't support 64-bit integer so calculate this here\n\t// 1 << 32 will return 1 so using multiply operation instead here.\n\t// There's a possibility that this method returns wrong value if the value\n\t// is out of the range between Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.\n\t// TODO: safely handle 64-bit integer\n\tgetInt64() {\n\n\t\tlet low, high;\n\n\t\tif ( this.littleEndian ) {\n\n\t\t\tlow = this.getUint32();\n\t\t\thigh = this.getUint32();\n\n\t\t} else {\n\n\t\t\thigh = this.getUint32();\n\t\t\tlow = this.getUint32();\n\n\t\t}\n\n\t\t// calculate negative value\n\t\tif ( high & 0x80000000 ) {\n\n\t\t\thigh = ~ high & 0xFFFFFFFF;\n\t\t\tlow = ~ low & 0xFFFFFFFF;\n\n\t\t\tif ( low === 0xFFFFFFFF ) high = ( high + 1 ) & 0xFFFFFFFF;\n\n\t\t\tlow = ( low + 1 ) & 0xFFFFFFFF;\n\n\t\t\treturn - ( high * 0x100000000 + low );\n\n\t\t}\n\n\t\treturn high * 0x100000000 + low;\n\n\t}\n\n\tgetInt64Array( size ) {\n\n\t\tconst a = [];\n\n\t\tfor ( let i = 0; i < size; i ++ ) {\n\n\t\t\ta.push( this.getInt64() );\n\n\t\t}\n\n\t\treturn a;\n\n\t}\n\n\t// Note: see getInt64() comment\n\tgetUint64() {\n\n\t\tlet low, high;\n\n\t\tif ( this.littleEndian ) {\n\n\t\t\tlow = this.getUint32();\n\t\t\thigh = this.getUint32();\n\n\t\t} else {\n\n\t\t\thigh = this.getUint32();\n\t\t\tlow = this.getUint32();\n\n\t\t}\n\n\t\treturn high * 0x100000000 + low;\n\n\t}\n\n\tgetFloat32() {\n\n\t\tconst value = this.dv.getFloat32( this.offset, this.littleEndian );\n\t\tthis.offset += 4;\n\t\treturn value;\n\n\t}\n\n\tgetFloat32Array( size ) {\n\n\t\tconst a = [];\n\n\t\tfor ( let i = 0; i < size; i ++ ) {\n\n\t\t\ta.push( this.getFloat32() );\n\n\t\t}\n\n\t\treturn a;\n\n\t}\n\n\tgetFloat64() {\n\n\t\tconst value = this.dv.getFloat64( this.offset, this.littleEndian );\n\t\tthis.offset += 8;\n\t\treturn value;\n\n\t}\n\n\tgetFloat64Array( size ) {\n\n\t\tconst a = [];\n\n\t\tfor ( let i = 0; i < size; i ++ ) {\n\n\t\t\ta.push( this.getFloat64() );\n\n\t\t}\n\n\t\treturn a;\n\n\t}\n\n\tgetArrayBuffer( size ) {\n\n\t\tconst value = this.dv.buffer.slice( this.offset, this.offset + size );\n\t\tthis.offset += size;\n\t\treturn value;\n\n\t}\n\n\tgetString( size ) {\n\n\t\tconst start = this.offset;\n\t\tlet a = new Uint8Array( this.dv.buffer, start, size );\n\n\t\tthis.skip( size );\n\n\t\tconst nullByte = a.indexOf( 0 );\n\t\tif ( nullByte >= 0 ) a = new Uint8Array( this.dv.buffer, start, nullByte );\n\n\t\treturn this._textDecoder.decode( a );\n\n\t}\n\n}\n\n// FBXTree holds a representation of the FBX data, returned by the TextParser ( FBX ASCII format)\n// and BinaryParser( FBX Binary format)\nclass FBXTree {\n\n\tadd( key, val ) {\n\n\t\tthis[ key ] = val;\n\n\t}\n\n}\n\n// ************** UTILITY FUNCTIONS **************\n\nfunction isFbxFormatBinary( buffer ) {\n\n\tconst CORRECT = 'Kaydara\\u0020FBX\\u0020Binary\\u0020\\u0020\\0';\n\n\treturn buffer.byteLength >= CORRECT.length && CORRECT === convertArrayBufferToString( buffer, 0, CORRECT.length );\n\n}\n\nfunction isFbxFormatASCII( text ) {\n\n\tconst CORRECT = [ 'K', 'a', 'y', 'd', 'a', 'r', 'a', '\\\\', 'F', 'B', 'X', '\\\\', 'B', 'i', 'n', 'a', 'r', 'y', '\\\\', '\\\\' ];\n\n\tlet cursor = 0;\n\n\tfunction read( offset ) {\n\n\t\tconst result = text[ offset - 1 ];\n\t\ttext = text.slice( cursor + offset );\n\t\tcursor ++;\n\t\treturn result;\n\n\t}\n\n\tfor ( let i = 0; i < CORRECT.length; ++ i ) {\n\n\t\tconst num = read( 1 );\n\t\tif ( num === CORRECT[ i ] ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t}\n\n\treturn true;\n\n}\n\nfunction getFbxVersion( text ) {\n\n\tconst versionRegExp = /FBXVersion: (\\d+)/;\n\tconst match = text.match( versionRegExp );\n\n\tif ( match ) {\n\n\t\tconst version = parseInt( match[ 1 ] );\n\t\treturn version;\n\n\t}\n\n\tthrow new Error( 'THREE.FBXLoader: Cannot find the version number for the file given.' );\n\n}\n\n// Converts FBX ticks into real time seconds.\nfunction convertFBXTimeToSeconds( time ) {\n\n\treturn time / 46186158000;\n\n}\n\nconst dataArray = [];\n\n// extracts the data from the correct position in the FBX array based on indexing type\nfunction getData( polygonVertexIndex, polygonIndex, vertexIndex, infoObject ) {\n\n\tlet index;\n\n\tswitch ( infoObject.mappingType ) {\n\n\t\tcase 'ByPolygonVertex' :\n\t\t\tindex = polygonVertexIndex;\n\t\t\tbreak;\n\t\tcase 'ByPolygon' :\n\t\t\tindex = polygonIndex;\n\t\t\tbreak;\n\t\tcase 'ByVertice' :\n\t\t\tindex = vertexIndex;\n\t\t\tbreak;\n\t\tcase 'AllSame' :\n\t\t\tindex = infoObject.indices[ 0 ];\n\t\t\tbreak;\n\t\tdefault :\n\t\t\tconsole.warn( 'THREE.FBXLoader: unknown attribute mapping type ' + infoObject.mappingType );\n\n\t}\n\n\tif ( infoObject.referenceType === 'IndexToDirect' ) index = infoObject.indices[ index ];\n\n\tconst from = index * infoObject.dataSize;\n\tconst to = from + infoObject.dataSize;\n\n\treturn slice( dataArray, infoObject.buffer, from, to );\n\n}\n\nconst tempEuler = new Euler();\nconst tempVec = new Vector3();\n\n// generate transformation from FBX transform data\n// ref: https://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_10CDD63C_79C1_4F2D_BB28_AD2BE65A02ED_htm\n// ref: http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/_transformations_2main_8cxx-example.html,topicNumber=cpp_ref__transformations_2main_8cxx_example_htmlfc10a1e1-b18d-4e72-9dc0-70d0f1959f5e\nfunction generateTransform( transformData ) {\n\n\tconst lTranslationM = new Matrix4();\n\tconst lPreRotationM = new Matrix4();\n\tconst lRotationM = new Matrix4();\n\tconst lPostRotationM = new Matrix4();\n\n\tconst lScalingM = new Matrix4();\n\tconst lScalingPivotM = new Matrix4();\n\tconst lScalingOffsetM = new Matrix4();\n\tconst lRotationOffsetM = new Matrix4();\n\tconst lRotationPivotM = new Matrix4();\n\n\tconst lParentGX = new Matrix4();\n\tconst lParentLX = new Matrix4();\n\tconst lGlobalT = new Matrix4();\n\n\tconst inheritType = ( transformData.inheritType ) ? transformData.inheritType : 0;\n\n\tif ( transformData.translation ) lTranslationM.setPosition( tempVec.fromArray( transformData.translation ) );\n\n\tif ( transformData.preRotation ) {\n\n\t\tconst array = transformData.preRotation.map( MathUtils.degToRad );\n\t\tarray.push( transformData.eulerOrder || Euler.DEFAULT_ORDER );\n\t\tlPreRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );\n\n\t}\n\n\tif ( transformData.rotation ) {\n\n\t\tconst array = transformData.rotation.map( MathUtils.degToRad );\n\t\tarray.push( transformData.eulerOrder || Euler.DEFAULT_ORDER );\n\t\tlRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );\n\n\t}\n\n\tif ( transformData.postRotation ) {\n\n\t\tconst array = transformData.postRotation.map( MathUtils.degToRad );\n\t\tarray.push( transformData.eulerOrder || Euler.DEFAULT_ORDER );\n\t\tlPostRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );\n\t\tlPostRotationM.invert();\n\n\t}\n\n\tif ( transformData.scale ) lScalingM.scale( tempVec.fromArray( transformData.scale ) );\n\n\t// Pivots and offsets\n\tif ( transformData.scalingOffset ) lScalingOffsetM.setPosition( tempVec.fromArray( transformData.scalingOffset ) );\n\tif ( transformData.scalingPivot ) lScalingPivotM.setPosition( tempVec.fromArray( transformData.scalingPivot ) );\n\tif ( transformData.rotationOffset ) lRotationOffsetM.setPosition( tempVec.fromArray( transformData.rotationOffset ) );\n\tif ( transformData.rotationPivot ) lRotationPivotM.setPosition( tempVec.fromArray( transformData.rotationPivot ) );\n\n\t// parent transform\n\tif ( transformData.parentMatrixWorld ) {\n\n\t\tlParentLX.copy( transformData.parentMatrix );\n\t\tlParentGX.copy( transformData.parentMatrixWorld );\n\n\t}\n\n\tconst lLRM = lPreRotationM.clone().multiply( lRotationM ).multiply( lPostRotationM );\n\t// Global Rotation\n\tconst lParentGRM = new Matrix4();\n\tlParentGRM.extractRotation( lParentGX );\n\n\t// Global Shear*Scaling\n\tconst lParentTM = new Matrix4();\n\tlParentTM.copyPosition( lParentGX );\n\n\tconst lParentGRSM = lParentTM.clone().invert().multiply( lParentGX );\n\tconst lParentGSM = lParentGRM.clone().invert().multiply( lParentGRSM );\n\tconst lLSM = lScalingM;\n\n\tconst lGlobalRS = new Matrix4();\n\n\tif ( inheritType === 0 ) {\n\n\t\tlGlobalRS.copy( lParentGRM ).multiply( lLRM ).multiply( lParentGSM ).multiply( lLSM );\n\n\t} else if ( inheritType === 1 ) {\n\n\t\tlGlobalRS.copy( lParentGRM ).multiply( lParentGSM ).multiply( lLRM ).multiply( lLSM );\n\n\t} else {\n\n\t\tconst lParentLSM = new Matrix4().scale( new Vector3().setFromMatrixScale( lParentLX ) );\n\t\tconst lParentLSM_inv = lParentLSM.clone().invert();\n\t\tconst lParentGSM_noLocal = lParentGSM.clone().multiply( lParentLSM_inv );\n\n\t\tlGlobalRS.copy( lParentGRM ).multiply( lLRM ).multiply( lParentGSM_noLocal ).multiply( lLSM );\n\n\t}\n\n\tconst lRotationPivotM_inv = lRotationPivotM.clone().invert();\n\tconst lScalingPivotM_inv = lScalingPivotM.clone().invert();\n\t// Calculate the local transform matrix\n\tlet lTransform = lTranslationM.clone().multiply( lRotationOffsetM ).multiply( lRotationPivotM ).multiply( lPreRotationM ).multiply( lRotationM ).multiply( lPostRotationM ).multiply( lRotationPivotM_inv ).multiply( lScalingOffsetM ).multiply( lScalingPivotM ).multiply( lScalingM ).multiply( lScalingPivotM_inv );\n\n\tconst lLocalTWithAllPivotAndOffsetInfo = new Matrix4().copyPosition( lTransform );\n\n\tconst lGlobalTranslation = lParentGX.clone().multiply( lLocalTWithAllPivotAndOffsetInfo );\n\tlGlobalT.copyPosition( lGlobalTranslation );\n\n\tlTransform = lGlobalT.clone().multiply( lGlobalRS );\n\n\t// from global to local\n\tlTransform.premultiply( lParentGX.invert() );\n\n\treturn lTransform;\n\n}\n\n// Returns the three.js intrinsic Euler order corresponding to FBX extrinsic Euler order\n// ref: http://help.autodesk.com/view/FBX/2017/ENU/?guid=__cpp_ref_class_fbx_euler_html\nfunction getEulerOrder( order ) {\n\n\torder = order || 0;\n\n\tconst enums = [\n\t\t'ZYX', // -> XYZ extrinsic\n\t\t'YZX', // -> XZY extrinsic\n\t\t'XZY', // -> YZX extrinsic\n\t\t'ZXY', // -> YXZ extrinsic\n\t\t'YXZ', // -> ZXY extrinsic\n\t\t'XYZ', // -> ZYX extrinsic\n\t\t//'SphericXYZ', // not possible to support\n\t];\n\n\tif ( order === 6 ) {\n\n\t\tconsole.warn( 'THREE.FBXLoader: unsupported Euler Order: Spherical XYZ. Animations and rotations may be incorrect.' );\n\t\treturn enums[ 0 ];\n\n\t}\n\n\treturn enums[ order ];\n\n}\n\n// Parses comma separated list of numbers and returns them an array.\n// Used internally by the TextParser\nfunction parseNumberArray( value ) {\n\n\tconst array = value.split( ',' ).map( function ( val ) {\n\n\t\treturn parseFloat( val );\n\n\t} );\n\n\treturn array;\n\n}\n\nfunction convertArrayBufferToString( buffer, from, to ) {\n\n\tif ( from === undefined ) from = 0;\n\tif ( to === undefined ) to = buffer.byteLength;\n\n\treturn new TextDecoder().decode( new Uint8Array( buffer, from, to ) );\n\n}\n\nfunction append( a, b ) {\n\n\tfor ( let i = 0, j = a.length, l = b.length; i < l; i ++, j ++ ) {\n\n\t\ta[ j ] = b[ i ];\n\n\t}\n\n}\n\nfunction slice( a, b, from, to ) {\n\n\tfor ( let i = from, j = 0; i < to; i ++, j ++ ) {\n\n\t\ta[ j ] = b[ i ];\n\n\t}\n\n\treturn a;\n\n}\n\n\nexport { FBXLoader };\n","import {\n\tDataTextureLoader,\n\tLinearMipmapLinearFilter\n} from 'three';\n\nclass TGALoader extends DataTextureLoader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tparse( buffer ) {\n\n\t\t// reference from vthibault, https://github.com/vthibault/roBrowser/blob/master/src/Loaders/Targa.js\n\n\t\tfunction tgaCheckHeader( header ) {\n\n\t\t\tswitch ( header.image_type ) {\n\n\t\t\t\t// check indexed type\n\n\t\t\t\tcase TGA_TYPE_INDEXED:\n\t\t\t\tcase TGA_TYPE_RLE_INDEXED:\n\t\t\t\t\tif ( header.colormap_length > 256 || header.colormap_size !== 24 || header.colormap_type !== 1 ) {\n\n\t\t\t\t\t\tthrow new Error( 'THREE.TGALoader: Invalid type colormap data for indexed type.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t\t// check colormap type\n\n\t\t\t\tcase TGA_TYPE_RGB:\n\t\t\t\tcase TGA_TYPE_GREY:\n\t\t\t\tcase TGA_TYPE_RLE_RGB:\n\t\t\t\tcase TGA_TYPE_RLE_GREY:\n\t\t\t\t\tif ( header.colormap_type ) {\n\n\t\t\t\t\t\tthrow new Error( 'THREE.TGALoader: Invalid type colormap data for colormap type.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t\t// What the need of a file without data ?\n\n\t\t\t\tcase TGA_TYPE_NO_DATA:\n\t\t\t\t\tthrow new Error( 'THREE.TGALoader: No data.' );\n\n\t\t\t\t\t// Invalid type ?\n\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error( 'THREE.TGALoader: Invalid type ' + header.image_type );\n\n\t\t\t}\n\n\t\t\t// check image width and height\n\n\t\t\tif ( header.width <= 0 || header.height <= 0 ) {\n\n\t\t\t\tthrow new Error( 'THREE.TGALoader: Invalid image size.' );\n\n\t\t\t}\n\n\t\t\t// check image pixel size\n\n\t\t\tif ( header.pixel_size !== 8 && header.pixel_size !== 16 &&\n\t\t\t\theader.pixel_size !== 24 && header.pixel_size !== 32 ) {\n\n\t\t\t\tthrow new Error( 'THREE.TGALoader: Invalid pixel size ' + header.pixel_size );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// parse tga image buffer\n\n\t\tfunction tgaParse( use_rle, use_pal, header, offset, data ) {\n\n\t\t\tlet pixel_data,\n\t\t\t\tpalettes;\n\n\t\t\tconst pixel_size = header.pixel_size >> 3;\n\t\t\tconst pixel_total = header.width * header.height * pixel_size;\n\n\t\t\t // read palettes\n\n\t\t\t if ( use_pal ) {\n\n\t\t\t\t palettes = data.subarray( offset, offset += header.colormap_length * ( header.colormap_size >> 3 ) );\n\n\t\t\t }\n\n\t\t\t // read RLE\n\n\t\t\t if ( use_rle ) {\n\n\t\t\t\t pixel_data = new Uint8Array( pixel_total );\n\n\t\t\t\tlet c, count, i;\n\t\t\t\tlet shift = 0;\n\t\t\t\tconst pixels = new Uint8Array( pixel_size );\n\n\t\t\t\twhile ( shift < pixel_total ) {\n\n\t\t\t\t\tc = data[ offset ++ ];\n\t\t\t\t\tcount = ( c & 0x7f ) + 1;\n\n\t\t\t\t\t// RLE pixels\n\n\t\t\t\t\tif ( c & 0x80 ) {\n\n\t\t\t\t\t\t// bind pixel tmp array\n\n\t\t\t\t\t\tfor ( i = 0; i < pixel_size; ++ i ) {\n\n\t\t\t\t\t\t\tpixels[ i ] = data[ offset ++ ];\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// copy pixel array\n\n\t\t\t\t\t\tfor ( i = 0; i < count; ++ i ) {\n\n\t\t\t\t\t\t\tpixel_data.set( pixels, shift + i * pixel_size );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tshift += pixel_size * count;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// raw pixels\n\n\t\t\t\t\t\tcount *= pixel_size;\n\n\t\t\t\t\t\tfor ( i = 0; i < count; ++ i ) {\n\n\t\t\t\t\t\t\tpixel_data[ shift + i ] = data[ offset ++ ];\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tshift += count;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t } else {\n\n\t\t\t\t// raw pixels\n\n\t\t\t\tpixel_data = data.subarray(\n\t\t\t\t\t offset, offset += ( use_pal ? header.width * header.height : pixel_total )\n\t\t\t\t);\n\n\t\t\t }\n\n\t\t\t return {\n\t\t\t\tpixel_data: pixel_data,\n\t\t\t\tpalettes: palettes\n\t\t\t };\n\n\t\t}\n\n\t\tfunction tgaGetImageData8bits( imageData, y_start, y_step, y_end, x_start, x_step, x_end, image, palettes ) {\n\n\t\t\tconst colormap = palettes;\n\t\t\tlet color, i = 0, x, y;\n\t\t\tconst width = header.width;\n\n\t\t\tfor ( y = y_start; y !== y_end; y += y_step ) {\n\n\t\t\t\tfor ( x = x_start; x !== x_end; x += x_step, i ++ ) {\n\n\t\t\t\t\tcolor = image[ i ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 3 ] = 255;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 2 ] = colormap[ ( color * 3 ) + 0 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 1 ] = colormap[ ( color * 3 ) + 1 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 0 ] = colormap[ ( color * 3 ) + 2 ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn imageData;\n\n\t\t}\n\n\t\tfunction tgaGetImageData16bits( imageData, y_start, y_step, y_end, x_start, x_step, x_end, image ) {\n\n\t\t\tlet color, i = 0, x, y;\n\t\t\tconst width = header.width;\n\n\t\t\tfor ( y = y_start; y !== y_end; y += y_step ) {\n\n\t\t\t\tfor ( x = x_start; x !== x_end; x += x_step, i += 2 ) {\n\n\t\t\t\t\tcolor = image[ i + 0 ] + ( image[ i + 1 ] << 8 );\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 0 ] = ( color & 0x7C00 ) >> 7;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 1 ] = ( color & 0x03E0 ) >> 2;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 2 ] = ( color & 0x001F ) << 3;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 3 ] = ( color & 0x8000 ) ? 0 : 255;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn imageData;\n\n\t\t}\n\n\t\tfunction tgaGetImageData24bits( imageData, y_start, y_step, y_end, x_start, x_step, x_end, image ) {\n\n\t\t\tlet i = 0, x, y;\n\t\t\tconst width = header.width;\n\n\t\t\tfor ( y = y_start; y !== y_end; y += y_step ) {\n\n\t\t\t\tfor ( x = x_start; x !== x_end; x += x_step, i += 3 ) {\n\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 3 ] = 255;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 2 ] = image[ i + 0 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 1 ] = image[ i + 1 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 0 ] = image[ i + 2 ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn imageData;\n\n\t\t}\n\n\t\tfunction tgaGetImageData32bits( imageData, y_start, y_step, y_end, x_start, x_step, x_end, image ) {\n\n\t\t\tlet i = 0, x, y;\n\t\t\tconst width = header.width;\n\n\t\t\tfor ( y = y_start; y !== y_end; y += y_step ) {\n\n\t\t\t\tfor ( x = x_start; x !== x_end; x += x_step, i += 4 ) {\n\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 2 ] = image[ i + 0 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 1 ] = image[ i + 1 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 0 ] = image[ i + 2 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 3 ] = image[ i + 3 ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn imageData;\n\n\t\t}\n\n\t\tfunction tgaGetImageDataGrey8bits( imageData, y_start, y_step, y_end, x_start, x_step, x_end, image ) {\n\n\t\t\tlet color, i = 0, x, y;\n\t\t\tconst width = header.width;\n\n\t\t\tfor ( y = y_start; y !== y_end; y += y_step ) {\n\n\t\t\t\tfor ( x = x_start; x !== x_end; x += x_step, i ++ ) {\n\n\t\t\t\t\tcolor = image[ i ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 0 ] = color;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 1 ] = color;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 2 ] = color;\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 3 ] = 255;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn imageData;\n\n\t\t}\n\n\t\tfunction tgaGetImageDataGrey16bits( imageData, y_start, y_step, y_end, x_start, x_step, x_end, image ) {\n\n\t\t\tlet i = 0, x, y;\n\t\t\tconst width = header.width;\n\n\t\t\tfor ( y = y_start; y !== y_end; y += y_step ) {\n\n\t\t\t\tfor ( x = x_start; x !== x_end; x += x_step, i += 2 ) {\n\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 0 ] = image[ i + 0 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 1 ] = image[ i + 0 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 2 ] = image[ i + 0 ];\n\t\t\t\t\timageData[ ( x + width * y ) * 4 + 3 ] = image[ i + 1 ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn imageData;\n\n\t\t}\n\n\t\tfunction getTgaRGBA( data, width, height, image, palette ) {\n\n\t\t\tlet x_start,\n\t\t\t\ty_start,\n\t\t\t\tx_step,\n\t\t\t\ty_step,\n\t\t\t\tx_end,\n\t\t\t\ty_end;\n\n\t\t\tswitch ( ( header.flags & TGA_ORIGIN_MASK ) >> TGA_ORIGIN_SHIFT ) {\n\n\t\t\t\tdefault:\n\t\t\t\tcase TGA_ORIGIN_UL:\n\t\t\t\t\tx_start = 0;\n\t\t\t\t\tx_step = 1;\n\t\t\t\t\tx_end = width;\n\t\t\t\t\ty_start = 0;\n\t\t\t\t\ty_step = 1;\n\t\t\t\t\ty_end = height;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase TGA_ORIGIN_BL:\n\t\t\t\t\tx_start = 0;\n\t\t\t\t\tx_step = 1;\n\t\t\t\t\tx_end = width;\n\t\t\t\t\ty_start = height - 1;\n\t\t\t\t\ty_step = - 1;\n\t\t\t\t\ty_end = - 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase TGA_ORIGIN_UR:\n\t\t\t\t\tx_start = width - 1;\n\t\t\t\t\tx_step = - 1;\n\t\t\t\t\tx_end = - 1;\n\t\t\t\t\ty_start = 0;\n\t\t\t\t\ty_step = 1;\n\t\t\t\t\ty_end = height;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase TGA_ORIGIN_BR:\n\t\t\t\t\tx_start = width - 1;\n\t\t\t\t\tx_step = - 1;\n\t\t\t\t\tx_end = - 1;\n\t\t\t\t\ty_start = height - 1;\n\t\t\t\t\ty_step = - 1;\n\t\t\t\t\ty_end = - 1;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( use_grey ) {\n\n\t\t\t\tswitch ( header.pixel_size ) {\n\n\t\t\t\t\tcase 8:\n\t\t\t\t\t\ttgaGetImageDataGrey8bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 16:\n\t\t\t\t\t\ttgaGetImageDataGrey16bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new Error( 'THREE.TGALoader: Format not supported.' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tswitch ( header.pixel_size ) {\n\n\t\t\t\t\tcase 8:\n\t\t\t\t\t\ttgaGetImageData8bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image, palette );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 16:\n\t\t\t\t\t\ttgaGetImageData16bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 24:\n\t\t\t\t\t\ttgaGetImageData24bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 32:\n\t\t\t\t\t\ttgaGetImageData32bits( data, y_start, y_step, y_end, x_start, x_step, x_end, image );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new Error( 'THREE.TGALoader: Format not supported.' );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Load image data according to specific method\n\t\t\t// let func = 'tgaGetImageData' + (use_grey ? 'Grey' : '') + (header.pixel_size) + 'bits';\n\t\t\t// func(data, y_start, y_step, y_end, x_start, x_step, x_end, width, image, palette );\n\t\t\treturn data;\n\n\t\t}\n\n\t\t// TGA constants\n\n\t\tconst TGA_TYPE_NO_DATA = 0,\n\t\t\tTGA_TYPE_INDEXED = 1,\n\t\t\tTGA_TYPE_RGB = 2,\n\t\t\tTGA_TYPE_GREY = 3,\n\t\t\tTGA_TYPE_RLE_INDEXED = 9,\n\t\t\tTGA_TYPE_RLE_RGB = 10,\n\t\t\tTGA_TYPE_RLE_GREY = 11,\n\n\t\t\tTGA_ORIGIN_MASK = 0x30,\n\t\t\tTGA_ORIGIN_SHIFT = 0x04,\n\t\t\tTGA_ORIGIN_BL = 0x00,\n\t\t\tTGA_ORIGIN_BR = 0x01,\n\t\t\tTGA_ORIGIN_UL = 0x02,\n\t\t\tTGA_ORIGIN_UR = 0x03;\n\n\t\tif ( buffer.length < 19 ) throw new Error( 'THREE.TGALoader: Not enough data to contain header.' );\n\n\t\tlet offset = 0;\n\n\t\tconst content = new Uint8Array( buffer ),\n\t\t\theader = {\n\t\t\t\tid_length: content[ offset ++ ],\n\t\t\t\tcolormap_type: content[ offset ++ ],\n\t\t\t\timage_type: content[ offset ++ ],\n\t\t\t\tcolormap_index: content[ offset ++ ] | content[ offset ++ ] << 8,\n\t\t\t\tcolormap_length: content[ offset ++ ] | content[ offset ++ ] << 8,\n\t\t\t\tcolormap_size: content[ offset ++ ],\n\t\t\t\torigin: [\n\t\t\t\t\tcontent[ offset ++ ] | content[ offset ++ ] << 8,\n\t\t\t\t\tcontent[ offset ++ ] | content[ offset ++ ] << 8\n\t\t\t\t],\n\t\t\t\twidth: content[ offset ++ ] | content[ offset ++ ] << 8,\n\t\t\t\theight: content[ offset ++ ] | content[ offset ++ ] << 8,\n\t\t\t\tpixel_size: content[ offset ++ ],\n\t\t\t\tflags: content[ offset ++ ]\n\t\t\t};\n\n\t\t// check tga if it is valid format\n\n\t\ttgaCheckHeader( header );\n\n\t\tif ( header.id_length + offset > buffer.length ) {\n\n\t\t\tthrow new Error( 'THREE.TGALoader: No data.' );\n\n\t\t}\n\n\t\t// skip the needn't data\n\n\t\toffset += header.id_length;\n\n\t\t// get targa information about RLE compression and palette\n\n\t\tlet use_rle = false,\n\t\t\tuse_pal = false,\n\t\t\tuse_grey = false;\n\n\t\tswitch ( header.image_type ) {\n\n\t\t\tcase TGA_TYPE_RLE_INDEXED:\n\t\t\t\tuse_rle = true;\n\t\t\t\tuse_pal = true;\n\t\t\t\tbreak;\n\n\t\t\tcase TGA_TYPE_INDEXED:\n\t\t\t\tuse_pal = true;\n\t\t\t\tbreak;\n\n\t\t\tcase TGA_TYPE_RLE_RGB:\n\t\t\t\tuse_rle = true;\n\t\t\t\tbreak;\n\n\t\t\tcase TGA_TYPE_RGB:\n\t\t\t\tbreak;\n\n\t\t\tcase TGA_TYPE_RLE_GREY:\n\t\t\t\tuse_rle = true;\n\t\t\t\tuse_grey = true;\n\t\t\t\tbreak;\n\n\t\t\tcase TGA_TYPE_GREY:\n\t\t\t\tuse_grey = true;\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\t//\n\n\t\tconst imageData = new Uint8Array( header.width * header.height * 4 );\n\t\tconst result = tgaParse( use_rle, use_pal, header, offset, content );\n\t\tgetTgaRGBA( imageData, header.width, header.height, result.pixel_data, result.palettes );\n\n\t\treturn {\n\n\t\t\tdata: imageData,\n\t\t\twidth: header.width,\n\t\t\theight: header.height,\n\t\t\tflipY: true,\n\t\t\tgenerateMipmaps: true,\n\t\t\tminFilter: LinearMipmapLinearFilter,\n\n\t\t};\n\n\t}\n\n}\n\nexport { TGALoader };\n","// 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 = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","require('./src/controls');\nrequire('./src/loaders');\nrequire('./src/misc');\nrequire('./src/pathfinding');\nrequire('./src/primitives');\n"],"names":[],"sourceRoot":""}