File: C:/Python311/Lib/site-packages/notebook/static/8929.f522b600b8907f9241c6.js.map
{"version":3,"file":"8929.f522b600b8907f9241c6.js?v=f522b600b8907f9241c6","mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAsE;AACjB;AACb;AACW;AACR;AACqB;AACI;AAChB;;AAEpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,mEAAiB;AACrC;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,mEAAiB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,sDAAQ;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,wDAAwD;AAC/E;AACA;AACA;AACA;AACA;AACA;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,sDAAQ;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,wDAAwD;AAC/E;AACA;AACA;AACA;AACA;AACA;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,sDAAQ;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,wDAAwD;AAC/E;AACA;AACA;AACA;AACA;AACA;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,sDAAQ;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,wDAAwD;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,sDAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,wDAAwD;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,sDAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,wDAAwD;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,UAAU;AAC5C,sCAAsC,UAAU;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,sDAAQ;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,oCAAoC;;AAErC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2DAA2D,OAAO;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC;AACvC;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC;AACrC;AACA;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAyC;AACzC;AACA;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C;AAC3C;AACA;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C;AAC1C;AACA;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C;AAC3C;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C;AAC3C;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C;AAC5C;AACA;AACA,kBAAkB,OAAO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,oCAAoC;AACrC;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,KAAK;AACL,CAAC,8BAA8B;;AAE/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B;AAC5B;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2DAA2D,OAAO;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,eAAe;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,wBAAwB,eAAe;AACvC;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,4BAA4B;AAC5B;AACA,wBAAwB,6BAA6B;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,eAAe;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,eAAe;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,eAAe;AACtD;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,eAAe;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,6BAA6B;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,8BAA8B;;AAE/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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,mBAAmB;AACjC;AACA;AACA;AACA,gBAAgB,sBAAsB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,sDAAQ;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,2BAA2B,kDAAI;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,gDAAgD;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,kDAAI;AAC/B;AACA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,kDAAI;AAC/B;AACA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,kDAAI;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,qCAAqC;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,gDAAgD;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,SAAS;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;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,cAAc,SAAS;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,gDAAgD;AACvE;AACA;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,mBAAmB;AACjC;AACA;AACA;AACA,cAAc,sBAAsB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,UAAU;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,sBAAsB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,gDAAgD;AACvE;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,8BAA8B;;AAE/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,qDAAM;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;AACA;AACA,eAAe,uDAAI;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,uDAAI;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,uDAAI;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,cAAc,SAAS;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,SAAS;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,8BAA8B;;AAE/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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,iDAAiD;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,gBAAgB;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD,OAAO;AAC5D;AACA,kBAAkB,iBAAiB;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,sCAAsC;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D,eAAe;AAC5E;AACA;AACA;AACA;AACA;AACA,0DAA0D,eAAe;AACzE;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;AACA,oDAAoD,SAAS;AAC7D;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD,SAAS;AAChE;AACA;AACA;AACA;AACA;AACA,oDAAoD,SAAS;AAC7D;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,qDAAM;AACtC;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,cAAc;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,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oGAAoG,IAAI;AACxG;AACA;AACA,4EAA4E,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,GAAG;AAC3I;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,oBAAoB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,mBAAmB;AAC1D;AACA;AACA,uCAAuC,mBAAmB;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,cAAc;AACtD;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,SAAS;AACT;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,mEAAiB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,EAAE,GAAG,EAAE,GAAG,EAAE;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,mEAAiB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,mEAAiB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,iCAAiC;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,yCAAyC;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,mEAAiB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,cAAc;AACtC;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,gBAAgB,mEAAiB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,mDAAM;AACrC;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iCAAiC;AACrD;AACA;AACA,yBAAyB,mDAAM;AAC/B;AACA;AACA;AACA,YAAY,mDAAM;AAClB;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,yEAAyE;AAC9E,CAAC,gCAAgC;;AAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,IAAI,GAAG,yBAAyB;AAC1D;AACA;AACA,2BAA2B,IAAI,GAAG,MAAM;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,qDAAM;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,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C;AAC9C,CAAC,8BAA8B;;AAE/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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,8BAA8B;;AAE/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;AAC3B,4BAA4B,qDAAM;AAClC,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB,yBAAyB;AACzB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,OAAO;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,uDAAQ,6BAA6B,qBAAqB;AACtE;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,uDAAQ,6BAA6B,qBAAqB;AACtE;AACA;AACA;AACA;AACA;AACA,uDAAuD,OAAO;AAC9D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACxB;AACA,4CAA4C,OAAO;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACxB;AACA,gBAAgB,uDAAQ;AACxB;AACA;AACA;AACA;AACA,4CAA4C,OAAO;AACnD;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD,OAAO;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,uDAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,uDAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,uDAAQ;AACzB;AACA;AACA,YAAY,uDAAQ;AACpB;AACA;AACA,yBAAyB,SAAS;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,8BAA8B;;AAE/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,mDAAM;AAC7B;AACA;AACA;AACA;AACA;AACA,4BAA4B;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,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT;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;AACA,6BAA6B,mDAAM;AACnC;AACA;AACA,+BAA+B,sDAAS,GAAG,yBAAyB;AACpE,+BAA+B,sDAAS,GAAG,2BAA2B;AACtE,iCAAiC,mDAAM;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;AACnB,QAAQ,0DAAW;AACnB,QAAQ,0DAAW;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,uDAAU,iCAAiC,mBAAmB;AACtE,QAAQ,uDAAU,mCAAmC,mBAAmB;AACxE,QAAQ,uDAAU,mCAAmC,mBAAmB;AACxE,QAAQ,uDAAU,qCAAqC,mBAAmB;AAC1E;AACA,yBAAyB,uDAAU;AACnC;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,YAAY;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,SAAS;AACvB;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,SAAS;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,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,iBAAiB;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC,WAAW;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,cAAc;AACtC;AACA;AACA;AACA,4BAA4B,cAAc;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAY;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,wDAAU;AACtC,4BAA4B,wDAAU;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,qBAAqB;AACxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;AACnB;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,oCAAoC;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,2BAA2B;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0CAA0C,sBAAsB;AAChE;AACA;AACA;AACA,0CAA0C,sBAAsB;AAChE;AACA;AACA;AACA;AACA,2CAA2C,sBAAsB;AACjE;AACA;AACA;AACA,2CAA2C,sBAAsB;AACjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,sBAAsB;AACjE;AACA;AACA;AACA,2CAA2C,sBAAsB;AACjE;AACA;AACA;AACA;AACA,4CAA4C,sBAAsB;AAClE;AACA;AACA;AACA,4CAA4C,sBAAsB;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,0DAAW,mBAAmB,mDAAM;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,gBAAgB;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,yBAAyB;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,0DAAW;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;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,sBAAsB;AACpC;AACA;AACA;AACA;AACA;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,sBAAsB;AACpC;AACA;AACA;AACA;AACA;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,sBAAsB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,sBAAsB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,mCAAmC;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,mCAAmC;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,2CAA2C;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,sDAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC,oCAAoC;AAC1E,uCAAuC,qCAAqC;AAC5E;AACA,uCAAuC,qCAAqC;AAC5E,wCAAwC,sCAAsC;AAC9E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,qBAAqB;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,aAAa;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,oBAAoB;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,aAAa;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;AAClC;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;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;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;AAClC;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;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,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;AAClC;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;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,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;AAClC;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;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,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,yBAAyB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4DAA4D,OAAO;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+DAA+D,OAAO;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+DAA+D,OAAO;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gEAAgE,OAAO;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,eAAe;AAClD;AACA;AACA;AACA,mCAAmC,eAAe;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,OAAO;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,OAAO;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8FAA8F,oCAAoC;AAClI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,SAAS;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0FAA0F,0DAA0D;AACpJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,4BAA4B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,iEAAkB;AAClD;AACA;AACA;AACA,sCAAsC,iEAAkB;AACxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,iEAAkB;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,iEAAkB;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC,iEAAkB;AACxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,8BAA8B;;AAE/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,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,CAAC,0BAA0B;;AAE3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B;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,kCAAkC,8DAAe;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEsiB;AACtiB","sources":["webpack://_JUPYTERLAB.CORE_OUTPUT/../node_modules/@lumino/datagrid/dist/index.es6.js"],"sourcesContent":["import { Platform, ClipboardExt, ElementExt } from '@lumino/domutils';\nimport { getKeyboardLayout } from '@lumino/keyboard';\nimport { Drag } from '@lumino/dragdrop';\nimport { some, ArrayExt } from '@lumino/algorithm';\nimport { Signal } from '@lumino/signaling';\nimport { Widget, ScrollBar, GridLayout } from '@lumino/widgets';\nimport { ConflatableMessage, MessageLoop } from '@lumino/messaging';\nimport { PromiseDelegate } from '@lumino/coreutils';\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * A basic implementation of a data grid key handler.\n *\n * #### Notes\n * This class may be subclassed and customized as needed.\n */\nclass BasicKeyHandler {\n constructor() {\n this._disposed = false;\n }\n /**\n * Whether the key handler is disposed.\n */\n get isDisposed() {\n return this._disposed;\n }\n /**\n * Dispose of the resources held by the key handler.\n */\n dispose() {\n this._disposed = true;\n }\n /**\n * Handle the key down event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keydown event of interest.\n *\n * #### Notes\n * This will not be called if the mouse button is pressed.\n */\n onKeyDown(grid, event) {\n // if grid is editable and cell selection available, start cell editing\n // on key press (letters, numbers and space only)\n if (grid.editable &&\n grid.selectionModel.cursorRow !== -1 &&\n grid.selectionModel.cursorColumn !== -1) {\n const input = String.fromCharCode(event.keyCode);\n if (/[a-zA-Z0-9-_ ]/.test(input)) {\n const row = grid.selectionModel.cursorRow;\n const column = grid.selectionModel.cursorColumn;\n const cell = {\n grid: grid,\n row: row,\n column: column\n };\n grid.editorController.edit(cell);\n if (getKeyboardLayout().keyForKeydownEvent(event) === 'Space') {\n event.stopPropagation();\n event.preventDefault();\n }\n return;\n }\n }\n switch (getKeyboardLayout().keyForKeydownEvent(event)) {\n case 'ArrowLeft':\n this.onArrowLeft(grid, event);\n break;\n case 'ArrowRight':\n this.onArrowRight(grid, event);\n break;\n case 'ArrowUp':\n this.onArrowUp(grid, event);\n break;\n case 'ArrowDown':\n this.onArrowDown(grid, event);\n break;\n case 'PageUp':\n this.onPageUp(grid, event);\n break;\n case 'PageDown':\n this.onPageDown(grid, event);\n break;\n case 'Escape':\n this.onEscape(grid, event);\n break;\n case 'Delete':\n this.onDelete(grid, event);\n break;\n case 'C':\n this.onKeyC(grid, event);\n break;\n case 'Enter':\n if (grid.selectionModel) {\n grid.moveCursor(event.shiftKey ? 'up' : 'down');\n grid.scrollToCursor();\n }\n break;\n case 'Tab':\n if (grid.selectionModel) {\n grid.moveCursor(event.shiftKey ? 'left' : 'right');\n grid.scrollToCursor();\n event.stopPropagation();\n event.preventDefault();\n }\n break;\n }\n }\n /**\n * Handle the `'ArrowLeft'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onArrowLeft(grid, event) {\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Fetch the modifier flags.\n let shift = event.shiftKey;\n let accel = Platform.accelKey(event);\n // Handle no model with the accel modifier.\n if (!model && accel) {\n grid.scrollTo(0, grid.scrollY);\n return;\n }\n // Handle no model and no modifier. (ignore shift)\n if (!model) {\n grid.scrollByStep('left');\n return;\n }\n // Fetch the selection mode.\n let mode = model.selectionMode;\n // Handle the row selection mode with accel key.\n if (mode === 'row' && accel) {\n grid.scrollTo(0, grid.scrollY);\n return;\n }\n // Handle the row selection mode with no modifier. (ignore shift)\n if (mode === 'row') {\n grid.scrollByStep('left');\n return;\n }\n // Fetch the cursor and selection.\n let r = model.cursorRow;\n let c = model.cursorColumn;\n let cs = model.currentSelection();\n // Set up the selection variables.\n let r1;\n let r2;\n let c1;\n let c2;\n let cr;\n let cc;\n let clear;\n // Dispatch based on the modifier keys.\n if (accel && shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 - 1 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (accel) {\n r1 = r;\n r2 = r;\n c1 = 0;\n c2 = 0;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n else {\n r1 = r;\n r2 = r;\n c1 = c - 1;\n c2 = c - 1;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n // Create the new selection.\n model.select({ r1, c1, r2, c2, cursorRow: cr, cursorColumn: cc, clear });\n // Re-fetch the current selection.\n cs = model.currentSelection();\n // Bail if there is no selection.\n if (!cs) {\n return;\n }\n // Scroll the grid appropriately.\n if (shift || mode === 'column') {\n grid.scrollToColumn(cs.c2);\n }\n else {\n grid.scrollToCursor();\n }\n }\n /**\n * Handle the `'ArrowRight'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onArrowRight(grid, event) {\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Fetch the modifier flags.\n let shift = event.shiftKey;\n let accel = Platform.accelKey(event);\n // Handle no model with the accel modifier.\n if (!model && accel) {\n grid.scrollTo(grid.maxScrollX, grid.scrollY);\n return;\n }\n // Handle no model and no modifier. (ignore shift)\n if (!model) {\n grid.scrollByStep('right');\n return;\n }\n // Fetch the selection mode.\n let mode = model.selectionMode;\n // Handle the row selection model with accel key.\n if (mode === 'row' && accel) {\n grid.scrollTo(grid.maxScrollX, grid.scrollY);\n return;\n }\n // Handle the row selection mode with no modifier. (ignore shift)\n if (mode === 'row') {\n grid.scrollByStep('right');\n return;\n }\n // Fetch the cursor and selection.\n let r = model.cursorRow;\n let c = model.cursorColumn;\n let cs = model.currentSelection();\n // Set up the selection variables.\n let r1;\n let r2;\n let c1;\n let c2;\n let cr;\n let cc;\n let clear;\n // Dispatch based on the modifier keys.\n if (accel && shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = Infinity;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 + 1 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (accel) {\n r1 = r;\n r2 = r;\n c1 = Infinity;\n c2 = Infinity;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n else {\n r1 = r;\n r2 = r;\n c1 = c + 1;\n c2 = c + 1;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n // Create the new selection.\n model.select({ r1, c1, r2, c2, cursorRow: cr, cursorColumn: cc, clear });\n // Re-fetch the current selection.\n cs = model.currentSelection();\n // Bail if there is no selection.\n if (!cs) {\n return;\n }\n // Scroll the grid appropriately.\n if (shift || mode === 'column') {\n grid.scrollToColumn(cs.c2);\n }\n else {\n grid.scrollToCursor();\n }\n }\n /**\n * Handle the `'ArrowUp'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onArrowUp(grid, event) {\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Fetch the modifier flags.\n let shift = event.shiftKey;\n let accel = Platform.accelKey(event);\n // Handle no model with the accel modifier.\n if (!model && accel) {\n grid.scrollTo(grid.scrollX, 0);\n return;\n }\n // Handle no model and no modifier. (ignore shift)\n if (!model) {\n grid.scrollByStep('up');\n return;\n }\n // Fetch the selection mode.\n let mode = model.selectionMode;\n // Handle the column selection mode with accel key.\n if (mode === 'column' && accel) {\n grid.scrollTo(grid.scrollX, 0);\n return;\n }\n // Handle the column selection mode with no modifier. (ignore shift)\n if (mode === 'column') {\n grid.scrollByStep('up');\n return;\n }\n // Fetch the cursor and selection.\n let r = model.cursorRow;\n let c = model.cursorColumn;\n let cs = model.currentSelection();\n // Set up the selection variables.\n let r1;\n let r2;\n let c1;\n let c2;\n let cr;\n let cc;\n let clear;\n // Dispatch based on the modifier keys.\n if (accel && shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = 0;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 - 1 : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (accel) {\n r1 = 0;\n r2 = 0;\n c1 = c;\n c2 = c;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n else {\n r1 = r - 1;\n r2 = r - 1;\n c1 = c;\n c2 = c;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n // Create the new selection.\n model.select({ r1, c1, r2, c2, cursorRow: cr, cursorColumn: cc, clear });\n // Re-fetch the current selection.\n cs = model.currentSelection();\n // Bail if there is no selection.\n if (!cs) {\n return;\n }\n // Scroll the grid appropriately.\n if (shift || mode === 'row') {\n grid.scrollToRow(cs.r2);\n }\n else {\n grid.scrollToCursor();\n }\n }\n /**\n * Handle the `'ArrowDown'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onArrowDown(grid, event) {\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Fetch the modifier flags.\n let shift = event.shiftKey;\n let accel = Platform.accelKey(event);\n // Handle no model with the accel modifier.\n if (!model && accel) {\n grid.scrollTo(grid.scrollX, grid.maxScrollY);\n return;\n }\n // Handle no model and no modifier. (ignore shift)\n if (!model) {\n grid.scrollByStep('down');\n return;\n }\n // Fetch the selection mode.\n let mode = model.selectionMode;\n // Handle the column selection mode with accel key.\n if (mode === 'column' && accel) {\n grid.scrollTo(grid.scrollX, grid.maxScrollY);\n return;\n }\n // Handle the column selection mode with no modifier. (ignore shift)\n if (mode === 'column') {\n grid.scrollByStep('down');\n return;\n }\n // Fetch the cursor and selection.\n let r = model.cursorRow;\n let c = model.cursorColumn;\n let cs = model.currentSelection();\n // Set up the selection variables.\n let r1;\n let r2;\n let c1;\n let c2;\n let cr;\n let cc;\n let clear;\n // Dispatch based on the modifier keys.\n if (accel && shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = Infinity;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (shift) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 + 1 : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else if (accel) {\n r1 = Infinity;\n r2 = Infinity;\n c1 = c;\n c2 = c;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n else {\n r1 = r + 1;\n r2 = r + 1;\n c1 = c;\n c2 = c;\n cr = r1;\n cc = c1;\n clear = 'all';\n }\n // Create the new selection.\n model.select({ r1, c1, r2, c2, cursorRow: cr, cursorColumn: cc, clear });\n // Re-fetch the current selection.\n cs = model.currentSelection();\n // Bail if there is no selection.\n if (!cs) {\n return;\n }\n // Scroll the grid appropriately.\n if (shift || mode === 'row') {\n grid.scrollToRow(cs.r2);\n }\n else {\n grid.scrollToCursor();\n }\n }\n /**\n * Handle the `'PageUp'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onPageUp(grid, event) {\n // Ignore the event if the accel key is pressed.\n if (Platform.accelKey(event)) {\n return;\n }\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Scroll by page if there is no selection model.\n if (!model || model.selectionMode === 'column') {\n grid.scrollByPage('up');\n return;\n }\n // Get the normal number of cells in the page height.\n let n = Math.floor(grid.pageHeight / grid.defaultSizes.rowHeight);\n // Fetch the cursor and selection.\n let r = model.cursorRow;\n let c = model.cursorColumn;\n let cs = model.currentSelection();\n // Set up the selection variables.\n let r1;\n let r2;\n let c1;\n let c2;\n let cr;\n let cc;\n let clear;\n // Select or resize as needed.\n if (event.shiftKey) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 - n : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else {\n r1 = cs ? cs.r1 - n : 0;\n r2 = r1;\n c1 = c;\n c2 = c;\n cr = r1;\n cc = c;\n clear = 'all';\n }\n // Create the new selection.\n model.select({ r1, c1, r2, c2, cursorRow: cr, cursorColumn: cc, clear });\n // Re-fetch the current selection.\n cs = model.currentSelection();\n // Bail if there is no selection.\n if (!cs) {\n return;\n }\n // Scroll the grid appropriately.\n grid.scrollToRow(cs.r2);\n }\n /**\n * Handle the `'PageDown'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onPageDown(grid, event) {\n // Ignore the event if the accel key is pressed.\n if (Platform.accelKey(event)) {\n return;\n }\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Scroll by page if there is no selection model.\n if (!model || model.selectionMode === 'column') {\n grid.scrollByPage('down');\n return;\n }\n // Get the normal number of cells in the page height.\n let n = Math.floor(grid.pageHeight / grid.defaultSizes.rowHeight);\n // Fetch the cursor and selection.\n let r = model.cursorRow;\n let c = model.cursorColumn;\n let cs = model.currentSelection();\n // Set up the selection variables.\n let r1;\n let r2;\n let c1;\n let c2;\n let cr;\n let cc;\n let clear;\n // Select or resize as needed.\n if (event.shiftKey) {\n r1 = cs ? cs.r1 : 0;\n r2 = cs ? cs.r2 + n : 0;\n c1 = cs ? cs.c1 : 0;\n c2 = cs ? cs.c2 : 0;\n cr = r;\n cc = c;\n clear = 'current';\n }\n else {\n r1 = cs ? cs.r1 + n : 0;\n r2 = r1;\n c1 = c;\n c2 = c;\n cr = r1;\n cc = c;\n clear = 'all';\n }\n // Create the new selection.\n model.select({ r1, c1, r2, c2, cursorRow: cr, cursorColumn: cc, clear });\n // Re-fetch the current selection.\n cs = model.currentSelection();\n // Bail if there is no selection.\n if (!cs) {\n return;\n }\n // Scroll the grid appropriately.\n grid.scrollToRow(cs.r2);\n }\n /**\n * Handle the `'Escape'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onEscape(grid, event) {\n if (grid.selectionModel) {\n grid.selectionModel.clear();\n }\n }\n /**\n * Handle the `'Delete'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onDelete(grid, event) {\n if (grid.editable && !grid.selectionModel.isEmpty) {\n const dataModel = grid.dataModel;\n // Fetch the max row and column.\n let maxRow = dataModel.rowCount('body') - 1;\n let maxColumn = dataModel.columnCount('body') - 1;\n for (let s of grid.selectionModel.selections()) {\n // Clamp the cell to the model bounds.\n let sr1 = Math.max(0, Math.min(s.r1, maxRow));\n let sc1 = Math.max(0, Math.min(s.c1, maxColumn));\n let sr2 = Math.max(0, Math.min(s.r2, maxRow));\n let sc2 = Math.max(0, Math.min(s.c2, maxColumn));\n for (let r = sr1; r <= sr2; ++r) {\n for (let c = sc1; c <= sc2; ++c) {\n dataModel.setData('body', r, c, null);\n }\n }\n }\n }\n }\n /**\n * Handle the `'C'` key press for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The keyboard event of interest.\n */\n onKeyC(grid, event) {\n // Bail early if the modifiers aren't correct for copy.\n if (event.shiftKey || !Platform.accelKey(event)) {\n return;\n }\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Copy the current selection to the clipboard.\n grid.copyToClipboard();\n }\n}\n\n/**\n * An object which renders the cells of a data grid.\n *\n * #### Notes\n * If the predefined cell renderers are insufficient for a particular\n * use case, a custom cell renderer can be defined which derives from\n * this class.\n *\n * The data grid renders cells in column-major order, by region. The\n * region order is: body, row header, column header, corner header.\n */\nclass CellRenderer {\n}\n/**\n * The namespace for the `CellRenderer` class statics.\n */\n(function (CellRenderer) {\n /**\n * Resolve a config option for a cell renderer.\n *\n * @param option - The config option to resolve.\n *\n * @param config - The cell config object.\n *\n * @returns The resolved value for the option.\n */\n function resolveOption(option, config) {\n return typeof option === 'function'\n ? option(config)\n : option;\n }\n CellRenderer.resolveOption = resolveOption;\n})(CellRenderer || (CellRenderer = {}));\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * A cell renderer which renders data values as text.\n */\nclass TextRenderer extends CellRenderer {\n /**\n * Construct a new text renderer.\n *\n * @param options - The options for initializing the renderer.\n */\n constructor(options = {}) {\n super();\n this.font = options.font || '12px sans-serif';\n this.textColor = options.textColor || '#000000';\n this.backgroundColor = options.backgroundColor || '';\n this.verticalAlignment = options.verticalAlignment || 'center';\n this.horizontalAlignment = options.horizontalAlignment || 'left';\n this.horizontalPadding = options.horizontalPadding || 8;\n this.format = options.format || TextRenderer.formatGeneric();\n this.elideDirection = options.elideDirection || 'none';\n this.wrapText = options.wrapText || false;\n }\n /**\n * Paint the content for a cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n paint(gc, config) {\n this.drawBackground(gc, config);\n this.drawText(gc, config);\n }\n /**\n * Draw the background for the cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n drawBackground(gc, config) {\n // Resolve the background color for the cell.\n let color = CellRenderer.resolveOption(this.backgroundColor, config);\n // Bail if there is no background color to draw.\n if (!color) {\n return;\n }\n // Fill the cell with the background color.\n gc.fillStyle = color;\n gc.fillRect(config.x, config.y, config.width, config.height);\n }\n /**\n * Get the full text to be rendered by the cell.\n */\n getText(config) {\n return this.format(config);\n }\n /**\n * Draw the text for the cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n drawText(gc, config) {\n // Resolve the font for the cell.\n let font = CellRenderer.resolveOption(this.font, config);\n // Bail if there is no font to draw.\n if (!font) {\n return;\n }\n // Resolve the text color for the cell.\n let color = CellRenderer.resolveOption(this.textColor, config);\n // Bail if there is no text color to draw.\n if (!color) {\n return;\n }\n // Format the cell value to text.\n let text = this.getText(config);\n // Bail if there is no text to draw.\n if (!text) {\n return;\n }\n // Resolve the vertical and horizontal alignment.\n let vAlign = CellRenderer.resolveOption(this.verticalAlignment, config);\n let hAlign = CellRenderer.resolveOption(this.horizontalAlignment, config);\n // Resolve the elision direction\n let elideDirection = CellRenderer.resolveOption(this.elideDirection, config);\n // Resolve the text wrapping flag\n let wrapText = CellRenderer.resolveOption(this.wrapText, config);\n // Compute the padded text box height for the specified alignment.\n let boxHeight = config.height - (vAlign === 'center' ? 1 : 2);\n // Bail if the text box has no effective size.\n if (boxHeight <= 0) {\n return;\n }\n // Compute the text height for the gc font.\n let textHeight = TextRenderer.measureFontHeight(font);\n // Set up the text position variables.\n let textX;\n let textY;\n let boxWidth;\n // Compute the Y position for the text.\n switch (vAlign) {\n case 'top':\n textY = config.y + 2 + textHeight;\n break;\n case 'center':\n textY = config.y + config.height / 2 + textHeight / 2;\n break;\n case 'bottom':\n textY = config.y + config.height - 2;\n break;\n default:\n throw 'unreachable';\n }\n // Compute the X position for the text.\n switch (hAlign) {\n case 'left':\n textX = config.x + this.horizontalPadding;\n boxWidth = config.width - 14;\n break;\n case 'center':\n textX = config.x + config.width / 2;\n boxWidth = config.width;\n break;\n case 'right':\n textX = config.x + config.width - this.horizontalPadding;\n boxWidth = config.width - 14;\n break;\n default:\n throw 'unreachable';\n }\n // Clip the cell if the text is taller than the text box height.\n if (textHeight > boxHeight) {\n gc.beginPath();\n gc.rect(config.x, config.y, config.width, config.height - 1);\n gc.clip();\n }\n // Set the gc state.\n gc.font = font;\n gc.fillStyle = color;\n gc.textAlign = hAlign;\n gc.textBaseline = 'bottom';\n // Terminate call here if we're not eliding or wrapping text\n if (elideDirection === 'none' && !wrapText) {\n gc.fillText(text, textX, textY);\n return;\n }\n // The current text width in pixels.\n let textWidth = gc.measureText(text).width;\n // Apply text wrapping if enabled.\n if (wrapText && textWidth > boxWidth) {\n // Make sure box clipping happens.\n gc.beginPath();\n gc.rect(config.x, config.y, config.width, config.height - 1);\n gc.clip();\n // Split column name to words based on\n // whitespace preceding a word boundary.\n // \"Hello world\" --> [\"Hello \", \"world\"]\n const wordsInColumn = text.split(/\\s(?=\\b)/);\n // Y-coordinate offset for any additional lines\n let curY = textY;\n let textInCurrentLine = wordsInColumn.shift();\n // Single word. Applying text wrap on word by splitting\n // it into characters and fitting the maximum number of\n // characters possible per line (box width).\n if (wordsInColumn.length === 0) {\n let curLineTextWidth = gc.measureText(textInCurrentLine).width;\n while (curLineTextWidth > boxWidth && textInCurrentLine !== '') {\n // Iterating from the end of the string until we find a\n // substring (0,i) which has a width less than the box width.\n for (let i = textInCurrentLine.length; i > 0; i--) {\n const curSubString = textInCurrentLine.substring(0, i);\n const curSubStringWidth = gc.measureText(curSubString).width;\n if (curSubStringWidth < boxWidth || curSubString.length === 1) {\n // Found a substring which has a width less than the current\n // box width. Rendering that substring on the current line\n // and setting the remainder of the parent string as the next\n // string to iterate on for the next line.\n const nextLineText = textInCurrentLine.substring(i, textInCurrentLine.length);\n textInCurrentLine = nextLineText;\n curLineTextWidth = gc.measureText(textInCurrentLine).width;\n gc.fillText(curSubString, textX, curY);\n curY += textHeight;\n // No need to continue iterating after we identified\n // an index to break the string on.\n break;\n }\n }\n }\n }\n // Multiple words in column header. Fitting maximum\n // number of words possible per line (box width).\n else {\n while (wordsInColumn.length !== 0) {\n // Processing the next word in the queue.\n const curWord = wordsInColumn.shift();\n // Joining that word with the existing text for\n // the current line.\n const incrementedText = [textInCurrentLine, curWord].join(' ');\n const incrementedTextWidth = gc.measureText(incrementedText).width;\n if (incrementedTextWidth > boxWidth) {\n // If the newly combined text has a width larger than\n // the box width, we render the line before the current\n // word was added. We set the current word as the next\n // line.\n gc.fillText(textInCurrentLine, textX, curY);\n curY += textHeight;\n textInCurrentLine = curWord;\n }\n else {\n // The combined text hasd a width less than the box width. We\n // set the the current line text to be the new combined text.\n textInCurrentLine = incrementedText;\n }\n }\n }\n gc.fillText(textInCurrentLine, textX, curY);\n // Terminating the call here as we don't want\n // to apply text eliding when wrapping is active.\n return;\n }\n // Elide text that is too long\n const elide = '\\u2026';\n // Loop until text width fits box or only one character remains\n while (textWidth > boxWidth && text.length > 1) {\n // Convert text string to array for dealing with astral symbols\n const textArr = [...text];\n if (elideDirection === 'right') {\n // If text width is substantially bigger, take half the string\n if (textArr.length > 4 && textWidth >= 2 * boxWidth) {\n text =\n textArr.slice(0, Math.floor(textArr.length / 2 + 1)).join('') +\n elide;\n }\n else {\n // Otherwise incrementally remove the last character\n text = textArr.slice(0, textArr.length - 2).join('') + elide;\n }\n }\n else {\n // If text width is substantially bigger, take half the string\n if (textArr.length > 4 && textWidth >= 2 * boxWidth) {\n text = elide + textArr.slice(Math.floor(textArr.length / 2)).join('');\n }\n else {\n // Otherwise incrementally remove the last character\n text = elide + textArr.slice(2).join('');\n }\n }\n // Measure new text width\n textWidth = gc.measureText(text).width;\n }\n // Draw the text for the cell.\n gc.fillText(text, textX, textY);\n }\n}\n/**\n * The namespace for the `TextRenderer` class statics.\n */\n(function (TextRenderer) {\n /**\n * Create a generic text format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new generic text format function.\n *\n * #### Notes\n * This formatter uses the builtin `String()` to coerce any value\n * to a string.\n */\n function formatGeneric(options = {}) {\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n return String(value);\n };\n }\n TextRenderer.formatGeneric = formatGeneric;\n /**\n * Create a fixed decimal format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new fixed decimal format function.\n *\n * #### Notes\n * This formatter uses the builtin `Number()` and `toFixed()` to\n * coerce values.\n *\n * The `formatIntlNumber()` formatter is more flexible, but slower.\n */\n function formatFixed(options = {}) {\n let digits = options.digits;\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n return Number(value).toFixed(digits);\n };\n }\n TextRenderer.formatFixed = formatFixed;\n /**\n * Create a significant figure format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new significant figure format function.\n *\n * #### Notes\n * This formatter uses the builtin `Number()` and `toPrecision()`\n * to coerce values.\n *\n * The `formatIntlNumber()` formatter is more flexible, but slower.\n */\n function formatPrecision(options = {}) {\n let digits = options.digits;\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n return Number(value).toPrecision(digits);\n };\n }\n TextRenderer.formatPrecision = formatPrecision;\n /**\n * Create a scientific notation format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new scientific notation format function.\n *\n * #### Notes\n * This formatter uses the builtin `Number()` and `toExponential()`\n * to coerce values.\n *\n * The `formatIntlNumber()` formatter is more flexible, but slower.\n */\n function formatExponential(options = {}) {\n let digits = options.digits;\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n return Number(value).toExponential(digits);\n };\n }\n TextRenderer.formatExponential = formatExponential;\n /**\n * Create an international number format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new international number format function.\n *\n * #### Notes\n * This formatter uses the builtin `Intl.NumberFormat` object to\n * coerce values.\n *\n * This is the most flexible (but slowest) number formatter.\n */\n function formatIntlNumber(options = {}) {\n let missing = options.missing || '';\n let nft = new Intl.NumberFormat(options.locales, options.options);\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n return nft.format(value);\n };\n }\n TextRenderer.formatIntlNumber = formatIntlNumber;\n /**\n * Create a date format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new date format function.\n *\n * #### Notes\n * This formatter uses `Date.toDateString()` to format the values.\n *\n * If a value is not a `Date` object, `new Date(value)` is used to\n * coerce the value to a date.\n *\n * The `formatIntlDateTime()` formatter is more flexible, but slower.\n */\n function formatDate(options = {}) {\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n if (value instanceof Date) {\n return value.toDateString();\n }\n return new Date(value).toDateString();\n };\n }\n TextRenderer.formatDate = formatDate;\n /**\n * Create a time format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new time format function.\n *\n * #### Notes\n * This formatter uses `Date.toTimeString()` to format the values.\n *\n * If a value is not a `Date` object, `new Date(value)` is used to\n * coerce the value to a date.\n *\n * The `formatIntlDateTime()` formatter is more flexible, but slower.\n */\n function formatTime(options = {}) {\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n if (value instanceof Date) {\n return value.toTimeString();\n }\n return new Date(value).toTimeString();\n };\n }\n TextRenderer.formatTime = formatTime;\n /**\n * Create an ISO datetime format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new ISO datetime format function.\n *\n * #### Notes\n * This formatter uses `Date.toISOString()` to format the values.\n *\n * If a value is not a `Date` object, `new Date(value)` is used to\n * coerce the value to a date.\n *\n * The `formatIntlDateTime()` formatter is more flexible, but slower.\n */\n function formatISODateTime(options = {}) {\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n return new Date(value).toISOString();\n };\n }\n TextRenderer.formatISODateTime = formatISODateTime;\n /**\n * Create a UTC datetime format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new UTC datetime format function.\n *\n * #### Notes\n * This formatter uses `Date.toUTCString()` to format the values.\n *\n * If a value is not a `Date` object, `new Date(value)` is used to\n * coerce the value to a date.\n *\n * The `formatIntlDateTime()` formatter is more flexible, but slower.\n */\n function formatUTCDateTime(options = {}) {\n let missing = options.missing || '';\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n if (value instanceof Date) {\n return value.toUTCString();\n }\n return new Date(value).toUTCString();\n };\n }\n TextRenderer.formatUTCDateTime = formatUTCDateTime;\n /**\n * Create an international datetime format function.\n *\n * @param options - The options for creating the format function.\n *\n * @returns A new international datetime format function.\n *\n * #### Notes\n * This formatter uses the builtin `Intl.DateTimeFormat` object to\n * coerce values.\n *\n * This is the most flexible (but slowest) datetime formatter.\n */\n function formatIntlDateTime(options = {}) {\n let missing = options.missing || '';\n let dtf = new Intl.DateTimeFormat(options.locales, options.options);\n return ({ value }) => {\n if (value === null || value === undefined) {\n return missing;\n }\n return dtf.format(value);\n };\n }\n TextRenderer.formatIntlDateTime = formatIntlDateTime;\n /**\n * Measure the height of a font.\n *\n * @param font - The CSS font string of interest.\n *\n * @returns The height of the font bounding box.\n *\n * #### Notes\n * This function uses a temporary DOM node to measure the text box\n * height for the specified font. The first call for a given font\n * will incur a DOM reflow, but the return value is cached, so any\n * subsequent call for the same font will return the cached value.\n */\n function measureFontHeight(font) {\n // Look up the cached font height.\n let height = Private$6.fontHeightCache[font];\n // Return the cached font height if it exists.\n if (height !== undefined) {\n return height;\n }\n // Normalize the font.\n Private$6.fontMeasurementGC.font = font;\n let normFont = Private$6.fontMeasurementGC.font;\n // Set the font on the measurement node.\n Private$6.fontMeasurementNode.style.font = normFont;\n // Add the measurement node to the document.\n document.body.appendChild(Private$6.fontMeasurementNode);\n // Measure the node height.\n height = Private$6.fontMeasurementNode.offsetHeight;\n // Remove the measurement node from the document.\n document.body.removeChild(Private$6.fontMeasurementNode);\n // Cache the measured height for the font and norm font.\n Private$6.fontHeightCache[font] = height;\n Private$6.fontHeightCache[normFont] = height;\n // Return the measured height.\n return height;\n }\n TextRenderer.measureFontHeight = measureFontHeight;\n})(TextRenderer || (TextRenderer = {}));\n/**\n * The namespace for the module implementation details.\n */\nvar Private$6;\n(function (Private) {\n /**\n * A cache of measured font heights.\n */\n Private.fontHeightCache = Object.create(null);\n /**\n * The DOM node used for font height measurement.\n */\n Private.fontMeasurementNode = (() => {\n let node = document.createElement('div');\n node.style.position = 'absolute';\n node.style.top = '-99999px';\n node.style.left = '-99999px';\n node.style.visibility = 'hidden';\n node.textContent = 'M';\n return node;\n })();\n /**\n * The GC used for font measurement.\n */\n Private.fontMeasurementGC = (() => {\n let canvas = document.createElement('canvas');\n canvas.width = 0;\n canvas.height = 0;\n return canvas.getContext('2d');\n })();\n})(Private$6 || (Private$6 = {}));\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * A cell renderer which renders data values as text.\n */\nclass HyperlinkRenderer extends TextRenderer {\n /**\n * Construct a new text renderer.\n *\n * @param options - The options for initializing the renderer.\n */\n constructor(options = {}) {\n // Set default parameters before passing over the super.\n options.textColor = options.textColor || 'navy';\n options.font = options.font || 'bold 12px sans-serif';\n super(options);\n this.url = options.url;\n this.urlName = options.urlName;\n }\n /**\n * Get the full text to be rendered by the cell.\n */\n getText(config) {\n let urlName = CellRenderer.resolveOption(this.urlName, config);\n // If we have a friendly URL name, use that.\n if (urlName) {\n return this.format({\n ...config,\n value: urlName\n });\n }\n // Otherwise use the raw value attribute.\n return this.format(config);\n }\n /**\n * Draw the text for the cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n drawText(gc, config) {\n // Resolve the font for the cell.\n let font = CellRenderer.resolveOption(this.font, config);\n // Bail if there is no font to draw.\n if (!font) {\n return;\n }\n // Resolve the text color for the cell.\n let color = CellRenderer.resolveOption(this.textColor, config);\n // Bail if there is no text color to draw.\n if (!color) {\n return;\n }\n let text = this.getText(config);\n // Bail if there is no text to draw.\n if (!text) {\n return;\n }\n // Resolve the vertical and horizontal alignment.\n let vAlign = CellRenderer.resolveOption(this.verticalAlignment, config);\n let hAlign = CellRenderer.resolveOption(this.horizontalAlignment, config);\n // Resolve the elision direction\n let elideDirection = CellRenderer.resolveOption(this.elideDirection, config);\n // Resolve the text wrapping flag\n let wrapText = CellRenderer.resolveOption(this.wrapText, config);\n // Compute the padded text box height for the specified alignment.\n let boxHeight = config.height - (vAlign === 'center' ? 1 : 2);\n // Bail if the text box has no effective size.\n if (boxHeight <= 0) {\n return;\n }\n // Compute the text height for the gc font.\n let textHeight = HyperlinkRenderer.measureFontHeight(font);\n // Set up the text position variables.\n let textX;\n let textY;\n let boxWidth;\n // Compute the Y position for the text.\n switch (vAlign) {\n case 'top':\n textY = config.y + 2 + textHeight;\n break;\n case 'center':\n textY = config.y + config.height / 2 + textHeight / 2;\n break;\n case 'bottom':\n textY = config.y + config.height - 2;\n break;\n default:\n throw 'unreachable';\n }\n // Compute the X position for the text.\n switch (hAlign) {\n case 'left':\n textX = config.x + 8;\n boxWidth = config.width - 14;\n break;\n case 'center':\n textX = config.x + config.width / 2;\n boxWidth = config.width;\n break;\n case 'right':\n textX = config.x + config.width - 8;\n boxWidth = config.width - 14;\n break;\n default:\n throw 'unreachable';\n }\n // Clip the cell if the text is taller than the text box height.\n if (textHeight > boxHeight) {\n gc.beginPath();\n gc.rect(config.x, config.y, config.width, config.height - 1);\n gc.clip();\n }\n // Set the gc state.\n gc.font = font;\n gc.fillStyle = color;\n gc.textAlign = hAlign;\n gc.textBaseline = 'bottom';\n // Terminate call here if we're not eliding or wrapping text\n if (elideDirection === 'none' && !wrapText) {\n gc.fillText(text, textX, textY);\n return;\n }\n // The current text width in pixels.\n let textWidth = gc.measureText(text).width;\n // Apply text wrapping if enabled.\n if (wrapText && textWidth > boxWidth) {\n // Make sure box clipping happens.\n gc.beginPath();\n gc.rect(config.x, config.y, config.width, config.height - 1);\n gc.clip();\n // Split column name to words based on\n // whitespace preceding a word boundary.\n // \"Hello world\" --> [\"Hello \", \"world\"]\n const wordsInColumn = text.split(/\\s(?=\\b)/);\n // Y-coordinate offset for any additional lines\n let curY = textY;\n let textInCurrentLine = wordsInColumn.shift();\n // Single word. Applying text wrap on word by splitting\n // it into characters and fitting the maximum number of\n // characters possible per line (box width).\n if (wordsInColumn.length === 0) {\n let curLineTextWidth = gc.measureText(textInCurrentLine).width;\n while (curLineTextWidth > boxWidth && textInCurrentLine !== '') {\n // Iterating from the end of the string until we find a\n // substring (0,i) which has a width less than the box width.\n for (let i = textInCurrentLine.length; i > 0; i--) {\n const curSubString = textInCurrentLine.substring(0, i);\n const curSubStringWidth = gc.measureText(curSubString).width;\n if (curSubStringWidth < boxWidth || curSubString.length === 1) {\n // Found a substring which has a width less than the current\n // box width. Rendering that substring on the current line\n // and setting the remainder of the parent string as the next\n // string to iterate on for the next line.\n const nextLineText = textInCurrentLine.substring(i, textInCurrentLine.length);\n textInCurrentLine = nextLineText;\n curLineTextWidth = gc.measureText(textInCurrentLine).width;\n gc.fillText(curSubString, textX, curY);\n curY += textHeight;\n // No need to continue iterating after we identified\n // an index to break the string on.\n break;\n }\n }\n }\n }\n // Multiple words in column header. Fitting maximum\n // number of words possible per line (box width).\n else {\n while (wordsInColumn.length !== 0) {\n // Processing the next word in the queue.\n const curWord = wordsInColumn.shift();\n // Joining that word with the existing text for\n // the current line.\n const incrementedText = [textInCurrentLine, curWord].join(' ');\n const incrementedTextWidth = gc.measureText(incrementedText).width;\n if (incrementedTextWidth > boxWidth) {\n // If the newly combined text has a width larger than\n // the box width, we render the line before the current\n // word was added. We set the current word as the next\n // line.\n gc.fillText(textInCurrentLine, textX, curY);\n curY += textHeight;\n textInCurrentLine = curWord;\n }\n else {\n // The combined text hasd a width less than the box width. We\n // set the the current line text to be the new combined text.\n textInCurrentLine = incrementedText;\n }\n }\n }\n gc.fillText(textInCurrentLine, textX, curY);\n // Terminating the call here as we don't want\n // to apply text eliding when wrapping is active.\n return;\n }\n // Elide text that is too long\n let elide = '\\u2026';\n // Compute elided text\n if (elideDirection === 'right') {\n while (textWidth > boxWidth && text.length > 1) {\n if (text.length > 4 && textWidth >= 2 * boxWidth) {\n // If text width is substantially bigger, take half the string\n text = text.substring(0, text.length / 2 + 1) + elide;\n }\n else {\n // Otherwise incrementally remove the last character\n text = text.substring(0, text.length - 2) + elide;\n }\n textWidth = gc.measureText(text).width;\n }\n }\n else {\n while (textWidth > boxWidth && text.length > 1) {\n if (text.length > 4 && textWidth >= 2 * boxWidth) {\n // If text width is substantially bigger, take half the string\n text = elide + text.substring(text.length / 2);\n }\n else {\n // Otherwise incrementally remove the last character\n text = elide + text.substring(2);\n }\n textWidth = gc.measureText(text).width;\n }\n }\n // Draw the text for the cell.\n gc.fillText(text, textX, textY);\n }\n}\n\n/*\n * Copyright (c) Jupyter Development Team.\n * Distributed under the terms of the Modified BSD License.\n */\n/**\n * A collection of helper functions relating to merged cell groups\n */\nvar CellGroup;\n(function (CellGroup) {\n /**\n * Checks if two cell-groups are intersecting\n * in the given axis.\n * @param group1\n * @param group2\n * @param axis\n */\n function areCellGroupsIntersectingAtAxis(group1, group2, axis) {\n if (axis === 'row') {\n return ((group1.r1 >= group2.r1 && group1.r1 <= group2.r2) ||\n (group1.r2 >= group2.r1 && group1.r2 <= group2.r2) ||\n (group2.r1 >= group1.r1 && group2.r1 <= group1.r2) ||\n (group2.r2 >= group1.r1 && group2.r2 <= group1.r2));\n }\n return ((group1.c1 >= group2.c1 && group1.c1 <= group2.c2) ||\n (group1.c2 >= group2.c1 && group1.c2 <= group2.c2) ||\n (group2.c1 >= group1.c1 && group2.c1 <= group1.c2) ||\n (group2.c2 >= group1.c1 && group2.c2 <= group1.c2));\n }\n CellGroup.areCellGroupsIntersectingAtAxis = areCellGroupsIntersectingAtAxis;\n /**\n * Checks if cell-groups are intersecting.\n * @param group1\n * @param group2\n */\n function areCellGroupsIntersecting(group1, group2) {\n return (((group1.r1 >= group2.r1 && group1.r1 <= group2.r2) ||\n (group1.r2 >= group2.r1 && group1.r2 <= group2.r2) ||\n (group2.r1 >= group1.r1 && group2.r1 <= group1.r2) ||\n (group2.r2 >= group1.r1 && group2.r2 <= group1.r2)) &&\n ((group1.c1 >= group2.c1 && group1.c1 <= group2.c2) ||\n (group1.c2 >= group2.c1 && group1.c2 <= group2.c2) ||\n (group2.c1 >= group1.c1 && group2.c1 <= group1.c2) ||\n (group2.c2 >= group1.c1 && group2.c2 <= group1.c2)));\n }\n CellGroup.areCellGroupsIntersecting = areCellGroupsIntersecting;\n /**\n * Retrieves the index of the cell-group to which\n * the cell at the given row, column belongs.\n * @param dataModel\n * @param rgn\n * @param row\n * @param column\n */\n function getGroupIndex(dataModel, rgn, row, column) {\n const numGroups = dataModel.groupCount(rgn);\n for (let i = 0; i < numGroups; i++) {\n const group = dataModel.group(rgn, i);\n if (row >= group.r1 &&\n row <= group.r2 &&\n column >= group.c1 &&\n column <= group.c2) {\n return i;\n }\n }\n return -1;\n }\n CellGroup.getGroupIndex = getGroupIndex;\n /**\n * Returns a cell-group for the given row/index coordinates.\n * @param dataModel\n * @param rgn\n * @param row\n * @param column\n */\n function getGroup(dataModel, rgn, row, column) {\n const groupIndex = getGroupIndex(dataModel, rgn, row, column);\n if (groupIndex === -1) {\n return null;\n }\n return dataModel.group(rgn, groupIndex);\n }\n CellGroup.getGroup = getGroup;\n /**\n * Returns all cell groups which belong to\n * a given cell cell region.\n * @param dataModel\n * @param rgn\n */\n function getCellGroupsAtRegion(dataModel, rgn) {\n let groupsAtRegion = [];\n const numGroups = dataModel.groupCount(rgn);\n for (let i = 0; i < numGroups; i++) {\n const group = dataModel.group(rgn, i);\n groupsAtRegion.push(group);\n }\n return groupsAtRegion;\n }\n CellGroup.getCellGroupsAtRegion = getCellGroupsAtRegion;\n /**\n * Calculates and returns a merged cell-group from\n * two cell-group objects.\n * @param groups\n */\n function joinCellGroups(groups) {\n let startRow = Number.MAX_VALUE;\n let endRow = Number.MIN_VALUE;\n let startColumn = Number.MAX_VALUE;\n let endColumn = Number.MIN_VALUE;\n for (const group of groups) {\n startRow = Math.min(startRow, group.r1);\n endRow = Math.max(endRow, group.r2);\n startColumn = Math.min(startColumn, group.c1);\n endColumn = Math.max(endColumn, group.c2);\n }\n return { r1: startRow, r2: endRow, c1: startColumn, c2: endColumn };\n }\n CellGroup.joinCellGroups = joinCellGroups;\n /**\n * Merges a cell group with other cells groups in the\n * same region if they intersect.\n * @param dataModel the data model of the grid.\n * @param group the target cell group.\n * @param region the region of the cell group.\n * @returns a new cell group after merging has happened.\n */\n function joinCellGroupWithMergedCellGroups(dataModel, group, region) {\n let joinedGroup = { ...group };\n const mergedCellGroups = getCellGroupsAtRegion(dataModel, region);\n for (let g = 0; g < mergedCellGroups.length; g++) {\n const mergedGroup = mergedCellGroups[g];\n if (areCellGroupsIntersecting(joinedGroup, mergedGroup)) {\n joinedGroup = joinCellGroups([joinedGroup, mergedGroup]);\n }\n }\n return joinedGroup;\n }\n CellGroup.joinCellGroupWithMergedCellGroups = joinCellGroupWithMergedCellGroups;\n /**\n * Retrieves a list of cell groups intersecting at\n * a given row.\n * @param dataModel data model of the grid.\n * @param rgn the cell region.\n * @param row the target row to look for intersections at.\n * @returns all cell groups intersecting with the row.\n */\n function getCellGroupsAtRow(dataModel, rgn, row) {\n let groupsAtRow = [];\n const numGroups = dataModel.groupCount(rgn);\n for (let i = 0; i < numGroups; i++) {\n const group = dataModel.group(rgn, i);\n if (row >= group.r1 && row <= group.r2) {\n groupsAtRow.push(group);\n }\n }\n return groupsAtRow;\n }\n CellGroup.getCellGroupsAtRow = getCellGroupsAtRow;\n /**\n * Retrieves a list of cell groups intersecting at\n * a given column.\n * @param dataModel data model of the grid.\n * @param rgn the cell region.\n * @param column the target column to look for intersections at.\n * @returns all cell groups intersecting with the column.\n */\n function getCellGroupsAtColumn(dataModel, rgn, column) {\n let groupsAtColumn = [];\n const numGroups = dataModel.groupCount(rgn);\n for (let i = 0; i < numGroups; i++) {\n const group = dataModel.group(rgn, i);\n if (column >= group.c1 && column <= group.c2) {\n groupsAtColumn.push(group);\n }\n }\n return groupsAtColumn;\n }\n CellGroup.getCellGroupsAtColumn = getCellGroupsAtColumn;\n /**\n * Merges a target cell group with any cell groups\n * it intersects with at a given row or column.\n * @param dataModel data model of the grid.\n * @param regions list of cell regions.\n * @param axis row or column.\n * @param group the target cell group.\n * @returns a new merged cell group.\n */\n function joinCellGroupsIntersectingAtAxis(dataModel, regions, axis, group) {\n let groupsAtAxis = [];\n if (axis === 'row') {\n for (const region of regions) {\n for (let r = group.r1; r <= group.r2; r++) {\n groupsAtAxis = groupsAtAxis.concat(CellGroup.getCellGroupsAtRow(dataModel, region, r));\n }\n }\n }\n else {\n for (const region of regions) {\n for (let c = group.c1; c <= group.c2; c++) {\n groupsAtAxis = groupsAtAxis.concat(CellGroup.getCellGroupsAtColumn(dataModel, region, c));\n }\n }\n }\n let mergedGroupAtAxis = CellGroup.joinCellGroups(groupsAtAxis);\n if (groupsAtAxis.length > 0) {\n let mergedCellGroups = [];\n for (const region of regions) {\n mergedCellGroups = mergedCellGroups.concat(CellGroup.getCellGroupsAtRegion(dataModel, region));\n }\n for (let g = 0; g < mergedCellGroups.length; g++) {\n const group = mergedCellGroups[g];\n if (CellGroup.areCellGroupsIntersectingAtAxis(mergedGroupAtAxis, group, axis)) {\n mergedGroupAtAxis = CellGroup.joinCellGroups([\n group,\n mergedGroupAtAxis\n ]);\n mergedCellGroups.splice(g, 1);\n g = 0;\n }\n }\n }\n return mergedGroupAtAxis;\n }\n CellGroup.joinCellGroupsIntersectingAtAxis = joinCellGroupsIntersectingAtAxis;\n})(CellGroup || (CellGroup = {}));\n\n/**\n * A basic implementation of a data grid mouse handler.\n *\n * #### Notes\n * This class may be subclassed and customized as needed.\n */\nclass BasicMouseHandler {\n constructor() {\n this._disposed = false;\n this._pressData = null;\n }\n /**\n * Dispose of the resources held by the mouse handler.\n */\n dispose() {\n // Bail early if the handler is already disposed.\n if (this._disposed) {\n return;\n }\n // Release any held resources.\n this.release();\n // Mark the handler as disposed.\n this._disposed = true;\n }\n /**\n * Whether the mouse handler is disposed.\n */\n get isDisposed() {\n return this._disposed;\n }\n /**\n * Release the resources held by the handler.\n */\n release() {\n // Bail early if the is no press data.\n if (!this._pressData) {\n return;\n }\n // Clear the autoselect timeout.\n if (this._pressData.type === 'select') {\n this._pressData.timeout = -1;\n }\n // Clear the press data.\n this._pressData.override.dispose();\n this._pressData = null;\n }\n /**\n * Handle the mouse hover event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The mouse hover event of interest.\n */\n onMouseHover(grid, event) {\n // Hit test the grid.\n let hit = grid.hitTest(event.clientX, event.clientY);\n // Get the resize handle for the hit test.\n let handle = Private$5.resizeHandleForHitTest(hit);\n // Fetch the cursor for the handle.\n let cursor = this.cursorForHandle(handle);\n // Hyperlink logic.\n const config = Private$5.createCellConfigObject(grid, hit);\n if (config) {\n // Retrieve renderer for hovered cell.\n const renderer = grid.cellRenderers.get(config);\n if (renderer instanceof HyperlinkRenderer) {\n cursor = this.cursorForHandle('hyperlink');\n }\n }\n // Update the viewport cursor based on the part.\n grid.viewport.node.style.cursor = cursor;\n // TODO support user-defined hover items\n }\n /**\n * Handle the mouse leave event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The mouse hover event of interest.\n */\n onMouseLeave(grid, event) {\n // TODO support user-defined hover popups.\n // Clear the viewport cursor.\n grid.viewport.node.style.cursor = '';\n }\n /**\n * Handle the mouse down event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The mouse down event of interest.\n */\n onMouseDown(grid, event) {\n // Unpack the event.\n let { clientX, clientY } = event;\n // Hit test the grid.\n let hit = grid.hitTest(clientX, clientY);\n // Unpack the hit test.\n const { region, row, column } = hit;\n // Bail if the hit test is on an uninteresting region.\n if (region === 'void') {\n return;\n }\n // Fetch the modifier flags.\n let shift = event.shiftKey;\n let accel = Platform.accelKey(event);\n // Hyperlink logic.\n if (grid) {\n // Create cell config object.\n const config = Private$5.createCellConfigObject(grid, hit);\n // Retrieve cell renderer.\n let renderer = grid.cellRenderers.get(config);\n // Only process hyperlink renderers.\n if (renderer instanceof HyperlinkRenderer) {\n // Use the url param if it exists.\n let url = CellRenderer.resolveOption(renderer.url, config);\n // Otherwise assume cell value is the URL.\n if (!url) {\n const format = TextRenderer.formatGeneric();\n url = format(config);\n }\n // Open the hyperlink only if user hit Ctrl+Click.\n if (accel) {\n window.open(url);\n // Reset cursor default after clicking\n const cursor = this.cursorForHandle('none');\n grid.viewport.node.style.cursor = cursor;\n // Not applying selections if navigating away.\n return;\n }\n }\n }\n // If the hit test is the body region, the only option is select.\n if (region === 'body') {\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Bail early if there is no selection model.\n if (!model) {\n return;\n }\n // Override the document cursor.\n let override = Drag.overrideCursor('default');\n // Set up the press data.\n this._pressData = {\n type: 'select',\n region,\n row,\n column,\n override,\n localX: -1,\n localY: -1,\n timeout: -1\n };\n // Set up the selection variables.\n let r1;\n let c1;\n let r2;\n let c2;\n let cursorRow;\n let cursorColumn;\n let clear;\n // Accel == new selection, keep old selections.\n if (accel) {\n r1 = row;\n r2 = row;\n c1 = column;\n c2 = column;\n cursorRow = row;\n cursorColumn = column;\n clear = 'none';\n }\n else if (shift) {\n r1 = model.cursorRow;\n r2 = row;\n c1 = model.cursorColumn;\n c2 = column;\n cursorRow = model.cursorRow;\n cursorColumn = model.cursorColumn;\n clear = 'current';\n }\n else {\n r1 = row;\n r2 = row;\n c1 = column;\n c2 = column;\n cursorRow = row;\n cursorColumn = column;\n clear = 'all';\n }\n // Make the selection.\n model.select({ r1, c1, r2, c2, cursorRow, cursorColumn, clear });\n // Done.\n return;\n }\n // Otherwise, the hit test is on a header region.\n // Convert the hit test into a part.\n let handle = Private$5.resizeHandleForHitTest(hit);\n // Fetch the cursor for the handle.\n let cursor = this.cursorForHandle(handle);\n // Handle horizontal resize.\n if (handle === 'left' || handle === 'right') {\n // Set up the resize data type.\n const type = 'column-resize';\n // Determine the column region.\n let rgn = region === 'column-header' ? 'body' : 'row-header';\n // Determine the section index.\n let index = handle === 'left' ? column - 1 : column;\n // Fetch the section size.\n let size = grid.columnSize(rgn, index);\n // Override the document cursor.\n let override = Drag.overrideCursor(cursor);\n // Create the temporary press data.\n this._pressData = { type, region: rgn, index, size, clientX, override };\n // Done.\n return;\n }\n // Handle vertical resize\n if (handle === 'top' || handle === 'bottom') {\n // Set up the resize data type.\n const type = 'row-resize';\n // Determine the row region.\n let rgn = region === 'row-header' ? 'body' : 'column-header';\n // Determine the section index.\n let index = handle === 'top' ? row - 1 : row;\n // Fetch the section size.\n let size = grid.rowSize(rgn, index);\n // Override the document cursor.\n let override = Drag.overrideCursor(cursor);\n // Create the temporary press data.\n this._pressData = { type, region: rgn, index, size, clientY, override };\n // Done.\n return;\n }\n // Otherwise, the only option is select.\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Bail if there is no selection model.\n if (!model) {\n return;\n }\n // Override the document cursor.\n let override = Drag.overrideCursor('default');\n // Set up the press data.\n this._pressData = {\n type: 'select',\n region,\n row,\n column,\n override,\n localX: -1,\n localY: -1,\n timeout: -1\n };\n // Set up the selection variables.\n let r1;\n let c1;\n let r2;\n let c2;\n let cursorRow;\n let cursorColumn;\n let clear;\n // Compute the selection based on the pressed region.\n if (region === 'corner-header') {\n r1 = 0;\n r2 = Infinity;\n c1 = 0;\n c2 = Infinity;\n cursorRow = accel ? 0 : shift ? model.cursorRow : 0;\n cursorColumn = accel ? 0 : shift ? model.cursorColumn : 0;\n clear = accel ? 'none' : shift ? 'current' : 'all';\n }\n else if (region === 'row-header') {\n r1 = accel ? row : shift ? model.cursorRow : row;\n r2 = row;\n const selectionGroup = { r1: r1, c1: 0, r2: r2, c2: 0 };\n const joinedGroup = CellGroup.joinCellGroupsIntersectingAtAxis(grid.dataModel, ['row-header', 'body'], 'row', selectionGroup);\n // Check if there are any merges\n if (joinedGroup.r1 != Number.MAX_VALUE) {\n r1 = joinedGroup.r1;\n r2 = joinedGroup.r2;\n }\n c1 = 0;\n c2 = Infinity;\n cursorRow = accel ? row : shift ? model.cursorRow : row;\n cursorColumn = accel ? 0 : shift ? model.cursorColumn : 0;\n clear = accel ? 'none' : shift ? 'current' : 'all';\n }\n else if (region === 'column-header') {\n r1 = 0;\n r2 = Infinity;\n c1 = accel ? column : shift ? model.cursorColumn : column;\n c2 = column;\n const selectionGroup = { r1: 0, c1: c1, r2: 0, c2: c2 };\n const joinedGroup = CellGroup.joinCellGroupsIntersectingAtAxis(grid.dataModel, ['column-header', 'body'], 'column', selectionGroup);\n // Check if there are any merges\n if (joinedGroup.c1 != Number.MAX_VALUE) {\n c1 = joinedGroup.c1;\n c2 = joinedGroup.c2;\n }\n cursorRow = accel ? 0 : shift ? model.cursorRow : 0;\n cursorColumn = accel ? column : shift ? model.cursorColumn : column;\n clear = accel ? 'none' : shift ? 'current' : 'all';\n }\n else {\n r1 = accel ? row : shift ? model.cursorRow : row;\n r2 = row;\n c1 = accel ? column : shift ? model.cursorColumn : column;\n c2 = column;\n cursorRow = accel ? row : shift ? model.cursorRow : row;\n cursorColumn = accel ? column : shift ? model.cursorColumn : column;\n clear = accel ? 'none' : shift ? 'current' : 'all';\n }\n // Make the selection.\n model.select({ r1, c1, r2, c2, cursorRow, cursorColumn, clear });\n }\n /**\n * Handle the mouse move event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The mouse move event of interest.\n */\n onMouseMove(grid, event) {\n // Fetch the press data.\n const data = this._pressData;\n // Bail early if there is no press data.\n if (!data) {\n return;\n }\n // Handle a row resize.\n if (data.type === 'row-resize') {\n let dy = event.clientY - data.clientY;\n grid.resizeRow(data.region, data.index, data.size + dy);\n return;\n }\n // Handle a column resize.\n if (data.type === 'column-resize') {\n let dx = event.clientX - data.clientX;\n grid.resizeColumn(data.region, data.index, data.size + dx);\n return;\n }\n // Otherwise, it's a select.\n // Mouse moves during a corner header press are a no-op.\n if (data.region === 'corner-header') {\n return;\n }\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Bail early if the selection model was removed.\n if (!model) {\n return;\n }\n // Map to local coordinates.\n let { lx, ly } = grid.mapToLocal(event.clientX, event.clientY);\n // Update the local mouse coordinates in the press data.\n data.localX = lx;\n data.localY = ly;\n // Fetch the grid geometry.\n let hw = grid.headerWidth;\n let hh = grid.headerHeight;\n let vpw = grid.viewportWidth;\n let vph = grid.viewportHeight;\n let sx = grid.scrollX;\n let sy = grid.scrollY;\n let msx = grid.maxScrollY;\n let msy = grid.maxScrollY;\n // Fetch the selection mode.\n let mode = model.selectionMode;\n // Set up the timeout variable.\n let timeout = -1;\n // Compute the timemout based on hit region and mouse position.\n if (data.region === 'row-header' || mode === 'row') {\n if (ly < hh && sy > 0) {\n timeout = Private$5.computeTimeout(hh - ly);\n }\n else if (ly >= vph && sy < msy) {\n timeout = Private$5.computeTimeout(ly - vph);\n }\n }\n else if (data.region === 'column-header' || mode === 'column') {\n if (lx < hw && sx > 0) {\n timeout = Private$5.computeTimeout(hw - lx);\n }\n else if (lx >= vpw && sx < msx) {\n timeout = Private$5.computeTimeout(lx - vpw);\n }\n }\n else {\n if (lx < hw && sx > 0) {\n timeout = Private$5.computeTimeout(hw - lx);\n }\n else if (lx >= vpw && sx < msx) {\n timeout = Private$5.computeTimeout(lx - vpw);\n }\n else if (ly < hh && sy > 0) {\n timeout = Private$5.computeTimeout(hh - ly);\n }\n else if (ly >= vph && sy < msy) {\n timeout = Private$5.computeTimeout(ly - vph);\n }\n }\n // Update or initiate the autoselect if needed.\n if (timeout >= 0) {\n if (data.timeout < 0) {\n data.timeout = timeout;\n setTimeout(() => {\n Private$5.autoselect(grid, data);\n }, timeout);\n }\n else {\n data.timeout = timeout;\n }\n return;\n }\n // Otherwise, clear the autoselect timeout.\n data.timeout = -1;\n // Map the position to virtual coordinates.\n let { vx, vy } = grid.mapToVirtual(event.clientX, event.clientY);\n // Clamp the coordinates to the limits.\n vx = Math.max(0, Math.min(vx, grid.bodyWidth - 1));\n vy = Math.max(0, Math.min(vy, grid.bodyHeight - 1));\n // Set up the selection variables.\n let r1;\n let c1;\n let r2;\n let c2;\n let cursorRow = model.cursorRow;\n let cursorColumn = model.cursorColumn;\n let clear = 'current';\n // Compute the selection based pressed region.\n if (data.region === 'row-header' || mode === 'row') {\n r1 = data.row;\n r2 = grid.rowAt('body', vy);\n const selectionGroup = { r1: r1, c1: 0, r2: r2, c2: 0 };\n const joinedGroup = CellGroup.joinCellGroupsIntersectingAtAxis(grid.dataModel, ['row-header', 'body'], 'row', selectionGroup);\n // Check if there are any merges\n if (joinedGroup.r1 != Number.MAX_VALUE) {\n r1 = Math.min(r1, joinedGroup.r1);\n r2 = Math.max(r2, joinedGroup.r2);\n }\n c1 = 0;\n c2 = Infinity;\n }\n else if (data.region === 'column-header' || mode === 'column') {\n r1 = 0;\n r2 = Infinity;\n c1 = data.column;\n c2 = grid.columnAt('body', vx);\n const selectionGroup = { r1: 0, c1: c1, r2: 0, c2: c2 };\n const joinedGroup = CellGroup.joinCellGroupsIntersectingAtAxis(grid.dataModel, ['column-header', 'body'], 'column', selectionGroup);\n // Check if there are any merges\n if (joinedGroup.c1 != Number.MAX_VALUE) {\n c1 = joinedGroup.c1;\n c2 = joinedGroup.c2;\n }\n }\n else {\n r1 = cursorRow;\n r2 = grid.rowAt('body', vy);\n c1 = cursorColumn;\n c2 = grid.columnAt('body', vx);\n }\n // Make the selection.\n model.select({ r1, c1, r2, c2, cursorRow, cursorColumn, clear });\n }\n /**\n * Handle the mouse up event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The mouse up event of interest.\n */\n onMouseUp(grid, event) {\n this.release();\n }\n /**\n * Handle the mouse double click event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The mouse up event of interest.\n */\n onMouseDoubleClick(grid, event) {\n var _a, _b, _c;\n if (!grid.dataModel) {\n this.release();\n return;\n }\n // Unpack the event.\n let { clientX, clientY } = event;\n // Hit test the grid.\n let hit = grid.hitTest(clientX, clientY);\n // Unpack the hit test.\n let { region, row, column } = hit;\n if (region === 'void') {\n this.release();\n return;\n }\n if (region === 'column-header' || region === 'corner-header') {\n // Convert the hit test into a part.\n const handle = Private$5.resizeHandleForHitTest(hit);\n if (handle === 'left' || handle === 'right') {\n let colIndex = handle === 'left' ? column - 1 : column;\n let colRegion = region === 'column-header' ? 'body' : 'row-header';\n if (colIndex < 0) {\n if (region === 'column-header') {\n // If the column is -1, it means we are in the corner header\n colIndex = grid.dataModel.columnCount('row-header') - 1;\n colRegion = 'row-header';\n }\n else {\n // If we are on the left edge of the row header, do nothing\n return;\n }\n }\n const cs = (_a = grid.selectionModel) === null || _a === void 0 ? void 0 : _a.currentSelection();\n const cv = grid.currentViewport;\n const rowCount = (_c = (_b = grid.selectionModel) === null || _b === void 0 ? void 0 : _b.dataModel.rowCount('body')) !== null && _c !== void 0 ? _c : 0;\n if (colRegion == 'body' &&\n cs != null &&\n cv != null &&\n cs.r1 == 0 &&\n cs.r2 == rowCount - 1) {\n // One or more columns are selected\n let c1 = Math.max(Math.min(cs.c1, cs.c2), cv.firstColumn);\n let c2 = Math.min(Math.max(cs.c1, cs.c2), cv.lastColumn);\n if (c1 <= colIndex && colIndex <= c2) {\n // When we double-click one of the selected column headers, resize all visible selected columns.\n for (let ci = c1; ci <= c2; ci++) {\n grid.resizeColumn(colRegion, ci, null);\n }\n }\n else {\n // When we double-click the column header outside the selection, resize only the clicked column.\n grid.resizeColumn(colRegion, colIndex, null);\n }\n }\n else {\n // When no columns are selected, resize only the clicked column.\n grid.resizeColumn(colRegion, colIndex, null);\n }\n }\n }\n if (region === 'body') {\n if (grid.editable) {\n const cell = {\n grid: grid,\n row: row,\n column: column\n };\n grid.editorController.edit(cell);\n }\n }\n this.release();\n }\n /**\n * Handle the context menu event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The context menu event of interest.\n */\n onContextMenu(grid, event) {\n // TODO support user-defined context menus\n }\n /**\n * Handle the wheel event for the data grid.\n *\n * @param grid - The data grid of interest.\n *\n * @param event - The wheel event of interest.\n */\n onWheel(grid, event) {\n // Bail if a mouse press is in progress.\n if (this._pressData) {\n return;\n }\n // Extract the delta X and Y movement.\n let dx = event.deltaX;\n let dy = event.deltaY;\n // Convert the delta values to pixel values.\n switch (event.deltaMode) {\n case 0: // DOM_DELTA_PIXEL\n break;\n case 1: {\n // DOM_DELTA_LINE\n let ds = grid.defaultSizes;\n dx *= ds.columnWidth;\n dy *= ds.rowHeight;\n break;\n }\n case 2: // DOM_DELTA_PAGE\n dx *= grid.pageWidth;\n dy *= grid.pageHeight;\n break;\n default:\n throw 'unreachable';\n }\n // Only scroll and stop the event propagation if needed.\n if (\n // Scrolling left and not reached min already\n (dx < 0 && grid.scrollX !== 0) ||\n // Scrolling right and not reached max already\n (dx > 0 && grid.scrollX !== grid.maxScrollX) ||\n // Scrolling top and not reached min already\n (dy < 0 && grid.scrollY !== 0) ||\n // Scrolling down and not reached max already\n (dy > 0 && grid.scrollY !== grid.maxScrollY)) {\n event.preventDefault();\n event.stopPropagation();\n // Scroll by the desired amount.\n grid.scrollBy(dx, dy);\n }\n }\n /**\n * Convert a resize handle into a cursor.\n */\n cursorForHandle(handle) {\n return Private$5.cursorMap[handle];\n }\n /**\n * Get the current pressData\n */\n get pressData() {\n return this._pressData;\n }\n}\n/**\n * The namespace for the module implementation details.\n */\nvar Private$5;\n(function (Private) {\n /**\n * Creates a CellConfig object from a hit region.\n */\n function createCellConfigObject(grid, hit) {\n const { region, row, column } = hit;\n // Terminate call if region is void.\n if (region === 'void') {\n return undefined;\n }\n // Augment hit region params with value and metadata.\n const value = grid.dataModel.data(region, row, column);\n const metadata = grid.dataModel.metadata(region, row, column);\n // Create cell config object to retrieve cell renderer.\n const config = {\n ...hit,\n value: value,\n metadata: metadata\n };\n return config;\n }\n Private.createCellConfigObject = createCellConfigObject;\n /**\n * Get the resize handle for a grid hit test.\n */\n function resizeHandleForHitTest(hit) {\n // Fetch the row and column.\n let r = hit.row;\n let c = hit.column;\n // Fetch the leading and trailing sizes.\n let lw = hit.x;\n let lh = hit.y;\n let tw = hit.width - hit.x;\n let th = hit.height - hit.y;\n // Set up the result variable.\n let result;\n // Dispatch based on hit test region.\n switch (hit.region) {\n case 'corner-header':\n if (c > 0 && lw <= 5) {\n result = 'left';\n }\n else if (tw <= 6) {\n result = 'right';\n }\n else if (r > 0 && lh <= 5) {\n result = 'top';\n }\n else if (th <= 6) {\n result = 'bottom';\n }\n else {\n result = 'none';\n }\n break;\n case 'column-header':\n if (c > 0 && lw <= 5) {\n result = 'left';\n }\n else if (tw <= 6) {\n result = 'right';\n }\n else if (r > 0 && lh <= 5) {\n result = 'top';\n }\n else if (th <= 6) {\n result = 'bottom';\n }\n else {\n result = 'none';\n }\n break;\n case 'row-header':\n if (c > 0 && lw <= 5) {\n result = 'left';\n }\n else if (tw <= 6) {\n result = 'right';\n }\n else if (r > 0 && lh <= 5) {\n result = 'top';\n }\n else if (th <= 6) {\n result = 'bottom';\n }\n else {\n result = 'none';\n }\n break;\n case 'body':\n result = 'none';\n break;\n case 'void':\n result = 'none';\n break;\n default:\n throw 'unreachable';\n }\n // Return the result.\n return result;\n }\n Private.resizeHandleForHitTest = resizeHandleForHitTest;\n /**\n * A timer callback for the autoselect loop.\n *\n * @param grid - The datagrid of interest.\n *\n * @param data - The select data of interest.\n */\n function autoselect(grid, data) {\n // Bail early if the timeout has been reset.\n if (data.timeout < 0) {\n return;\n }\n // Fetch the selection model.\n let model = grid.selectionModel;\n // Bail early if the selection model has been removed.\n if (!model) {\n return;\n }\n // Fetch the current selection.\n let cs = model.currentSelection();\n // Bail early if there is no current selection.\n if (!cs) {\n return;\n }\n // Fetch local X and Y coordinates of the mouse.\n let lx = data.localX;\n let ly = data.localY;\n // Set up the selection variables.\n let r1 = cs.r1;\n let c1 = cs.c1;\n let r2 = cs.r2;\n let c2 = cs.c2;\n let cursorRow = model.cursorRow;\n let cursorColumn = model.cursorColumn;\n let clear = 'current';\n // Fetch the grid geometry.\n let hw = grid.headerWidth;\n let hh = grid.headerHeight;\n let vpw = grid.viewportWidth;\n let vph = grid.viewportHeight;\n // Fetch the selection mode.\n let mode = model.selectionMode;\n // Update the selection based on the hit region.\n if (data.region === 'row-header' || mode === 'row') {\n r2 += ly <= hh ? -1 : ly >= vph ? 1 : 0;\n }\n else if (data.region === 'column-header' || mode === 'column') {\n c2 += lx <= hw ? -1 : lx >= vpw ? 1 : 0;\n }\n else {\n r2 += ly <= hh ? -1 : ly >= vph ? 1 : 0;\n c2 += lx <= hw ? -1 : lx >= vpw ? 1 : 0;\n }\n // Update the current selection.\n model.select({ r1, c1, r2, c2, cursorRow, cursorColumn, clear });\n // Re-fetch the current selection.\n cs = model.currentSelection();\n // Bail if there is no selection.\n if (!cs) {\n return;\n }\n // Scroll the grid based on the hit region.\n if (data.region === 'row-header' || mode === 'row') {\n grid.scrollToRow(cs.r2);\n }\n else if (data.region === 'column-header' || mode == 'column') {\n grid.scrollToColumn(cs.c2);\n }\n else if (mode === 'cell') {\n grid.scrollToCell(cs.r2, cs.c2);\n }\n // Schedule the next call with the current timeout.\n setTimeout(() => {\n autoselect(grid, data);\n }, data.timeout);\n }\n Private.autoselect = autoselect;\n /**\n * Compute the scroll timeout for the given delta distance.\n *\n * @param delta - The delta pixels from the origin.\n *\n * @returns The scaled timeout in milliseconds.\n */\n function computeTimeout(delta) {\n return 5 + 120 * (1 - Math.min(128, Math.abs(delta)) / 128);\n }\n Private.computeTimeout = computeTimeout;\n /**\n * A mapping of resize handle to cursor.\n */\n Private.cursorMap = {\n top: 'ns-resize',\n left: 'ew-resize',\n right: 'ew-resize',\n bottom: 'ns-resize',\n hyperlink: 'pointer',\n none: 'default'\n };\n})(Private$5 || (Private$5 = {}));\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * A base class for creating data grid selection models.\n *\n * #### Notes\n * If the predefined selection models are insufficient for a particular\n * use case, a custom model can be defined which derives from this class.\n */\nclass SelectionModel {\n /**\n * Construct a new selection model.\n *\n * @param options - The options for initializing the model.\n */\n constructor(options) {\n this._changed = new Signal(this);\n this._selectionMode = 'cell';\n this.dataModel = options.dataModel;\n this._selectionMode = options.selectionMode || 'cell';\n this.dataModel.changed.connect(this.onDataModelChanged, this);\n }\n /**\n * A signal emitted when the selection model has changed.\n */\n get changed() {\n return this._changed;\n }\n /**\n * Get the selection mode for the model.\n */\n get selectionMode() {\n return this._selectionMode;\n }\n /**\n * Set the selection mode for the model.\n *\n * #### Notes\n * This will clear the selection model.\n */\n set selectionMode(value) {\n // Bail early if the mode does not change.\n if (this._selectionMode === value) {\n return;\n }\n // Update the internal mode.\n this._selectionMode = value;\n // Clear the current selections.\n this.clear();\n }\n /**\n * Test whether any selection intersects a row.\n *\n * @param index - The row index of interest.\n *\n * @returns Whether any selection intersects the row.\n *\n * #### Notes\n * This method may be reimplemented in a subclass.\n */\n isRowSelected(index) {\n return some(this.selections(), s => Private$4.containsRow(s, index));\n }\n /**\n * Test whether any selection intersects a column.\n *\n * @param index - The column index of interest.\n *\n * @returns Whether any selection intersects the column.\n *\n * #### Notes\n * This method may be reimplemented in a subclass.\n */\n isColumnSelected(index) {\n return some(this.selections(), s => Private$4.containsColumn(s, index));\n }\n /**\n * Test whether any selection intersects a cell.\n *\n * @param row - The row index of interest.\n *\n * @param column - The column index of interest.\n *\n * @returns Whether any selection intersects the cell.\n *\n * #### Notes\n * This method may be reimplemented in a subclass.\n */\n isCellSelected(row, column) {\n return some(this.selections(), s => Private$4.containsCell(s, row, column));\n }\n /**\n * A signal handler for the data model `changed` signal.\n *\n * @param args - The arguments for the signal.\n *\n * #### Notes\n * Selection model implementations should update their selections\n * in a manner that is relevant for the changes to the data model.\n *\n * The default implementation of this method is a no-op.\n */\n onDataModelChanged(sender, args) {\n // pass\n }\n /**\n * Emit the `changed` signal for the selection model.\n *\n * #### Notes\n * Subclasses should call this method whenever the selection model\n * has changed so that attached data grids can update themselves.\n */\n emitChanged() {\n this._changed.emit(undefined);\n }\n}\n/**\n * The namespace for the module implementation details.\n */\nvar Private$4;\n(function (Private) {\n /**\n * Test whether a selection contains a given row.\n */\n function containsRow(selection, row) {\n let { r1, r2 } = selection;\n return (row >= r1 && row <= r2) || (row >= r2 && row <= r1);\n }\n Private.containsRow = containsRow;\n /**\n * Test whether a selection contains a given column.\n */\n function containsColumn(selection, column) {\n let { c1, c2 } = selection;\n return (column >= c1 && column <= c2) || (column >= c2 && column <= c1);\n }\n Private.containsColumn = containsColumn;\n /**\n * Test whether a selection contains a given cell.\n */\n function containsCell(selection, row, column) {\n return containsRow(selection, row) && containsColumn(selection, column);\n }\n Private.containsCell = containsCell;\n})(Private$4 || (Private$4 = {}));\n\n/**\n * A basic selection model implementation.\n *\n * #### Notes\n * This selection model is sufficient for most use cases where\n * structural knowledge of the data source is *not* required.\n */\nclass BasicSelectionModel extends SelectionModel {\n constructor() {\n super(...arguments);\n this._cursorRow = -1;\n this._cursorColumn = -1;\n this._cursorRectIndex = -1;\n this._selections = [];\n }\n /**\n * Whether the selection model is empty.\n */\n get isEmpty() {\n return this._selections.length === 0;\n }\n /**\n * The row index of the cursor.\n */\n get cursorRow() {\n return this._cursorRow;\n }\n /**\n * The column index of the cursor.\n */\n get cursorColumn() {\n return this._cursorColumn;\n }\n /**\n * Move cursor down/up/left/right while making sure it remains\n * within the bounds of selected rectangles\n *\n * @param direction - The direction of the movement.\n */\n moveCursorWithinSelections(direction) {\n // Bail early if there are no selections or no existing cursor\n if (this.isEmpty || this.cursorRow === -1 || this._cursorColumn === -1) {\n return;\n }\n // Bail early if only single cell is selected\n const firstSelection = this._selections[0];\n if (this._selections.length === 1 &&\n firstSelection.r1 === firstSelection.r2 &&\n firstSelection.c1 === firstSelection.c2) {\n return;\n }\n // start from last selection rectangle\n if (this._cursorRectIndex === -1) {\n this._cursorRectIndex = this._selections.length - 1;\n }\n let cursorRect = this._selections[this._cursorRectIndex];\n const dr = direction === 'down' ? 1 : direction === 'up' ? -1 : 0;\n const dc = direction === 'right' ? 1 : direction === 'left' ? -1 : 0;\n let newRow = this._cursorRow + dr;\n let newColumn = this._cursorColumn + dc;\n const r1 = Math.min(cursorRect.r1, cursorRect.r2);\n const r2 = Math.max(cursorRect.r1, cursorRect.r2);\n const c1 = Math.min(cursorRect.c1, cursorRect.c2);\n const c2 = Math.max(cursorRect.c1, cursorRect.c2);\n const moveToNextRect = () => {\n this._cursorRectIndex =\n (this._cursorRectIndex + 1) % this._selections.length;\n cursorRect = this._selections[this._cursorRectIndex];\n newRow = Math.min(cursorRect.r1, cursorRect.r2);\n newColumn = Math.min(cursorRect.c1, cursorRect.c2);\n };\n const moveToPreviousRect = () => {\n this._cursorRectIndex =\n this._cursorRectIndex === 0\n ? this._selections.length - 1\n : this._cursorRectIndex - 1;\n cursorRect = this._selections[this._cursorRectIndex];\n newRow = Math.max(cursorRect.r1, cursorRect.r2);\n newColumn = Math.max(cursorRect.c1, cursorRect.c2);\n };\n if (newRow > r2) {\n newRow = r1;\n newColumn += 1;\n if (newColumn > c2) {\n moveToNextRect();\n }\n }\n else if (newRow < r1) {\n newRow = r2;\n newColumn -= 1;\n if (newColumn < c1) {\n moveToPreviousRect();\n }\n }\n else if (newColumn > c2) {\n newColumn = c1;\n newRow += 1;\n if (newRow > r2) {\n moveToNextRect();\n }\n }\n else if (newColumn < c1) {\n newColumn = c2;\n newRow -= 1;\n if (newRow < r1) {\n moveToPreviousRect();\n }\n }\n this._cursorRow = newRow;\n this._cursorColumn = newColumn;\n // Emit the changed signal.\n this.emitChanged();\n }\n /**\n * Get the current selection in the selection model.\n *\n * @returns The current selection or `null`.\n *\n * #### Notes\n * This is the selection which holds the cursor.\n */\n currentSelection() {\n return this._selections[this._selections.length - 1] || null;\n }\n /**\n * Get an iterator of the selections in the model.\n *\n * @returns A new iterator of the current selections.\n *\n * #### Notes\n * The data grid will render the selections in order.\n */\n *selections() {\n yield* this._selections;\n }\n /**\n * Select the specified cells.\n *\n * @param args - The arguments for the selection.\n */\n select(args) {\n // Fetch the current row and column counts;\n let rowCount = this.dataModel.rowCount('body');\n let columnCount = this.dataModel.columnCount('body');\n // Bail early if there is no content.\n if (rowCount <= 0 || columnCount <= 0) {\n return;\n }\n // Unpack the arguments.\n let { r1, c1, r2, c2, cursorRow, cursorColumn, clear } = args;\n // Clear the necessary selections.\n if (clear === 'all') {\n this._selections.length = 0;\n }\n else if (clear === 'current') {\n this._selections.pop();\n }\n // Clamp to the data model bounds.\n r1 = Math.max(0, Math.min(r1, rowCount - 1));\n r2 = Math.max(0, Math.min(r2, rowCount - 1));\n c1 = Math.max(0, Math.min(c1, columnCount - 1));\n c2 = Math.max(0, Math.min(c2, columnCount - 1));\n // Indicate if a row/column has already been selected.\n let alreadySelected = false;\n // Handle the selection mode.\n if (this.selectionMode === 'row') {\n c1 = 0;\n c2 = columnCount - 1;\n alreadySelected =\n this._selections.filter(selection => selection.r1 === r1).length !== 0;\n // Remove from selections if already selected.\n this._selections = alreadySelected\n ? this._selections.filter(selection => selection.r1 !== r1)\n : this._selections;\n }\n else if (this.selectionMode === 'column') {\n r1 = 0;\n r2 = rowCount - 1;\n alreadySelected =\n this._selections.filter(selection => selection.c1 === c1).length !== 0;\n // Remove from selections if already selected.\n this._selections = alreadySelected\n ? this._selections.filter(selection => selection.c1 !== c1)\n : this._selections;\n }\n // Alias the cursor row and column.\n let cr = cursorRow;\n let cc = cursorColumn;\n // Compute the new cursor location.\n if (cr < 0 || (cr < r1 && cr < r2) || (cr > r1 && cr > r2)) {\n cr = r1;\n }\n if (cc < 0 || (cc < c1 && cc < c2) || (cc > c1 && cc > c2)) {\n cc = c1;\n }\n // Update the cursor.\n this._cursorRow = cr;\n this._cursorColumn = cc;\n this._cursorRectIndex = this._selections.length;\n // Add the new selection if it wasn't already selected.\n if (!alreadySelected) {\n this._selections.push({ r1, c1, r2, c2 });\n }\n // Emit the changed signal.\n this.emitChanged();\n }\n /**\n * Clear all selections in the selection model.\n */\n clear() {\n // Bail early if there are no selections.\n if (this._selections.length === 0) {\n return;\n }\n // Reset the internal state.\n this._cursorRow = -1;\n this._cursorColumn = -1;\n this._cursorRectIndex = -1;\n this._selections.length = 0;\n // Emit the changed signal.\n this.emitChanged();\n }\n /**\n * A signal handler for the data model `changed` signal.\n *\n * @param args - The arguments for the signal.\n */\n onDataModelChanged(sender, args) {\n // Bail early if the model has no current selections.\n if (this._selections.length === 0) {\n return;\n }\n // Bail early if the cells have changed in place.\n if (args.type === 'cells-changed') {\n return;\n }\n // Bail early if there is no change to the row or column count.\n if (args.type === 'rows-moved' || args.type === 'columns-moved') {\n return;\n }\n // Fetch the last row and column index.\n let lr = sender.rowCount('body') - 1;\n let lc = sender.columnCount('body') - 1;\n // Bail early if the data model is empty.\n if (lr < 0 || lc < 0) {\n this._selections.length = 0;\n this.emitChanged();\n return;\n }\n // Fetch the selection mode.\n let mode = this.selectionMode;\n // Set up the assignment index variable.\n let j = 0;\n // Iterate over the current selections.\n for (let i = 0, n = this._selections.length; i < n; ++i) {\n // Unpack the selection.\n let { r1, c1, r2, c2 } = this._selections[i];\n // Skip the selection if it will disappear.\n if ((lr < r1 && lr < r2) || (lc < c1 && lc < c2)) {\n continue;\n }\n // Modify the bounds based on the selection mode.\n if (mode === 'row') {\n r1 = Math.max(0, Math.min(r1, lr));\n r2 = Math.max(0, Math.min(r2, lr));\n c1 = 0;\n c2 = lc;\n }\n else if (mode === 'column') {\n r1 = 0;\n r2 = lr;\n c1 = Math.max(0, Math.min(c1, lc));\n c2 = Math.max(0, Math.min(c2, lc));\n }\n else {\n r1 = Math.max(0, Math.min(r1, lr));\n r2 = Math.max(0, Math.min(r2, lr));\n c1 = Math.max(0, Math.min(c1, lc));\n c2 = Math.max(0, Math.min(c2, lc));\n }\n // Assign the modified selection to the array.\n this._selections[j++] = { r1, c1, r2, c2 };\n }\n // Remove the stale selections.\n this._selections.length = j;\n // Emit the changed signal.\n this.emitChanged();\n }\n}\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2023, Lumino Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * An object which renders the cells of a data grid asynchronously.\n *\n * #### Notes\n * For performance reason, the datagrid only paints cells synchronously,\n * though if your cell renderer inherits from AsyncCellRenderer, you will\n * be able to do some asynchronous work prior to painting the cell.\n * See `ImageRenderer` for an example of an asynchronous renderer.\n */\nclass AsyncCellRenderer extends CellRenderer {\n}\n\n/*\n * Copyright (c) Jupyter Development Team.\n * Distributed under the terms of the Modified BSD License.\n */\n// default validation error message\nconst DEFAULT_INVALID_INPUT_MESSAGE = 'Invalid input!';\n/**\n * A cell input validator object which always returns valid.\n */\nclass PassInputValidator {\n /**\n * Validate cell input.\n *\n * @param cell - The object holding cell configuration data.\n *\n * @param value - The cell value input.\n *\n * @returns An object with validation result.\n */\n validate(cell, value) {\n return { valid: true };\n }\n}\n/**\n * Text cell input validator.\n */\nclass TextInputValidator {\n constructor() {\n /**\n * Minimum text length\n *\n * The default is Number.NaN, meaning no minimum constraint\n */\n this.minLength = Number.NaN;\n /**\n * Maximum text length\n *\n * The default is Number.NaN, meaning no maximum constraint\n */\n this.maxLength = Number.NaN;\n /**\n * Required text pattern as regular expression\n *\n * The default is null, meaning no pattern constraint\n */\n this.pattern = null;\n }\n /**\n * Validate cell input.\n *\n * @param cell - The object holding cell configuration data.\n *\n * @param value - The cell value input.\n *\n * @returns An object with validation result.\n */\n validate(cell, value) {\n if (value === null) {\n return { valid: true };\n }\n if (typeof value !== 'string') {\n return {\n valid: false,\n message: 'Input must be valid text'\n };\n }\n if (!isNaN(this.minLength) && value.length < this.minLength) {\n return {\n valid: false,\n message: `Text length must be greater than ${this.minLength}`\n };\n }\n if (!isNaN(this.maxLength) && value.length > this.maxLength) {\n return {\n valid: false,\n message: `Text length must be less than ${this.maxLength}`\n };\n }\n if (this.pattern && !this.pattern.test(value)) {\n return {\n valid: false,\n message: `Text doesn't match the required pattern`\n };\n }\n return { valid: true };\n }\n}\n/**\n * Integer cell input validator.\n */\nclass IntegerInputValidator {\n constructor() {\n /**\n * Minimum value\n *\n * The default is Number.NaN, meaning no minimum constraint\n */\n this.min = Number.NaN;\n /**\n * Maximum value\n *\n * The default is Number.NaN, meaning no maximum constraint\n */\n this.max = Number.NaN;\n }\n /**\n * Validate cell input.\n *\n * @param cell - The object holding cell configuration data.\n *\n * @param value - The cell value input.\n *\n * @returns An object with validation result.\n */\n validate(cell, value) {\n if (value === null) {\n return { valid: true };\n }\n if (isNaN(value) || value % 1 !== 0) {\n return {\n valid: false,\n message: 'Input must be valid integer'\n };\n }\n if (!isNaN(this.min) && value < this.min) {\n return {\n valid: false,\n message: `Input must be greater than ${this.min}`\n };\n }\n if (!isNaN(this.max) && value > this.max) {\n return {\n valid: false,\n message: `Input must be less than ${this.max}`\n };\n }\n return { valid: true };\n }\n}\n/**\n * Real number cell input validator.\n */\nclass NumberInputValidator {\n constructor() {\n /**\n * Minimum value\n *\n * The default is Number.NaN, meaning no minimum constraint\n */\n this.min = Number.NaN;\n /**\n * Maximum value\n *\n * The default is Number.NaN, meaning no maximum constraint\n */\n this.max = Number.NaN;\n }\n /**\n * Validate cell input.\n *\n * @param cell - The object holding cell configuration data.\n *\n * @param value - The cell value input.\n *\n * @returns An object with validation result.\n */\n validate(cell, value) {\n if (value === null) {\n return { valid: true };\n }\n if (isNaN(value)) {\n return {\n valid: false,\n message: 'Input must be valid number'\n };\n }\n if (!isNaN(this.min) && value < this.min) {\n return {\n valid: false,\n message: `Input must be greater than ${this.min}`\n };\n }\n if (!isNaN(this.max) && value > this.max) {\n return {\n valid: false,\n message: `Input must be less than ${this.max}`\n };\n }\n return { valid: true };\n }\n}\n/**\n * An abstract base class that provides the most of the functionality\n * needed by a cell editor. All of the built-in cell editors\n * for various cell types are derived from this base class. Custom cell editors\n * can be easily implemented by extending this class.\n */\nclass CellEditor {\n /**\n * Construct a new cell editor.\n */\n constructor() {\n /**\n * A signal emitted when input changes.\n */\n this.inputChanged = new Signal(this);\n /**\n * Notification popup used to show validation error messages.\n */\n this.validityNotification = null;\n /**\n * Whether the cell editor is disposed.\n */\n this._disposed = false;\n /**\n * Whether the value input is valid.\n */\n this._validInput = true;\n /**\n * Grid wheel event handler.\n */\n this._gridWheelEventHandler = null;\n this.inputChanged.connect(() => {\n this.validate();\n });\n }\n /**\n * Whether the cell editor is disposed.\n */\n get isDisposed() {\n return this._disposed;\n }\n /**\n * Dispose of the resources held by cell editor.\n */\n dispose() {\n if (this._disposed) {\n return;\n }\n if (this._gridWheelEventHandler) {\n this.cell.grid.node.removeEventListener('wheel', this._gridWheelEventHandler);\n this._gridWheelEventHandler = null;\n }\n this._closeValidityNotification();\n this._disposed = true;\n this.cell.grid.node.removeChild(this.viewportOccluder);\n }\n /**\n * Start editing the cell.\n *\n * @param cell - The object holding cell configuration data.\n *\n * @param options - The cell editing options.\n */\n edit(cell, options) {\n this.cell = cell;\n this.onCommit = options && options.onCommit;\n this.onCancel = options && options.onCancel;\n this.validator =\n options && options.validator\n ? options.validator\n : this.createValidatorBasedOnType();\n this._gridWheelEventHandler = () => {\n this._closeValidityNotification();\n this.updatePosition();\n };\n cell.grid.node.addEventListener('wheel', this._gridWheelEventHandler);\n this._addContainer();\n this.updatePosition();\n this.startEditing();\n }\n /**\n * Cancel editing the cell.\n */\n cancel() {\n if (this._disposed) {\n return;\n }\n this.dispose();\n if (this.onCancel) {\n this.onCancel();\n }\n }\n /**\n * Whether the value input is valid.\n */\n get validInput() {\n return this._validInput;\n }\n /**\n * Validate the cell input. Shows validation error notification when input is invalid.\n */\n validate() {\n let value;\n try {\n value = this.getInput();\n }\n catch (error) {\n console.log(`Input error: ${error.message}`);\n this.setValidity(false, error.message || DEFAULT_INVALID_INPUT_MESSAGE);\n return;\n }\n if (this.validator) {\n const result = this.validator.validate(this.cell, value);\n if (result.valid) {\n this.setValidity(true);\n }\n else {\n this.setValidity(false, result.message || DEFAULT_INVALID_INPUT_MESSAGE);\n }\n }\n else {\n this.setValidity(true);\n }\n }\n /**\n * Set validity flag.\n *\n * @param valid - Whether the input is valid.\n *\n * @param message - Notification message to show.\n *\n * If message is set to empty string (which is the default)\n * existing notification popup is removed if any.\n */\n setValidity(valid, message = '') {\n this._validInput = valid;\n this._closeValidityNotification();\n if (valid) {\n this.editorContainer.classList.remove('lm-mod-invalid');\n }\n else {\n this.editorContainer.classList.add('lm-mod-invalid');\n // show a notification popup\n if (message !== '') {\n this.validityNotification = new CellEditor.Notification({\n target: this.editorContainer,\n message: message,\n placement: 'bottom',\n timeout: 5000\n });\n this.validityNotification.show();\n }\n }\n }\n /**\n * Create and return a cell input validator based on configuration of the\n * cell being edited. If no suitable validator can be found, it returns undefined.\n */\n createValidatorBasedOnType() {\n const cell = this.cell;\n const metadata = cell.grid.dataModel.metadata('body', cell.row, cell.column);\n switch (metadata && metadata.type) {\n case 'string':\n {\n const validator = new TextInputValidator();\n if (typeof metadata.format === 'string') {\n const format = metadata.format;\n switch (format) {\n case 'email':\n validator.pattern = new RegExp('^([a-z0-9_.-]+)@([da-z.-]+).([a-z.]{2,6})$');\n break;\n case 'uuid':\n validator.pattern = new RegExp('[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}');\n break;\n }\n }\n if (metadata.constraint) {\n if (metadata.constraint.minLength !== undefined) {\n validator.minLength = metadata.constraint.minLength;\n }\n if (metadata.constraint.maxLength !== undefined) {\n validator.maxLength = metadata.constraint.maxLength;\n }\n if (typeof metadata.constraint.pattern === 'string') {\n validator.pattern = new RegExp(metadata.constraint.pattern);\n }\n }\n return validator;\n }\n case 'number':\n {\n const validator = new NumberInputValidator();\n if (metadata.constraint) {\n if (metadata.constraint.minimum !== undefined) {\n validator.min = metadata.constraint.minimum;\n }\n if (metadata.constraint.maximum !== undefined) {\n validator.max = metadata.constraint.maximum;\n }\n }\n return validator;\n }\n case 'integer':\n {\n const validator = new IntegerInputValidator();\n if (metadata.constraint) {\n if (metadata.constraint.minimum !== undefined) {\n validator.min = metadata.constraint.minimum;\n }\n if (metadata.constraint.maximum !== undefined) {\n validator.max = metadata.constraint.maximum;\n }\n }\n return validator;\n }\n }\n return undefined;\n }\n /**\n * Compute cell rectangle and return with other cell properties.\n */\n getCellInfo(cell) {\n const { grid, row, column } = cell;\n let data, columnX, rowY, width, height;\n const cellGroup = CellGroup.getGroup(grid.dataModel, 'body', row, column);\n if (cellGroup) {\n columnX =\n grid.headerWidth -\n grid.scrollX +\n grid.columnOffset('body', cellGroup.c1);\n rowY =\n grid.headerHeight - grid.scrollY + grid.rowOffset('body', cellGroup.r1);\n width = 0;\n height = 0;\n for (let r = cellGroup.r1; r <= cellGroup.r2; r++) {\n height += grid.rowSize('body', r);\n }\n for (let c = cellGroup.c1; c <= cellGroup.c2; c++) {\n width += grid.columnSize('body', c);\n }\n data = grid.dataModel.data('body', cellGroup.r1, cellGroup.c1);\n }\n else {\n columnX =\n grid.headerWidth - grid.scrollX + grid.columnOffset('body', column);\n rowY = grid.headerHeight - grid.scrollY + grid.rowOffset('body', row);\n width = grid.columnSize('body', column);\n height = grid.rowSize('body', row);\n data = grid.dataModel.data('body', row, column);\n }\n return {\n grid: grid,\n row: row,\n column: column,\n data: data,\n x: columnX,\n y: rowY,\n width: width,\n height: height\n };\n }\n /**\n * Reposition cell editor by moving viewport occluder and cell editor container.\n */\n updatePosition() {\n const grid = this.cell.grid;\n const cellInfo = this.getCellInfo(this.cell);\n const headerHeight = grid.headerHeight;\n const headerWidth = grid.headerWidth;\n this.viewportOccluder.style.top = headerHeight + 'px';\n this.viewportOccluder.style.left = headerWidth + 'px';\n this.viewportOccluder.style.width = grid.viewportWidth - headerWidth + 'px';\n this.viewportOccluder.style.height =\n grid.viewportHeight - headerHeight + 'px';\n this.viewportOccluder.style.position = 'absolute';\n this.editorContainer.style.left = cellInfo.x - 1 - headerWidth + 'px';\n this.editorContainer.style.top = cellInfo.y - 1 - headerHeight + 'px';\n this.editorContainer.style.width = cellInfo.width + 1 + 'px';\n this.editorContainer.style.height = cellInfo.height + 1 + 'px';\n this.editorContainer.style.visibility = 'visible';\n this.editorContainer.style.position = 'absolute';\n }\n /**\n * Commit the edited value.\n *\n * @param cursorMovement - Cursor move direction based on keys pressed to end the edit.\n *\n * @returns true on valid input, false otherwise.\n */\n commit(cursorMovement = 'none') {\n this.validate();\n if (!this._validInput) {\n return false;\n }\n let value;\n try {\n value = this.getInput();\n }\n catch (error) {\n console.log(`Input error: ${error.message}`);\n return false;\n }\n this.dispose();\n if (this.onCommit) {\n this.onCommit({\n cell: this.cell,\n value: value,\n cursorMovement: cursorMovement\n });\n }\n return true;\n }\n /**\n * Create container elements needed to prevent editor widget overflow\n * beyond viewport and to position cell editor widget.\n */\n _addContainer() {\n this.viewportOccluder = document.createElement('div');\n this.viewportOccluder.className = 'lm-DataGrid-cellEditorOccluder';\n this.cell.grid.node.appendChild(this.viewportOccluder);\n this.editorContainer = document.createElement('div');\n this.editorContainer.className = 'lm-DataGrid-cellEditorContainer';\n this.viewportOccluder.appendChild(this.editorContainer);\n // update mouse event pass-through state based on input validity\n this.editorContainer.addEventListener('mouseleave', (event) => {\n this.viewportOccluder.style.pointerEvents = this._validInput\n ? 'none'\n : 'auto';\n });\n this.editorContainer.addEventListener('mouseenter', (event) => {\n this.viewportOccluder.style.pointerEvents = 'none';\n });\n }\n /**\n * Remove validity notification popup.\n */\n _closeValidityNotification() {\n if (this.validityNotification) {\n this.validityNotification.close();\n this.validityNotification = null;\n }\n }\n}\n/**\n * Abstract base class with shared functionality\n * for cell editors which use HTML Input widget as editor.\n */\nclass InputCellEditor extends CellEditor {\n /**\n * Handle the DOM events for the editor.\n *\n * @param event - The DOM event sent to the editor.\n */\n handleEvent(event) {\n switch (event.type) {\n case 'keydown':\n this._onKeyDown(event);\n break;\n case 'blur':\n this._onBlur(event);\n break;\n case 'input':\n this._onInput(event);\n break;\n }\n }\n /**\n * Dispose of the resources held by cell editor.\n */\n dispose() {\n if (this.isDisposed) {\n return;\n }\n this._unbindEvents();\n super.dispose();\n }\n /**\n * Start editing the cell.\n */\n startEditing() {\n this.createWidget();\n const cell = this.cell;\n const cellInfo = this.getCellInfo(cell);\n this.input.value = this.deserialize(cellInfo.data);\n this.editorContainer.appendChild(this.input);\n this.input.focus();\n this.input.select();\n this.bindEvents();\n }\n deserialize(value) {\n if (value === null || value === undefined) {\n return '';\n }\n return value.toString();\n }\n createWidget() {\n const input = document.createElement('input');\n input.classList.add('lm-DataGrid-cellEditorWidget');\n input.classList.add('lm-DataGrid-cellEditorInput');\n input.spellcheck = false;\n input.type = this.inputType;\n this.input = input;\n }\n bindEvents() {\n this.input.addEventListener('keydown', this);\n this.input.addEventListener('blur', this);\n this.input.addEventListener('input', this);\n }\n _unbindEvents() {\n this.input.removeEventListener('keydown', this);\n this.input.removeEventListener('blur', this);\n this.input.removeEventListener('input', this);\n }\n _onKeyDown(event) {\n switch (getKeyboardLayout().keyForKeydownEvent(event)) {\n case 'Enter':\n this.commit(event.shiftKey ? 'up' : 'down');\n break;\n case 'Tab':\n this.commit(event.shiftKey ? 'left' : 'right');\n event.stopPropagation();\n event.preventDefault();\n break;\n case 'Escape':\n this.cancel();\n break;\n }\n }\n _onBlur(event) {\n if (this.isDisposed) {\n return;\n }\n if (!this.commit()) {\n event.preventDefault();\n event.stopPropagation();\n this.input.focus();\n }\n }\n _onInput(event) {\n this.inputChanged.emit(void 0);\n }\n}\n/**\n * Cell editor for text cells.\n */\nclass TextCellEditor extends InputCellEditor {\n constructor() {\n super(...arguments);\n this.inputType = 'text';\n }\n /**\n * Return the current text input entered.\n */\n getInput() {\n return this.input.value;\n }\n}\n/**\n * Cell editor for real number cells.\n */\nclass NumberCellEditor extends InputCellEditor {\n constructor() {\n super(...arguments);\n this.inputType = 'number';\n }\n /**\n * Start editing the cell.\n */\n startEditing() {\n super.startEditing();\n this.input.step = 'any';\n const cell = this.cell;\n const metadata = cell.grid.dataModel.metadata('body', cell.row, cell.column);\n const constraint = metadata.constraint;\n if (constraint) {\n if (constraint.minimum) {\n this.input.min = constraint.minimum;\n }\n if (constraint.maximum) {\n this.input.max = constraint.maximum;\n }\n }\n }\n /**\n * Return the current number input entered. This method throws exception\n * if input is invalid.\n */\n getInput() {\n let value = this.input.value;\n if (value.trim() === '') {\n return null;\n }\n const floatValue = parseFloat(value);\n if (isNaN(floatValue)) {\n throw new Error('Invalid input');\n }\n return floatValue;\n }\n}\n/**\n * Cell editor for integer cells.\n */\nclass IntegerCellEditor extends InputCellEditor {\n constructor() {\n super(...arguments);\n this.inputType = 'number';\n }\n /**\n * Start editing the cell.\n */\n startEditing() {\n super.startEditing();\n this.input.step = '1';\n const cell = this.cell;\n const metadata = cell.grid.dataModel.metadata('body', cell.row, cell.column);\n const constraint = metadata.constraint;\n if (constraint) {\n if (constraint.minimum) {\n this.input.min = constraint.minimum;\n }\n if (constraint.maximum) {\n this.input.max = constraint.maximum;\n }\n }\n }\n /**\n * Return the current integer input entered. This method throws exception\n * if input is invalid.\n */\n getInput() {\n let value = this.input.value;\n if (value.trim() === '') {\n return null;\n }\n let intValue = parseInt(value);\n if (isNaN(intValue)) {\n throw new Error('Invalid input');\n }\n return intValue;\n }\n}\n/**\n * Cell editor for date cells.\n */\nclass DateCellEditor extends CellEditor {\n /**\n * Handle the DOM events for the editor.\n *\n * @param event - The DOM event sent to the editor.\n */\n handleEvent(event) {\n switch (event.type) {\n case 'keydown':\n this._onKeyDown(event);\n break;\n case 'blur':\n this._onBlur(event);\n break;\n }\n }\n /**\n * Dispose of the resources held by cell editor.\n */\n dispose() {\n if (this.isDisposed) {\n return;\n }\n this._unbindEvents();\n super.dispose();\n }\n /**\n * Start editing the cell.\n */\n startEditing() {\n this._createWidget();\n const cell = this.cell;\n const cellInfo = this.getCellInfo(cell);\n this._input.value = this._deserialize(cellInfo.data);\n this.editorContainer.appendChild(this._input);\n this._input.focus();\n this._bindEvents();\n }\n /**\n * Return the current date input entered.\n */\n getInput() {\n return this._input.value;\n }\n _deserialize(value) {\n if (value === null || value === undefined) {\n return '';\n }\n return value.toString();\n }\n _createWidget() {\n const input = document.createElement('input');\n input.type = 'date';\n input.pattern = 'd{4}-d{2}-d{2}';\n input.classList.add('lm-DataGrid-cellEditorWidget');\n input.classList.add('lm-DataGrid-cellEditorInput');\n this._input = input;\n }\n _bindEvents() {\n this._input.addEventListener('keydown', this);\n this._input.addEventListener('blur', this);\n }\n _unbindEvents() {\n this._input.removeEventListener('keydown', this);\n this._input.removeEventListener('blur', this);\n }\n _onKeyDown(event) {\n switch (getKeyboardLayout().keyForKeydownEvent(event)) {\n case 'Enter':\n this.commit(event.shiftKey ? 'up' : 'down');\n break;\n case 'Tab':\n this.commit(event.shiftKey ? 'left' : 'right');\n event.stopPropagation();\n event.preventDefault();\n break;\n case 'Escape':\n this.cancel();\n break;\n }\n }\n _onBlur(event) {\n if (this.isDisposed) {\n return;\n }\n if (!this.commit()) {\n event.preventDefault();\n event.stopPropagation();\n this._input.focus();\n }\n }\n}\n/**\n * Cell editor for boolean cells.\n */\nclass BooleanCellEditor extends CellEditor {\n /**\n * Handle the DOM events for the editor.\n *\n * @param event - The DOM event sent to the editor.\n */\n handleEvent(event) {\n switch (event.type) {\n case 'keydown':\n this._onKeyDown(event);\n break;\n case 'mousedown':\n // fix focus loss problem in Safari and Firefox\n this._input.focus();\n event.stopPropagation();\n event.preventDefault();\n break;\n case 'blur':\n this._onBlur(event);\n break;\n }\n }\n /**\n * Dispose of the resources held by cell editor.\n */\n dispose() {\n if (this.isDisposed) {\n return;\n }\n this._unbindEvents();\n super.dispose();\n }\n /**\n * Start editing the cell.\n */\n startEditing() {\n this._createWidget();\n const cell = this.cell;\n const cellInfo = this.getCellInfo(cell);\n this._input.checked = this._deserialize(cellInfo.data);\n this.editorContainer.appendChild(this._input);\n this._input.focus();\n this._bindEvents();\n }\n /**\n * Return the current boolean input entered.\n */\n getInput() {\n return this._input.checked;\n }\n _deserialize(value) {\n if (value === null || value === undefined) {\n return false;\n }\n return value == true;\n }\n _createWidget() {\n const input = document.createElement('input');\n input.classList.add('lm-DataGrid-cellEditorWidget');\n input.classList.add('lm-DataGrid-cellEditorCheckbox');\n input.type = 'checkbox';\n input.spellcheck = false;\n this._input = input;\n }\n _bindEvents() {\n this._input.addEventListener('keydown', this);\n this._input.addEventListener('mousedown', this);\n this._input.addEventListener('blur', this);\n }\n _unbindEvents() {\n this._input.removeEventListener('keydown', this);\n this._input.removeEventListener('mousedown', this);\n this._input.removeEventListener('blur', this);\n }\n _onKeyDown(event) {\n switch (getKeyboardLayout().keyForKeydownEvent(event)) {\n case 'Enter':\n this.commit(event.shiftKey ? 'up' : 'down');\n break;\n case 'Tab':\n this.commit(event.shiftKey ? 'left' : 'right');\n event.stopPropagation();\n event.preventDefault();\n break;\n case 'Escape':\n this.cancel();\n break;\n }\n }\n _onBlur(event) {\n if (this.isDisposed) {\n return;\n }\n if (!this.commit()) {\n event.preventDefault();\n event.stopPropagation();\n this._input.focus();\n }\n }\n}\n/**\n * Cell editor for option cells.\n *\n * It supports multiple option selection. If cell metadata contains\n * type attribute 'array', then it behaves as a multi select.\n * In that case cell data is expected to be list of string values.\n */\nclass OptionCellEditor extends CellEditor {\n constructor() {\n super(...arguments);\n this._isMultiSelect = false;\n }\n /**\n * Dispose of the resources held by cell editor.\n */\n dispose() {\n if (this.isDisposed) {\n return;\n }\n super.dispose();\n if (this._isMultiSelect) {\n document.body.removeChild(this._select);\n }\n }\n /**\n * Start editing the cell.\n */\n startEditing() {\n const cell = this.cell;\n const cellInfo = this.getCellInfo(cell);\n const metadata = cell.grid.dataModel.metadata('body', cell.row, cell.column);\n this._isMultiSelect = metadata.type === 'array';\n this._createWidget();\n if (this._isMultiSelect) {\n this._select.multiple = true;\n const values = this._deserialize(cellInfo.data);\n for (let i = 0; i < this._select.options.length; ++i) {\n const option = this._select.options.item(i);\n option.selected = values.indexOf(option.value) !== -1;\n }\n document.body.appendChild(this._select);\n }\n else {\n this._select.value = this._deserialize(cellInfo.data);\n this.editorContainer.appendChild(this._select);\n }\n this._select.focus();\n this._bindEvents();\n this.updatePosition();\n }\n /**\n * Return the current option input.\n */\n getInput() {\n if (this._isMultiSelect) {\n const input = [];\n for (let i = 0; i < this._select.selectedOptions.length; ++i) {\n input.push(this._select.selectedOptions.item(i).value);\n }\n return input;\n }\n else {\n return this._select.value;\n }\n }\n /**\n * Reposition cell editor.\n */\n updatePosition() {\n super.updatePosition();\n if (!this._isMultiSelect) {\n return;\n }\n const cellInfo = this.getCellInfo(this.cell);\n this._select.style.position = 'absolute';\n const editorContainerRect = this.editorContainer.getBoundingClientRect();\n this._select.style.left = editorContainerRect.left + 'px';\n this._select.style.top = editorContainerRect.top + cellInfo.height + 'px';\n this._select.style.width = editorContainerRect.width + 'px';\n this._select.style.maxHeight = '60px';\n this.editorContainer.style.visibility = 'hidden';\n }\n _deserialize(value) {\n if (value === null || value === undefined) {\n return '';\n }\n if (this._isMultiSelect) {\n const values = [];\n if (Array.isArray(value)) {\n for (let item of value) {\n values.push(item.toString());\n }\n }\n return values;\n }\n else {\n return value.toString();\n }\n }\n _createWidget() {\n const cell = this.cell;\n const metadata = cell.grid.dataModel.metadata('body', cell.row, cell.column);\n const items = metadata.constraint.enum;\n const select = document.createElement('select');\n select.classList.add('lm-DataGrid-cellEditorWidget');\n for (let item of items) {\n const option = document.createElement('option');\n option.value = item;\n option.text = item;\n select.appendChild(option);\n }\n this._select = select;\n }\n _bindEvents() {\n this._select.addEventListener('keydown', this._onKeyDown.bind(this));\n this._select.addEventListener('blur', this._onBlur.bind(this));\n }\n _onKeyDown(event) {\n switch (getKeyboardLayout().keyForKeydownEvent(event)) {\n case 'Enter':\n this.commit(event.shiftKey ? 'up' : 'down');\n break;\n case 'Tab':\n this.commit(event.shiftKey ? 'left' : 'right');\n event.stopPropagation();\n event.preventDefault();\n break;\n case 'Escape':\n this.cancel();\n break;\n }\n }\n _onBlur(event) {\n if (this.isDisposed) {\n return;\n }\n if (!this.commit()) {\n event.preventDefault();\n event.stopPropagation();\n this._select.focus();\n }\n }\n}\n/**\n * Cell editor for option cells whose value can be any value\n * from set of pre-defined options or values that can be input by user.\n */\nclass DynamicOptionCellEditor extends CellEditor {\n /**\n * Handle the DOM events for the editor.\n *\n * @param event - The DOM event sent to the editor.\n */\n handleEvent(event) {\n switch (event.type) {\n case 'keydown':\n this._onKeyDown(event);\n break;\n case 'blur':\n this._onBlur(event);\n break;\n }\n }\n /**\n * Dispose of the resources held by cell editor.\n */\n dispose() {\n if (this.isDisposed) {\n return;\n }\n this._unbindEvents();\n super.dispose();\n }\n /**\n * Start editing the cell.\n */\n startEditing() {\n this._createWidget();\n const cell = this.cell;\n const cellInfo = this.getCellInfo(cell);\n this._input.value = this._deserialize(cellInfo.data);\n this.editorContainer.appendChild(this._input);\n this._input.focus();\n this._input.select();\n this._bindEvents();\n }\n /**\n * Return the current option input.\n */\n getInput() {\n return this._input.value;\n }\n _deserialize(value) {\n if (value === null || value === undefined) {\n return '';\n }\n return value.toString();\n }\n _createWidget() {\n const cell = this.cell;\n const grid = cell.grid;\n const dataModel = grid.dataModel;\n const rowCount = dataModel.rowCount('body');\n const listId = 'cell-editor-list';\n const list = document.createElement('datalist');\n list.id = listId;\n const input = document.createElement('input');\n input.classList.add('lm-DataGrid-cellEditorWidget');\n input.classList.add('lm-DataGrid-cellEditorInput');\n const valueSet = new Set();\n for (let r = 0; r < rowCount; ++r) {\n const data = dataModel.data('body', r, cell.column);\n if (data) {\n valueSet.add(data);\n }\n }\n valueSet.forEach((value) => {\n const option = document.createElement('option');\n option.value = value;\n option.text = value;\n list.appendChild(option);\n });\n this.editorContainer.appendChild(list);\n input.setAttribute('list', listId);\n this._input = input;\n }\n _bindEvents() {\n this._input.addEventListener('keydown', this);\n this._input.addEventListener('blur', this);\n }\n _unbindEvents() {\n this._input.removeEventListener('keydown', this);\n this._input.removeEventListener('blur', this);\n }\n _onKeyDown(event) {\n switch (getKeyboardLayout().keyForKeydownEvent(event)) {\n case 'Enter':\n this.commit(event.shiftKey ? 'up' : 'down');\n break;\n case 'Tab':\n this.commit(event.shiftKey ? 'left' : 'right');\n event.stopPropagation();\n event.preventDefault();\n break;\n case 'Escape':\n this.cancel();\n break;\n }\n }\n _onBlur(event) {\n if (this.isDisposed) {\n return;\n }\n if (!this.commit()) {\n event.preventDefault();\n event.stopPropagation();\n this._input.focus();\n }\n }\n}\n/**\n * The namespace for the `CellEditor` class statics.\n */\n(function (CellEditor) {\n /**\n * A widget which implements a notification popup.\n */\n class Notification extends Widget {\n /**\n * Construct a new notification.\n *\n * @param options - The options for initializing the notification.\n */\n constructor(options) {\n super({ node: Notification.createNode() });\n this._message = '';\n this.addClass('lm-DataGrid-notification');\n this.setFlag(Widget.Flag.DisallowLayout);\n this._target = options.target;\n this._message = options.message || '';\n this._placement = options.placement || 'bottom';\n Widget.attach(this, document.body);\n if (options.timeout && options.timeout > 0) {\n setTimeout(() => {\n this.close();\n }, options.timeout);\n }\n }\n /**\n * Handle the DOM events for the notification.\n *\n * @param event - The DOM event sent to the notification.\n *\n * #### Notes\n * This method implements the DOM `EventListener` interface and is\n * called in response to events on the notification's DOM node.\n *\n * This should not be called directly by user code.\n */\n handleEvent(event) {\n switch (event.type) {\n case 'mousedown':\n this._evtMouseDown(event);\n break;\n case 'contextmenu':\n event.preventDefault();\n event.stopPropagation();\n break;\n }\n }\n /**\n * Get the placement of the notification.\n */\n get placement() {\n return this._placement;\n }\n /**\n * Set the placement of the notification.\n */\n set placement(value) {\n // Do nothing if the placement does not change.\n if (this._placement === value) {\n return;\n }\n // Update the internal placement.\n this._placement = value;\n // Schedule an update for notification.\n this.update();\n }\n /**\n * Get the current value of the message.\n */\n get message() {\n return this._message;\n }\n /**\n * Set the current value of the message.\n *\n */\n set message(value) {\n // Do nothing if the value does not change.\n if (this._message === value) {\n return;\n }\n // Update the internal value.\n this._message = value;\n // Schedule an update for notification.\n this.update();\n }\n /**\n * Get the node presenting the message.\n */\n get messageNode() {\n return this.node.getElementsByClassName('lm-DataGrid-notificationMessage')[0];\n }\n /**\n * A method invoked on a 'before-attach' message.\n */\n onBeforeAttach(msg) {\n this.node.addEventListener('mousedown', this);\n this.update();\n }\n /**\n * A method invoked on an 'after-detach' message.\n */\n onAfterDetach(msg) {\n this.node.removeEventListener('mousedown', this);\n }\n /**\n * A method invoked on an 'update-request' message.\n */\n onUpdateRequest(msg) {\n const targetRect = this._target.getBoundingClientRect();\n const style = this.node.style;\n switch (this._placement) {\n case 'bottom':\n style.left = targetRect.left + 'px';\n style.top = targetRect.bottom + 'px';\n break;\n case 'top':\n style.left = targetRect.left + 'px';\n style.height = targetRect.top + 'px';\n style.top = '0';\n style.alignItems = 'flex-end';\n style.justifyContent = 'flex-end';\n break;\n case 'left':\n style.left = '0';\n style.width = targetRect.left + 'px';\n style.top = targetRect.top + 'px';\n style.alignItems = 'flex-end';\n style.justifyContent = 'flex-end';\n break;\n case 'right':\n style.left = targetRect.right + 'px';\n style.top = targetRect.top + 'px';\n break;\n }\n this.messageNode.innerHTML = this._message;\n }\n /**\n * Handle the `'mousedown'` event for the notification.\n */\n _evtMouseDown(event) {\n // Do nothing if it's not a left mouse press.\n if (event.button !== 0) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n this.close();\n }\n }\n CellEditor.Notification = Notification;\n /**\n * The namespace for the `Notification` class statics.\n */\n (function (Notification) {\n /**\n * Create the DOM node for notification.\n */\n function createNode() {\n const node = document.createElement('div');\n const container = document.createElement('div');\n container.className = 'lm-DataGrid-notificationContainer';\n const message = document.createElement('span');\n message.className = 'lm-DataGrid-notificationMessage';\n container.appendChild(message);\n node.appendChild(container);\n return node;\n }\n Notification.createNode = createNode;\n })(Notification = CellEditor.Notification || (CellEditor.Notification = {}));\n})(CellEditor || (CellEditor = {}));\n\n/*\n * Copyright (c) Jupyter Development Team.\n * Distributed under the terms of the Modified BSD License.\n */\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * Resolve a config option for a cell editor.\n *\n * @param option - The config option to resolve.\n *\n * @param config - The cell config object.\n *\n * @returns The resolved value for the option.\n */\nfunction resolveOption(option, config) {\n return typeof option === 'function'\n ? option(config)\n : option;\n}\n/**\n * An object which manages cell editing. It stores editor overrides,\n * decides which editor to use for a cell, makes sure there is only one editor active.\n */\nclass CellEditorController {\n constructor() {\n // active cell editor\n this._editor = null;\n // active cell being edited\n this._cell = null;\n // cell editor overrides based on cell data type identifier\n this._typeBasedOverrides = new Map();\n // cell editor overrides based on partial metadata match\n this._metadataBasedOverrides = new Map();\n }\n /**\n * Override cell editor for the cells matching the identifier.\n *\n * @param identifier - Cell identifier to use when matching cells.\n * if identifier is a CellDataType, then cell matching is done using data type of the cell,\n * if identifier is a Metadata, then partial match of the cell metadata with identifier is used for match,\n * if identifier is 'default' then override is used as default editor when no other editor is found suitable\n *\n * @param editor - The cell editor to use or resolver to use to get an editor for matching cells.\n */\n setEditor(identifier, editor) {\n if (typeof identifier === 'string') {\n this._typeBasedOverrides.set(identifier, editor);\n }\n else {\n const key = this._metadataIdentifierToKey(identifier);\n this._metadataBasedOverrides.set(key, [identifier, editor]);\n }\n }\n /**\n * Start editing a cell.\n *\n * @param cell - The object holding cell configuration data.\n *\n * @param options - The cell editing options.\n */\n edit(cell, options) {\n const grid = cell.grid;\n if (!grid.editable) {\n console.error('Grid cannot be edited!');\n return false;\n }\n this.cancel();\n this._cell = cell;\n options = options || {};\n options.onCommit = options.onCommit || this._onCommit.bind(this);\n options.onCancel = options.onCancel || this._onCancel.bind(this);\n // if an editor is passed in with options, then use it for editing\n if (options.editor) {\n this._editor = options.editor;\n options.editor.edit(cell, options);\n return true;\n }\n // choose an editor based on overrides / cell data type\n const editor = this._getEditor(cell);\n if (editor) {\n this._editor = editor;\n editor.edit(cell, options);\n return true;\n }\n return false;\n }\n /**\n * Cancel editing.\n */\n cancel() {\n if (this._editor) {\n this._editor.cancel();\n this._editor = null;\n }\n this._cell = null;\n }\n _onCommit(response) {\n const cell = this._cell;\n if (!cell) {\n return;\n }\n const grid = cell.grid;\n const dataModel = grid.dataModel;\n let row = cell.row;\n let column = cell.column;\n const cellGroup = CellGroup.getGroup(grid.dataModel, 'body', row, column);\n if (cellGroup) {\n row = cellGroup.r1;\n column = cellGroup.c1;\n }\n dataModel.setData('body', row, column, response.value);\n grid.viewport.node.focus();\n if (response.cursorMovement !== 'none') {\n grid.moveCursor(response.cursorMovement);\n grid.scrollToCursor();\n }\n }\n _onCancel() {\n if (!this._cell) {\n return;\n }\n this._cell.grid.viewport.node.focus();\n }\n _getDataTypeKey(cell) {\n const metadata = cell.grid.dataModel\n ? cell.grid.dataModel.metadata('body', cell.row, cell.column)\n : null;\n if (!metadata) {\n return 'default';\n }\n let key = '';\n if (metadata) {\n key = metadata.type;\n }\n if (metadata.constraint && metadata.constraint.enum) {\n if (metadata.constraint.enum === 'dynamic') {\n key += ':dynamic-option';\n }\n else {\n key += ':option';\n }\n }\n return key;\n }\n _objectToKey(object) {\n let str = '';\n for (let key in object) {\n const value = object[key];\n if (typeof value === 'object') {\n str += `${key}:${this._objectToKey(value)}`;\n }\n else {\n str += `[${key}:${value}]`;\n }\n }\n return str;\n }\n _metadataIdentifierToKey(metadata) {\n return this._objectToKey(metadata);\n }\n _metadataMatchesIdentifier(metadata, identifier) {\n for (let key in identifier) {\n if (!metadata.hasOwnProperty(key)) {\n return false;\n }\n const identifierValue = identifier[key];\n const metadataValue = metadata[key];\n if (typeof identifierValue === 'object') {\n if (!this._metadataMatchesIdentifier(metadataValue, identifierValue)) {\n return false;\n }\n }\n else if (metadataValue !== identifierValue) {\n return false;\n }\n }\n return true;\n }\n _getMetadataBasedEditor(cell) {\n let editorMatched;\n const metadata = cell.grid.dataModel.metadata('body', cell.row, cell.column);\n if (metadata) {\n this._metadataBasedOverrides.forEach(value => {\n if (!editorMatched) {\n let [identifier, editor] = value;\n if (this._metadataMatchesIdentifier(metadata, identifier)) {\n editorMatched = resolveOption(editor, cell);\n }\n }\n });\n }\n return editorMatched;\n }\n /**\n * Choose the most appropriate cell editor to use based on overrides / cell data type.\n *\n * If no match is found in overrides or based on cell data type, and if cell has a primitive\n * data type then TextCellEditor is used as default cell editor. If 'default' cell editor\n * is overridden, then it is used instead of TextCellEditor for default.\n */\n _getEditor(cell) {\n const dtKey = this._getDataTypeKey(cell);\n // find an editor based on data type based override\n if (this._typeBasedOverrides.has(dtKey)) {\n const editor = this._typeBasedOverrides.get(dtKey);\n return resolveOption(editor, cell);\n } // find an editor based on metadata match based override\n else if (this._metadataBasedOverrides.size > 0) {\n const editor = this._getMetadataBasedEditor(cell);\n if (editor) {\n return editor;\n }\n }\n // choose an editor based on data type\n switch (dtKey) {\n case 'string':\n return new TextCellEditor();\n case 'number':\n return new NumberCellEditor();\n case 'integer':\n return new IntegerCellEditor();\n case 'boolean':\n return new BooleanCellEditor();\n case 'date':\n return new DateCellEditor();\n case 'string:option':\n case 'number:option':\n case 'integer:option':\n case 'date:option':\n case 'array:option':\n return new OptionCellEditor();\n case 'string:dynamic-option':\n case 'number:dynamic-option':\n case 'integer:dynamic-option':\n case 'date:dynamic-option':\n return new DynamicOptionCellEditor();\n }\n // if an override exists for 'default', then use it\n if (this._typeBasedOverrides.has('default')) {\n const editor = this._typeBasedOverrides.get('default');\n return resolveOption(editor, cell);\n }\n // if cell has a primitive data type then use TextCellEditor\n const data = cell.grid.dataModel.data('body', cell.row, cell.column);\n if (!data || typeof data !== 'object') {\n return new TextCellEditor();\n }\n // no suitable editor found for the cell\n return undefined;\n }\n}\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * An object which provides the data for a data grid.\n *\n * #### Notes\n * If the predefined data models are insufficient for a particular use\n * case, a custom model can be defined which derives from this class.\n */\nclass DataModel {\n constructor() {\n this._changed = new Signal(this);\n }\n /**\n * A signal emitted when the data model has changed.\n */\n get changed() {\n return this._changed;\n }\n /**\n * Get the count of merged cell groups pertaining to a given\n * cell region.\n * @param region the target cell region.\n */\n groupCount(region) {\n return 0;\n }\n /**\n * Get the metadata for a cell in the data model.\n *\n * @param region - The cell region of interest.\n *\n * @param row - The row index of the cell of interest.\n *\n * @param column - The column index of the cell of interest.\n *\n * @returns The metadata for the specified cell.\n *\n * #### Notes\n * The returned metadata should be treated as immutable.\n *\n * This method is called often, and so should be efficient.\n *\n * The default implementation returns `{}`.\n */\n metadata(region, row, column) {\n return DataModel.emptyMetadata;\n }\n /**\n * Get the merged cell group corresponding to a region and index number.\n * @param region the cell region of cell group.\n * @param groupIndex the group index of the cell group.\n * @returns a cell group.\n */\n group(region, groupIndex) {\n return null;\n }\n /**\n * Emit the `changed` signal for the data model.\n *\n * #### Notes\n * Subclasses should call this method whenever the data model has\n * changed so that attached data grids can update themselves.\n */\n emitChanged(args) {\n this._changed.emit(args);\n }\n}\n/**\n * An object which provides the mutable data for a data grid.\n *\n * #### Notes\n * This object is an extension to `DataModel` and it only adds ability to\n * change data for cells.\n */\nclass MutableDataModel extends DataModel {\n}\n/**\n * The namespace for the `DataModel` class statics.\n */\n(function (DataModel) {\n /**\n * A singleton empty metadata object.\n */\n DataModel.emptyMetadata = Object.freeze({});\n})(DataModel || (DataModel = {}));\n\n/**\n * A thin caching wrapper around a 2D canvas rendering context.\n *\n * #### Notes\n * This class is mostly a transparent wrapper around a canvas rendering\n * context which improves performance when writing context state.\n *\n * For best performance, avoid reading state from the `gc`. Writes are\n * cached based on the previously written value.\n *\n * Unless otherwise specified, the API and semantics of this class are\n * identical to the builtin 2D canvas rendering context:\n * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D\n *\n * The wrapped canvas context should not be manipulated externally\n * until the wrapping `GraphicsContext` object is disposed.\n */\nclass GraphicsContext {\n /**\n * Create a new graphics context object.\n *\n * @param context - The 2D canvas rendering context to wrap.\n */\n constructor(context) {\n this._disposed = false;\n this._context = context;\n this._state = Private$3.State.create(context);\n }\n dispose() {\n // Bail if the gc is already disposed.\n if (this._disposed) {\n return;\n }\n // Mark the gc as disposed.\n this._disposed = true;\n // Pop any unrestored saves.\n while (this._state.next) {\n this._state = this._state.next;\n this._context.restore();\n }\n }\n get isDisposed() {\n return this._disposed;\n }\n get fillStyle() {\n return this._context.fillStyle;\n }\n set fillStyle(value) {\n if (this._state.fillStyle !== value) {\n this._state.fillStyle = value;\n this._context.fillStyle = value;\n }\n }\n get strokeStyle() {\n return this._context.strokeStyle;\n }\n set strokeStyle(value) {\n if (this._state.strokeStyle !== value) {\n this._state.strokeStyle = value;\n this._context.strokeStyle = value;\n }\n }\n get font() {\n return this._context.font;\n }\n set font(value) {\n if (this._state.font !== value) {\n this._state.font = value;\n this._context.font = value;\n }\n }\n get textAlign() {\n return this._context.textAlign;\n }\n set textAlign(value) {\n if (this._state.textAlign !== value) {\n this._state.textAlign = value;\n this._context.textAlign = value;\n }\n }\n get textBaseline() {\n return this._context.textBaseline;\n }\n set textBaseline(value) {\n if (this._state.textBaseline !== value) {\n this._state.textBaseline = value;\n this._context.textBaseline = value;\n }\n }\n get lineCap() {\n return this._context.lineCap;\n }\n set lineCap(value) {\n if (this._state.lineCap !== value) {\n this._state.lineCap = value;\n this._context.lineCap = value;\n }\n }\n get lineDashOffset() {\n return this._context.lineDashOffset;\n }\n set lineDashOffset(value) {\n if (this._state.lineDashOffset !== value) {\n this._state.lineDashOffset = value;\n this._context.lineDashOffset = value;\n }\n }\n get lineJoin() {\n return this._context.lineJoin;\n }\n set lineJoin(value) {\n if (this._state.lineJoin !== value) {\n this._state.lineJoin = value;\n this._context.lineJoin = value;\n }\n }\n get lineWidth() {\n return this._context.lineWidth;\n }\n set lineWidth(value) {\n if (this._state.lineWidth !== value) {\n this._state.lineWidth = value;\n this._context.lineWidth = value;\n }\n }\n get miterLimit() {\n return this._context.miterLimit;\n }\n set miterLimit(value) {\n if (this._state.miterLimit !== value) {\n this._state.miterLimit = value;\n this._context.miterLimit = value;\n }\n }\n get shadowBlur() {\n return this._context.shadowBlur;\n }\n set shadowBlur(value) {\n if (this._state.shadowBlur !== value) {\n this._state.shadowBlur = value;\n this._context.shadowBlur = value;\n }\n }\n get shadowColor() {\n return this._context.shadowColor;\n }\n set shadowColor(value) {\n if (this._state.shadowColor !== value) {\n this._state.shadowColor = value;\n this._context.shadowColor = value;\n }\n }\n get shadowOffsetX() {\n return this._context.shadowOffsetX;\n }\n set shadowOffsetX(value) {\n if (this._state.shadowOffsetX !== value) {\n this._state.shadowOffsetX = value;\n this._context.shadowOffsetX = value;\n }\n }\n get shadowOffsetY() {\n return this._context.shadowOffsetY;\n }\n set shadowOffsetY(value) {\n if (this._state.shadowOffsetY !== value) {\n this._state.shadowOffsetY = value;\n this._context.shadowOffsetY = value;\n }\n }\n get imageSmoothingEnabled() {\n return this._context.imageSmoothingEnabled;\n }\n set imageSmoothingEnabled(value) {\n if (this._state.imageSmoothingEnabled !== value) {\n this._state.imageSmoothingEnabled = value;\n this._context.imageSmoothingEnabled = value;\n }\n }\n get globalAlpha() {\n return this._context.globalAlpha;\n }\n set globalAlpha(value) {\n if (this._state.globalAlpha !== value) {\n this._state.globalAlpha = value;\n this._context.globalAlpha = value;\n }\n }\n get globalCompositeOperation() {\n return this._context.globalCompositeOperation;\n }\n set globalCompositeOperation(value) {\n if (this._state.globalCompositeOperation !== value) {\n this._state.globalCompositeOperation = value;\n this._context.globalCompositeOperation = value;\n }\n }\n getLineDash() {\n return this._context.getLineDash();\n }\n setLineDash(segments) {\n this._context.setLineDash(segments);\n }\n rotate(angle) {\n this._context.rotate(angle);\n }\n scale(x, y) {\n this._context.scale(x, y);\n }\n transform(m11, m12, m21, m22, dx, dy) {\n this._context.transform(m11, m12, m21, m22, dx, dy);\n }\n translate(x, y) {\n this._context.translate(x, y);\n }\n setTransform(m11, m12, m21, m22, dx, dy) {\n this._context.setTransform(m11, m12, m21, m22, dx, dy);\n }\n save() {\n // Clone an push the current state to the stack.\n this._state = Private$3.State.push(this._state);\n // Save the wrapped context state.\n this._context.save();\n }\n restore() {\n // Bail if there is no state to restore.\n if (!this._state.next) {\n return;\n }\n // Pop the saved state from the stack.\n this._state = Private$3.State.pop(this._state);\n // Restore the wrapped context state.\n this._context.restore();\n }\n beginPath() {\n return this._context.beginPath();\n }\n closePath() {\n this._context.closePath();\n }\n isPointInPath(x, y, fillRule) {\n let result;\n if (arguments.length === 2) {\n result = this._context.isPointInPath(x, y);\n }\n else {\n result = this._context.isPointInPath(x, y, fillRule);\n }\n return result;\n }\n arc(x, y, radius, startAngle, endAngle, anticlockwise) {\n if (arguments.length === 5) {\n this._context.arc(x, y, radius, startAngle, endAngle);\n }\n else {\n this._context.arc(x, y, radius, startAngle, endAngle, anticlockwise);\n }\n }\n arcTo(x1, y1, x2, y2, radius) {\n this._context.arcTo(x1, y1, x2, y2, radius);\n }\n bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {\n this._context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);\n }\n ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise) {\n if (arguments.length === 7) {\n this._context.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle);\n }\n else {\n this._context.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise);\n }\n }\n lineTo(x, y) {\n this._context.lineTo(x, y);\n }\n moveTo(x, y) {\n this._context.moveTo(x, y);\n }\n quadraticCurveTo(cpx, cpy, x, y) {\n this._context.quadraticCurveTo(cpx, cpy, x, y);\n }\n rect(x, y, w, h) {\n this._context.rect(x, y, w, h);\n }\n clip(fillRule) {\n if (arguments.length === 0) {\n this._context.clip();\n }\n else {\n this._context.clip(fillRule);\n }\n }\n fill(fillRule) {\n if (arguments.length === 0) {\n this._context.fill();\n }\n else {\n this._context.fill(fillRule);\n }\n }\n stroke() {\n this._context.stroke();\n }\n clearRect(x, y, w, h) {\n return this._context.clearRect(x, y, w, h);\n }\n fillRect(x, y, w, h) {\n this._context.fillRect(x, y, w, h);\n }\n fillText(text, x, y, maxWidth) {\n if (arguments.length === 3) {\n this._context.fillText(text, x, y);\n }\n else {\n this._context.fillText(text, x, y, maxWidth);\n }\n }\n strokeRect(x, y, w, h) {\n this._context.strokeRect(x, y, w, h);\n }\n strokeText(text, x, y, maxWidth) {\n if (arguments.length === 3) {\n this._context.strokeText(text, x, y);\n }\n else {\n this._context.strokeText(text, x, y, maxWidth);\n }\n }\n measureText(text) {\n return this._context.measureText(text);\n }\n createLinearGradient(x0, y0, x1, y1) {\n return this._context.createLinearGradient(x0, y0, x1, y1);\n }\n createRadialGradient(x0, y0, r0, x1, y1, r1) {\n return this._context.createRadialGradient(x0, y0, r0, x1, y1, r1);\n }\n createPattern(image, repetition) {\n return this._context.createPattern(image, repetition);\n }\n createImageData() {\n // eslint-disable-next-line prefer-spread, prefer-rest-params\n return this._context.createImageData.apply(this._context, arguments);\n }\n getImageData(sx, sy, sw, sh) {\n return this._context.getImageData(sx, sy, sw, sh);\n }\n putImageData() {\n // eslint-disable-next-line prefer-spread, prefer-rest-params\n this._context.putImageData.apply(this._context, arguments);\n }\n drawImage() {\n // eslint-disable-next-line prefer-spread, prefer-rest-params\n this._context.drawImage.apply(this._context, arguments);\n }\n drawFocusIfNeeded(element) {\n this._context.drawFocusIfNeeded(element);\n }\n}\n/**\n * The namespace for the module implementation details.\n */\nvar Private$3;\n(function (Private) {\n /**\n * The index of next valid pool object.\n */\n let pi = -1;\n /**\n * A state object allocation pool.\n */\n const pool = [];\n /**\n * An object which holds the state for a gc.\n */\n class State {\n /**\n * Create a gc state object from a 2D canvas context.\n */\n static create(context) {\n let state = pi < 0 ? new State() : pool[pi--];\n state.next = null;\n state.fillStyle = context.fillStyle;\n state.font = context.font;\n state.globalAlpha = context.globalAlpha;\n state.globalCompositeOperation = context.globalCompositeOperation;\n state.imageSmoothingEnabled = context.imageSmoothingEnabled;\n state.lineCap = context.lineCap;\n state.lineDashOffset = context.lineDashOffset;\n state.lineJoin = context.lineJoin;\n state.lineWidth = context.lineWidth;\n state.miterLimit = context.miterLimit;\n state.shadowBlur = context.shadowBlur;\n state.shadowColor = context.shadowColor;\n state.shadowOffsetX = context.shadowOffsetX;\n state.shadowOffsetY = context.shadowOffsetY;\n state.strokeStyle = context.strokeStyle;\n state.textAlign = context.textAlign;\n state.textBaseline = context.textBaseline;\n return state;\n }\n /**\n * Clone an existing gc state object and add it to the state stack.\n */\n static push(other) {\n let state = pi < 0 ? new State() : pool[pi--];\n state.next = other;\n state.fillStyle = other.fillStyle;\n state.font = other.font;\n state.globalAlpha = other.globalAlpha;\n state.globalCompositeOperation = other.globalCompositeOperation;\n state.imageSmoothingEnabled = other.imageSmoothingEnabled;\n state.lineCap = other.lineCap;\n state.lineDashOffset = other.lineDashOffset;\n state.lineJoin = other.lineJoin;\n state.lineWidth = other.lineWidth;\n state.miterLimit = other.miterLimit;\n state.shadowBlur = other.shadowBlur;\n state.shadowColor = other.shadowColor;\n state.shadowOffsetX = other.shadowOffsetX;\n state.shadowOffsetY = other.shadowOffsetY;\n state.strokeStyle = other.strokeStyle;\n state.textAlign = other.textAlign;\n state.textBaseline = other.textBaseline;\n return state;\n }\n /**\n * Pop the next state object and return the current to the pool\n */\n static pop(state) {\n state.fillStyle = '';\n state.strokeStyle = '';\n pool[++pi] = state;\n return state.next;\n }\n }\n Private.State = State;\n})(Private$3 || (Private$3 = {}));\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * A class which manages the mapping of cell renderers.\n */\nclass RendererMap {\n /**\n * Construct a new renderer map.\n *\n * @param values - The initial values for the map.\n *\n * @param fallback - The renderer of last resort.\n */\n constructor(values = {}, fallback) {\n this._changed = new Signal(this);\n this._values = { ...values };\n this._fallback = fallback || new TextRenderer();\n }\n /**\n * A signal emitted when the renderer map has changed.\n */\n get changed() {\n return this._changed;\n }\n /**\n * Get the cell renderer to use for the given cell config.\n *\n * @param config - The cell config of interest.\n *\n * @returns The renderer to use for the cell.\n */\n get(config) {\n // Fetch the renderer from the values map.\n let renderer = this._values[config.region];\n // Execute a resolver function if necessary.\n if (typeof renderer === 'function') {\n try {\n renderer = renderer(config);\n }\n catch (err) {\n renderer = undefined;\n console.error(err);\n }\n }\n // Return the renderer or the fallback.\n return renderer || this._fallback;\n }\n /**\n * Update the renderer map with new values\n *\n * @param values - The updated values for the map.\n *\n * @param fallback - The renderer of last resort.\n *\n * #### Notes\n * This method always emits the `changed` signal.\n */\n update(values = {}, fallback) {\n this._values = { ...this._values, ...values };\n this._fallback = fallback || this._fallback;\n this._changed.emit(undefined);\n }\n}\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2019, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\n/**\n * An object which manages a collection of variable sized sections.\n *\n * #### Notes\n * This class is an implementation detail. It is designed to manage\n * the variable row and column sizes for a data grid. User code will\n * not interact with this class directly.\n */\nclass SectionList {\n /**\n * Construct a new section list.\n *\n * @param options - The options for initializing the list.\n */\n constructor(options) {\n this._count = 0;\n this._length = 0;\n this._sections = [];\n this._minimumSize = options.minimumSize || 2;\n this._defaultSize = Math.max(this._minimumSize, Math.floor(options.defaultSize));\n }\n /**\n * The total size of all sections in the list.\n *\n * #### Complexity\n * Constant.\n */\n get length() {\n return this._length;\n }\n /**\n * The total number of sections in the list.\n *\n * #### Complexity\n * Constant.\n */\n get count() {\n return this._count;\n }\n /**\n * Get the minimum size of sections in the list.\n *\n * #### Complexity\n * Constant.\n */\n get minimumSize() {\n return this._minimumSize;\n }\n /**\n * Set the minimum size of sections in the list.\n *\n * #### Complexity\n * Linear on the number of resized sections.\n */\n set minimumSize(value) {\n // Normalize the value.\n value = Math.max(2, Math.floor(value));\n // Bail early if the value does not change.\n if (this._minimumSize === value) {\n return;\n }\n // Update the internal minimum size.\n this._minimumSize = value;\n // Update default size if larger than minimum size\n if (value > this._defaultSize) {\n this.defaultSize = value;\n }\n }\n /**\n * Get the default size of sections in the list.\n *\n * #### Complexity\n * Constant.\n */\n get defaultSize() {\n return this._defaultSize;\n }\n /**\n * Set the default size of sections in the list.\n *\n * #### Complexity\n * Linear on the number of resized sections.\n */\n set defaultSize(value) {\n // Normalize the value.\n value = Math.max(this._minimumSize, Math.floor(value));\n // Bail early if the value does not change.\n if (this._defaultSize === value) {\n return;\n }\n // Compute the delta default size.\n let delta = value - this._defaultSize;\n // Update the internal default size.\n this._defaultSize = value;\n // Update the length.\n this._length += delta * (this._count - this._sections.length);\n // Bail early if there are no modified sections.\n if (this._sections.length === 0) {\n return;\n }\n // Recompute the offsets of the modified sections.\n for (let i = 0, n = this._sections.length; i < n; ++i) {\n // Look up the previous and current modified sections.\n let prev = this._sections[i - 1];\n let curr = this._sections[i];\n // Adjust the offset for the current section.\n if (prev) {\n let count = curr.index - prev.index - 1;\n curr.offset = prev.offset + prev.size + count * value;\n }\n else {\n curr.offset = curr.index * value;\n }\n }\n }\n /**\n * Clamp a size to the minimum section size\n *\n * @param size - The size to clamp.\n *\n * @returns The size or the section minimum size, whichever is larger\n */\n clampSize(size) {\n return Math.max(this._minimumSize, Math.floor(size));\n }\n /**\n * Find the index of the section which covers the given offset.\n *\n * @param offset - The offset of the section of interest.\n *\n * @returns The index of the section which covers the given offset,\n * or `-1` if the offset is out of range.\n *\n * #### Complexity\n * Logarithmic on the number of resized sections.\n */\n indexOf(offset) {\n // Bail early if the offset is out of range.\n if (offset < 0 || offset >= this._length || this._count === 0) {\n return -1;\n }\n // Handle the simple case of no modified sections.\n if (this._sections.length === 0) {\n return Math.floor(offset / this._defaultSize);\n }\n // Find the modified section for the given offset.\n let i = ArrayExt.lowerBound(this._sections, offset, Private$2.offsetCmp);\n // Return the index of an exact match.\n if (i < this._sections.length && this._sections[i].offset <= offset) {\n return this._sections[i].index;\n }\n // Handle the case of no modified sections before the offset.\n if (i === 0) {\n return Math.floor(offset / this._defaultSize);\n }\n // Compute the index from the previous modified section.\n let section = this._sections[i - 1];\n let span = offset - (section.offset + section.size);\n return section.index + Math.floor(span / this._defaultSize) + 1;\n }\n /**\n * Find the offset of the section at the given index.\n *\n * @param index - The index of the section of interest.\n *\n * @returns The offset of the section at the given index, or `-1`\n * if the index is out of range.\n *\n * #### Undefined Behavior\n * An `index` which is non-integral.\n *\n * #### Complexity\n * Logarithmic on the number of resized sections.\n */\n offsetOf(index) {\n // Bail early if the index is out of range.\n if (index < 0 || index >= this._count) {\n return -1;\n }\n // Handle the simple case of no modified sections.\n if (this._sections.length === 0) {\n return index * this._defaultSize;\n }\n // Find the modified section for the given index.\n let i = ArrayExt.lowerBound(this._sections, index, Private$2.indexCmp);\n // Return the offset of an exact match.\n if (i < this._sections.length && this._sections[i].index === index) {\n return this._sections[i].offset;\n }\n // Handle the case of no modified sections before the index.\n if (i === 0) {\n return index * this._defaultSize;\n }\n // Compute the offset from the previous modified section.\n let section = this._sections[i - 1];\n let span = index - section.index - 1;\n return section.offset + section.size + span * this._defaultSize;\n }\n /**\n * Find the extent of the section at the given index.\n *\n * @param index - The index of the section of interest.\n *\n * @returns The extent of the section at the given index, or `-1`\n * if the index is out of range.\n *\n * #### Undefined Behavior\n * An `index` which is non-integral.\n *\n * #### Complexity\n * Logarithmic on the number of resized sections.\n */\n extentOf(index) {\n // Bail early if the index is out of range.\n if (index < 0 || index >= this._count) {\n return -1;\n }\n // Handle the simple case of no modified sections.\n if (this._sections.length === 0) {\n return (index + 1) * this._defaultSize - 1;\n }\n // Find the modified section for the given index.\n let i = ArrayExt.lowerBound(this._sections, index, Private$2.indexCmp);\n // Return the offset of an exact match.\n if (i < this._sections.length && this._sections[i].index === index) {\n return this._sections[i].offset + this._sections[i].size - 1;\n }\n // Handle the case of no modified sections before the index.\n if (i === 0) {\n return (index + 1) * this._defaultSize - 1;\n }\n // Compute the offset from the previous modified section.\n let section = this._sections[i - 1];\n let span = index - section.index;\n return section.offset + section.size + span * this._defaultSize - 1;\n }\n /**\n * Find the size of the section at the given index.\n *\n * @param index - The index of the section of interest.\n *\n * @returns The size of the section at the given index, or `-1`\n * if the index is out of range.\n *\n * #### Undefined Behavior\n * An `index` which is non-integral.\n *\n * #### Complexity\n * Logarithmic on the number of resized sections.\n */\n sizeOf(index) {\n // Bail early if the index is out of range.\n if (index < 0 || index >= this._count) {\n return -1;\n }\n // Handle the simple case of no modified sections.\n if (this._sections.length === 0) {\n return this._defaultSize;\n }\n // Find the modified section for the given index.\n let i = ArrayExt.lowerBound(this._sections, index, Private$2.indexCmp);\n // Return the size of an exact match.\n if (i < this._sections.length && this._sections[i].index === index) {\n return this._sections[i].size;\n }\n // Return the default size for all other cases.\n return this._defaultSize;\n }\n /**\n * Resize a section in the list.\n *\n * @param index - The index of the section to resize. This method\n * is a no-op if this value is out of range.\n *\n * @param size - The new size of the section. This value will be\n * clamped to an integer `>= 0`.\n *\n * #### Undefined Behavior\n * An `index` which is non-integral.\n *\n * #### Complexity\n * Linear on the number of resized sections.\n */\n resize(index, size) {\n // Bail early if the index is out of range.\n if (index < 0 || index >= this._count) {\n return;\n }\n // Clamp the size to an integer >= minimum size.\n size = Math.max(this._minimumSize, Math.floor(size));\n // Find the modified section for the given index.\n let i = ArrayExt.lowerBound(this._sections, index, Private$2.indexCmp);\n // Update or create the modified section as needed.\n let delta;\n if (i < this._sections.length && this._sections[i].index === index) {\n let section = this._sections[i];\n delta = size - section.size;\n section.size = size;\n }\n else if (i === 0) {\n let offset = index * this._defaultSize;\n ArrayExt.insert(this._sections, i, { index, offset, size });\n delta = size - this._defaultSize;\n }\n else {\n let section = this._sections[i - 1];\n let span = index - section.index - 1;\n let offset = section.offset + section.size + span * this._defaultSize;\n ArrayExt.insert(this._sections, i, { index, offset, size });\n delta = size - this._defaultSize;\n }\n // Adjust the length.\n this._length += delta;\n // Update all modified sections after the resized section.\n for (let j = i + 1, n = this._sections.length; j < n; ++j) {\n this._sections[j].offset += delta;\n }\n }\n /**\n * Insert sections into the list.\n *\n * @param index - The index at which to insert the sections. This\n * value will be clamped to the bounds of the list.\n *\n * @param count - The number of sections to insert. This method\n * is a no-op if this value is `<= 0`.\n *\n * #### Undefined Behavior\n * An `index` or `count` which is non-integral.\n *\n * #### Complexity\n * Linear on the number of resized sections.\n */\n insert(index, count) {\n // Bail early if there are no sections to insert.\n if (count <= 0) {\n return;\n }\n // Clamp the index to the bounds of the list.\n index = Math.max(0, Math.min(index, this._count));\n // Add the new sections to the totals.\n let span = count * this._defaultSize;\n this._count += count;\n this._length += span;\n // Bail early if there are no modified sections to update.\n if (this._sections.length === 0) {\n return;\n }\n // Find the modified section for the given index.\n let i = ArrayExt.lowerBound(this._sections, index, Private$2.indexCmp);\n // Update all modified sections after the insert location.\n for (let n = this._sections.length; i < n; ++i) {\n let section = this._sections[i];\n section.index += count;\n section.offset += span;\n }\n }\n /**\n * Remove sections from the list.\n *\n * @param index - The index of the first section to remove. This\n * method is a no-op if this value is out of range.\n *\n * @param count - The number of sections to remove. This method\n * is a no-op if this value is `<= 0`.\n *\n * #### Undefined Behavior\n * An `index` or `count` which is non-integral.\n *\n * #### Complexity\n * Linear on the number of resized sections.\n */\n remove(index, count) {\n // Bail early if there is nothing to remove.\n if (index < 0 || index >= this._count || count <= 0) {\n return;\n }\n // Clamp the count to the bounds of the list.\n count = Math.min(this._count - index, count);\n // Handle the simple case of no modified sections to update.\n if (this._sections.length === 0) {\n this._count -= count;\n this._length -= count * this._defaultSize;\n return;\n }\n // Handle the simple case of removing all sections.\n if (count === this._count) {\n this._length = 0;\n this._count = 0;\n this._sections.length = 0;\n return;\n }\n // Find the modified section for the start index.\n let i = ArrayExt.lowerBound(this._sections, index, Private$2.indexCmp);\n // Find the modified section for the end index.\n let j = ArrayExt.lowerBound(this._sections, index + count, Private$2.indexCmp);\n // Remove the relevant modified sections.\n let removed = this._sections.splice(i, j - i);\n // Compute the total removed span.\n let span = (count - removed.length) * this._defaultSize;\n for (let k = 0, n = removed.length; k < n; ++k) {\n span += removed[k].size;\n }\n // Adjust the totals.\n this._count -= count;\n this._length -= span;\n // Update all modified sections after the removed span.\n for (let k = i, n = this._sections.length; k < n; ++k) {\n let section = this._sections[k];\n section.index -= count;\n section.offset -= span;\n }\n }\n /**\n * Move sections within the list.\n *\n * @param index - The index of the first section to move. This method\n * is a no-op if this value is out of range.\n *\n * @param count - The number of sections to move. This method is a\n * no-op if this value is `<= 0`.\n *\n * @param destination - The destination index for the first section.\n * This value will be clamped to the allowable range.\n *\n * #### Undefined Behavior\n * An `index`, `count`, or `destination` which is non-integral.\n *\n * #### Complexity\n * Linear on the number of moved resized sections.\n */\n move(index, count, destination) {\n // Bail early if there is nothing to move.\n if (index < 0 || index >= this._count || count <= 0) {\n return;\n }\n // Handle the simple case of no modified sections.\n if (this._sections.length === 0) {\n return;\n }\n // Clamp the move count to the limit.\n count = Math.min(count, this._count - index);\n // Clamp the destination index to the limit.\n destination = Math.min(Math.max(0, destination), this._count - count);\n // Bail early if there is no effective move.\n if (index === destination) {\n return;\n }\n // Compute the first affected index.\n let i1 = Math.min(index, destination);\n // Look up the first affected modified section.\n let k1 = ArrayExt.lowerBound(this._sections, i1, Private$2.indexCmp);\n // Bail early if there are no affected modified sections.\n if (k1 === this._sections.length) {\n return;\n }\n // Compute the last affected index.\n let i2 = Math.max(index + count - 1, destination + count - 1);\n // Look up the last affected modified section.\n let k2 = ArrayExt.upperBound(this._sections, i2, Private$2.indexCmp) - 1;\n // Bail early if there are no affected modified sections.\n if (k2 < k1) {\n return;\n }\n // Compute the pivot index.\n let pivot = destination < index ? index : index + count;\n // Compute the count for each side of the pivot.\n let count1 = pivot - i1;\n let count2 = i2 - pivot + 1;\n // Compute the span for each side of the pivot.\n let span1 = count1 * this._defaultSize;\n let span2 = count2 * this._defaultSize;\n // Adjust the spans for the modified sections.\n for (let j = k1; j <= k2; ++j) {\n let section = this._sections[j];\n if (section.index < pivot) {\n span1 += section.size - this._defaultSize;\n }\n else {\n span2 += section.size - this._defaultSize;\n }\n }\n // Look up the pivot section.\n let k3 = ArrayExt.lowerBound(this._sections, pivot, Private$2.indexCmp);\n // Rotate the modified sections if needed.\n if (k1 <= k3 && k3 <= k2) {\n ArrayExt.rotate(this._sections, k3 - k1, k1, k2);\n }\n // Adjust the modified section indices and offsets.\n for (let j = k1; j <= k2; ++j) {\n let section = this._sections[j];\n if (section.index < pivot) {\n section.index += count2;\n section.offset += span2;\n }\n else {\n section.index -= count1;\n section.offset -= span1;\n }\n }\n }\n /**\n * Reset all modified sections to the default size.\n *\n * #### Complexity\n * Constant.\n */\n reset() {\n this._sections.length = 0;\n this._length = this._count * this._defaultSize;\n }\n /**\n * Remove all sections from the list.\n *\n * #### Complexity\n * Constant.\n */\n clear() {\n this._count = 0;\n this._length = 0;\n this._sections.length = 0;\n }\n}\n/**\n * The namespace for the module implementation details.\n */\nvar Private$2;\n(function (Private) {\n /**\n * A comparison function for searching by offset.\n */\n function offsetCmp(section, offset) {\n if (offset < section.offset) {\n return 1;\n }\n if (section.offset + section.size <= offset) {\n return -1;\n }\n return 0;\n }\n Private.offsetCmp = offsetCmp;\n /**\n * A comparison function for searching by index.\n */\n function indexCmp(section, index) {\n return section.index - index;\n }\n Private.indexCmp = indexCmp;\n})(Private$2 || (Private$2 = {}));\n\n/**\n * A widget which implements a high-performance tabular data grid.\n *\n * #### Notes\n * A data grid is implemented as a composition of child widgets. These\n * child widgets are considered an implementation detail. Manipulating\n * the child widgets of a data grid directly is undefined behavior.\n *\n * This class is not designed to be subclassed.\n *\n * See also the related [example](../../examples/datagrid/index.html) and\n * its [source](https://github.com/jupyterlab/lumino/tree/main/examples/example-datagrid).\n */\nclass DataGrid extends Widget {\n /**\n * Construct a new data grid.\n *\n * @param options - The options for initializing the data grid.\n */\n constructor(options = {}) {\n super();\n this._scrollX = 0;\n this._scrollY = 0;\n this._viewportWidth = 0;\n this._viewportHeight = 0;\n this._mousedown = false;\n this._keyHandler = null;\n this._mouseHandler = null;\n this._vScrollBarMinWidth = 0;\n this._hScrollBarMinHeight = 0;\n this._dpiRatio = Math.ceil(window.devicePixelRatio);\n this._dataModel = null;\n this._selectionModel = null;\n this._editingEnabled = false;\n this.addClass('lm-DataGrid');\n // Parse the simple options.\n this._style = options.style || DataGrid.defaultStyle;\n this._stretchLastRow = options.stretchLastRow || false;\n this._stretchLastColumn = options.stretchLastColumn || false;\n this._headerVisibility = options.headerVisibility || 'all';\n this._cellRenderers = options.cellRenderers || new RendererMap();\n this._copyConfig = options.copyConfig || DataGrid.defaultCopyConfig;\n // Connect to the renderer map changed signal.\n this._cellRenderers.changed.connect(this._onRenderersChanged, this);\n // Parse the default sizes.\n let defaultSizes = options.defaultSizes || DataGrid.defaultSizes;\n let minimumSizes = options.minimumSizes || DataGrid.minimumSizes;\n // Set up the sections lists.\n this._rowSections = new SectionList({\n defaultSize: defaultSizes.rowHeight,\n minimumSize: minimumSizes.rowHeight\n });\n this._columnSections = new SectionList({\n defaultSize: defaultSizes.columnWidth,\n minimumSize: minimumSizes.columnWidth\n });\n this._rowHeaderSections = new SectionList({\n defaultSize: defaultSizes.rowHeaderWidth,\n minimumSize: minimumSizes.rowHeaderWidth\n });\n this._columnHeaderSections = new SectionList({\n defaultSize: defaultSizes.columnHeaderHeight,\n minimumSize: minimumSizes.columnHeaderHeight\n });\n // Create the canvas, buffer, and overlay objects.\n this._canvas = Private$1.createCanvas();\n this._buffer = Private$1.createCanvas();\n this._overlay = Private$1.createCanvas();\n // Get the graphics contexts for the canvases.\n this._canvasGC = this._canvas.getContext('2d');\n this._bufferGC = this._buffer.getContext('2d');\n this._overlayGC = this._overlay.getContext('2d');\n // Set up the on-screen canvas.\n this._canvas.style.position = 'absolute';\n this._canvas.style.top = '0px';\n this._canvas.style.left = '0px';\n this._canvas.style.width = '0px';\n this._canvas.style.height = '0px';\n // Set up the on-screen overlay.\n this._overlay.style.position = 'absolute';\n this._overlay.style.top = '0px';\n this._overlay.style.left = '0px';\n this._overlay.style.width = '0px';\n this._overlay.style.height = '0px';\n // Create the internal widgets for the data grid.\n this._viewport = new Widget();\n this._viewport.node.tabIndex = -1;\n this._viewport.node.style.outline = 'none';\n this._vScrollBar = new ScrollBar({ orientation: 'vertical' });\n this._hScrollBar = new ScrollBar({ orientation: 'horizontal' });\n this._scrollCorner = new Widget();\n this._editorController = new CellEditorController();\n // Add the extra class names to the child widgets.\n this._viewport.addClass('lm-DataGrid-viewport');\n this._vScrollBar.addClass('lm-DataGrid-scrollBar');\n this._hScrollBar.addClass('lm-DataGrid-scrollBar');\n this._scrollCorner.addClass('lm-DataGrid-scrollCorner');\n // Add the on-screen canvas to the viewport node.\n this._viewport.node.appendChild(this._canvas);\n // Add the on-screen overlay to the viewport node.\n this._viewport.node.appendChild(this._overlay);\n // Install the message hooks.\n MessageLoop.installMessageHook(this._viewport, this);\n MessageLoop.installMessageHook(this._hScrollBar, this);\n MessageLoop.installMessageHook(this._vScrollBar, this);\n // Hide the scroll bars and corner from the outset.\n this._vScrollBar.hide();\n this._hScrollBar.hide();\n this._scrollCorner.hide();\n // Connect to the scroll bar signals.\n this._vScrollBar.thumbMoved.connect(this._onThumbMoved, this);\n this._hScrollBar.thumbMoved.connect(this._onThumbMoved, this);\n this._vScrollBar.pageRequested.connect(this._onPageRequested, this);\n this._hScrollBar.pageRequested.connect(this._onPageRequested, this);\n this._vScrollBar.stepRequested.connect(this._onStepRequested, this);\n this._hScrollBar.stepRequested.connect(this._onStepRequested, this);\n // Set the layout cell config for the child widgets.\n GridLayout.setCellConfig(this._viewport, { row: 0, column: 0 });\n GridLayout.setCellConfig(this._vScrollBar, { row: 0, column: 1 });\n GridLayout.setCellConfig(this._hScrollBar, { row: 1, column: 0 });\n GridLayout.setCellConfig(this._scrollCorner, { row: 1, column: 1 });\n // Create the layout for the data grid.\n let layout = new GridLayout({\n rowCount: 2,\n columnCount: 2,\n rowSpacing: 0,\n columnSpacing: 0,\n fitPolicy: 'set-no-constraint'\n });\n // Set the stretch factors for the grid.\n layout.setRowStretch(0, 1);\n layout.setRowStretch(1, 0);\n layout.setColumnStretch(0, 1);\n layout.setColumnStretch(1, 0);\n // Add the child widgets to the layout.\n layout.addWidget(this._viewport);\n layout.addWidget(this._vScrollBar);\n layout.addWidget(this._hScrollBar);\n layout.addWidget(this._scrollCorner);\n // Install the layout on the data grid.\n this.layout = layout;\n }\n /**\n * Dispose of the resources held by the widgets.\n */\n dispose() {\n // Release the mouse.\n this._releaseMouse();\n // Dispose of the handlers.\n if (this._keyHandler) {\n this._keyHandler.dispose();\n }\n if (this._mouseHandler) {\n this._mouseHandler.dispose();\n }\n this._keyHandler = null;\n this._mouseHandler = null;\n // Clear the models.\n this._dataModel = null;\n this._selectionModel = null;\n // Clear the section lists.\n this._rowSections.clear();\n this._columnSections.clear();\n this._rowHeaderSections.clear();\n this._columnHeaderSections.clear();\n // Dispose of the base class.\n super.dispose();\n }\n /**\n * Get the data model for the data grid.\n */\n get dataModel() {\n return this._dataModel;\n }\n /**\n * Set the data model for the data grid.\n *\n * #### Notes\n * This will automatically remove the current selection model.\n */\n set dataModel(value) {\n // Do nothing if the model does not change.\n if (this._dataModel === value) {\n return;\n }\n // Release the mouse.\n this._releaseMouse();\n // Clear the selection model.\n this.selectionModel = null;\n // Disconnect the change handler from the old model.\n if (this._dataModel) {\n this._dataModel.changed.disconnect(this._onDataModelChanged, this);\n }\n // Connect the change handler for the new model.\n if (value) {\n value.changed.connect(this._onDataModelChanged, this);\n }\n // Update the internal model reference.\n this._dataModel = value;\n // Clear the section lists.\n this._rowSections.clear();\n this._columnSections.clear();\n this._rowHeaderSections.clear();\n this._columnHeaderSections.clear();\n // Populate the section lists.\n if (value) {\n this._rowSections.insert(0, value.rowCount('body'));\n this._columnSections.insert(0, value.columnCount('body'));\n this._rowHeaderSections.insert(0, value.columnCount('row-header'));\n this._columnHeaderSections.insert(0, value.rowCount('column-header'));\n }\n // Reset the scroll position.\n this._scrollX = 0;\n this._scrollY = 0;\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Get the selection model for the data grid.\n */\n get selectionModel() {\n return this._selectionModel;\n }\n /**\n * Set the selection model for the data grid.\n */\n set selectionModel(value) {\n // Do nothing if the selection model does not change.\n if (this._selectionModel === value) {\n return;\n }\n // Release the mouse.\n this._releaseMouse();\n // Ensure the data models are a match.\n if (value && value.dataModel !== this._dataModel) {\n throw new Error('SelectionModel.dataModel !== DataGrid.dataModel');\n }\n // Disconnect the change handler from the old model.\n if (this._selectionModel) {\n this._selectionModel.changed.disconnect(this._onSelectionsChanged, this);\n }\n // Connect the change handler for the new model.\n if (value) {\n value.changed.connect(this._onSelectionsChanged, this);\n }\n // Update the internal selection model reference.\n this._selectionModel = value;\n // Schedule a repaint of the overlay.\n this.repaintOverlay();\n }\n /**\n * Get the key handler for the data grid.\n */\n get keyHandler() {\n return this._keyHandler;\n }\n /**\n * Set the key handler for the data grid.\n */\n set keyHandler(value) {\n this._keyHandler = value;\n }\n /**\n * Get the mouse handler for the data grid.\n */\n get mouseHandler() {\n return this._mouseHandler;\n }\n /**\n * Set the mouse handler for the data grid.\n */\n set mouseHandler(value) {\n // Bail early if the mouse handler does not change.\n if (this._mouseHandler === value) {\n return;\n }\n // Release the mouse.\n this._releaseMouse();\n // Update the internal mouse handler.\n this._mouseHandler = value;\n }\n /**\n * Get the style for the data grid.\n */\n get style() {\n return this._style;\n }\n /**\n * Set the style for the data grid.\n */\n set style(value) {\n // Bail if the style does not change.\n if (this._style === value) {\n return;\n }\n // Update the internal style.\n this._style = { ...value };\n // Schedule a repaint of the content.\n this.repaintContent();\n // Schedule a repaint of the overlay.\n this.repaintOverlay();\n }\n /**\n * Get the cell renderer map for the data grid.\n */\n get cellRenderers() {\n return this._cellRenderers;\n }\n /**\n * Set the cell renderer map for the data grid.\n */\n set cellRenderers(value) {\n // Bail if the renderer map does not change.\n if (this._cellRenderers === value) {\n return;\n }\n // Disconnect the old map.\n this._cellRenderers.changed.disconnect(this._onRenderersChanged, this);\n // Connect the new map.\n value.changed.connect(this._onRenderersChanged, this);\n // Update the internal renderer map.\n this._cellRenderers = value;\n // Schedule a repaint of the grid content.\n this.repaintContent();\n }\n /**\n * Get the header visibility for the data grid.\n */\n get headerVisibility() {\n return this._headerVisibility;\n }\n /**\n * Set the header visibility for the data grid.\n */\n set headerVisibility(value) {\n // Bail if the visibility does not change.\n if (this._headerVisibility === value) {\n return;\n }\n // Update the internal visibility.\n this._headerVisibility = value;\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Get the default sizes for the various sections of the data grid.\n */\n get defaultSizes() {\n let rowHeight = this._rowSections.defaultSize;\n let columnWidth = this._columnSections.defaultSize;\n let rowHeaderWidth = this._rowHeaderSections.defaultSize;\n let columnHeaderHeight = this._columnHeaderSections.defaultSize;\n return { rowHeight, columnWidth, rowHeaderWidth, columnHeaderHeight };\n }\n /**\n * Set the default sizes for the various sections of the data grid.\n */\n set defaultSizes(value) {\n // Update the section default sizes.\n this._rowSections.defaultSize = value.rowHeight;\n this._columnSections.defaultSize = value.columnWidth;\n this._rowHeaderSections.defaultSize = value.rowHeaderWidth;\n this._columnHeaderSections.defaultSize = value.columnHeaderHeight;\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Get the minimum sizes for the various sections of the data grid.\n */\n get minimumSizes() {\n let rowHeight = this._rowSections.minimumSize;\n let columnWidth = this._columnSections.minimumSize;\n let rowHeaderWidth = this._rowHeaderSections.minimumSize;\n let columnHeaderHeight = this._columnHeaderSections.minimumSize;\n return { rowHeight, columnWidth, rowHeaderWidth, columnHeaderHeight };\n }\n /**\n * Set the minimum sizes for the various sections of the data grid.\n */\n set minimumSizes(value) {\n // Update the section default sizes.\n this._rowSections.minimumSize = value.rowHeight;\n this._columnSections.minimumSize = value.columnWidth;\n this._rowHeaderSections.minimumSize = value.rowHeaderWidth;\n this._columnHeaderSections.minimumSize = value.columnHeaderHeight;\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Get the copy configuration for the data grid.\n */\n get copyConfig() {\n return this._copyConfig;\n }\n /**\n * Set the copy configuration for the data grid.\n */\n set copyConfig(value) {\n this._copyConfig = value;\n }\n /**\n * Get whether the last row is stretched.\n */\n get stretchLastRow() {\n return this._stretchLastRow;\n }\n /**\n * Set whether the last row is stretched.\n */\n set stretchLastRow(value) {\n // Bail early if the value does not change.\n if (value === this._stretchLastRow) {\n return;\n }\n // Update the internal value.\n this._stretchLastRow = value;\n // Sync the viewport\n this._syncViewport();\n }\n /**\n * Get whether the last column is stretched.\n */\n get stretchLastColumn() {\n return this._stretchLastColumn;\n }\n /**\n * Set whether the last column is stretched.\n */\n set stretchLastColumn(value) {\n // Bail early if the value does not change.\n if (value === this._stretchLastColumn) {\n return;\n }\n // Update the internal value.\n this._stretchLastColumn = value;\n // Sync the viewport\n this._syncViewport();\n }\n /**\n * The virtual width of the row headers.\n */\n get headerWidth() {\n if (this._headerVisibility === 'none') {\n return 0;\n }\n if (this._headerVisibility === 'column') {\n return 0;\n }\n return this._rowHeaderSections.length;\n }\n /**\n * The virtual height of the column headers.\n */\n get headerHeight() {\n if (this._headerVisibility === 'none') {\n return 0;\n }\n if (this._headerVisibility === 'row') {\n return 0;\n }\n return this._columnHeaderSections.length;\n }\n /**\n * The virtual width of the grid body.\n *\n * #### Notes\n * This does *not* account for a stretched last column.\n */\n get bodyWidth() {\n return this._columnSections.length;\n }\n /**\n * The virtual height of the grid body.\n *\n * #### Notes\n * This does *not* account for a stretched last row.\n */\n get bodyHeight() {\n return this._rowSections.length;\n }\n /**\n * The virtual width of the entire grid.\n *\n * #### Notes\n * This does *not* account for a stretched last column.\n */\n get totalWidth() {\n return this.headerWidth + this.bodyWidth;\n }\n /**\n * The virtual height of the entire grid.\n *\n * #### Notes\n * This does *not* account for a stretched last row.\n */\n get totalHeight() {\n return this.headerHeight + this.bodyHeight;\n }\n /**\n * The actual width of the viewport.\n */\n get viewportWidth() {\n return this._viewportWidth;\n }\n /**\n * The actual height of the viewport.\n */\n get viewportHeight() {\n return this._viewportHeight;\n }\n /**\n * The width of the visible portion of the grid body.\n */\n get pageWidth() {\n return Math.max(0, this.viewportWidth - this.headerWidth);\n }\n /**\n * The height of the visible portion of the grid body.\n */\n get pageHeight() {\n return Math.max(0, this.viewportHeight - this.headerHeight);\n }\n /**\n * The current scroll X position of the viewport.\n */\n get scrollX() {\n return this._hScrollBar.value;\n }\n /**\n * The current scroll Y position of the viewport.\n */\n get scrollY() {\n return this._vScrollBar.value;\n }\n /**\n * The maximum scroll X position for the grid.\n */\n get maxScrollX() {\n return Math.max(0, this.bodyWidth - this.pageWidth - 1);\n }\n /**\n * The maximum scroll Y position for the grid.\n */\n get maxScrollY() {\n return Math.max(0, this.bodyHeight - this.pageHeight - 1);\n }\n /**\n * The viewport widget for the data grid.\n */\n get viewport() {\n return this._viewport;\n }\n /**\n * The cell editor controller object for the data grid.\n */\n get editorController() {\n return this._editorController;\n }\n set editorController(controller) {\n this._editorController = controller;\n }\n /**\n * Whether the cell editing is enabled for the data grid.\n */\n get editingEnabled() {\n return this._editingEnabled;\n }\n set editingEnabled(enabled) {\n this._editingEnabled = enabled;\n }\n /**\n * Whether the grid cells are editable.\n *\n * `editingEnabled` flag must be on and grid must have required\n * selection model, editor controller and data model properties.\n */\n get editable() {\n return (this._editingEnabled &&\n this._selectionModel !== null &&\n this._editorController !== null &&\n this.dataModel instanceof MutableDataModel);\n }\n /**\n * The rendering context for painting the data grid.\n */\n get canvasGC() {\n return this._canvasGC;\n }\n /**\n * The row sections of the data grid.\n */\n get rowSections() {\n return this._rowSections;\n }\n /**\n * The column sections of the data grid.\n */\n get columnSections() {\n return this._columnSections;\n }\n /**\n * The row header sections of the data grid.\n */\n get rowHeaderSections() {\n return this._rowHeaderSections;\n }\n /**\n * The column header sections of the data grid.\n */\n get columnHeaderSections() {\n return this._columnHeaderSections;\n }\n /**\n * Scroll the grid to the specified row.\n *\n * @param row - The row index of the cell.\n *\n * #### Notes\n * This is a no-op if the row is already visible.\n */\n scrollToRow(row) {\n // Fetch the row count.\n let nr = this._rowSections.count;\n // Bail early if there is no content.\n if (nr === 0) {\n return;\n }\n // Floor the row index.\n row = Math.floor(row);\n // Clamp the row index.\n row = Math.max(0, Math.min(row, nr - 1));\n // Get the virtual bounds of the row.\n let y1 = this._rowSections.offsetOf(row);\n let y2 = this._rowSections.extentOf(row);\n // Get the virtual bounds of the viewport.\n let vy1 = this._scrollY;\n let vy2 = this._scrollY + this.pageHeight - 1;\n // Set up the delta variables.\n let dy = 0;\n // Compute the delta Y scroll.\n if (y1 < vy1) {\n dy = y1 - vy1 - 10;\n }\n else if (y2 > vy2) {\n dy = y2 - vy2 + 10;\n }\n // Bail early if no scroll is needed.\n if (dy === 0) {\n return;\n }\n // Scroll by the computed delta.\n this.scrollBy(0, dy);\n }\n /**\n * Scroll the grid to the specified column.\n *\n * @param column - The column index of the cell.\n *\n * #### Notes\n * This is a no-op if the column is already visible.\n */\n scrollToColumn(column) {\n // Fetch the column count.\n let nc = this._columnSections.count;\n // Bail early if there is no content.\n if (nc === 0) {\n return;\n }\n // Floor the column index.\n column = Math.floor(column);\n // Clamp the column index.\n column = Math.max(0, Math.min(column, nc - 1));\n // Get the virtual bounds of the column.\n let x1 = this._columnSections.offsetOf(column);\n let x2 = this._columnSections.extentOf(column);\n // Get the virtual bounds of the viewport.\n let vx1 = this._scrollX;\n let vx2 = this._scrollX + this.pageWidth - 1;\n // Set up the delta variables.\n let dx = 0;\n // Compute the delta X scroll.\n if (x1 < vx1) {\n dx = x1 - vx1 - 10;\n }\n else if (x2 > vx2) {\n dx = x2 - vx2 + 10;\n }\n // Bail early if no scroll is needed.\n if (dx === 0) {\n return;\n }\n // Scroll by the computed delta.\n this.scrollBy(dx, 0);\n }\n /**\n * Scroll the grid to the specified cell.\n *\n * @param row - The row index of the cell.\n *\n * @param column - The column index of the cell.\n *\n * #### Notes\n * This is a no-op if the cell is already visible.\n */\n scrollToCell(row, column) {\n // Fetch the row and column count.\n let nr = this._rowSections.count;\n let nc = this._columnSections.count;\n // Bail early if there is no content.\n if (nr === 0 || nc === 0) {\n return;\n }\n // Floor the cell index.\n row = Math.floor(row);\n column = Math.floor(column);\n // Clamp the cell index.\n row = Math.max(0, Math.min(row, nr - 1));\n column = Math.max(0, Math.min(column, nc - 1));\n // Get the virtual bounds of the cell.\n let x1 = this._columnSections.offsetOf(column);\n let x2 = this._columnSections.extentOf(column);\n let y1 = this._rowSections.offsetOf(row);\n let y2 = this._rowSections.extentOf(row);\n // Get the virtual bounds of the viewport.\n let vx1 = this._scrollX;\n let vx2 = this._scrollX + this.pageWidth - 1;\n let vy1 = this._scrollY;\n let vy2 = this._scrollY + this.pageHeight - 1;\n // Set up the delta variables.\n let dx = 0;\n let dy = 0;\n // Compute the delta X scroll.\n if (x1 < vx1) {\n dx = x1 - vx1 - 10;\n }\n else if (x2 > vx2) {\n dx = x2 - vx2 + 10;\n }\n // Compute the delta Y scroll.\n if (y1 < vy1) {\n dy = y1 - vy1 - 10;\n }\n else if (y2 > vy2) {\n dy = y2 - vy2 + 10;\n }\n // Bail early if no scroll is needed.\n if (dx === 0 && dy === 0) {\n return;\n }\n // Scroll by the computed delta.\n this.scrollBy(dx, dy);\n }\n /**\n * Move cursor down/up/left/right while making sure it remains\n * within the bounds of selected rectangles\n *\n * @param direction - The direction of the movement.\n */\n moveCursor(direction) {\n // Bail early if there is no selection\n if (!this.dataModel ||\n !this._selectionModel ||\n this._selectionModel.isEmpty) {\n return;\n }\n const iter = this._selectionModel.selections();\n const onlyOne = iter.next() && !iter.next();\n // if there is a single selection that is a single cell selection\n // then move the selection and cursor within grid bounds\n if (onlyOne) {\n const currentSel = this._selectionModel.currentSelection();\n if (currentSel.r1 === currentSel.r2 && currentSel.c1 === currentSel.c2) {\n const dr = direction === 'down' ? 1 : direction === 'up' ? -1 : 0;\n const dc = direction === 'right' ? 1 : direction === 'left' ? -1 : 0;\n let newRow = currentSel.r1 + dr;\n let newColumn = currentSel.c1 + dc;\n const rowCount = this.dataModel.rowCount('body');\n const columnCount = this.dataModel.columnCount('body');\n if (newRow >= rowCount) {\n newRow = 0;\n newColumn += 1;\n }\n else if (newRow === -1) {\n newRow = rowCount - 1;\n newColumn -= 1;\n }\n if (newColumn >= columnCount) {\n newColumn = 0;\n newRow += 1;\n if (newRow >= rowCount) {\n newRow = 0;\n }\n }\n else if (newColumn === -1) {\n newColumn = columnCount - 1;\n newRow -= 1;\n if (newRow === -1) {\n newRow = rowCount - 1;\n }\n }\n this._selectionModel.select({\n r1: newRow,\n c1: newColumn,\n r2: newRow,\n c2: newColumn,\n cursorRow: newRow,\n cursorColumn: newColumn,\n clear: 'all'\n });\n return;\n }\n }\n // if there are multiple selections, move cursor\n // within selection rectangles\n this._selectionModel.moveCursorWithinSelections(direction);\n }\n /**\n * Scroll the grid to the current cursor position.\n *\n * #### Notes\n * This is a no-op if the cursor is already visible or\n * if there is no selection model installed on the grid.\n */\n scrollToCursor() {\n // Bail early if there is no selection model.\n if (!this._selectionModel) {\n return;\n }\n // Fetch the cursor row and column.\n let row = this._selectionModel.cursorRow;\n let column = this._selectionModel.cursorColumn;\n // Scroll to the cursor cell.\n this.scrollToCell(row, column);\n }\n /**\n * Scroll the viewport by the specified amount.\n *\n * @param dx - The X scroll amount.\n *\n * @param dy - The Y scroll amount.\n */\n scrollBy(dx, dy) {\n this.scrollTo(this.scrollX + dx, this.scrollY + dy);\n }\n /**\n * Scroll the viewport by one page.\n *\n * @param dir - The desired direction of the scroll.\n */\n scrollByPage(dir) {\n let dx = 0;\n let dy = 0;\n switch (dir) {\n case 'up':\n dy = -this.pageHeight;\n break;\n case 'down':\n dy = this.pageHeight;\n break;\n case 'left':\n dx = -this.pageWidth;\n break;\n case 'right':\n dx = this.pageWidth;\n break;\n default:\n throw 'unreachable';\n }\n this.scrollTo(this.scrollX + dx, this.scrollY + dy);\n }\n /**\n * Scroll the viewport by one cell-aligned step.\n *\n * @param dir - The desired direction of the scroll.\n */\n scrollByStep(dir) {\n let r;\n let c;\n let x = this.scrollX;\n let y = this.scrollY;\n let rows = this._rowSections;\n let columns = this._columnSections;\n switch (dir) {\n case 'up':\n r = rows.indexOf(y - 1);\n y = r < 0 ? y : rows.offsetOf(r);\n break;\n case 'down':\n r = rows.indexOf(y);\n y = r < 0 ? y : rows.offsetOf(r) + rows.sizeOf(r);\n break;\n case 'left':\n c = columns.indexOf(x - 1);\n x = c < 0 ? x : columns.offsetOf(c);\n break;\n case 'right':\n c = columns.indexOf(x);\n x = c < 0 ? x : columns.offsetOf(c) + columns.sizeOf(c);\n break;\n default:\n throw 'unreachable';\n }\n this.scrollTo(x, y);\n }\n /**\n * Scroll to the specified offset position.\n *\n * @param x - The desired X position.\n *\n * @param y - The desired Y position.\n */\n scrollTo(x, y) {\n // Floor and clamp the position to the allowable range.\n x = Math.max(0, Math.min(Math.floor(x), this.maxScrollX));\n y = Math.max(0, Math.min(Math.floor(y), this.maxScrollY));\n // Update the scroll bar values with the desired position.\n this._hScrollBar.value = x;\n this._vScrollBar.value = y;\n // Post a scroll request message to the viewport.\n MessageLoop.postMessage(this._viewport, Private$1.ScrollRequest);\n }\n /**\n * Get the row count for a particular region in the data grid.\n *\n * @param region - The row region of interest.\n *\n * @returns The row count for the specified region.\n */\n rowCount(region) {\n let count;\n if (region === 'body') {\n count = this._rowSections.count;\n }\n else {\n count = this._columnHeaderSections.count;\n }\n return count;\n }\n /**\n * Get the column count for a particular region in the data grid.\n *\n * @param region - The column region of interest.\n *\n * @returns The column count for the specified region.\n */\n columnCount(region) {\n let count;\n if (region === 'body') {\n count = this._columnSections.count;\n }\n else {\n count = this._rowHeaderSections.count;\n }\n return count;\n }\n /**\n * Get the row at a virtual offset in the data grid.\n *\n * @param region - The region which holds the row of interest.\n *\n * @param offset - The virtual offset of the row of interest.\n *\n * @returns The index of the row, or `-1` if the offset is out of range.\n *\n * #### Notes\n * This method accounts for a stretched last row.\n */\n rowAt(region, offset) {\n // Bail early if the offset is negative.\n if (offset < 0) {\n return -1;\n }\n // Return early for the column header region.\n if (region === 'column-header') {\n return this._columnHeaderSections.indexOf(offset);\n }\n // Fetch the index.\n let index = this._rowSections.indexOf(offset);\n // Return early if the section is found.\n if (index >= 0) {\n return index;\n }\n // Bail early if the last row is not stretched.\n if (!this._stretchLastRow) {\n return -1;\n }\n // Fetch the geometry.\n let bh = this.bodyHeight;\n let ph = this.pageHeight;\n // Bail early if no row stretching is required.\n if (ph <= bh) {\n return -1;\n }\n // Bail early if the offset is out of bounds.\n if (offset >= ph) {\n return -1;\n }\n // Otherwise, return the last row.\n return this._rowSections.count - 1;\n }\n /**\n * Get the column at a virtual offset in the data grid.\n *\n * @param region - The region which holds the column of interest.\n *\n * @param offset - The virtual offset of the column of interest.\n *\n * @returns The index of the column, or `-1` if the offset is out of range.\n *\n * #### Notes\n * This method accounts for a stretched last column.\n */\n columnAt(region, offset) {\n if (offset < 0) {\n return -1;\n }\n // Return early for the row header region.\n if (region === 'row-header') {\n return this._rowHeaderSections.indexOf(offset);\n }\n // Fetch the index.\n let index = this._columnSections.indexOf(offset);\n // Return early if the section is found.\n if (index >= 0) {\n return index;\n }\n // Bail early if the last column is not stretched.\n if (!this._stretchLastColumn) {\n return -1;\n }\n // Fetch the geometry.\n let bw = this.bodyWidth;\n let pw = this.pageWidth;\n // Bail early if no column stretching is required.\n if (pw <= bw) {\n return -1;\n }\n // Bail early if the offset is out of bounds.\n if (offset >= pw) {\n return -1;\n }\n // Otherwise, return the last column.\n return this._columnSections.count - 1;\n }\n /**\n * Get the offset of a row in the data grid.\n *\n * @param region - The region which holds the row of interest.\n *\n * @param index - The index of the row of interest.\n *\n * @returns The offset of the row, or `-1` if the index is out of range.\n *\n * #### Notes\n * A stretched last row has no effect on the return value.\n */\n rowOffset(region, index) {\n let offset;\n if (region === 'body') {\n offset = this._rowSections.offsetOf(index);\n }\n else {\n offset = this._columnHeaderSections.offsetOf(index);\n }\n return offset;\n }\n /**\n * Get the offset of a column in the data grid.\n *\n * @param region - The region which holds the column of interest.\n *\n * @param index - The index of the column of interest.\n *\n * @returns The offset of the column, or `-1` if the index is out of range.\n *\n * #### Notes\n * A stretched last column has no effect on the return value.\n */\n columnOffset(region, index) {\n let offset;\n if (region === 'body') {\n offset = this._columnSections.offsetOf(index);\n }\n else {\n offset = this._rowHeaderSections.offsetOf(index);\n }\n return offset;\n }\n /**\n * Get the size of a row in the data grid.\n *\n * @param region - The region which holds the row of interest.\n *\n * @param index - The index of the row of interest.\n *\n * @returns The size of the row, or `-1` if the index is out of range.\n *\n * #### Notes\n * This method accounts for a stretched last row.\n */\n rowSize(region, index) {\n // Return early for the column header region.\n if (region === 'column-header') {\n return this._columnHeaderSections.sizeOf(index);\n }\n // Fetch the row size.\n let size = this._rowSections.sizeOf(index);\n // Bail early if the index is out of bounds.\n if (size < 0) {\n return size;\n }\n // Return early if the last row is not stretched.\n if (!this._stretchLastRow) {\n return size;\n }\n // Return early if its not the last row.\n if (index < this._rowSections.count - 1) {\n return size;\n }\n // Fetch the geometry.\n let bh = this.bodyHeight;\n let ph = this.pageHeight;\n // Return early if no stretching is needed.\n if (ph <= bh) {\n return size;\n }\n // Return the adjusted size.\n return size + (ph - bh);\n }\n /**\n * Get the size of a column in the data grid.\n *\n * @param region - The region which holds the column of interest.\n *\n * @param index - The index of the column of interest.\n *\n * @returns The size of the column, or `-1` if the index is out of range.\n *\n * #### Notes\n * This method accounts for a stretched last column.\n */\n columnSize(region, index) {\n // Return early for the row header region.\n if (region === 'row-header') {\n return this._rowHeaderSections.sizeOf(index);\n }\n // Fetch the column size.\n let size = this._columnSections.sizeOf(index);\n // Bail early if the index is out of bounds.\n if (size < 0) {\n return size;\n }\n // Return early if the last column is not stretched.\n if (!this._stretchLastColumn) {\n return size;\n }\n // Return early if its not the last column.\n if (index < this._columnSections.count - 1) {\n return size;\n }\n // Fetch the geometry.\n let bw = this.bodyWidth;\n let pw = this.pageWidth;\n // Return early if no stretching is needed.\n if (pw <= bw) {\n return size;\n }\n // Return the adjusted size.\n return size + (pw - bw);\n }\n /**\n * Resize a row in the data grid.\n *\n * @param region - The region which holds the row of interest.\n *\n * @param index - The index of the row of interest.\n *\n * @param size - The desired size of the row.\n */\n resizeRow(region, index, size) {\n let msg = new Private$1.RowResizeRequest(region, index, size);\n MessageLoop.postMessage(this._viewport, msg);\n }\n /**\n * Resize a column in the data grid.\n *\n * @param region - The region which holds the column of interest.\n *\n * @param index - The index of the column of interest.\n *\n * @param size - The desired size of the column.\n */\n resizeColumn(region, index, size) {\n let msg = new Private$1.ColumnResizeRequest(region, index, size);\n MessageLoop.postMessage(this._viewport, msg);\n }\n /**\n * Reset modified rows to their default size.\n *\n * @param region - The row region of interest.\n */\n resetRows(region) {\n switch (region) {\n case 'all':\n this._rowSections.reset();\n this._columnHeaderSections.reset();\n break;\n case 'body':\n this._rowSections.reset();\n break;\n case 'column-header':\n this._columnHeaderSections.reset();\n break;\n default:\n throw 'unreachable';\n }\n this.repaintContent();\n this.repaintOverlay();\n }\n /**\n * Reset modified columns to their default size.\n *\n * @param region - The column region of interest.\n */\n resetColumns(region) {\n switch (region) {\n case 'all':\n this._columnSections.reset();\n this._rowHeaderSections.reset();\n break;\n case 'body':\n this._columnSections.reset();\n break;\n case 'row-header':\n this._rowHeaderSections.reset();\n break;\n default:\n throw 'unreachable';\n }\n this.repaintContent();\n this.repaintOverlay();\n }\n /**\n * Auto sizes column-header widths based on their text content.\n * @param area which area to resize: 'body', 'row-header' or 'all'.\n * @param padding padding added to resized columns (pixels).\n * @param numCols specify cap on the number of column resizes (optional).\n */\n fitColumnNames(area = 'all', padding = 15, numCols) {\n // Attempt resizing only if a data model is present.\n if (this.dataModel) {\n // Tracking remaining columns to be resized if numCols arg passed.\n let colsRemaining = numCols === undefined || numCols < 0 ? undefined : numCols;\n if (area === 'row-header' || area === 'all') {\n // Respecting any column resize cap, if one has been passed.\n if (colsRemaining !== undefined) {\n const rowColumnCount = this.dataModel.columnCount('row-header');\n /*\n If we have more row-header columns than columns available\n for resize, resize only remaining columns as per allowance\n and set remaining resize allowance number to 0.\n */\n if (colsRemaining - rowColumnCount < 0) {\n this._fitRowColumnHeaders(this.dataModel, padding, colsRemaining);\n colsRemaining = 0;\n }\n else {\n /*\n Otherwise the entire row-header column count can be resized.\n Resize all row-header columns and subtract from remaining\n column resize allowance.\n */\n this._fitRowColumnHeaders(this.dataModel, padding, rowColumnCount);\n colsRemaining = colsRemaining - rowColumnCount;\n }\n }\n else {\n // No column resize cap passed - resizing all columns.\n this._fitRowColumnHeaders(this.dataModel, padding);\n }\n }\n if (area === 'body' || area === 'all') {\n // Respecting any column resize cap, if one has been passed.\n if (colsRemaining !== undefined) {\n const bodyColumnCount = this.dataModel.columnCount('body');\n /*\n If we have more body columns than columns available\n for resize, resize only remaining columns as per allowance\n and set remaining resize allowance number to 0.\n */\n if (colsRemaining - bodyColumnCount < 0) {\n this._fitBodyColumnHeaders(this.dataModel, padding, colsRemaining);\n }\n else {\n /*\n Otherwise the entire body column count can be resized.\n Resize based on the smallest number between remaining\n resize allowance and body column count.\n */\n this._fitBodyColumnHeaders(this.dataModel, padding, Math.min(colsRemaining, bodyColumnCount));\n }\n }\n else {\n // No column resize cap passed - resizing all columns.\n this._fitBodyColumnHeaders(this.dataModel, padding);\n }\n }\n }\n }\n /**\n * Map a client position to local viewport coordinates.\n *\n * @param clientX - The client X position of the mouse.\n *\n * @param clientY - The client Y position of the mouse.\n *\n * @returns The local viewport coordinates for the position.\n */\n mapToLocal(clientX, clientY) {\n // Fetch the viewport rect.\n let rect = this._viewport.node.getBoundingClientRect();\n // Extract the rect coordinates.\n let { left, top } = rect;\n // Round the rect coordinates for sub-pixel positioning.\n left = Math.floor(left);\n top = Math.floor(top);\n // Convert to local coordinates.\n let lx = clientX - left;\n let ly = clientY - top;\n // Return the local coordinates.\n return { lx, ly };\n }\n /**\n * Map a client position to virtual grid coordinates.\n *\n * @param clientX - The client X position of the mouse.\n *\n * @param clientY - The client Y position of the mouse.\n *\n * @returns The virtual grid coordinates for the position.\n */\n mapToVirtual(clientX, clientY) {\n // Convert to local coordiates.\n let { lx, ly } = this.mapToLocal(clientX, clientY);\n // Convert to virtual coordinates.\n let vx = lx + this.scrollX - this.headerWidth;\n let vy = ly + this.scrollY - this.headerHeight;\n // Return the local coordinates.\n return { vx, vy };\n }\n /**\n * Hit test the viewport for the given client position.\n *\n * @param clientX - The client X position of the mouse.\n *\n * @param clientY - The client Y position of the mouse.\n *\n * @returns The hit test result, or `null` if the client\n * position is out of bounds.\n *\n * #### Notes\n * This method accounts for a stretched last row and/or column.\n */\n hitTest(clientX, clientY) {\n // Convert the mouse position into local coordinates.\n let { lx, ly } = this.mapToLocal(clientX, clientY);\n // Fetch the header and body dimensions.\n let hw = this.headerWidth;\n let hh = this.headerHeight;\n let bw = this.bodyWidth;\n let bh = this.bodyHeight;\n let ph = this.pageHeight;\n let pw = this.pageWidth;\n // Adjust the body width for a stretched last column.\n if (this._stretchLastColumn && pw > bw) {\n bw = pw;\n }\n // Adjust the body height for a stretched last row.\n if (this._stretchLastRow && ph > bh) {\n bh = ph;\n }\n // Check for a corner header hit.\n if (lx >= 0 && lx < hw && ly >= 0 && ly < hh) {\n // Convert to unscrolled virtual coordinates.\n let vx = lx;\n let vy = ly;\n // Fetch the row and column index.\n let row = this.rowAt('column-header', vy);\n let column = this.columnAt('row-header', vx);\n // Fetch the cell offset position.\n let ox = this.columnOffset('row-header', column);\n let oy = this.rowOffset('column-header', row);\n // Fetch cell width and height.\n let width = this.columnSize('row-header', column);\n let height = this.rowSize('column-header', row);\n // Compute the leading and trailing positions.\n let x = vx - ox;\n let y = vy - oy;\n // Return the hit test result.\n return { region: 'corner-header', row, column, x, y, width, height };\n }\n // Check for a column header hit.\n if (ly >= 0 && ly < hh && lx >= 0 && lx < hw + bw) {\n // Convert to unscrolled virtual coordinates.\n let vx = lx + this._scrollX - hw;\n let vy = ly;\n // Fetch the row and column index.\n let row = this.rowAt('column-header', vy);\n let column = this.columnAt('body', vx);\n // Fetch the cell offset position.\n let ox = this.columnOffset('body', column);\n let oy = this.rowOffset('column-header', row);\n // Fetch the cell width and height.\n let width = this.columnSize('body', column);\n let height = this.rowSize('column-header', row);\n // Compute the leading and trailing positions.\n let x = vx - ox;\n let y = vy - oy;\n // Return the hit test result.\n return { region: 'column-header', row, column, x, y, width, height };\n }\n // Check for a row header hit.\n if (lx >= 0 && lx < hw && ly >= 0 && ly < hh + bh) {\n // Convert to unscrolled virtual coordinates.\n let vx = lx;\n let vy = ly + this._scrollY - hh;\n // Fetch the row and column index.\n let row = this.rowAt('body', vy);\n let column = this.columnAt('row-header', vx);\n // Fetch the cell offset position.\n let ox = this.columnOffset('row-header', column);\n let oy = this.rowOffset('body', row);\n // Fetch the cell width and height.\n let width = this.columnSize('row-header', column);\n let height = this.rowSize('body', row);\n // Compute the leading and trailing positions.\n let x = vx - ox;\n let y = vy - oy;\n // Return the hit test result.\n return { region: 'row-header', row, column, x, y, width, height };\n }\n // Check for a body hit.\n if (lx >= hw && lx < hw + bw && ly >= hh && ly < hh + bh) {\n // Convert to unscrolled virtual coordinates.\n let vx = lx + this._scrollX - hw;\n let vy = ly + this._scrollY - hh;\n // Fetch the row and column index.\n let row = this.rowAt('body', vy);\n let column = this.columnAt('body', vx);\n // Fetch the cell offset position.\n let ox = this.columnOffset('body', column);\n let oy = this.rowOffset('body', row);\n // Fetch the cell width and height.\n let width = this.columnSize('body', column);\n let height = this.rowSize('body', row);\n // Compute the part coordinates.\n let x = vx - ox;\n let y = vy - oy;\n // Return the result.\n return { region: 'body', row, column, x, y, width, height };\n }\n // Otherwise, it's a void space hit.\n let row = -1;\n let column = -1;\n let x = -1;\n let y = -1;\n let width = -1;\n let height = -1;\n // Return the hit test result.\n return { region: 'void', row, column, x, y, width, height };\n }\n /**\n * Copy the current selection to the system clipboard.\n *\n * #### Notes\n * The grid must have a data model and a selection model.\n *\n * The behavior can be configured via `DataGrid.copyConfig`.\n */\n copyToClipboard() {\n // Fetch the data model.\n let dataModel = this._dataModel;\n // Bail early if there is no data model.\n if (!dataModel) {\n return;\n }\n // Fetch the selection model.\n let selectionModel = this._selectionModel;\n // Bail early if there is no selection model.\n if (!selectionModel) {\n return;\n }\n // Coerce the selections to an array.\n let selections = Array.from(selectionModel.selections());\n // Bail early if there are no selections.\n if (selections.length === 0) {\n return;\n }\n // Alert that multiple selections cannot be copied.\n if (selections.length > 1) {\n alert('Cannot copy multiple grid selections.');\n return;\n }\n // Fetch the model counts.\n let br = dataModel.rowCount('body');\n let bc = dataModel.columnCount('body');\n // Bail early if there is nothing to copy.\n if (br === 0 || bc === 0) {\n return;\n }\n // Unpack the selection.\n let { r1, c1, r2, c2 } = selections[0];\n // Clamp the selection to the model bounds.\n r1 = Math.max(0, Math.min(r1, br - 1));\n c1 = Math.max(0, Math.min(c1, bc - 1));\n r2 = Math.max(0, Math.min(r2, br - 1));\n c2 = Math.max(0, Math.min(c2, bc - 1));\n // Ensure the limits are well-orderd.\n if (r2 < r1)\n [r1, r2] = [r2, r1];\n if (c2 < c1)\n [c1, c2] = [c2, c1];\n // Fetch the header counts.\n let rhc = dataModel.columnCount('row-header');\n let chr = dataModel.rowCount('column-header');\n // Unpack the copy config.\n let separator = this._copyConfig.separator;\n let format = this._copyConfig.format;\n let headers = this._copyConfig.headers;\n let warningThreshold = this._copyConfig.warningThreshold;\n // Compute the number of cells to be copied.\n let rowCount = r2 - r1 + 1;\n let colCount = c2 - c1 + 1;\n switch (headers) {\n case 'none':\n rhc = 0;\n chr = 0;\n break;\n case 'row':\n chr = 0;\n colCount += rhc;\n break;\n case 'column':\n rhc = 0;\n rowCount += chr;\n break;\n case 'all':\n rowCount += chr;\n colCount += rhc;\n break;\n default:\n throw 'unreachable';\n }\n // Compute the total cell count.\n let cellCount = rowCount * colCount;\n // Allow the user to cancel a large copy request.\n if (cellCount > warningThreshold) {\n let msg = `Copying ${cellCount} cells may take a while. Continue?`;\n if (!window.confirm(msg)) {\n return;\n }\n }\n // Set up the format args.\n let args = {\n region: 'body',\n row: 0,\n column: 0,\n value: null,\n metadata: {}\n };\n // Allocate the array of rows.\n let rows = new Array(rowCount);\n // Iterate over the rows.\n for (let j = 0; j < rowCount; ++j) {\n // Allocate the array of cells.\n let cells = new Array(colCount);\n // Iterate over the columns.\n for (let i = 0; i < colCount; ++i) {\n // Set up the format variables.\n let region;\n let row;\n let column;\n // Populate the format variables.\n if (j < chr && i < rhc) {\n region = 'corner-header';\n row = j;\n column = i;\n }\n else if (j < chr) {\n region = 'column-header';\n row = j;\n column = i - rhc + c1;\n }\n else if (i < rhc) {\n region = 'row-header';\n row = j - chr + r1;\n column = i;\n }\n else {\n region = 'body';\n row = j - chr + r1;\n column = i - rhc + c1;\n }\n // Populate the format args.\n args.region = region;\n args.row = row;\n args.column = column;\n args.value = dataModel.data(region, row, column);\n args.metadata = dataModel.metadata(region, row, column);\n // Format the cell.\n cells[i] = format(args);\n }\n // Save the row of cells.\n rows[j] = cells;\n }\n // Convert the cells into lines.\n let lines = rows.map(cells => cells.join(separator));\n // Convert the lines into text.\n let text = lines.join('\\n');\n // Copy the text to the clipboard.\n ClipboardExt.copyText(text);\n }\n /**\n * Process a message sent to the widget.\n *\n * @param msg - The message sent to the widget.\n */\n processMessage(msg) {\n // Ignore child show/hide messages. The data grid controls the\n // visibility of its children, and will manually dispatch the\n // fit-request messages as a result of visibility change.\n if (msg.type === 'child-shown' || msg.type === 'child-hidden') {\n return;\n }\n // Recompute the scroll bar minimums before the layout refits.\n if (msg.type === 'fit-request') {\n let vsbLimits = ElementExt.sizeLimits(this._vScrollBar.node);\n let hsbLimits = ElementExt.sizeLimits(this._hScrollBar.node);\n this._vScrollBarMinWidth = vsbLimits.minWidth;\n this._hScrollBarMinHeight = hsbLimits.minHeight;\n }\n // Process all other messages as normal.\n super.processMessage(msg);\n }\n /**\n * Intercept a message sent to a message handler.\n *\n * @param handler - The target handler of the message.\n *\n * @param msg - The message to be sent to the handler.\n *\n * @returns `true` if the message should continue to be processed\n * as normal, or `false` if processing should cease immediately.\n */\n messageHook(handler, msg) {\n // Process viewport messages.\n if (handler === this._viewport) {\n this._processViewportMessage(msg);\n return true;\n }\n // Process horizontal scroll bar messages.\n if (handler === this._hScrollBar && msg.type === 'activate-request') {\n this.activate();\n return false;\n }\n // Process vertical scroll bar messages.\n if (handler === this._vScrollBar && msg.type === 'activate-request') {\n this.activate();\n return false;\n }\n // Ignore all other messages.\n return true;\n }\n /**\n * Handle the DOM events for the data grid.\n *\n * @param event - The DOM event sent to the data grid.\n *\n * #### Notes\n * This method implements the DOM `EventListener` interface and is\n * called in response to events on the data grid's DOM node. It\n * should not be called directly by user code.\n */\n handleEvent(event) {\n switch (event.type) {\n case 'keydown':\n this._evtKeyDown(event);\n break;\n case 'mousedown':\n this._evtMouseDown(event);\n break;\n case 'mousemove':\n this._evtMouseMove(event);\n break;\n case 'mouseup':\n this._evtMouseUp(event);\n break;\n case 'dblclick':\n this._evtMouseDoubleClick(event);\n break;\n case 'mouseleave':\n this._evtMouseLeave(event);\n break;\n case 'contextmenu':\n this._evtContextMenu(event);\n break;\n case 'wheel':\n this._evtWheel(event);\n break;\n case 'resize':\n this._refreshDPI();\n break;\n }\n }\n /**\n * Get the current viewport.\n *\n * @returns The current viewport as row/column coordinates.\n * Returns undefined if the grid is not visible.\n */\n get currentViewport() {\n let width = this.viewport.node.offsetWidth;\n let height = this.viewport.node.offsetHeight;\n width = Math.round(width);\n height = Math.round(height);\n if (width <= 0 || height <= 0) {\n return;\n }\n const contentW = this._columnSections.length - this.scrollX;\n const contentH = this._rowSections.length - this.scrollY;\n const contentX = this.headerWidth;\n const contentY = this.headerHeight;\n const x1 = contentX;\n const y1 = contentY;\n const x2 = Math.min(width - 1, contentX + contentW - 1);\n const y2 = Math.min(height - 1, contentY + contentH - 1);\n const firstRow = this._rowSections.indexOf(y1 - contentY + this.scrollY);\n const firstColumn = this._columnSections.indexOf(x1 - contentX + this.scrollX);\n const lastRow = this._rowSections.indexOf(y2 - contentY + this.scrollY);\n const lastColumn = this._columnSections.indexOf(x2 - contentX + this.scrollX);\n return {\n firstRow,\n firstColumn,\n lastRow,\n lastColumn\n };\n }\n /**\n * A message handler invoked on an `'activate-request'` message.\n */\n onActivateRequest(msg) {\n this.viewport.node.focus({ preventScroll: true });\n }\n /**\n * A message handler invoked on a `'before-attach'` message.\n */\n onBeforeAttach(msg) {\n window.addEventListener('resize', this);\n this.node.addEventListener('wheel', this);\n this._viewport.node.addEventListener('keydown', this);\n this._viewport.node.addEventListener('mousedown', this);\n this._viewport.node.addEventListener('mousemove', this);\n this._viewport.node.addEventListener('dblclick', this);\n this._viewport.node.addEventListener('mouseleave', this);\n this._viewport.node.addEventListener('contextmenu', this);\n this.repaintContent();\n this.repaintOverlay();\n }\n /**\n * A message handler invoked on an `'after-detach'` message.\n */\n onAfterDetach(msg) {\n window.removeEventListener('resize', this);\n this.node.removeEventListener('wheel', this);\n this._viewport.node.removeEventListener('keydown', this);\n this._viewport.node.removeEventListener('mousedown', this);\n this._viewport.node.removeEventListener('mousemove', this);\n this._viewport.node.removeEventListener('mouseleave', this);\n this._viewport.node.removeEventListener('dblclick', this);\n this._viewport.node.removeEventListener('contextmenu', this);\n this._releaseMouse();\n }\n /**\n * A message handler invoked on a `'before-show'` message.\n */\n onBeforeShow(msg) {\n this.repaintContent();\n this.repaintOverlay();\n }\n /**\n * A message handler invoked on a `'resize'` message.\n */\n onResize(msg) {\n if (this._editorController) {\n this._editorController.cancel();\n }\n this._syncScrollState();\n }\n /**\n * Schedule a repaint of all of the grid content.\n */\n repaintContent() {\n let msg = new Private$1.PaintRequest('all', 0, 0, 0, 0);\n MessageLoop.postMessage(this._viewport, msg);\n }\n /**\n * Schedule a repaint of specific grid content.\n */\n repaintRegion(region, r1, c1, r2, c2) {\n let msg = new Private$1.PaintRequest(region, r1, c1, r2, c2);\n MessageLoop.postMessage(this._viewport, msg);\n }\n /**\n * Schedule a repaint of the overlay.\n */\n repaintOverlay() {\n MessageLoop.postMessage(this._viewport, Private$1.OverlayPaintRequest);\n }\n _getMaxWidthInColumn(index, columnRegion) {\n const dataModel = this.dataModel;\n if (!dataModel) {\n return null;\n }\n const columnHeaderRegion = columnRegion == 'row-header' ? 'corner-header' : 'column-header';\n return Math.max(this._getMaxWidthInArea(dataModel, index, columnHeaderRegion, 'column-header'), this._getMaxWidthInArea(dataModel, index, columnRegion, 'body'));\n }\n _getMaxWidthInArea(dataModel, index, region, rowRegion) {\n const numRows = dataModel.rowCount(rowRegion);\n // Will only allocate up to 1_000_000 elements otherwise performance can tank.\n const configs = Array.from({ length: Math.min(numRows, 1000000) }, (_val, idx) => DataGrid._getConfig(dataModel, idx, index, region));\n // Heuristic: Sort by the length of the text to render and only fully calculate the text width\n // for the top 100_000 rows by text length\n if (numRows > 100000) {\n // Sort by descending length\n configs.sort(x => -this._getTextToRender(x).length);\n }\n let maxWidth = 0;\n for (let i = 0; i < numRows && i < 100000; ++i) {\n const textWidth = this._getCellTextWidth(configs[i]);\n maxWidth = Math.max(maxWidth, textWidth);\n }\n return maxWidth;\n }\n static _getConfig(dataModel, row, col, location) {\n return {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n region: location,\n row: row,\n column: col,\n value: DataGrid._getCellValue(dataModel, location, row, col),\n metadata: DataGrid._getCellMetadata(dataModel, location, row, col)\n };\n }\n _getTextToRender(config) {\n const renderer = this.cellRenderers.get(config);\n return renderer.getText(config);\n }\n _getCellTextWidth(config) {\n // Get the renderer for the given cell.\n const renderer = this.cellRenderers.get(config);\n // Use the canvas context to measure the cell's text width\n const gc = this.canvasGC;\n gc.font = CellRenderer.resolveOption(renderer.font, config);\n gc.fillStyle = CellRenderer.resolveOption(renderer.textColor, config);\n gc.textAlign = CellRenderer.resolveOption(renderer.horizontalAlignment, config);\n gc.textBaseline = 'bottom';\n const text = this._getTextToRender(config);\n return gc.measureText(text).width + 2 * renderer.horizontalPadding;\n }\n /**\n * Ensure the canvas is at least the specified size.\n *\n * This method will retain the valid canvas content.\n */\n _resizeCanvasIfNeeded(width, height) {\n // Scale the size by the dpi ratio.\n width = width * this._dpiRatio;\n height = height * this._dpiRatio;\n // Compute the maximum canvas size for the given width and height.\n let maxW = (Math.ceil((width + 1) / 512) + 1) * 512;\n let maxH = (Math.ceil((height + 1) / 512) + 1) * 512;\n // Get the current size of the canvas.\n let curW = this._canvas.width;\n let curH = this._canvas.height;\n // Bail early if the canvas size is within bounds.\n if (curW >= width && curH >= height && curW <= maxW && curH <= maxH) {\n return;\n }\n // Compute the expanded canvas size.\n let expW = maxW - 512;\n let expH = maxH - 512;\n // Set the transforms to the identity matrix.\n this._canvasGC.setTransform(1, 0, 0, 1, 0, 0);\n this._bufferGC.setTransform(1, 0, 0, 1, 0, 0);\n this._overlayGC.setTransform(1, 0, 0, 1, 0, 0);\n // Resize the buffer if needed.\n if (curW < width) {\n this._buffer.width = expW;\n }\n else if (curW > maxW) {\n this._buffer.width = maxW;\n }\n // Resize the buffer height if needed.\n if (curH < height) {\n this._buffer.height = expH;\n }\n else if (curH > maxH) {\n this._buffer.height = maxH;\n }\n // Test whether there is content to blit.\n let needBlit = curW > 0 && curH > 0 && width > 0 && height > 0;\n // Copy the valid canvas content into the buffer if needed.\n if (needBlit) {\n this._bufferGC.drawImage(this._canvas, 0, 0);\n }\n // Resize the canvas width if needed.\n if (curW < width) {\n this._canvas.width = expW;\n this._canvas.style.width = `${expW / this._dpiRatio}px`;\n }\n else if (curW > maxW) {\n this._canvas.width = maxW;\n this._canvas.style.width = `${maxW / this._dpiRatio}px`;\n }\n // Resize the canvas height if needed.\n if (curH < height) {\n this._canvas.height = expH;\n this._canvas.style.height = `${expH / this._dpiRatio}px`;\n }\n else if (curH > maxH) {\n this._canvas.height = maxH;\n this._canvas.style.height = `${maxH / this._dpiRatio}px`;\n }\n // Copy the valid canvas content from the buffer if needed.\n if (needBlit) {\n this._canvasGC.drawImage(this._buffer, 0, 0);\n }\n // Copy the valid overlay content into the buffer if needed.\n if (needBlit) {\n this._bufferGC.drawImage(this._overlay, 0, 0);\n }\n // Resize the overlay width if needed.\n if (curW < width) {\n this._overlay.width = expW;\n this._overlay.style.width = `${expW / this._dpiRatio}px`;\n }\n else if (curW > maxW) {\n this._overlay.width = maxW;\n this._overlay.style.width = `${maxW / this._dpiRatio}px`;\n }\n // Resize the overlay height if needed.\n if (curH < height) {\n this._overlay.height = expH;\n this._overlay.style.height = `${expH / this._dpiRatio}px`;\n }\n else if (curH > maxH) {\n this._overlay.height = maxH;\n this._overlay.style.height = `${maxH / this._dpiRatio}px`;\n }\n // Copy the valid overlay content from the buffer if needed.\n if (needBlit) {\n this._overlayGC.drawImage(this._buffer, 0, 0);\n }\n }\n /**\n * Sync the scroll bars and scroll state with the viewport.\n *\n * #### Notes\n * If the visibility of either scroll bar changes, a synchronous\n * fit-request will be dispatched to the data grid to immediately\n * resize the viewport.\n */\n _syncScrollState() {\n // Fetch the viewport dimensions.\n let bw = this.bodyWidth;\n let bh = this.bodyHeight;\n let pw = this.pageWidth;\n let ph = this.pageHeight;\n // Get the current scroll bar visibility.\n let hasVScroll = !this._vScrollBar.isHidden;\n let hasHScroll = !this._hScrollBar.isHidden;\n // Get the minimum sizes of the scroll bars.\n let vsw = this._vScrollBarMinWidth;\n let hsh = this._hScrollBarMinHeight;\n // Get the page size as if no scroll bars are visible.\n let apw = pw + (hasVScroll ? vsw : 0);\n let aph = ph + (hasHScroll ? hsh : 0);\n // Test whether scroll bars are needed for the adjusted size.\n let needVScroll = aph < bh - 1;\n let needHScroll = apw < bw - 1;\n // Re-test the horizontal scroll if a vertical scroll is needed.\n if (needVScroll && !needHScroll) {\n needHScroll = apw - vsw < bw - 1;\n }\n // Re-test the vertical scroll if a horizontal scroll is needed.\n if (needHScroll && !needVScroll) {\n needVScroll = aph - hsh < bh - 1;\n }\n // If the visibility changes, immediately refit the grid.\n if (needVScroll !== hasVScroll || needHScroll !== hasHScroll) {\n this._vScrollBar.setHidden(!needVScroll);\n this._hScrollBar.setHidden(!needHScroll);\n this._scrollCorner.setHidden(!needVScroll || !needHScroll);\n MessageLoop.sendMessage(this, Widget.Msg.FitRequest);\n }\n // Update the scroll bar limits.\n this._vScrollBar.maximum = this.maxScrollY;\n this._vScrollBar.page = this.pageHeight;\n this._hScrollBar.maximum = this.maxScrollX;\n this._hScrollBar.page = this.pageWidth;\n // Re-clamp the scroll position.\n this._scrollTo(this._scrollX, this._scrollY);\n }\n /**\n * Sync the viewport to the given scroll position.\n *\n * #### Notes\n * This schedules a full repaint and syncs the scroll state.\n */\n _syncViewport() {\n this.repaintContent();\n this.repaintOverlay();\n this._syncScrollState();\n }\n /**\n * Process a message sent to the viewport\n */\n _processViewportMessage(msg) {\n switch (msg.type) {\n case 'resize':\n this._onViewportResize(msg);\n break;\n case 'scroll-request':\n this._onViewportScrollRequest(msg);\n break;\n case 'paint-request':\n this._onViewportPaintRequest(msg);\n break;\n case 'overlay-paint-request':\n this._onViewportOverlayPaintRequest(msg);\n break;\n case 'row-resize-request':\n this._onViewportRowResizeRequest(msg);\n break;\n case 'column-resize-request':\n this._onViewportColumnResizeRequest(msg);\n break;\n }\n }\n /**\n * A message hook invoked on a viewport `'resize'` message.\n */\n _onViewportResize(msg) {\n // Bail early if the viewport is not visible.\n if (!this._viewport.isVisible) {\n return;\n }\n // Unpack the message data.\n let { width, height } = msg;\n // Measure the viewport node if the dimensions are unknown.\n if (width === -1) {\n width = this._viewport.node.offsetWidth;\n }\n if (height === -1) {\n height = this._viewport.node.offsetHeight;\n }\n // Round the dimensions to the nearest pixel.\n width = Math.round(width);\n height = Math.round(height);\n // Get the current size of the viewport.\n let oldWidth = this._viewportWidth;\n let oldHeight = this._viewportHeight;\n // Updated internal viewport size.\n this._viewportWidth = width;\n this._viewportHeight = height;\n // Resize the canvas if needed.\n this._resizeCanvasIfNeeded(width, height);\n // Bail early if there is nothing to paint.\n if (width === 0 || height === 0) {\n return;\n }\n // Paint the whole grid if the old size was zero.\n if (oldWidth === 0 || oldHeight === 0) {\n this.paintContent(0, 0, width, height);\n this._paintOverlay();\n return;\n }\n // Paint the right edge as needed.\n if (this._stretchLastColumn && this.pageWidth > this.bodyWidth) {\n let bx = this._columnSections.offsetOf(this._columnSections.count - 1);\n let x = Math.min(this.headerWidth + bx, oldWidth);\n this.paintContent(x, 0, width - x, height);\n }\n else if (width > oldWidth) {\n this.paintContent(oldWidth, 0, width - oldWidth + 1, height);\n }\n // Paint the bottom edge as needed.\n if (this._stretchLastRow && this.pageHeight > this.bodyHeight) {\n let by = this._rowSections.offsetOf(this._rowSections.count - 1);\n let y = Math.min(this.headerHeight + by, oldHeight);\n this.paintContent(0, y, width, height - y);\n }\n else if (height > oldHeight) {\n this.paintContent(0, oldHeight, width, height - oldHeight + 1);\n }\n // Paint the overlay.\n this._paintOverlay();\n }\n /**\n * A message hook invoked on a viewport `'scroll-request'` message.\n */\n _onViewportScrollRequest(msg) {\n this._scrollTo(this._hScrollBar.value, this._vScrollBar.value);\n }\n /**\n * A message hook invoked on a viewport `'paint-request'` message.\n */\n _onViewportPaintRequest(msg) {\n // Bail early if the viewport is not visible.\n if (!this._viewport.isVisible) {\n return;\n }\n // Bail early if the viewport has zero area.\n if (this._viewportWidth === 0 || this._viewportHeight === 0) {\n return;\n }\n // Set up the paint limits.\n let xMin = 0;\n let yMin = 0;\n let xMax = this._viewportWidth - 1;\n let yMax = this._viewportHeight - 1;\n // Fetch the scroll position.\n let sx = this._scrollX;\n let sy = this._scrollY;\n // Fetch the header dimensions.\n let hw = this.headerWidth;\n let hh = this.headerHeight;\n // Fetch the section lists.\n let rs = this._rowSections;\n let cs = this._columnSections;\n let rhs = this._rowHeaderSections;\n let chs = this._columnHeaderSections;\n // Unpack the message data.\n let { region, r1, c1, r2, c2 } = msg;\n // Set up the paint variables.\n let x1;\n let y1;\n let x2;\n let y2;\n // Fill the paint variables based on the paint region.\n switch (region) {\n case 'all':\n x1 = xMin;\n y1 = yMin;\n x2 = xMax;\n y2 = yMax;\n break;\n case 'body':\n r1 = Math.max(0, Math.min(r1, rs.count));\n c1 = Math.max(0, Math.min(c1, cs.count));\n r2 = Math.max(0, Math.min(r2, rs.count));\n c2 = Math.max(0, Math.min(c2, cs.count));\n x1 = cs.offsetOf(c1) - sx + hw;\n y1 = rs.offsetOf(r1) - sy + hh;\n x2 = cs.extentOf(c2) - sx + hw;\n y2 = rs.extentOf(r2) - sy + hh;\n break;\n case 'row-header':\n r1 = Math.max(0, Math.min(r1, rs.count));\n c1 = Math.max(0, Math.min(c1, rhs.count));\n r2 = Math.max(0, Math.min(r2, rs.count));\n c2 = Math.max(0, Math.min(c2, rhs.count));\n x1 = rhs.offsetOf(c1);\n y1 = rs.offsetOf(r1) - sy + hh;\n x2 = rhs.extentOf(c2);\n y2 = rs.extentOf(r2) - sy + hh;\n break;\n case 'column-header':\n r1 = Math.max(0, Math.min(r1, chs.count));\n c1 = Math.max(0, Math.min(c1, cs.count));\n r2 = Math.max(0, Math.min(r2, chs.count));\n c2 = Math.max(0, Math.min(c2, cs.count));\n x1 = cs.offsetOf(c1) - sx + hw;\n y1 = chs.offsetOf(r1);\n x2 = cs.extentOf(c2) - sx + hw;\n y2 = chs.extentOf(r2);\n break;\n case 'corner-header':\n r1 = Math.max(0, Math.min(r1, chs.count));\n c1 = Math.max(0, Math.min(c1, rhs.count));\n r2 = Math.max(0, Math.min(r2, chs.count));\n c2 = Math.max(0, Math.min(c2, rhs.count));\n x1 = rhs.offsetOf(c1);\n y1 = chs.offsetOf(r1);\n x2 = rhs.extentOf(c2);\n y2 = chs.extentOf(r2);\n break;\n default:\n throw 'unreachable';\n }\n // Bail early if the dirty rect is outside the bounds.\n if (x2 < xMin || y2 < yMin || x1 > xMax || y1 > yMax) {\n return;\n }\n // Clamp the dirty rect to the paint bounds.\n x1 = Math.max(xMin, Math.min(x1, xMax));\n y1 = Math.max(yMin, Math.min(y1, yMax));\n x2 = Math.max(xMin, Math.min(x2, xMax));\n y2 = Math.max(yMin, Math.min(y2, yMax));\n // Paint the content of the dirty rect.\n this.paintContent(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\n }\n /**\n * A message hook invoked on a viewport `'overlay-paint-request'` message.\n */\n _onViewportOverlayPaintRequest(msg) {\n // Bail early if the viewport is not visible.\n if (!this._viewport.isVisible) {\n return;\n }\n // Bail early if the viewport has zero area.\n if (this._viewportWidth === 0 || this._viewportHeight === 0) {\n return;\n }\n // Paint the content of the overlay.\n this._paintOverlay();\n }\n /**\n * A message hook invoked on a viewport `'row-resize-request'` message.\n */\n _onViewportRowResizeRequest(msg) {\n if (msg.region === 'body') {\n this._resizeRow(msg.index, msg.size);\n }\n else {\n this._resizeColumnHeader(msg.index, msg.size);\n }\n }\n /**\n * A message hook invoked on a viewport `'column-resize-request'` message.\n */\n _onViewportColumnResizeRequest(msg) {\n if (msg.region === 'body') {\n this._resizeColumn(msg.index, msg.size);\n }\n else {\n this._resizeRowHeader(msg.index, msg.size);\n }\n }\n /**\n * Handle the `thumbMoved` signal from a scroll bar.\n */\n _onThumbMoved(sender) {\n MessageLoop.postMessage(this._viewport, Private$1.ScrollRequest);\n }\n /**\n * Handle the `pageRequested` signal from a scroll bar.\n */\n _onPageRequested(sender, dir) {\n if (sender === this._vScrollBar) {\n this.scrollByPage(dir === 'decrement' ? 'up' : 'down');\n }\n else {\n this.scrollByPage(dir === 'decrement' ? 'left' : 'right');\n }\n }\n /**\n * Handle the `stepRequested` signal from a scroll bar.\n */\n _onStepRequested(sender, dir) {\n if (sender === this._vScrollBar) {\n this.scrollByStep(dir === 'decrement' ? 'up' : 'down');\n }\n else {\n this.scrollByStep(dir === 'decrement' ? 'left' : 'right');\n }\n }\n /**\n * A signal handler for the data model `changed` signal.\n */\n _onDataModelChanged(sender, args) {\n switch (args.type) {\n case 'rows-inserted':\n this._onRowsInserted(args);\n break;\n case 'columns-inserted':\n this._onColumnsInserted(args);\n break;\n case 'rows-removed':\n this._onRowsRemoved(args);\n break;\n case 'columns-removed':\n this._onColumnsRemoved(args);\n break;\n case 'rows-moved':\n this._onRowsMoved(args);\n break;\n case 'columns-moved':\n this._onColumnsMoved(args);\n break;\n case 'cells-changed':\n this._onCellsChanged(args);\n break;\n case 'model-reset':\n this._onModelReset(args);\n break;\n default:\n throw 'unreachable';\n }\n }\n /**\n * A signal handler for the selection model `changed` signal.\n */\n _onSelectionsChanged(sender) {\n this.repaintOverlay();\n }\n /**\n * Handle rows being inserted in the data model.\n */\n _onRowsInserted(args) {\n // Unpack the arg data.\n let { region, index, span } = args;\n // Bail early if there are no sections to insert.\n if (span <= 0) {\n return;\n }\n // Look up the relevant section list.\n let list;\n if (region === 'body') {\n list = this._rowSections;\n }\n else {\n list = this._columnHeaderSections;\n }\n // Insert the span, maintaining the scroll position as needed.\n if (this._scrollY === this.maxScrollY && this.maxScrollY > 0) {\n list.insert(index, span);\n this._scrollY = this.maxScrollY;\n }\n else {\n list.insert(index, span);\n }\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Handle columns being inserted into the data model.\n */\n _onColumnsInserted(args) {\n // Unpack the arg data.\n let { region, index, span } = args;\n // Bail early if there are no sections to insert.\n if (span <= 0) {\n return;\n }\n // Look up the relevant section list.\n let list;\n if (region === 'body') {\n list = this._columnSections;\n }\n else {\n list = this._rowHeaderSections;\n }\n // Insert the span, maintaining the scroll position as needed.\n if (this._scrollX === this.maxScrollX && this.maxScrollX > 0) {\n list.insert(index, span);\n this._scrollX = this.maxScrollX;\n }\n else {\n list.insert(index, span);\n }\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Handle rows being removed from the data model.\n */\n _onRowsRemoved(args) {\n // Unpack the arg data.\n let { region, index, span } = args;\n // Bail early if there are no sections to remove.\n if (span <= 0) {\n return;\n }\n // Look up the relevant section list.\n let list;\n if (region === 'body') {\n list = this._rowSections;\n }\n else {\n list = this._columnHeaderSections;\n }\n // Bail if the index or is invalid\n if (index < 0 || index >= list.count) {\n return;\n }\n // Remove the span, maintaining the scroll position as needed.\n if (this._scrollY === this.maxScrollY && this.maxScrollY > 0) {\n list.remove(index, span);\n this._scrollY = this.maxScrollY;\n }\n else {\n list.remove(index, span);\n }\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Handle columns being removed from the data model.\n */\n _onColumnsRemoved(args) {\n // Unpack the arg data.\n let { region, index, span } = args;\n // Bail early if there are no sections to remove.\n if (span <= 0) {\n return;\n }\n // Look up the relevant section list.\n let list;\n if (region === 'body') {\n list = this._columnSections;\n }\n else {\n list = this._rowHeaderSections;\n }\n // Bail if the index or is invalid\n if (index < 0 || index >= list.count) {\n return;\n }\n // Remove the span, maintaining the scroll position as needed.\n if (this._scrollX === this.maxScrollX && this.maxScrollX > 0) {\n list.remove(index, span);\n this._scrollX = this.maxScrollX;\n }\n else {\n list.remove(index, span);\n }\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Handle rows moving in the data model.\n */\n _onRowsMoved(args) {\n // Unpack the arg data.\n let { region, index, span, destination } = args;\n // Bail early if there are no sections to move.\n if (span <= 0) {\n return;\n }\n // Look up the relevant section list.\n let list;\n if (region === 'body') {\n list = this._rowSections;\n }\n else {\n list = this._columnHeaderSections;\n }\n // Bail early if the index is out of range.\n if (index < 0 || index >= list.count) {\n return;\n }\n // Clamp the move span to the limit.\n span = Math.min(span, list.count - index);\n // Clamp the destination index to the limit.\n destination = Math.min(Math.max(0, destination), list.count - span);\n // Bail early if there is no effective move.\n if (index === destination) {\n return;\n }\n // Compute the first affected index.\n let r1 = Math.min(index, destination);\n // Compute the last affected index.\n let r2 = Math.max(index + span - 1, destination + span - 1);\n // Move the sections in the list.\n list.move(index, span, destination);\n // Schedule a repaint of the dirty cells.\n if (region === 'body') {\n this.repaintRegion('body', r1, 0, r2, Infinity);\n this.repaintRegion('row-header', r1, 0, r2, Infinity);\n }\n else {\n this.repaintRegion('column-header', r1, 0, r2, Infinity);\n this.repaintRegion('corner-header', r1, 0, r2, Infinity);\n }\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Handle columns moving in the data model.\n */\n _onColumnsMoved(args) {\n // Unpack the arg data.\n let { region, index, span, destination } = args;\n // Bail early if there are no sections to move.\n if (span <= 0) {\n return;\n }\n // Look up the relevant section list.\n let list;\n if (region === 'body') {\n list = this._columnSections;\n }\n else {\n list = this._rowHeaderSections;\n }\n // Bail early if the index is out of range.\n if (index < 0 || index >= list.count) {\n return;\n }\n // Clamp the move span to the limit.\n span = Math.min(span, list.count - index);\n // Clamp the destination index to the limit.\n destination = Math.min(Math.max(0, destination), list.count - span);\n // Bail early if there is no effective move.\n if (index === destination) {\n return;\n }\n // Move the sections in the list.\n list.move(index, span, destination);\n // Compute the first affected index.\n let c1 = Math.min(index, destination);\n // Compute the last affected index.\n let c2 = Math.max(index + span - 1, destination + span - 1);\n // Schedule a repaint of the dirty cells.\n if (region === 'body') {\n this.repaintRegion('body', 0, c1, Infinity, c2);\n this.repaintRegion('column-header', 0, c1, Infinity, c2);\n }\n else {\n this.repaintRegion('row-header', 0, c1, Infinity, c2);\n this.repaintRegion('corner-header', 0, c1, Infinity, c2);\n }\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * Handle cells changing in the data model.\n */\n _onCellsChanged(args) {\n // Unpack the arg data.\n let { region, row, column, rowSpan, columnSpan } = args;\n // Bail early if there are no cells to modify.\n if (rowSpan <= 0 && columnSpan <= 0) {\n return;\n }\n // Compute the changed cell bounds.\n let r1 = row;\n let c1 = column;\n let r2 = r1 + rowSpan - 1;\n let c2 = c1 + columnSpan - 1;\n // Schedule a repaint of the cell content.\n this.repaintRegion(region, r1, c1, r2, c2);\n }\n /**\n * Handle a full data model reset.\n */\n _onModelReset(args) {\n // Look up the various current section counts.\n let nr = this._rowSections.count;\n let nc = this._columnSections.count;\n let nrh = this._rowHeaderSections.count;\n let nch = this._columnHeaderSections.count;\n // Compute the delta count for each region.\n let dr = this._dataModel.rowCount('body') - nr;\n let dc = this._dataModel.columnCount('body') - nc;\n let drh = this._dataModel.columnCount('row-header') - nrh;\n let dch = this._dataModel.rowCount('column-header') - nch;\n // Update the row sections, if needed.\n if (dr > 0) {\n this._rowSections.insert(nr, dr);\n }\n else if (dr < 0) {\n this._rowSections.remove(nr + dr, -dr);\n }\n // Update the column sections, if needed.\n if (dc > 0) {\n this._columnSections.insert(nc, dc);\n }\n else if (dc < 0) {\n this._columnSections.remove(nc + dc, -dc);\n }\n // Update the row header sections, if needed.\n if (drh > 0) {\n this._rowHeaderSections.insert(nrh, drh);\n }\n else if (drh < 0) {\n this._rowHeaderSections.remove(nrh + drh, -drh);\n }\n // Update the column header sections, if needed.\n if (dch > 0) {\n this._columnHeaderSections.insert(nch, dch);\n }\n else if (dch < 0) {\n this._columnHeaderSections.remove(nch + dch, -dch);\n }\n // Sync the viewport.\n this._syncViewport();\n }\n /**\n * A signal handler for the renderer map `changed` signal.\n */\n _onRenderersChanged() {\n this.repaintContent();\n }\n /**\n * Handle the `'keydown'` event for the data grid.\n */\n _evtKeyDown(event) {\n if (this._mousedown) {\n event.preventDefault();\n event.stopPropagation();\n }\n else if (this._keyHandler) {\n this._keyHandler.onKeyDown(this, event);\n }\n }\n /**\n * Handle the `'mousedown'` event for the data grid.\n */\n _evtMouseDown(event) {\n // Ignore everything except the left mouse button.\n if (event.button !== 0) {\n return;\n }\n // Activate the grid.\n this.activate();\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Add the extra document listeners.\n document.addEventListener('keydown', this, true);\n document.addEventListener('mouseup', this, true);\n document.addEventListener('mousedown', this, true);\n document.addEventListener('mousemove', this, true);\n document.addEventListener('contextmenu', this, true);\n // Flip the mousedown flag.\n this._mousedown = true;\n // Dispatch to the mouse handler.\n if (this._mouseHandler) {\n this._mouseHandler.onMouseDown(this, event);\n }\n }\n /**\n * Handle the `'mousemove'` event for the data grid.\n */\n _evtMouseMove(event) {\n // Stop the event propagation if the mouse is down.\n if (this._mousedown) {\n event.preventDefault();\n event.stopPropagation();\n }\n // Bail if there is no mouse handler.\n if (!this._mouseHandler) {\n return;\n }\n // Dispatch to the mouse handler.\n if (this._mousedown) {\n this._mouseHandler.onMouseMove(this, event);\n }\n else {\n this._mouseHandler.onMouseHover(this, event);\n }\n }\n /**\n * Handle the `'mouseup'` event for the data grid.\n */\n _evtMouseUp(event) {\n // Ignore everything except the left mouse button.\n if (event.button !== 0) {\n return;\n }\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Dispatch to the mouse handler.\n if (this._mouseHandler) {\n this._mouseHandler.onMouseUp(this, event);\n }\n // Release the mouse.\n this._releaseMouse();\n }\n /**\n * Handle the `'dblclick'` event for the data grid.\n */\n _evtMouseDoubleClick(event) {\n // Ignore everything except the left mouse button.\n if (event.button !== 0) {\n return;\n }\n // Stop the event propagation.\n event.preventDefault();\n event.stopPropagation();\n // Dispatch to the mouse handler.\n if (this._mouseHandler) {\n this._mouseHandler.onMouseDoubleClick(this, event);\n }\n // Release the mouse.\n this._releaseMouse();\n }\n /**\n * Handle the `'mouseleave'` event for the data grid.\n */\n _evtMouseLeave(event) {\n if (this._mousedown) {\n event.preventDefault();\n event.stopPropagation();\n }\n else if (this._mouseHandler) {\n this._mouseHandler.onMouseLeave(this, event);\n }\n }\n /**\n * Handle the `'contextmenu'` event for the data grid.\n */\n _evtContextMenu(event) {\n if (this._mousedown) {\n event.preventDefault();\n event.stopPropagation();\n }\n else if (this._mouseHandler) {\n this._mouseHandler.onContextMenu(this, event);\n }\n }\n /**\n * Handle the `'wheel'` event for the data grid.\n */\n _evtWheel(event) {\n // Ignore the event if `accel` is held.\n if (Platform.accelKey(event)) {\n return;\n }\n // Bail early if there is no mouse handler.\n if (!this._mouseHandler) {\n return;\n }\n // Dispatch to the mouse handler.\n this._mouseHandler.onWheel(this, event);\n }\n /**\n * Release the mouse grab.\n */\n _releaseMouse() {\n // Clear the mousedown flag.\n this._mousedown = false;\n // Relase the mouse handler.\n if (this._mouseHandler) {\n this._mouseHandler.release();\n }\n // Remove the document listeners.\n document.removeEventListener('keydown', this, true);\n document.removeEventListener('mouseup', this, true);\n document.removeEventListener('mousedown', this, true);\n document.removeEventListener('mousemove', this, true);\n document.removeEventListener('contextmenu', this, true);\n }\n /**\n * Refresh the dpi ratio.\n */\n _refreshDPI() {\n // Get the best integral value for the dpi ratio.\n let dpiRatio = Math.ceil(window.devicePixelRatio);\n // Bail early if the computed dpi ratio has not changed.\n if (this._dpiRatio === dpiRatio) {\n return;\n }\n // Update the internal dpi ratio.\n this._dpiRatio = dpiRatio;\n // Schedule a repaint of the content.\n this.repaintContent();\n // Schedule a repaint of the overlay.\n this.repaintOverlay();\n // Update the canvas size for the new dpi ratio.\n this._resizeCanvasIfNeeded(this._viewportWidth, this._viewportHeight);\n // Ensure the canvas style is scaled for the new ratio.\n this._canvas.style.width = `${this._canvas.width / this._dpiRatio}px`;\n this._canvas.style.height = `${this._canvas.height / this._dpiRatio}px`;\n // Ensure the overlay style is scaled for the new ratio.\n this._overlay.style.width = `${this._overlay.width / this._dpiRatio}px`;\n this._overlay.style.height = `${this._overlay.height / this._dpiRatio}px`;\n }\n /**\n * Resize a row section immediately.\n */\n _resizeRow(index, size) {\n // Look up the target section list.\n let list = this._rowSections;\n // Bail early if the index is out of range.\n if (index < 0 || index >= list.count) {\n return;\n }\n // Look up the old size of the section.\n let oldSize = list.sizeOf(index);\n // Normalize the new size of the section.\n let newSize = list.clampSize(size);\n // Bail early if the size does not change.\n if (oldSize === newSize) {\n return;\n }\n // Resize the section in the list.\n list.resize(index, newSize);\n // Get the current size of the viewport.\n let vw = this._viewportWidth;\n let vh = this._viewportHeight;\n // If there is nothing to paint, sync the scroll state.\n if (!this._viewport.isVisible || vw === 0 || vh === 0) {\n this._syncScrollState();\n return;\n }\n // Compute the size delta.\n let delta = newSize - oldSize;\n // Look up the column header height.\n let hh = this.headerHeight;\n // Compute the viewport offset of the section.\n let offset = list.offsetOf(index) + hh - this._scrollY;\n // Bail early if there is nothing to paint.\n if (hh >= vh || offset >= vh) {\n this._syncScrollState();\n return;\n }\n // Update the scroll position if the section is not visible.\n if (offset + oldSize <= hh) {\n this._scrollY += delta;\n this._syncScrollState();\n return;\n }\n // Compute the paint origin of the section.\n let pos = Math.max(hh, offset);\n // Paint from the section onward if it spans the viewport.\n if (offset + oldSize >= vh || offset + newSize >= vh) {\n this.paintContent(0, pos, vw, vh - pos);\n this._paintOverlay();\n this._syncScrollState();\n return;\n }\n // Compute the X blit dimensions.\n let sx = 0;\n let sw = vw;\n let dx = 0;\n // Compute the Y blit dimensions.\n let sy;\n let sh;\n let dy;\n if (offset + newSize <= hh) {\n sy = hh - delta;\n sh = vh - sy;\n dy = hh;\n }\n else {\n sy = offset + oldSize;\n sh = vh - sy;\n dy = sy + delta;\n }\n // Blit the valid content to the destination.\n this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy);\n // Repaint the section if needed.\n if (newSize > 0 && offset + newSize > hh) {\n this.paintContent(0, pos, vw, offset + newSize - pos);\n }\n // Paint the trailing space as needed.\n if (this._stretchLastRow && this.pageHeight > this.bodyHeight) {\n let r = this._rowSections.count - 1;\n let y = hh + this._rowSections.offsetOf(r);\n this.paintContent(0, y, vw, vh - y);\n }\n else if (delta < 0) {\n this.paintContent(0, vh + delta, vw, -delta);\n }\n // Repaint merged cells that are intersected by the resized row\n // Otherwise it will be cut in two by the valid content, and drawn incorrectly\n for (const rgn of ['body', 'row-header']) {\n const cellGroups = CellGroup.getCellGroupsAtRow(this.dataModel, rgn, index);\n let paintRgn = {\n region: rgn,\n xMin: 0,\n xMax: 0,\n yMin: 0,\n yMax: 0\n };\n let backgroundColor = undefined;\n switch (rgn) {\n case 'body':\n paintRgn.xMin = this.headerWidth;\n paintRgn.xMax = this.headerWidth + this.bodyWidth;\n paintRgn.yMin = this.headerHeight;\n paintRgn.yMax = this.headerHeight + this.bodyHeight;\n backgroundColor = this._style.backgroundColor;\n break;\n case 'row-header':\n paintRgn.xMin = 0;\n paintRgn.xMax = this.headerWidth;\n paintRgn.yMin = this.headerHeight;\n paintRgn.yMax = this.headerHeight + this.bodyHeight;\n backgroundColor = this._style.headerBackgroundColor;\n break;\n }\n this._paintMergedCells(cellGroups, paintRgn, backgroundColor);\n }\n // Paint the overlay.\n this._paintOverlay();\n // Sync the scroll state.\n this._syncScrollState();\n }\n /**\n * Resize a column section immediately.\n */\n _resizeColumn(index, size) {\n // Look up the target section list.\n let list = this._columnSections;\n // Bail early if the index is out of range.\n if (index < 0 || index >= list.count) {\n return;\n }\n const adjustedSize = size !== null && size !== void 0 ? size : this._getMaxWidthInColumn(index, 'body');\n if (!adjustedSize || adjustedSize == 0) {\n return;\n }\n // Look up the old size of the section.\n let oldSize = list.sizeOf(index);\n // Normalize the new size of the section.\n let newSize = list.clampSize(adjustedSize);\n // Bail early if the size does not change.\n if (oldSize === newSize) {\n return;\n }\n // Resize the section in the list.\n list.resize(index, newSize);\n // Get the current size of the viewport.\n let vw = this._viewportWidth;\n let vh = this._viewportHeight;\n // If there is nothing to paint, sync the scroll state.\n if (!this._viewport.isVisible || vw === 0 || vh === 0) {\n this._syncScrollState();\n return;\n }\n // Compute the size delta.\n let delta = newSize - oldSize;\n // Look up the row header width.\n let hw = this.headerWidth;\n // Compute the viewport offset of the section.\n let offset = list.offsetOf(index) + hw - this._scrollX;\n // Bail early if there is nothing to paint.\n if (hw >= vw || offset >= vw) {\n this._syncScrollState();\n return;\n }\n // Update the scroll position if the section is not visible.\n if (offset + oldSize <= hw) {\n this._scrollX += delta;\n this._syncScrollState();\n return;\n }\n // Compute the paint origin of the section.\n let pos = Math.max(hw, offset);\n // Paint from the section onward if it spans the viewport.\n if (offset + oldSize >= vw || offset + newSize >= vw) {\n this.paintContent(pos, 0, vw - pos, vh);\n this._paintOverlay();\n this._syncScrollState();\n return;\n }\n // Compute the Y blit dimensions.\n let sy = 0;\n let sh = vh;\n let dy = 0;\n // Compute the X blit dimensions.\n let sx;\n let sw;\n let dx;\n if (offset + newSize <= hw) {\n sx = hw - delta;\n sw = vw - sx;\n dx = hw;\n }\n else {\n sx = offset + oldSize;\n sw = vw - sx;\n dx = sx + delta;\n }\n // Blit the valid content to the destination.\n this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy);\n // Repaint the section if needed.\n if (newSize > 0 && offset + newSize > hw) {\n this.paintContent(pos, 0, offset + newSize - pos, vh);\n }\n // Paint the trailing space as needed.\n if (this._stretchLastColumn && this.pageWidth > this.bodyWidth) {\n let c = this._columnSections.count - 1;\n let x = hw + this._columnSections.offsetOf(c);\n this.paintContent(x, 0, vw - x, vh);\n }\n else if (delta < 0) {\n this.paintContent(vw + delta, 0, -delta, vh);\n }\n // Repaint merged cells that are intersected by the resized column\n // Otherwise it will be cut in two by the valid content, and drawn incorrectly\n for (const rgn of ['body', 'column-header']) {\n const cellGroups = CellGroup.getCellGroupsAtColumn(this.dataModel, rgn, index);\n let paintRgn = {\n region: rgn,\n xMin: 0,\n xMax: 0,\n yMin: 0,\n yMax: 0\n };\n let backgroundColor = undefined;\n switch (rgn) {\n case 'body':\n paintRgn.xMin = this.headerWidth;\n paintRgn.xMax = this.headerWidth + this.bodyWidth;\n paintRgn.yMin = this.headerHeight;\n paintRgn.yMax = this.headerHeight + this.bodyHeight;\n backgroundColor = this._style.backgroundColor;\n break;\n case 'column-header':\n paintRgn.xMin = this.headerWidth;\n paintRgn.xMax = this.headerWidth + this.bodyWidth;\n paintRgn.yMin = 0;\n paintRgn.yMax = this.headerHeight;\n backgroundColor = this._style.headerBackgroundColor;\n break;\n }\n this._paintMergedCells(cellGroups, paintRgn, backgroundColor);\n }\n // Paint the overlay.\n this._paintOverlay();\n // Sync the scroll state after painting.\n this._syncScrollState();\n }\n /**\n * Resize a row header section immediately.\n */\n _resizeRowHeader(index, size) {\n // Look up the target section list.\n let list = this._rowHeaderSections;\n // Bail early if the index is out of range.\n if (index < 0 || index >= list.count) {\n return;\n }\n const adjustedSize = size !== null && size !== void 0 ? size : this._getMaxWidthInColumn(index, 'row-header');\n if (!adjustedSize || adjustedSize == 0) {\n return;\n }\n // Look up the old size of the section.\n let oldSize = list.sizeOf(index);\n // Normalize the new size of the section.\n let newSize = list.clampSize(adjustedSize);\n // Bail early if the size does not change.\n if (oldSize === newSize) {\n return;\n }\n // Resize the section in the list.\n list.resize(index, newSize);\n // Get the current size of the viewport.\n let vw = this._viewportWidth;\n let vh = this._viewportHeight;\n // If there is nothing to paint, sync the scroll state.\n if (!this._viewport.isVisible || vw === 0 || vh === 0) {\n this._syncScrollState();\n return;\n }\n // Compute the size delta.\n let delta = newSize - oldSize;\n // Look up the offset of the section.\n let offset = list.offsetOf(index);\n // Bail early if the section is fully outside the viewport.\n if (offset >= vw) {\n this._syncScrollState();\n return;\n }\n // Paint the entire tail if the section spans the viewport.\n if (offset + oldSize >= vw || offset + newSize >= vw) {\n this.paintContent(offset, 0, vw - offset, vh);\n this._paintOverlay();\n this._syncScrollState();\n return;\n }\n // Compute the blit content dimensions.\n let sx = offset + oldSize;\n let sy = 0;\n let sw = vw - sx;\n let sh = vh;\n let dx = sx + delta;\n let dy = 0;\n // Blit the valid content to the destination.\n this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy);\n // Repaint the header section if needed.\n if (newSize > 0) {\n this.paintContent(offset, 0, newSize, vh);\n }\n // Paint the trailing space as needed.\n if (this._stretchLastColumn && this.pageWidth > this.bodyWidth) {\n let c = this._columnSections.count - 1;\n let x = this.headerWidth + this._columnSections.offsetOf(c);\n this.paintContent(x, 0, vw - x, vh);\n }\n else if (delta < 0) {\n this.paintContent(vw + delta, 0, -delta, vh);\n }\n // Repaint merged cells that are intersected by the resized row\n // Otherwise it will be cut in two by the valid content, and drawn incorrectly\n for (const rgn of [\n 'corner-header',\n 'row-header'\n ]) {\n const cellGroups = CellGroup.getCellGroupsAtColumn(this.dataModel, rgn, index);\n let paintRgn = {\n region: rgn,\n xMin: 0,\n xMax: 0,\n yMin: 0,\n yMax: 0\n };\n switch (rgn) {\n case 'corner-header':\n paintRgn.xMin = 0;\n paintRgn.xMax = this.headerWidth;\n paintRgn.yMin = 0;\n paintRgn.yMax = this.headerHeight;\n break;\n case 'row-header':\n paintRgn.xMin = 0;\n paintRgn.xMax = this.headerWidth;\n paintRgn.yMin = this.headerHeight;\n paintRgn.yMax = this.headerHeight + this.bodyHeight;\n break;\n }\n this._paintMergedCells(cellGroups, paintRgn, this._style.headerBackgroundColor);\n }\n // Paint the overlay.\n this._paintOverlay();\n // Sync the scroll state after painting.\n this._syncScrollState();\n }\n /**\n * Resize a column header section immediately.\n */\n _resizeColumnHeader(index, size) {\n // Look up the target section list.\n let list = this._columnHeaderSections;\n // Bail early if the index is out of range.\n if (index < 0 || index >= list.count) {\n return;\n }\n // Look up the old size of the section.\n let oldSize = list.sizeOf(index);\n // Normalize the new size of the section.\n let newSize = list.clampSize(size);\n // Bail early if the size does not change.\n if (oldSize === newSize) {\n return;\n }\n // Resize the section in the list.\n list.resize(index, newSize);\n // Get the current size of the viewport.\n let vw = this._viewportWidth;\n let vh = this._viewportHeight;\n // If there is nothing to paint, sync the scroll state.\n if (!this._viewport.isVisible || vw === 0 || vh === 0) {\n this._syncScrollState();\n return;\n }\n // Paint the overlay.\n this._paintOverlay();\n // Compute the size delta.\n let delta = newSize - oldSize;\n // Look up the offset of the section.\n let offset = list.offsetOf(index);\n // Bail early if the section is fully outside the viewport.\n if (offset >= vh) {\n this._syncScrollState();\n return;\n }\n // Paint the entire tail if the section spans the viewport.\n if (offset + oldSize >= vh || offset + newSize >= vh) {\n this.paintContent(0, offset, vw, vh - offset);\n this._paintOverlay();\n this._syncScrollState();\n return;\n }\n // Compute the blit content dimensions.\n let sx = 0;\n let sy = offset + oldSize;\n let sw = vw;\n let sh = vh - sy;\n let dx = 0;\n let dy = sy + delta;\n // Blit the valid contents to the destination.\n this._blitContent(this._canvas, sx, sy, sw, sh, dx, dy);\n // Repaint the header section if needed.\n if (newSize > 0) {\n this.paintContent(0, offset, vw, newSize);\n }\n // Paint the trailing space as needed.\n if (this._stretchLastRow && this.pageHeight > this.bodyHeight) {\n let r = this._rowSections.count - 1;\n let y = this.headerHeight + this._rowSections.offsetOf(r);\n this.paintContent(0, y, vw, vh - y);\n }\n else if (delta < 0) {\n this.paintContent(0, vh + delta, vw, -delta);\n }\n // Repaint merged cells that are intersected by the resized row\n // Otherwise it will be cut in two by the valid content, and drawn incorrectly\n for (const rgn of [\n 'corner-header',\n 'column-header'\n ]) {\n const cellGroups = CellGroup.getCellGroupsAtRow(this.dataModel, rgn, index);\n let paintRgn = {\n region: rgn,\n xMin: 0,\n xMax: 0,\n yMin: 0,\n yMax: 0\n };\n switch (rgn) {\n case 'corner-header':\n paintRgn.xMin = 0;\n paintRgn.xMax = this.headerWidth;\n paintRgn.yMin = 0;\n paintRgn.yMax = this.headerHeight;\n break;\n case 'column-header':\n paintRgn.xMin = this.headerWidth;\n paintRgn.xMax = this.headerWidth + this.bodyWidth;\n paintRgn.yMin = 0;\n paintRgn.yMax = this.headerHeight;\n break;\n }\n this._paintMergedCells(cellGroups, paintRgn, this._style.headerBackgroundColor);\n }\n // Paint the overlay.\n this._paintOverlay();\n // Sync the scroll state after painting.\n this._syncScrollState();\n }\n /**\n * Scroll immediately to the specified offset position.\n */\n _scrollTo(x, y) {\n // Bail if no data model found.\n if (!this.dataModel) {\n return;\n }\n // Floor and clamp the position to the allowable range.\n x = Math.max(0, Math.min(Math.floor(x), this.maxScrollX));\n y = Math.max(0, Math.min(Math.floor(y), this.maxScrollY));\n // Synchronize the scroll bar values.\n this._hScrollBar.value = x;\n this._vScrollBar.value = y;\n // Compute the delta scroll amount.\n let dx = x - this._scrollX;\n let dy = y - this._scrollY;\n // Bail early if there is no effective scroll.\n if (dx === 0 && dy === 0) {\n return;\n }\n // Bail early if the viewport is not visible.\n if (!this._viewport.isVisible) {\n this._scrollX = x;\n this._scrollY = y;\n return;\n }\n // Get the current size of the viewport.\n let width = this._viewportWidth;\n let height = this._viewportHeight;\n // Bail early if the viewport is empty.\n if (width === 0 || height === 0) {\n this._scrollX = x;\n this._scrollY = y;\n return;\n }\n // Get the visible content origin.\n let contentX = this.headerWidth;\n let contentY = this.headerHeight;\n // Get the visible content dimensions.\n let contentWidth = width - contentX;\n let contentHeight = height - contentY;\n // Bail early if there is no content to draw.\n if (contentWidth <= 0 && contentHeight <= 0) {\n this._scrollX = x;\n this._scrollY = y;\n return;\n }\n // Compute the area which needs painting for the `dx` scroll.\n let dxArea = 0;\n if (dx !== 0 && contentWidth > 0) {\n if (Math.abs(dx) >= contentWidth) {\n dxArea = contentWidth * height;\n }\n else {\n dxArea = Math.abs(dx) * height;\n }\n }\n // Compute the area which needs painting for the `dy` scroll.\n let dyArea = 0;\n if (dy !== 0 && contentHeight > 0) {\n if (Math.abs(dy) >= contentHeight) {\n dyArea = width * contentHeight;\n }\n else {\n dyArea = width * Math.abs(dy);\n }\n }\n // If the area sum is larger than the total, paint everything.\n if (dxArea + dyArea >= width * height) {\n this._scrollX = x;\n this._scrollY = y;\n this.paintContent(0, 0, width, height);\n this._paintOverlay();\n return;\n }\n // Update the internal Y scroll position.\n this._scrollY = y;\n // Scroll the Y axis if needed. If the scroll distance exceeds\n // the visible height, paint everything. Otherwise, blit the\n // valid content and paint the dirty region.\n if (dy !== 0 && contentHeight > 0) {\n if (Math.abs(dy) >= contentHeight) {\n this.paintContent(0, contentY, width, contentHeight);\n }\n else {\n const x = 0;\n const y = dy < 0 ? contentY : contentY + dy;\n const w = width;\n const h = contentHeight - Math.abs(dy);\n this._blitContent(this._canvas, x, y, w, h, x, y - dy);\n this.paintContent(0, dy < 0 ? contentY : height - dy, width, Math.abs(dy));\n // Repaint merged cells that are intersected by the scroll level\n // Otherwise it will be cut in two by the valid content, and drawn incorrectly\n for (const rgn of ['body', 'row-header']) {\n const cellgroups = CellGroup.getCellGroupsAtRegion(this.dataModel, rgn);\n let paintRgn = {\n region: rgn,\n xMin: 0,\n xMax: 0,\n yMin: 0,\n yMax: 0\n };\n let backgroundColor = undefined;\n switch (rgn) {\n case 'body':\n paintRgn.xMin = this.headerWidth;\n paintRgn.xMax = this.headerWidth + this.bodyWidth;\n paintRgn.yMin = this.headerHeight;\n paintRgn.yMax = this.headerHeight + this.bodyHeight;\n backgroundColor = this._style.backgroundColor;\n break;\n case 'row-header':\n paintRgn.xMin = 0;\n paintRgn.xMax = this.headerWidth;\n paintRgn.yMin = this.headerHeight;\n paintRgn.yMax = this.headerHeight + this.bodyHeight;\n backgroundColor = this._style.headerBackgroundColor;\n break;\n }\n this._paintMergedCells(cellgroups, paintRgn, backgroundColor);\n }\n }\n }\n // Update the internal X scroll position.\n this._scrollX = x;\n // Scroll the X axis if needed. If the scroll distance exceeds\n // the visible width, paint everything. Otherwise, blit the\n // valid content and paint the dirty region.\n if (dx !== 0 && contentWidth > 0) {\n if (Math.abs(dx) >= contentWidth) {\n this.paintContent(contentX, 0, contentWidth, height);\n }\n else {\n const x = dx < 0 ? contentX : contentX + dx;\n const y = 0;\n const w = contentWidth - Math.abs(dx);\n const h = height;\n this._blitContent(this._canvas, x, y, w, h, x - dx, y);\n this.paintContent(dx < 0 ? contentX : width - dx, 0, Math.abs(dx), height);\n // Repaint merged cells that are intersected by the scroll level\n // Otherwise it will be cut in two by the valid content, and drawn incorrectly\n for (const rgn of ['body', 'column-header']) {\n const cellGroups = CellGroup.getCellGroupsAtRegion(this.dataModel, rgn);\n let paintRgn = {\n region: rgn,\n xMin: 0,\n xMax: 0,\n yMin: 0,\n yMax: 0\n };\n let backgroundColor = undefined;\n switch (rgn) {\n case 'body':\n paintRgn.xMin = this.headerWidth;\n paintRgn.xMax = this.headerWidth + this.bodyWidth;\n paintRgn.yMin = this.headerHeight;\n paintRgn.yMax = this.headerHeight + this.bodyHeight;\n backgroundColor = this._style.backgroundColor;\n break;\n case 'column-header':\n paintRgn.xMin = this.headerWidth;\n paintRgn.xMax = this.headerWidth + this.bodyWidth;\n paintRgn.yMin = 0;\n paintRgn.yMax = this.headerHeight;\n backgroundColor = this._style.headerBackgroundColor;\n break;\n }\n this._paintMergedCells(cellGroups, paintRgn, backgroundColor);\n }\n }\n }\n // Paint the overlay.\n this._paintOverlay();\n }\n /**\n * Blit content into the on-screen grid canvas.\n *\n * The rect should be expressed in viewport coordinates.\n *\n * This automatically accounts for the dpi ratio.\n */\n _blitContent(source, x, y, w, h, dx, dy) {\n // Scale the blit coordinates by the dpi ratio.\n x *= this._dpiRatio;\n y *= this._dpiRatio;\n w *= this._dpiRatio;\n h *= this._dpiRatio;\n dx *= this._dpiRatio;\n dy *= this._dpiRatio;\n // Save the current gc state.\n this._canvasGC.save();\n // Set the transform to the identity matrix.\n this._canvasGC.setTransform(1, 0, 0, 1, 0, 0);\n // Draw the specified content.\n this._canvasGC.drawImage(source, x, y, w, h, dx, dy, w, h);\n // Restore the gc state.\n this._canvasGC.restore();\n }\n /**\n * Paint the grid content for the given dirty rect.\n *\n * The rect should be expressed in valid viewport coordinates.\n *\n * This is the primary paint entry point. The individual `_draw*`\n * methods should not be invoked directly. This method dispatches\n * to the drawing methods in the correct order.\n */\n paintContent(rx, ry, rw, rh) {\n // Scale the canvas and buffer GC for the dpi ratio.\n this._canvasGC.setTransform(this._dpiRatio, 0, 0, this._dpiRatio, 0, 0);\n this._bufferGC.setTransform(this._dpiRatio, 0, 0, this._dpiRatio, 0, 0);\n // Clear the dirty rect of all content.\n this._canvasGC.clearRect(rx, ry, rw, rh);\n // Draw the void region.\n this._drawVoidRegion(rx, ry, rw, rh);\n // Draw the body region.\n this._drawBodyRegion(rx, ry, rw, rh);\n // Draw the row header region.\n this._drawRowHeaderRegion(rx, ry, rw, rh);\n // Draw the column header region.\n this._drawColumnHeaderRegion(rx, ry, rw, rh);\n // Draw the corner header region.\n this.drawCornerHeaderRegion(rx, ry, rw, rh);\n }\n /**\n * Resizes body column headers so their text fits\n * without clipping or wrapping.\n * @param dataModel\n */\n _fitBodyColumnHeaders(dataModel, padding, numCols) {\n // Get the body column count\n const bodyColumnCount = numCols === undefined ? dataModel.columnCount('body') : numCols;\n for (let i = 0; i < bodyColumnCount; i++) {\n /*\n if we're working with nested column headers,\n retrieve the nested levels and iterate on them.\n */\n const numRows = dataModel.rowCount('column-header');\n /*\n Calculate the maximum text width, across\n all nested rows under a given column number.\n */\n let maxWidth = 0;\n for (let j = 0; j < numRows; j++) {\n const config = DataGrid._getConfig(dataModel, j, i, 'column-header');\n const textWidth = this._getCellTextWidth(config);\n // Update the maximum width for that column.\n maxWidth = Math.max(maxWidth, textWidth);\n }\n /*\n Send a resize message with new width for the given column.\n Using a padding of 15 pixels to leave some room.\n */\n this.resizeColumn('body', i, maxWidth + padding);\n }\n }\n /**\n * Resizes row header columns so their text fits\n * without clipping or wrapping.\n * @param dataModel\n */\n _fitRowColumnHeaders(dataModel, padding, numCols) {\n /*\n if we're working with nested row headers,\n retrieve the nested levels and iterate on them.\n */\n const rowColumnCount = numCols === undefined ? dataModel.columnCount('row-header') : numCols;\n for (let i = 0; i < rowColumnCount; i++) {\n const numCols = dataModel.rowCount('column-header');\n /*\n Calculate the maximum text width, across\n all nested columns under a given row index.\n */\n let maxWidth = 0;\n for (let j = 0; j < numCols; j++) {\n const config = DataGrid._getConfig(dataModel, j, i, 'corner-header');\n const textWidth = this._getCellTextWidth(config);\n maxWidth = Math.max(maxWidth, textWidth);\n }\n /*\n Send a resize message with new width for the given column.\n Using a padding of 15 pixels to leave some room.\n */\n this.resizeColumn('row-header', i, maxWidth + padding);\n }\n }\n /**\n * Paint the overlay content for the entire grid.\n *\n * This is the primary overlay paint entry point. The individual\n * `_draw*` methods should not be invoked directly. This method\n * dispatches to the drawing methods in the correct order.\n */\n _paintOverlay() {\n // Scale the overlay GC for the dpi ratio.\n this._overlayGC.setTransform(this._dpiRatio, 0, 0, this._dpiRatio, 0, 0);\n // Clear the overlay of all content.\n this._overlayGC.clearRect(0, 0, this._overlay.width, this._overlay.height);\n // Draw the body selections.\n this._drawBodySelections();\n // Draw the row header selections.\n this._drawRowHeaderSelections();\n // Draw the column header selections.\n this._drawColumnHeaderSelections();\n // Draw the cursor.\n this._drawCursor();\n // Draw the shadows.\n this._drawShadows();\n }\n /**\n * Draw the void region for the dirty rect.\n */\n _drawVoidRegion(rx, ry, rw, rh) {\n // Look up the void color.\n let color = this._style.voidColor;\n // Bail if there is no void color.\n if (!color) {\n return;\n }\n // Fill the dirty rect with the void color.\n this._canvasGC.fillStyle = color;\n this._canvasGC.fillRect(rx, ry, rw, rh);\n }\n /**\n * Draw the body region which intersects the dirty rect.\n */\n _drawBodyRegion(rx, ry, rw, rh) {\n // Get the visible content dimensions.\n let contentW = this._columnSections.length - this._scrollX;\n let contentH = this._rowSections.length - this._scrollY;\n // Bail if there is no content to draw.\n if (contentW <= 0 || contentH <= 0) {\n return;\n }\n // Get the visible content origin.\n let contentX = this.headerWidth;\n let contentY = this.headerHeight;\n // Bail if the dirty rect does not intersect the content area.\n if (rx + rw <= contentX) {\n return;\n }\n if (ry + rh <= contentY) {\n return;\n }\n if (rx >= contentX + contentW) {\n return;\n }\n if (ry >= contentY + contentH) {\n return;\n }\n // Fetch the geometry.\n let bh = this.bodyHeight;\n let bw = this.bodyWidth;\n let ph = this.pageHeight;\n let pw = this.pageWidth;\n // Get the upper and lower bounds of the dirty content area.\n let x1 = Math.max(rx, contentX);\n let y1 = Math.max(ry, contentY);\n let x2 = Math.min(rx + rw - 1, contentX + contentW - 1);\n let y2 = Math.min(ry + rh - 1, contentY + contentH - 1);\n // Convert the dirty content bounds into cell bounds.\n let r1 = this._rowSections.indexOf(y1 - contentY + this._scrollY);\n let c1 = this._columnSections.indexOf(x1 - contentX + this._scrollX);\n let r2 = this._rowSections.indexOf(y2 - contentY + this._scrollY);\n let c2 = this._columnSections.indexOf(x2 - contentX + this._scrollX);\n // Fetch the max row and column.\n let maxRow = this._rowSections.count - 1;\n let maxColumn = this._columnSections.count - 1;\n // Handle a dirty content area larger than the cell count.\n if (r2 < 0) {\n r2 = maxRow;\n }\n if (c2 < 0) {\n c2 = maxColumn;\n }\n // Convert the cell bounds back to visible coordinates.\n let x = this._columnSections.offsetOf(c1) + contentX - this._scrollX;\n let y = this._rowSections.offsetOf(r1) + contentY - this._scrollY;\n // Set up the paint region size variables.\n let width = 0;\n let height = 0;\n // Allocate the section sizes arrays.\n let rowSizes = new Array(r2 - r1 + 1);\n let columnSizes = new Array(c2 - c1 + 1);\n // Get the row sizes for the region.\n for (let j = r1; j <= r2; ++j) {\n let size = this._rowSections.sizeOf(j);\n rowSizes[j - r1] = size;\n height += size;\n }\n // Get the column sizes for the region.\n for (let i = c1; i <= c2; ++i) {\n let size = this._columnSections.sizeOf(i);\n columnSizes[i - c1] = size;\n width += size;\n }\n // Adjust the geometry if the last row is streched.\n if (this._stretchLastRow && ph > bh && r2 === maxRow) {\n let dh = this.pageHeight - this.bodyHeight;\n rowSizes[rowSizes.length - 1] += dh;\n height += dh;\n y2 += dh;\n }\n // Adjust the geometry if the last column is streched.\n if (this._stretchLastColumn && pw > bw && c2 === maxColumn) {\n let dw = this.pageWidth - this.bodyWidth;\n columnSizes[columnSizes.length - 1] += dw;\n width += dw;\n x2 += dw;\n }\n // Create the paint region object.\n let rgn = {\n region: 'body',\n xMin: x1,\n yMin: y1,\n xMax: x2,\n yMax: y2,\n x,\n y,\n width,\n height,\n row: r1,\n column: c1,\n rowSizes,\n columnSizes\n };\n // Draw the background.\n this._drawBackground(rgn, this._style.backgroundColor);\n // Draw the row background.\n this._drawRowBackground(rgn, this._style.rowBackgroundColor);\n // Draw the column background.\n this._drawColumnBackground(rgn, this._style.columnBackgroundColor);\n // Draw the cell content for the paint region.\n this._drawCells(rgn);\n // Draw the horizontal grid lines.\n this._drawHorizontalGridLines(rgn, this._style.horizontalGridLineColor || this._style.gridLineColor);\n // Draw the vertical grid lines.\n this._drawVerticalGridLines(rgn, this._style.verticalGridLineColor || this._style.gridLineColor);\n // Get the cellgroups from the cell-region that intersects with the paint region\n const cellGroups = CellGroup.getCellGroupsAtRegion(this.dataModel, rgn.region).filter(group => {\n return this.cellGroupInteresectsRegion(group, rgn);\n });\n // Draw merged cells\n this._paintMergedCells(cellGroups, rgn, this._style.backgroundColor);\n }\n /**\n * Draw the row header region which intersects the dirty rect.\n */\n _drawRowHeaderRegion(rx, ry, rw, rh) {\n // Get the visible content dimensions.\n let contentW = this.headerWidth;\n let contentH = this.bodyHeight - this._scrollY;\n // Bail if there is no content to draw.\n if (contentW <= 0 || contentH <= 0) {\n return;\n }\n // Get the visible content origin.\n let contentX = 0;\n let contentY = this.headerHeight;\n // Bail if the dirty rect does not intersect the content area.\n if (rx + rw <= contentX) {\n return;\n }\n if (ry + rh <= contentY) {\n return;\n }\n if (rx >= contentX + contentW) {\n return;\n }\n if (ry >= contentY + contentH) {\n return;\n }\n // Fetch the geometry.\n let bh = this.bodyHeight;\n let ph = this.pageHeight;\n // Get the upper and lower bounds of the dirty content area.\n let x1 = rx;\n let y1 = Math.max(ry, contentY);\n let x2 = Math.min(rx + rw - 1, contentX + contentW - 1);\n let y2 = Math.min(ry + rh - 1, contentY + contentH - 1);\n // Convert the dirty content bounds into cell bounds.\n let r1 = this._rowSections.indexOf(y1 - contentY + this._scrollY);\n let c1 = this._rowHeaderSections.indexOf(x1);\n let r2 = this._rowSections.indexOf(y2 - contentY + this._scrollY);\n let c2 = this._rowHeaderSections.indexOf(x2);\n // Fetch max row and column.\n let maxRow = this._rowSections.count - 1;\n let maxColumn = this._rowHeaderSections.count - 1;\n // Handle a dirty content area larger than the cell count.\n if (r2 < 0) {\n r2 = maxRow;\n }\n if (c2 < 0) {\n c2 = maxColumn;\n }\n // Convert the cell bounds back to visible coordinates.\n let x = this._rowHeaderSections.offsetOf(c1);\n let y = this._rowSections.offsetOf(r1) + contentY - this._scrollY;\n // Set up the paint region size variables.\n let width = 0;\n let height = 0;\n // Allocate the section sizes arrays.\n let rowSizes = new Array(r2 - r1 + 1);\n let columnSizes = new Array(c2 - c1 + 1);\n // Get the row sizes for the region.\n for (let j = r1; j <= r2; ++j) {\n let size = this._rowSections.sizeOf(j);\n rowSizes[j - r1] = size;\n height += size;\n }\n // Get the column sizes for the region.\n for (let i = c1; i <= c2; ++i) {\n let size = this._rowHeaderSections.sizeOf(i);\n columnSizes[i - c1] = size;\n width += size;\n }\n // Adjust the geometry if the last row is stretched.\n if (this._stretchLastRow && ph > bh && r2 === maxRow) {\n let dh = this.pageHeight - this.bodyHeight;\n rowSizes[rowSizes.length - 1] += dh;\n height += dh;\n y2 += dh;\n }\n // Create the paint region object.\n let rgn = {\n region: 'row-header',\n xMin: x1,\n yMin: y1,\n xMax: x2,\n yMax: y2,\n x,\n y,\n width,\n height,\n row: r1,\n column: c1,\n rowSizes,\n columnSizes\n };\n // Draw the background.\n this._drawBackground(rgn, this._style.headerBackgroundColor);\n // Draw the cell content for the paint region.\n this._drawCells(rgn);\n // Draw the horizontal grid lines.\n this._drawHorizontalGridLines(rgn, this._style.headerHorizontalGridLineColor ||\n this._style.headerGridLineColor);\n // Draw the vertical grid lines.\n this._drawVerticalGridLines(rgn, this._style.headerVerticalGridLineColor || this._style.headerGridLineColor);\n // Get the cellgroups from the cell-region that intersects with the paint region\n const cellGroups = CellGroup.getCellGroupsAtRegion(this.dataModel, rgn.region).filter(group => {\n return this.cellGroupInteresectsRegion(group, rgn);\n });\n // Draw merged cells\n this._paintMergedCells(cellGroups, rgn, this._style.headerBackgroundColor);\n }\n /**\n * Draw the column header region which intersects the dirty rect.\n */\n _drawColumnHeaderRegion(rx, ry, rw, rh) {\n // Get the visible content dimensions.\n let contentW = this.bodyWidth - this._scrollX;\n let contentH = this.headerHeight;\n // Bail if there is no content to draw.\n if (contentW <= 0 || contentH <= 0) {\n return;\n }\n // Get the visible content origin.\n let contentX = this.headerWidth;\n let contentY = 0;\n // Bail if the dirty rect does not intersect the content area.\n if (rx + rw <= contentX) {\n return;\n }\n if (ry + rh <= contentY) {\n return;\n }\n if (rx >= contentX + contentW) {\n return;\n }\n if (ry >= contentY + contentH) {\n return;\n }\n // Fetch the geometry.\n let bw = this.bodyWidth;\n let pw = this.pageWidth;\n // Get the upper and lower bounds of the dirty content area.\n let x1 = Math.max(rx, contentX);\n let y1 = ry;\n let x2 = Math.min(rx + rw - 1, contentX + contentW - 1);\n let y2 = Math.min(ry + rh - 1, contentY + contentH - 1);\n // Convert the dirty content bounds into cell bounds.\n let r1 = this._columnHeaderSections.indexOf(y1);\n let c1 = this._columnSections.indexOf(x1 - contentX + this._scrollX);\n let r2 = this._columnHeaderSections.indexOf(y2);\n let c2 = this._columnSections.indexOf(x2 - contentX + this._scrollX);\n // Fetch the max row and column.\n let maxRow = this._columnHeaderSections.count - 1;\n let maxColumn = this._columnSections.count - 1;\n // Handle a dirty content area larger than the cell count.\n if (r2 < 0) {\n r2 = maxRow;\n }\n if (c2 < 0) {\n c2 = maxColumn;\n }\n // Convert the cell bounds back to visible coordinates.\n let x = this._columnSections.offsetOf(c1) + contentX - this._scrollX;\n let y = this._columnHeaderSections.offsetOf(r1);\n // Set up the paint region size variables.\n let width = 0;\n let height = 0;\n // Allocate the section sizes arrays.\n let rowSizes = new Array(r2 - r1 + 1);\n let columnSizes = new Array(c2 - c1 + 1);\n // Get the row sizes for the region.\n for (let j = r1; j <= r2; ++j) {\n let size = this._columnHeaderSections.sizeOf(j);\n rowSizes[j - r1] = size;\n height += size;\n }\n // Get the column sizes for the region.\n for (let i = c1; i <= c2; ++i) {\n let size = this._columnSections.sizeOf(i);\n columnSizes[i - c1] = size;\n width += size;\n }\n // Adjust the geometry if the last column is stretched.\n if (this._stretchLastColumn && pw > bw && c2 === maxColumn) {\n let dw = this.pageWidth - this.bodyWidth;\n columnSizes[columnSizes.length - 1] += dw;\n width += dw;\n x2 += dw;\n }\n // Create the paint region object.\n let rgn = {\n region: 'column-header',\n xMin: x1,\n yMin: y1,\n xMax: x2,\n yMax: y2,\n x,\n y,\n width,\n height,\n row: r1,\n column: c1,\n rowSizes,\n columnSizes\n };\n // Draw the background.\n this._drawBackground(rgn, this._style.headerBackgroundColor);\n // Draw the cell content for the paint region.\n this._drawCells(rgn);\n // Draw the horizontal grid lines.\n this._drawHorizontalGridLines(rgn, this._style.headerHorizontalGridLineColor ||\n this._style.headerGridLineColor);\n // Draw the vertical grid lines.\n this._drawVerticalGridLines(rgn, this._style.headerVerticalGridLineColor || this._style.headerGridLineColor);\n // Get the cellgroups from the cell-region that intersects with the paint region\n const cellGroups = CellGroup.getCellGroupsAtRegion(this.dataModel, rgn.region).filter(group => {\n return this.cellGroupInteresectsRegion(group, rgn);\n });\n // Draw merged cells\n this._paintMergedCells(cellGroups, rgn, this._style.headerBackgroundColor);\n }\n /**\n * Draw the corner header region which intersects the dirty rect.\n */\n drawCornerHeaderRegion(rx, ry, rw, rh) {\n // Get the visible content dimensions.\n let contentW = this.headerWidth;\n let contentH = this.headerHeight;\n // Bail if there is no content to draw.\n if (contentW <= 0 || contentH <= 0) {\n return;\n }\n // Get the visible content origin.\n let contentX = 0;\n let contentY = 0;\n // Bail if the dirty rect does not intersect the content area.\n if (rx + rw <= contentX) {\n return;\n }\n if (ry + rh <= contentY) {\n return;\n }\n if (rx >= contentX + contentW) {\n return;\n }\n if (ry >= contentY + contentH) {\n return;\n }\n // Get the upper and lower bounds of the dirty content area.\n let x1 = rx;\n let y1 = ry;\n let x2 = Math.min(rx + rw - 1, contentX + contentW - 1);\n let y2 = Math.min(ry + rh - 1, contentY + contentH - 1);\n // Convert the dirty content bounds into cell bounds.\n let r1 = this._columnHeaderSections.indexOf(y1);\n let c1 = this._rowHeaderSections.indexOf(x1);\n let r2 = this._columnHeaderSections.indexOf(y2);\n let c2 = this._rowHeaderSections.indexOf(x2);\n // Handle a dirty content area larger than the cell count.\n if (r2 < 0) {\n r2 = this._columnHeaderSections.count - 1;\n }\n if (c2 < 0) {\n c2 = this._rowHeaderSections.count - 1;\n }\n // Convert the cell bounds back to visible coordinates.\n let x = this._rowHeaderSections.offsetOf(c1);\n let y = this._columnHeaderSections.offsetOf(r1);\n // Set up the paint region size variables.\n let width = 0;\n let height = 0;\n // Allocate the section sizes arrays.\n let rowSizes = new Array(r2 - r1 + 1);\n let columnSizes = new Array(c2 - c1 + 1);\n // Get the row sizes for the region.\n for (let j = r1; j <= r2; ++j) {\n let size = this._columnHeaderSections.sizeOf(j);\n rowSizes[j - r1] = size;\n height += size;\n }\n // Get the column sizes for the region.\n for (let i = c1; i <= c2; ++i) {\n let size = this._rowHeaderSections.sizeOf(i);\n columnSizes[i - c1] = size;\n width += size;\n }\n // Create the paint region object.\n let rgn = {\n region: 'corner-header',\n xMin: x1,\n yMin: y1,\n xMax: x2,\n yMax: y2,\n x,\n y,\n width,\n height,\n row: r1,\n column: c1,\n rowSizes,\n columnSizes\n };\n // Draw the background.\n this._drawBackground(rgn, this._style.headerBackgroundColor);\n // Draw the cell content for the paint region.\n this._drawCells(rgn);\n // Draw the horizontal grid lines.\n this._drawHorizontalGridLines(rgn, this._style.headerHorizontalGridLineColor ||\n this._style.headerGridLineColor);\n // Draw the vertical grid lines.\n this._drawVerticalGridLines(rgn, this._style.headerVerticalGridLineColor || this._style.headerGridLineColor);\n // Get the cellgroups from the cell-region that intersects with the paint region\n const cellGroups = CellGroup.getCellGroupsAtRegion(this.dataModel, rgn.region).filter(group => {\n return this.cellGroupInteresectsRegion(group, rgn);\n });\n // Draw merged cells\n this._paintMergedCells(cellGroups, rgn, this._style.headerBackgroundColor);\n }\n /**\n * Draw the background for the given paint region.\n */\n _drawBackground(rgn, color) {\n // Bail if there is no color to draw.\n if (!color) {\n return;\n }\n // Unpack the region.\n let { xMin, yMin, xMax, yMax } = rgn;\n // Fill the region with the specified color.\n this._canvasGC.fillStyle = color;\n this._canvasGC.fillRect(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);\n }\n /**\n * Draw the row background for the given paint region.\n */\n _drawRowBackground(rgn, colorFn) {\n // Bail if there is no color function.\n if (!colorFn) {\n return;\n }\n // Compute the X bounds for the row.\n let x1 = Math.max(rgn.xMin, rgn.x);\n let x2 = Math.min(rgn.x + rgn.width - 1, rgn.xMax);\n // Draw the background for the rows in the region.\n for (let y = rgn.y, j = 0, n = rgn.rowSizes.length; j < n; ++j) {\n // Fetch the size of the row.\n let size = rgn.rowSizes[j];\n // Skip zero sized rows.\n if (size === 0) {\n continue;\n }\n // Get the background color for the row.\n let color = colorFn(rgn.row + j);\n // Fill the row with the background color if needed.\n if (color) {\n let y1 = Math.max(rgn.yMin, y);\n let y2 = Math.min(y + size - 1, rgn.yMax);\n this._canvasGC.fillStyle = color;\n this._canvasGC.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\n }\n // Increment the running Y coordinate.\n y += size;\n }\n }\n /**\n * Draw the column background for the given paint region.\n */\n _drawColumnBackground(rgn, colorFn) {\n // Bail if there is no color function.\n if (!colorFn) {\n return;\n }\n // Compute the Y bounds for the column.\n let y1 = Math.max(rgn.yMin, rgn.y);\n let y2 = Math.min(rgn.y + rgn.height - 1, rgn.yMax);\n // Draw the background for the columns in the region.\n for (let x = rgn.x, i = 0, n = rgn.columnSizes.length; i < n; ++i) {\n // Fetch the size of the column.\n let size = rgn.columnSizes[i];\n // Skip zero sized columns.\n if (size === 0) {\n continue;\n }\n // Get the background color for the column.\n let color = colorFn(rgn.column + i);\n // Fill the column with the background color if needed.\n if (color) {\n let x1 = Math.max(rgn.xMin, x);\n let x2 = Math.min(x + size - 1, rgn.xMax);\n this._canvasGC.fillStyle = color;\n this._canvasGC.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\n }\n // Increment the running X coordinate.\n x += size;\n }\n }\n /**\n * Returns column size\n * @param region\n * @param index\n */\n _getColumnSize(region, index) {\n if (region === 'corner-header') {\n return this._rowHeaderSections.sizeOf(index);\n }\n return this.columnSize(region, index);\n }\n /**\n * Returns row size\n * @param region\n * @param index\n */\n _getRowSize(region, index) {\n if (region === 'corner-header') {\n return this._columnHeaderSections.sizeOf(index);\n }\n return this.rowSize(region, index);\n }\n /**\n * Draw the cells for the given paint region.\n */\n _drawCells(rgn) {\n // Bail if there is no data model.\n if (!this._dataModel) {\n return;\n }\n // Set up the cell config object for rendering.\n let config = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n region: rgn.region,\n row: 0,\n column: 0,\n value: null,\n metadata: DataModel.emptyMetadata\n };\n let groupIndex = -1;\n // Save the buffer gc before wrapping.\n this._bufferGC.save();\n // Wrap the buffer gc for painting the cells.\n let gc = new GraphicsContext(this._bufferGC);\n let height = 0;\n // Loop over the columns in the region.\n for (let x = rgn.x, i = 0, n = rgn.columnSizes.length; i < n; ++i) {\n // Fetch the size of the column.\n let width = rgn.columnSizes[i];\n // Skip zero sized columns.\n if (width === 0) {\n continue;\n }\n // Compute the column index.\n let column = rgn.column + i;\n // Update the config for the current column.\n config.x = x;\n config.width = width;\n config.column = column;\n // Loop over the rows in the column.\n for (let y = rgn.y, j = 0, n = rgn.rowSizes.length; j < n; ++j) {\n // Fetch the size of the row.\n height = rgn.rowSizes[j];\n // Skip zero sized rows.\n if (height === 0) {\n continue;\n }\n // Compute the row index.\n let row = rgn.row + j;\n groupIndex = CellGroup.getGroupIndex(this.dataModel, config.region, row, column);\n // For merged cell regions, don't do anything, we draw merged regions later.\n if (groupIndex !== -1) {\n y += height;\n continue;\n }\n // Clear the buffer rect for the cell.\n gc.clearRect(x, y, width, height);\n let value = DataGrid._getCellValue(this.dataModel, rgn.region, row, column);\n let metadata = DataGrid._getCellMetadata(this.dataModel, rgn.region, row, column);\n // Update the config for the current cell.\n config.y = y;\n config.height = height;\n config.width = width;\n config.row = row;\n config.value = value;\n config.metadata = metadata;\n // Get the renderer for the cell.\n let renderer = this._cellRenderers.get(config);\n // Save the GC state.\n gc.save();\n // Paint the cell into the off-screen buffer.\n try {\n if (renderer instanceof AsyncCellRenderer) {\n if (renderer.isReady(config)) {\n renderer.paint(gc, config);\n }\n else {\n renderer.paintPlaceholder(gc, config);\n renderer.load(config).then(() => {\n const r1 = row;\n const r2 = row + 1;\n const c1 = column;\n const c2 = column + 1;\n this.repaintRegion(rgn.region, r1, c1, r2, c2);\n });\n }\n }\n else {\n renderer.paint(gc, config);\n }\n }\n catch (err) {\n console.error(err);\n }\n // Restore the GC state.\n gc.restore();\n // Compute the actual X bounds for the cell.\n let x1 = Math.max(rgn.xMin, config.x);\n let x2 = Math.min(config.x + config.width - 1, rgn.xMax);\n // Compute the actual Y bounds for the cell.\n let y1 = Math.max(rgn.yMin, config.y);\n let y2 = Math.min(config.y + config.height - 1, rgn.yMax);\n this._blitContent(this._buffer, x1, y1, x2 - x1 + 1, y2 - y1 + 1, x1, y1);\n // Increment the running Y coordinate.\n y += height;\n }\n // Restore the GC state.\n gc.restore();\n // Increment the running X coordinate.\n x += width;\n }\n // Dispose of the wrapped gc.\n gc.dispose();\n // Restore the final buffer gc state.\n this._bufferGC.restore();\n }\n // TODO Move this in the utils file (but we need the PaintRegion typing)\n cellGroupInteresectsRegion(group, rgn) {\n const rgnR1 = rgn.row;\n const rgnR2 = rgn.row + rgn.rowSizes.length;\n const rgnC1 = rgn.column;\n const rgnC2 = rgn.column + rgn.columnSizes.length;\n const dx = Math.min(group.r2, rgnR2) - Math.max(group.r1, rgnR1);\n const dy = Math.min(group.c2, rgnC2) - Math.max(group.c1, rgnC1);\n return dx >= 0 && dy >= 0;\n }\n static _getCellValue(dm, region, row, col) {\n // Get the value for the cell.\n try {\n return dm.data(region, row, col);\n }\n catch (err) {\n console.error(err);\n return null;\n }\n }\n static _getCellMetadata(dm, region, row, col) {\n // Get the metadata for the cell.\n try {\n return dm.metadata(region, row, col);\n }\n catch (err) {\n console.error(err);\n return DataModel.emptyMetadata;\n }\n }\n /**\n * Paint group cells.\n */\n _paintMergedCells(cellGroups, rgn, backgroundColor) {\n // Bail if there is no data model.\n if (!this._dataModel) {\n return;\n }\n // Set up the cell config object for rendering.\n let config = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n region: rgn.region,\n row: 0,\n column: 0,\n value: null,\n metadata: DataModel.emptyMetadata\n };\n if (backgroundColor) {\n this._canvasGC.fillStyle = backgroundColor;\n }\n // Set the line width for the grid lines.\n this._canvasGC.lineWidth = 1;\n // Save the buffer gc before wrapping.\n this._bufferGC.save();\n // Wrap the buffer gc for painting the cells.\n let gc = new GraphicsContext(this._bufferGC);\n for (const group of cellGroups) {\n let width = 0;\n for (let c = group.c1; c <= group.c2; c++) {\n width += this._getColumnSize(rgn.region, c);\n }\n let height = 0;\n for (let r = group.r1; r <= group.r2; r++) {\n height += this._getRowSize(rgn.region, r);\n }\n let value = DataGrid._getCellValue(this.dataModel, rgn.region, group.r1, group.c1);\n let metadata = DataGrid._getCellMetadata(this.dataModel, rgn.region, group.r1, group.c2);\n let x = 0;\n let y = 0;\n switch (rgn.region) {\n case 'body':\n x =\n this._columnSections.offsetOf(group.c1) +\n this.headerWidth -\n this._scrollX;\n y =\n this._rowSections.offsetOf(group.r1) +\n this.headerHeight -\n this._scrollY;\n break;\n case 'column-header':\n x =\n this._columnSections.offsetOf(group.c1) +\n this.headerWidth -\n this._scrollX;\n y = this._rowSections.offsetOf(group.r1);\n break;\n case 'row-header':\n x = this._columnSections.offsetOf(group.c1);\n y =\n this._rowSections.offsetOf(group.r1) +\n this.headerHeight -\n this._scrollY;\n break;\n case 'corner-header':\n x = this._columnSections.offsetOf(group.c1);\n y = this._rowSections.offsetOf(group.r1);\n break;\n }\n config.x = x;\n config.y = y;\n config.width = width;\n config.height = height;\n config.region = rgn.region;\n config.row = group.r1;\n config.column = group.c1;\n config.value = value;\n config.metadata = metadata;\n // Compute the actual X bounds for the cell.\n const x1 = Math.max(rgn.xMin, x);\n const x2 = Math.min(x + width - 2, rgn.xMax);\n // Compute the actual Y bounds for the cell.\n const y1 = Math.max(rgn.yMin, y);\n const y2 = Math.min(y + height - 2, rgn.yMax);\n if (x2 <= x1 || y2 <= y1) {\n continue;\n }\n // Draw the background.\n if (backgroundColor) {\n this._canvasGC.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\n }\n // Get the renderer for the cell.\n let renderer = this._cellRenderers.get(config);\n // Clear the buffer rect for the cell.\n gc.clearRect(config.x, config.y, width, height);\n // Save the GC state.\n gc.save();\n // Paint the cell into the off-screen buffer.\n try {\n if (renderer instanceof AsyncCellRenderer) {\n if (renderer.isReady(config)) {\n renderer.paint(gc, config);\n }\n else {\n renderer.paintPlaceholder(gc, config);\n const r1 = group.r1;\n const r2 = group.r2;\n const c1 = group.c1;\n const c2 = group.c2;\n renderer.load(config).then(() => {\n this.repaintRegion(rgn.region, r1, c1, r2, c2);\n });\n }\n }\n else {\n renderer.paint(gc, config);\n }\n }\n catch (err) {\n console.error(err);\n }\n // Restore the GC state.\n gc.restore();\n this._blitContent(this._buffer, x1, y1, x2 - x1 + 1, y2 - y1 + 1, x1, y1);\n }\n // Dispose of the wrapped gc.\n gc.dispose();\n // Restore the final buffer gc state.\n this._bufferGC.restore();\n }\n /**\n * Draw the horizontal grid lines for the given paint region.\n */\n _drawHorizontalGridLines(rgn, color) {\n // Bail if there is no color to draw.\n if (!color) {\n return;\n }\n // Compute the X bounds for the horizontal lines.\n const x1 = Math.max(rgn.xMin, rgn.x);\n const x2 = Math.min(rgn.x + rgn.width, rgn.xMax + 1);\n // Begin the path for the grid lines.\n this._canvasGC.beginPath();\n // Set the line width for the grid lines.\n this._canvasGC.lineWidth = 1;\n // Fetch the geometry.\n const bh = this.bodyHeight;\n const ph = this.pageHeight;\n // Fetch the number of grid lines to be drawn.\n let n = rgn.rowSizes.length;\n // Adjust the count down if the last line shouldn't be drawn.\n if (this._stretchLastRow && ph > bh) {\n if (rgn.row + n === this._rowSections.count) {\n n -= 1;\n }\n }\n // Draw the horizontal grid lines.\n for (let y = rgn.y, j = 0; j < n; ++j) {\n // Fetch the size of the row.\n let size = rgn.rowSizes[j];\n // Skip zero sized rows.\n if (size === 0) {\n continue;\n }\n // Compute the Y position of the line.\n let pos = y + size - 1;\n // Draw the line if it's in range of the dirty rect.\n if (pos >= rgn.yMin && pos <= rgn.yMax) {\n this._canvasGC.moveTo(x1, pos + 0.5);\n this._canvasGC.lineTo(x2, pos + 0.5);\n }\n // Increment the running Y coordinate.\n y += size;\n }\n // Stroke the lines with the specified color.\n this._canvasGC.strokeStyle = color;\n this._canvasGC.stroke();\n }\n /**\n * Draw the vertical grid lines for the given paint region.\n */\n _drawVerticalGridLines(rgn, color) {\n // Bail if there is no color to draw.\n if (!color) {\n return;\n }\n // Compute the Y bounds for the vertical lines.\n const y1 = Math.max(rgn.yMin, rgn.y);\n const y2 = Math.min(rgn.y + rgn.height, rgn.yMax + 1);\n // Begin the path for the grid lines\n this._canvasGC.beginPath();\n // Set the line width for the grid lines.\n this._canvasGC.lineWidth = 1;\n // Fetch the geometry.\n const bw = this.bodyWidth;\n const pw = this.pageWidth;\n // Fetch the number of grid lines to be drawn.\n let n = rgn.columnSizes.length;\n // Adjust the count down if the last line shouldn't be drawn.\n if (this._stretchLastColumn && pw > bw) {\n if (rgn.column + n === this._columnSections.count) {\n n -= 1;\n }\n }\n // Draw the vertical grid lines.\n for (let x = rgn.x, i = 0; i < n; ++i) {\n // Fetch the size of the column.\n let size = rgn.columnSizes[i];\n // Skip zero sized columns.\n if (size === 0) {\n continue;\n }\n // Compute the X position of the line.\n let pos = x + size - 1;\n // Draw the line if it's in range of the dirty rect.\n if (pos >= rgn.xMin && pos <= rgn.xMax) {\n this._canvasGC.moveTo(pos + 0.5, y1);\n this._canvasGC.lineTo(pos + 0.5, y2);\n }\n // Increment the running X coordinate.\n x += size;\n }\n // Stroke the lines with the specified color.\n this._canvasGC.strokeStyle = color;\n this._canvasGC.stroke();\n }\n /**\n * Draw the body selections for the data grid.\n */\n _drawBodySelections() {\n // Fetch the selection model.\n let model = this._selectionModel;\n // Bail early if there are no selections.\n if (!model || model.isEmpty) {\n return;\n }\n // Fetch the selection colors.\n let fill = this._style.selectionFillColor;\n let stroke = this._style.selectionBorderColor;\n // Bail early if there is nothing to draw.\n if (!fill && !stroke) {\n return;\n }\n // Fetch the scroll geometry.\n let sx = this._scrollX;\n let sy = this._scrollY;\n // Get the first visible cell of the grid.\n let r1 = this._rowSections.indexOf(sy);\n let c1 = this._columnSections.indexOf(sx);\n // Bail early if there are no visible cells.\n if (r1 < 0 || c1 < 0) {\n return;\n }\n // Fetch the extra geometry.\n let bw = this.bodyWidth;\n let bh = this.bodyHeight;\n let pw = this.pageWidth;\n let ph = this.pageHeight;\n let hw = this.headerWidth;\n let hh = this.headerHeight;\n // Get the last visible cell of the grid.\n let r2 = this._rowSections.indexOf(sy + ph);\n let c2 = this._columnSections.indexOf(sx + pw);\n // Fetch the max row and column.\n let maxRow = this._rowSections.count - 1;\n let maxColumn = this._columnSections.count - 1;\n // Clamp the last cell if the void space is visible.\n r2 = r2 < 0 ? maxRow : r2;\n c2 = c2 < 0 ? maxColumn : c2;\n // Fetch the overlay gc.\n let gc = this._overlayGC;\n // Save the gc state.\n gc.save();\n // Set up the body clipping rect.\n gc.beginPath();\n gc.rect(hw, hh, pw, ph);\n gc.clip();\n // Set up the gc style.\n if (fill) {\n gc.fillStyle = fill;\n }\n if (stroke) {\n gc.strokeStyle = stroke;\n gc.lineWidth = 1;\n }\n // Iterate over the selections.\n for (let s of model.selections()) {\n // Skip the section if it's not visible.\n if (s.r1 < r1 && s.r2 < r1) {\n continue;\n }\n if (s.r1 > r2 && s.r2 > r2) {\n continue;\n }\n if (s.c1 < c1 && s.c2 < c1) {\n continue;\n }\n if (s.c1 > c2 && s.c2 > c2) {\n continue;\n }\n // Clamp the cell to the model bounds.\n let sr1 = Math.max(0, Math.min(s.r1, maxRow));\n let sc1 = Math.max(0, Math.min(s.c1, maxColumn));\n let sr2 = Math.max(0, Math.min(s.r2, maxRow));\n let sc2 = Math.max(0, Math.min(s.c2, maxColumn));\n // Swap index order if needed.\n let tmp;\n if (sr1 > sr2) {\n tmp = sr1;\n sr1 = sr2;\n sr2 = tmp;\n }\n if (sc1 > sc2) {\n tmp = sc1;\n sc1 = sc2;\n sc2 = tmp;\n }\n const joinedGroup = CellGroup.joinCellGroupWithMergedCellGroups(this.dataModel, { r1: sr1, r2: sr2, c1: sc1, c2: sc2 }, 'body');\n sr1 = joinedGroup.r1;\n sr2 = joinedGroup.r2;\n sc1 = joinedGroup.c1;\n sc2 = joinedGroup.c2;\n // Convert to pixel coordinates.\n let x1 = this._columnSections.offsetOf(sc1) - sx + hw;\n let y1 = this._rowSections.offsetOf(sr1) - sy + hh;\n let x2 = this._columnSections.extentOf(sc2) - sx + hw;\n let y2 = this._rowSections.extentOf(sr2) - sy + hh;\n // Adjust the trailing X coordinate for column stretch.\n if (this._stretchLastColumn && pw > bw && sc2 === maxColumn) {\n x2 = hw + pw - 1;\n }\n // Adjust the trailing Y coordinate for row stretch.\n if (this._stretchLastRow && ph > bh && sr2 === maxRow) {\n y2 = hh + ph - 1;\n }\n // Clamp the bounds to just outside of the clipping rect.\n x1 = Math.max(hw - 1, x1);\n y1 = Math.max(hh - 1, y1);\n x2 = Math.min(hw + pw + 1, x2);\n y2 = Math.min(hh + ph + 1, y2);\n // Skip zero sized ranges.\n if (x2 < x1 || y2 < y1) {\n continue;\n }\n // Fill the rect if needed.\n if (fill) {\n gc.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\n }\n // Stroke the rect if needed.\n if (stroke) {\n gc.strokeRect(x1 - 0.5, y1 - 0.5, x2 - x1 + 1, y2 - y1 + 1);\n }\n }\n // Restore the gc state.\n gc.restore();\n }\n /**\n * Draw the row header selections for the data grid.\n */\n _drawRowHeaderSelections() {\n // Fetch the selection model.\n let model = this._selectionModel;\n // Bail early if there are no selections or if the selectionMode is the entire column.\n if (!model || model.isEmpty || model.selectionMode == 'column') {\n return;\n }\n // Bail early if the row headers are not visible.\n if (this.headerWidth === 0 || this.pageHeight === 0) {\n return;\n }\n // Fetch the selection colors.\n let fill = this._style.headerSelectionFillColor;\n let stroke = this._style.headerSelectionBorderColor;\n // Bail early if there is nothing to draw.\n if (!fill && !stroke) {\n return;\n }\n // Fetch common geometry.\n let sy = this._scrollY;\n let bh = this.bodyHeight;\n let ph = this.pageHeight;\n let hw = this.headerWidth;\n let hh = this.headerHeight;\n let rs = this._rowSections;\n // Fetch the overlay gc.\n let gc = this._overlayGC;\n // Save the gc state.\n gc.save();\n // Set up the header clipping rect.\n gc.beginPath();\n gc.rect(0, hh, hw, ph);\n gc.clip();\n // Set up the gc style.\n if (fill) {\n gc.fillStyle = fill;\n }\n if (stroke) {\n gc.strokeStyle = stroke;\n gc.lineWidth = 1;\n }\n // Fetch the max row.\n let maxRow = rs.count - 1;\n // Fetch the visible rows.\n let r1 = rs.indexOf(sy);\n let r2 = rs.indexOf(sy + ph - 1);\n r2 = r2 < 0 ? maxRow : r2;\n // Iterate over the visible rows.\n for (let j = r1; j <= r2; ++j) {\n // Skip rows which aren't selected.\n if (!model.isRowSelected(j)) {\n continue;\n }\n // Get the dimensions of the row.\n let y = rs.offsetOf(j) - sy + hh;\n let h = rs.sizeOf(j);\n // Adjust the height for row stretch.\n if (this._stretchLastRow && ph > bh && j === maxRow) {\n h = hh + ph - y;\n }\n // Skip zero sized rows.\n if (h === 0) {\n continue;\n }\n // Fill the rect if needed.\n if (fill) {\n gc.fillRect(0, y, hw, h);\n }\n // Draw the border if needed.\n if (stroke) {\n gc.beginPath();\n gc.moveTo(hw - 0.5, y - 1);\n gc.lineTo(hw - 0.5, y + h);\n gc.stroke();\n }\n }\n // Restore the gc state.\n gc.restore();\n }\n /**\n * Draw the column header selections for the data grid.\n */\n _drawColumnHeaderSelections() {\n // Fetch the selection model.\n let model = this._selectionModel;\n // Bail early if there are no selections or if the selectionMode is the entire row\n if (!model || model.isEmpty || model.selectionMode == 'row') {\n return;\n }\n // Bail early if the column headers are not visible.\n if (this.headerHeight === 0 || this.pageWidth === 0) {\n return;\n }\n // Fetch the selection colors.\n let fill = this._style.headerSelectionFillColor;\n let stroke = this._style.headerSelectionBorderColor;\n // Bail early if there is nothing to draw.\n if (!fill && !stroke) {\n return;\n }\n // Fetch common geometry.\n let sx = this._scrollX;\n let bw = this.bodyWidth;\n let pw = this.pageWidth;\n let hw = this.headerWidth;\n let hh = this.headerHeight;\n let cs = this._columnSections;\n // Fetch the overlay gc.\n let gc = this._overlayGC;\n // Save the gc state.\n gc.save();\n // Set up the header clipping rect.\n gc.beginPath();\n gc.rect(hw, 0, pw, hh);\n gc.clip();\n // Set up the gc style.\n if (fill) {\n gc.fillStyle = fill;\n }\n if (stroke) {\n gc.strokeStyle = stroke;\n gc.lineWidth = 1;\n }\n // Fetch the max column.\n let maxCol = cs.count - 1;\n // Fetch the visible columns.\n let c1 = cs.indexOf(sx);\n let c2 = cs.indexOf(sx + pw - 1);\n c2 = c2 < 0 ? maxCol : c2;\n // Iterate over the visible columns.\n for (let i = c1; i <= c2; ++i) {\n // Skip columns which aren't selected.\n if (!model.isColumnSelected(i)) {\n continue;\n }\n // Get the dimensions of the column.\n let x = cs.offsetOf(i) - sx + hw;\n let w = cs.sizeOf(i);\n // Adjust the width for column stretch.\n if (this._stretchLastColumn && pw > bw && i === maxCol) {\n w = hw + pw - x;\n }\n // Skip zero sized columns.\n if (w === 0) {\n continue;\n }\n // Fill the rect if needed.\n if (fill) {\n gc.fillRect(x, 0, w, hh);\n }\n // Draw the border if needed.\n if (stroke) {\n gc.beginPath();\n gc.moveTo(x - 1, hh - 0.5);\n gc.lineTo(x + w, hh - 0.5);\n gc.stroke();\n }\n }\n // Restore the gc state.\n gc.restore();\n }\n /**\n * Draw the overlay cursor for the data grid.\n */\n _drawCursor() {\n // Fetch the selection model.\n let model = this._selectionModel;\n // Bail early if there is no cursor.\n if (!model || model.isEmpty || model.selectionMode !== 'cell') {\n return;\n }\n // Extract the style information.\n let fill = this._style.cursorFillColor;\n let stroke = this._style.cursorBorderColor;\n // Bail early if there is nothing to draw.\n if (!fill && !stroke) {\n return;\n }\n // Fetch the cursor location.\n let startRow = model.cursorRow;\n let startColumn = model.cursorColumn;\n // Fetch the max row and column.\n let maxRow = this._rowSections.count - 1;\n let maxColumn = this._columnSections.count - 1;\n // Bail early if the cursor is out of bounds.\n if (startRow < 0 || startRow > maxRow) {\n return;\n }\n if (startColumn < 0 || startColumn > maxColumn) {\n return;\n }\n let endRow = startRow;\n let endColumn = startColumn;\n const joinedGroup = CellGroup.joinCellGroupWithMergedCellGroups(this.dataModel, { r1: startRow, r2: endRow, c1: startColumn, c2: endColumn }, 'body');\n startRow = joinedGroup.r1;\n endRow = joinedGroup.r2;\n startColumn = joinedGroup.c1;\n endColumn = joinedGroup.c2;\n // Fetch geometry.\n let sx = this._scrollX;\n let sy = this._scrollY;\n let bw = this.bodyWidth;\n let bh = this.bodyHeight;\n let pw = this.pageWidth;\n let ph = this.pageHeight;\n let hw = this.headerWidth;\n let hh = this.headerHeight;\n let vw = this._viewportWidth;\n let vh = this._viewportHeight;\n // Get the cursor bounds in viewport coordinates.\n let x1 = this._columnSections.offsetOf(startColumn) - sx + hw;\n let x2 = this._columnSections.extentOf(endColumn) - sx + hw;\n let y1 = this._rowSections.offsetOf(startRow) - sy + hh;\n let y2 = this._rowSections.extentOf(endRow) - sy + hh;\n // Adjust the trailing X coordinate for column stretch.\n if (this._stretchLastColumn && pw > bw && startColumn === maxColumn) {\n x2 = vw - 1;\n }\n // Adjust the trailing Y coordinate for row stretch.\n if (this._stretchLastRow && ph > bh && startRow === maxRow) {\n y2 = vh - 1;\n }\n // Skip zero sized cursors.\n if (x2 < x1 || y2 < y1) {\n return;\n }\n // Bail early if the cursor is off the screen.\n if (x1 - 1 >= vw || y1 - 1 >= vh || x2 + 1 < hw || y2 + 1 < hh) {\n return;\n }\n // Fetch the overlay gc.\n let gc = this._overlayGC;\n // Save the gc state.\n gc.save();\n // Set up the body clipping rect.\n gc.beginPath();\n gc.rect(hw, hh, pw, ph);\n gc.clip();\n // Clear any existing overlay content.\n gc.clearRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\n // Fill the cursor rect if needed.\n if (fill) {\n // Set up the fill style.\n gc.fillStyle = fill;\n // Fill the cursor rect.\n gc.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);\n }\n // Stroke the cursor border if needed.\n if (stroke) {\n // Set up the stroke style.\n gc.strokeStyle = stroke;\n gc.lineWidth = 2;\n // Stroke the cursor rect.\n gc.strokeRect(x1, y1, x2 - x1, y2 - y1);\n }\n // Restore the gc state.\n gc.restore();\n }\n /**\n * Draw the overlay shadows for the data grid.\n */\n _drawShadows() {\n // Fetch the scroll shadow from the style.\n let shadow = this._style.scrollShadow;\n // Bail early if there is no shadow to draw.\n if (!shadow) {\n return;\n }\n // Fetch the scroll position.\n let sx = this._scrollX;\n let sy = this._scrollY;\n // Fetch maximum scroll position.\n let sxMax = this.maxScrollX;\n let syMax = this.maxScrollY;\n // Fetch the header width and height.\n let hw = this.headerWidth;\n let hh = this.headerHeight;\n // Fetch the page width and height.\n let pw = this.pageWidth;\n let ph = this.pageHeight;\n // Fetch the viewport width and height.\n let vw = this._viewportWidth;\n let vh = this._viewportHeight;\n // Fetch the body width and height.\n let bw = this.bodyWidth;\n let bh = this.bodyHeight;\n // Adjust the body size for row and column stretch.\n if (this._stretchLastRow && ph > bh) {\n bh = ph;\n }\n if (this._stretchLastColumn && pw > bw) {\n bw = pw;\n }\n // Fetch the gc object.\n let gc = this._overlayGC;\n // Save the gc state.\n gc.save();\n // Draw the column header shadow if needed.\n if (sy > 0) {\n // Set up the gradient coordinates.\n let x0 = 0;\n let y0 = hh;\n let x1 = 0;\n let y1 = y0 + shadow.size;\n // Create the gradient object.\n let grad = gc.createLinearGradient(x0, y0, x1, y1);\n // Set the gradient stops.\n grad.addColorStop(0, shadow.color1);\n grad.addColorStop(0.5, shadow.color2);\n grad.addColorStop(1, shadow.color3);\n // Set up the rect coordinates.\n let x = 0;\n let y = hh;\n let w = hw + Math.min(pw, bw - sx);\n let h = shadow.size;\n // Fill the shadow rect with the fill style.\n gc.fillStyle = grad;\n gc.fillRect(x, y, w, h);\n }\n // Draw the row header shadow if needed.\n if (sx > 0) {\n // Set up the gradient coordinates.\n let x0 = hw;\n let y0 = 0;\n let x1 = x0 + shadow.size;\n let y1 = 0;\n // Create the gradient object.\n let grad = gc.createLinearGradient(x0, y0, x1, y1);\n // Set the gradient stops.\n grad.addColorStop(0, shadow.color1);\n grad.addColorStop(0.5, shadow.color2);\n grad.addColorStop(1, shadow.color3);\n // Set up the rect coordinates.\n let x = hw;\n let y = 0;\n let w = shadow.size;\n let h = hh + Math.min(ph, bh - sy);\n // Fill the shadow rect with the fill style.\n gc.fillStyle = grad;\n gc.fillRect(x, y, w, h);\n }\n // Draw the column footer shadow if needed.\n if (sy < syMax) {\n // Set up the gradient coordinates.\n let x0 = 0;\n let y0 = vh;\n let x1 = 0;\n let y1 = vh - shadow.size;\n // Create the gradient object.\n let grad = gc.createLinearGradient(x0, y0, x1, y1);\n // Set the gradient stops.\n grad.addColorStop(0, shadow.color1);\n grad.addColorStop(0.5, shadow.color2);\n grad.addColorStop(1, shadow.color3);\n // Set up the rect coordinates.\n let x = 0;\n let y = vh - shadow.size;\n let w = hw + Math.min(pw, bw - sx);\n let h = shadow.size;\n // Fill the shadow rect with the fill style.\n gc.fillStyle = grad;\n gc.fillRect(x, y, w, h);\n }\n // Draw the row footer shadow if needed.\n if (sx < sxMax) {\n // Set up the gradient coordinates.\n let x0 = vw;\n let y0 = 0;\n let x1 = vw - shadow.size;\n let y1 = 0;\n // Create the gradient object.\n let grad = gc.createLinearGradient(x0, y0, x1, y1);\n // Set the gradient stops.\n grad.addColorStop(0, shadow.color1);\n grad.addColorStop(0.5, shadow.color2);\n grad.addColorStop(1, shadow.color3);\n // Set up the rect coordinates.\n let x = vw - shadow.size;\n let y = 0;\n let w = shadow.size;\n let h = hh + Math.min(ph, bh - sy);\n // Fill the shadow rect with the fill style.\n gc.fillStyle = grad;\n gc.fillRect(x, y, w, h);\n }\n // Restore the gc state.\n gc.restore();\n }\n}\n/**\n * The namespace for the `DataGrid` class statics.\n */\n(function (DataGrid) {\n /**\n * A generic format function for the copy handler.\n *\n * @param args - The format args for the function.\n *\n * @returns The string representation of the value.\n *\n * #### Notes\n * This function uses `String()` to coerce a value to a string.\n */\n function copyFormatGeneric(args) {\n if (args.value === null || args.value === undefined) {\n return '';\n }\n return String(args.value);\n }\n DataGrid.copyFormatGeneric = copyFormatGeneric;\n /**\n * The default theme for a data grid.\n */\n DataGrid.defaultStyle = {\n voidColor: '#F3F3F3',\n backgroundColor: '#FFFFFF',\n gridLineColor: 'rgba(20, 20, 20, 0.15)',\n headerBackgroundColor: '#F3F3F3',\n headerGridLineColor: 'rgba(20, 20, 20, 0.25)',\n selectionFillColor: 'rgba(49, 119, 229, 0.2)',\n selectionBorderColor: 'rgba(0, 107, 247, 1.0)',\n cursorBorderColor: 'rgba(0, 107, 247, 1.0)',\n headerSelectionFillColor: 'rgba(20, 20, 20, 0.1)',\n headerSelectionBorderColor: 'rgba(0, 107, 247, 1.0)',\n scrollShadow: {\n size: 10,\n color1: 'rgba(0, 0, 0, 0.20)',\n color2: 'rgba(0, 0, 0, 0.05)',\n color3: 'rgba(0, 0, 0, 0.00)'\n }\n };\n /**\n * The default sizes for a data grid.\n */\n DataGrid.defaultSizes = {\n rowHeight: 20,\n columnWidth: 64,\n rowHeaderWidth: 64,\n columnHeaderHeight: 20\n };\n /**\n * The default minimum sizes for a data grid.\n */\n DataGrid.minimumSizes = {\n rowHeight: 20,\n columnWidth: 10,\n rowHeaderWidth: 10,\n columnHeaderHeight: 20\n };\n /**\n * The default copy config for a data grid.\n */\n DataGrid.defaultCopyConfig = {\n separator: '\\t',\n format: copyFormatGeneric,\n headers: 'none',\n warningThreshold: 1e6\n };\n})(DataGrid || (DataGrid = {}));\n/**\n * The namespace for the module implementation details.\n */\nvar Private$1;\n(function (Private) {\n /**\n * A singleton `scroll-request` conflatable message.\n */\n Private.ScrollRequest = new ConflatableMessage('scroll-request');\n /**\n * A singleton `overlay-paint-request` conflatable message.\n */\n Private.OverlayPaintRequest = new ConflatableMessage('overlay-paint-request');\n /**\n * Create a new zero-sized canvas element.\n */\n function createCanvas() {\n let canvas = document.createElement('canvas');\n canvas.width = 0;\n canvas.height = 0;\n return canvas;\n }\n Private.createCanvas = createCanvas;\n /**\n * Checks whether a given regions has merged cells in it.\n * @param dataModel grid's data model.\n * @param region the paint region to be checked.\n * @returns boolean.\n */\n function regionHasMergedCells(dataModel, region) {\n const regionGroups = CellGroup.getCellGroupsAtRegion(dataModel, region);\n return regionGroups.length > 0;\n }\n Private.regionHasMergedCells = regionHasMergedCells;\n /**\n * A conflatable message which merges dirty paint regions.\n */\n class PaintRequest extends ConflatableMessage {\n /**\n * Construct a new paint request messages.\n *\n * @param region - The cell region for the paint.\n *\n * @param r1 - The top-left row of the dirty region.\n *\n * @param c1 - The top-left column of the dirty region.\n *\n * @param r2 - The bottom-right row of the dirty region.\n *\n * @param c2 - The bottom-right column of the dirty region.\n */\n constructor(region, r1, c1, r2, c2) {\n super('paint-request');\n this._region = region;\n this._r1 = r1;\n this._c1 = c1;\n this._r2 = r2;\n this._c2 = c2;\n }\n /**\n * The cell region for the paint.\n */\n get region() {\n return this._region;\n }\n /**\n * The top-left row of the dirty region.\n */\n get r1() {\n return this._r1;\n }\n /**\n * The top-left column of the dirty region.\n */\n get c1() {\n return this._c1;\n }\n /**\n * The bottom-right row of the dirty region.\n */\n get r2() {\n return this._r2;\n }\n /**\n * The bottom-right column of the dirty region.\n */\n get c2() {\n return this._c2;\n }\n /**\n * Conflate this message with another paint request.\n */\n conflate(other) {\n // Bail early if the request is already painting everything.\n if (this._region === 'all') {\n return true;\n }\n // Any region can conflate with the `'all'` region.\n if (other._region === 'all') {\n this._region = 'all';\n return true;\n }\n // Otherwise, do not conflate with a different region.\n if (this._region !== other._region) {\n return false;\n }\n // Conflate the region to the total boundary.\n this._r1 = Math.min(this._r1, other._r1);\n this._c1 = Math.min(this._c1, other._c1);\n this._r2 = Math.max(this._r2, other._r2);\n this._c2 = Math.max(this._c2, other._c2);\n return true;\n }\n }\n Private.PaintRequest = PaintRequest;\n /**\n * A conflatable message for resizing rows.\n */\n class RowResizeRequest extends ConflatableMessage {\n /**\n * Construct a new row resize request.\n *\n * @param region - The row region which holds the section.\n *\n * @param index - The index of row in the region.\n *\n * @param size - The target size of the section.\n */\n constructor(region, index, size) {\n super('row-resize-request');\n this._region = region;\n this._index = index;\n this._size = size;\n }\n /**\n * The row region which holds the section.\n */\n get region() {\n return this._region;\n }\n /**\n * The index of the row in the region.\n */\n get index() {\n return this._index;\n }\n /**\n * The target size of the section.\n */\n get size() {\n return this._size;\n }\n /**\n * Conflate this message with another row resize request.\n */\n conflate(other) {\n if (this._region !== other._region || this._index !== other._index) {\n return false;\n }\n this._size = other._size;\n return true;\n }\n }\n Private.RowResizeRequest = RowResizeRequest;\n /**\n * A conflatable message for resizing columns.\n */\n class ColumnResizeRequest extends ConflatableMessage {\n /**\n * Construct a new column resize request.\n *\n * @param region - The column region which holds the section.\n *\n * @param index - The index of column in the region.\n *\n * @param size - The target size of the section.\n * If null, then infer the size to fit.\n */\n constructor(region, index, size) {\n super('column-resize-request');\n this._region = region;\n this._index = index;\n this._size = size;\n }\n /**\n * The column region which holds the section.\n */\n get region() {\n return this._region;\n }\n /**\n * The index of the column in the region.\n */\n get index() {\n return this._index;\n }\n /**\n * The target size of the section.\n */\n get size() {\n return this._size;\n }\n /**\n * Conflate this message with another column resize request.\n */\n conflate(other) {\n if (this._region !== other._region || this._index !== other._index) {\n return false;\n }\n this._size = other._size;\n return true;\n }\n }\n Private.ColumnResizeRequest = ColumnResizeRequest;\n})(Private$1 || (Private$1 = {}));\n\n/**\n * A data model implementation for in-memory JSON data.\n */\nclass JSONModel extends DataModel {\n /**\n * Create a data model with static JSON data.\n *\n * @param options - The options for initializing the data model.\n */\n constructor(options) {\n super();\n let split = Private.splitFields(options.schema);\n this._data = options.data;\n this._bodyFields = split.bodyFields;\n this._headerFields = split.headerFields;\n this._missingValues = Private.createMissingMap(options.schema);\n }\n /**\n * Get the row count for a region in the data model.\n *\n * @param region - The row region of interest.\n *\n * @returns - The row count for the region.\n */\n rowCount(region) {\n if (region === 'body') {\n return this._data.length;\n }\n return 1; // TODO multiple column-header rows?\n }\n /**\n * Get the column count for a region in the data model.\n *\n * @param region - The column region of interest.\n *\n * @returns - The column count for the region.\n */\n columnCount(region) {\n if (region === 'body') {\n return this._bodyFields.length;\n }\n return this._headerFields.length;\n }\n /**\n * Get the data value for a cell in the data model.\n *\n * @param region - The cell region of interest.\n *\n * @param row - The row index of the cell of interest.\n *\n * @param column - The column index of the cell of interest.\n *\n * @returns - The data value for the specified cell.\n *\n * #### Notes\n * A `missingValue` as defined by the schema is converted to `null`.\n */\n data(region, row, column) {\n // Set up the field and value variables.\n let field;\n let value;\n // Look up the field and value for the region.\n switch (region) {\n case 'body':\n field = this._bodyFields[column];\n value = this._data[row][field.name];\n break;\n case 'column-header':\n field = this._bodyFields[column];\n value = field.title || field.name;\n break;\n case 'row-header':\n field = this._headerFields[column];\n value = this._data[row][field.name];\n break;\n case 'corner-header':\n field = this._headerFields[column];\n value = field.title || field.name;\n break;\n default:\n throw 'unreachable';\n }\n // Test whether the value is a missing value.\n let missing = this._missingValues !== null &&\n typeof value === 'string' &&\n this._missingValues[value] === true;\n // Return the final value.\n return missing ? null : value;\n }\n /**\n * Get the metadata for a cell in the data model.\n *\n * @param region - The cell region of interest.\n *\n * @param row - The row index of the cell of of interest.\n *\n * @param column - The column index of the cell of interest.\n *\n * @returns The metadata for the cell.\n */\n metadata(region, row, column) {\n if (region === 'body' || region === 'column-header') {\n return this._bodyFields[column];\n }\n return this._headerFields[column];\n }\n}\n/**\n * The namespace for the module implementation details.\n */\nvar Private;\n(function (Private) {\n /**\n * Split the schema fields into header and body fields.\n */\n function splitFields(schema) {\n // Normalize the primary keys.\n let primaryKeys;\n if (schema.primaryKey === undefined) {\n primaryKeys = [];\n }\n else if (typeof schema.primaryKey === 'string') {\n primaryKeys = [schema.primaryKey];\n }\n else {\n primaryKeys = schema.primaryKey;\n }\n // Separate the fields for the body and header.\n let bodyFields = [];\n let headerFields = [];\n for (let field of schema.fields) {\n if (primaryKeys.indexOf(field.name) === -1) {\n bodyFields.push(field);\n }\n else {\n headerFields.push(field);\n }\n }\n // Return the separated fields.\n return { bodyFields, headerFields };\n }\n Private.splitFields = splitFields;\n /**\n * Create a missing values map for a schema.\n *\n * This returns `null` if there are no missing values.\n */\n function createMissingMap(schema) {\n // Bail early if there are no missing values.\n if (!schema.missingValues || schema.missingValues.length === 0) {\n return null;\n }\n // Collect the missing values into a map.\n let result = Object.create(null);\n for (let value of schema.missingValues) {\n result[value] = true;\n }\n // Return the populated map.\n return result;\n }\n Private.createMissingMap = createMissingMap;\n})(Private || (Private = {}));\n\n// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2023, Lumino Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\nconst PERCENTAGE_REGEX = /^(\\d+(\\.\\d+)?)%$/;\nconst PIXEL_REGEX = /^(\\d+(\\.\\d+)?)px$/;\n/**\n * A cell renderer which renders data values as images.\n */\nclass ImageRenderer extends AsyncCellRenderer {\n /**\n * Construct a new text renderer.\n *\n * @param options - The options for initializing the renderer.\n */\n constructor(options = {}) {\n super();\n this.backgroundColor = options.backgroundColor || '';\n this.textColor = options.textColor || '#000000';\n this.placeholder = options.placeholder || '...';\n this.width = options.width || '';\n // Not using the || operator, because the empty string '' is a valid value\n this.height = options.height === undefined ? '100%' : options.height;\n }\n /**\n * Whether the renderer is ready or not for that specific config.\n * If it's not ready, the datagrid will paint the placeholder.\n * If it's ready, the datagrid will paint the image synchronously.\n *\n * @param config - The configuration data for the cell.\n *\n * @returns Whether the renderer is ready for this config or not.\n */\n isReady(config) {\n return (!config.value || ImageRenderer.dataCache.get(config.value) !== undefined);\n }\n /**\n * Load the image asynchronously for a specific config.\n *\n * @param config - The configuration data for the cell.\n */\n async load(config) {\n // Bail early if there is nothing to do\n if (!config.value) {\n return;\n }\n const value = config.value;\n const loadedPromise = new PromiseDelegate();\n ImageRenderer.dataCache.set(value, undefined);\n const img = new Image();\n img.onload = () => {\n ImageRenderer.dataCache.set(value, img);\n loadedPromise.resolve();\n };\n img.src = value;\n return loadedPromise.promise;\n }\n /**\n * Paint the placeholder for a cell, waiting for the renderer to be ready.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n paintPlaceholder(gc, config) {\n this.drawBackground(gc, config);\n this.drawPlaceholder(gc, config);\n }\n /**\n * Paint the content for a cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n paint(gc, config) {\n this.drawBackground(gc, config);\n this.drawImage(gc, config);\n }\n /**\n * Draw the background for the cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n drawBackground(gc, config) {\n // Resolve the background color for the cell.\n const color = CellRenderer.resolveOption(this.backgroundColor, config);\n // Bail if there is no background color to draw.\n if (!color) {\n return;\n }\n // Fill the cell with the background color.\n gc.fillStyle = color;\n gc.fillRect(config.x, config.y, config.width, config.height);\n }\n /**\n * Draw the placeholder for the cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n drawPlaceholder(gc, config) {\n const placeholder = CellRenderer.resolveOption(this.placeholder, config);\n const color = CellRenderer.resolveOption(this.textColor, config);\n const textX = config.x + config.width / 2;\n const textY = config.y + config.height / 2;\n // Draw the placeholder.\n gc.fillStyle = color;\n gc.fillText(placeholder, textX, textY);\n }\n /**\n * Draw the image for the cell.\n *\n * @param gc - The graphics context to use for drawing.\n *\n * @param config - The configuration data for the cell.\n */\n drawImage(gc, config) {\n // Bail early if there is nothing to draw\n if (!config.value) {\n return;\n }\n const img = ImageRenderer.dataCache.get(config.value);\n // If it's not loaded yet, show the placeholder\n if (!img) {\n return this.drawPlaceholder(gc, config);\n }\n const width = CellRenderer.resolveOption(this.width, config);\n const height = CellRenderer.resolveOption(this.height, config);\n // width and height are unset, we display the image with its original size\n if (!width && !height) {\n gc.drawImage(img, config.x, config.y);\n return;\n }\n let requestedWidth = img.width;\n let requestedHeight = img.height;\n let widthPercentageMatch;\n let widthPixelMatch;\n let heightPercentageMatch;\n let heightPixelMatch;\n if ((widthPercentageMatch = width.match(PERCENTAGE_REGEX))) {\n requestedWidth =\n (parseFloat(widthPercentageMatch[1]) / 100) * config.width;\n }\n else if ((widthPixelMatch = width.match(PIXEL_REGEX))) {\n requestedWidth = parseFloat(widthPixelMatch[1]);\n }\n if ((heightPercentageMatch = height.match(PERCENTAGE_REGEX))) {\n requestedHeight =\n (parseFloat(heightPercentageMatch[1]) / 100) * config.height;\n }\n else if ((heightPixelMatch = height.match(PIXEL_REGEX))) {\n requestedHeight = parseFloat(heightPixelMatch[1]);\n }\n // If width is not set, we compute it respecting the image size ratio\n if (!width) {\n requestedWidth = (img.width / img.height) * requestedHeight;\n }\n // If height is not set, we compute it respecting the image size ratio\n if (!height) {\n requestedHeight = (img.height / img.width) * requestedWidth;\n }\n gc.drawImage(img, config.x, config.y, requestedWidth, requestedHeight);\n }\n}\nImageRenderer.dataCache = new Map();\n\nexport { AsyncCellRenderer, BasicKeyHandler, BasicMouseHandler, BasicSelectionModel, BooleanCellEditor, CellEditor, CellEditorController, CellGroup, CellRenderer, DataGrid, DataModel, DateCellEditor, DynamicOptionCellEditor, GraphicsContext, HyperlinkRenderer, ImageRenderer, InputCellEditor, IntegerCellEditor, IntegerInputValidator, JSONModel, MutableDataModel, NumberCellEditor, NumberInputValidator, OptionCellEditor, PassInputValidator, RendererMap, SectionList, SelectionModel, TextCellEditor, TextInputValidator, TextRenderer, resolveOption };\n//# sourceMappingURL=index.es6.js.map\n"],"names":[],"sourceRoot":""}