notebook 7.4.0a2__py3-none-any.whl → 7.4.0b0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of notebook might be problematic. Click here for more details.

Files changed (111) hide show
  1. notebook/_version.py +1 -1
  2. notebook/static/{131.ae628045345ebd7a085c.js → 131.c728b25b3e9d5fbfed0e.js} +3 -3
  3. notebook/static/{131.ae628045345ebd7a085c.js.map → 131.c728b25b3e9d5fbfed0e.js.map} +1 -1
  4. notebook/static/{1650.4a594c955e102170fba4.js → 1650.3994c2ae58820a51ef6e.js} +4 -4
  5. notebook/static/{1650.4a594c955e102170fba4.js.map → 1650.3994c2ae58820a51ef6e.js.map} +1 -1
  6. notebook/static/{1684.181747c0fff533fb7be1.js → 1684.ffb57250d6932201e986.js} +5 -5
  7. notebook/static/{1684.181747c0fff533fb7be1.js.map → 1684.ffb57250d6932201e986.js.map} +1 -1
  8. notebook/static/{2065.e9b5d8d0a8bec3304454.js → 2065.4ca1081010e8ed491cb3.js} +3 -3
  9. notebook/static/{2065.e9b5d8d0a8bec3304454.js.map → 2065.4ca1081010e8ed491cb3.js.map} +1 -1
  10. notebook/static/{3146.50775b118f3b16c03cf8.js → 3146.f7405571592f8081c229.js} +5 -5
  11. notebook/static/{3146.50775b118f3b16c03cf8.js.map → 3146.f7405571592f8081c229.js.map} +1 -1
  12. notebook/static/{3768.1c37846cbecbfb1cedf4.js → 3768.622e6043f171d5e91c22.js} +21 -21
  13. notebook/static/{7302.bae18f113fbc82bde8dd.js.map → 3768.622e6043f171d5e91c22.js.map} +1 -1
  14. notebook/static/{3797.861e562685aa1e1621bb.js → 3797.ad30e7a4bf8dc994e5be.js} +2 -2
  15. notebook/static/{3797.861e562685aa1e1621bb.js.map → 3797.ad30e7a4bf8dc994e5be.js.map} +1 -1
  16. notebook/static/{4382.c1adbfb7b5186a697e8f.js → 4382.24932cb1b66431a2cfc7.js} +3 -3
  17. notebook/static/{4382.c1adbfb7b5186a697e8f.js.map → 4382.24932cb1b66431a2cfc7.js.map} +1 -1
  18. notebook/static/{4406.aa6e48d547067e1f6a24.js → 4406.02ce3b8ea2a22f9d7909.js} +4 -4
  19. notebook/static/{4406.aa6e48d547067e1f6a24.js.map → 4406.02ce3b8ea2a22f9d7909.js.map} +1 -1
  20. notebook/static/{4645.442bd00fdfca9f0b5f06.js → 4645.f1cd6ed7dc083b4ee676.js} +5 -5
  21. notebook/static/{4645.442bd00fdfca9f0b5f06.js.map → 4645.f1cd6ed7dc083b4ee676.js.map} +1 -1
  22. notebook/static/{4837.3c1870387da3d1a7e16f.js → 4837.ecf66262e53d123e977f.js} +5 -5
  23. notebook/static/{4837.3c1870387da3d1a7e16f.js.map → 4837.ecf66262e53d123e977f.js.map} +1 -1
  24. notebook/static/{4926.c68927936b855fd893c5.js → 4926.7abeef2c6f94f22366bf.js} +4 -4
  25. notebook/static/{4926.c68927936b855fd893c5.js.map → 4926.7abeef2c6f94f22366bf.js.map} +1 -1
  26. notebook/static/{6008.b4fc0ceb2a3939eb8b68.js → 4951.d8baaf3632bee27d4888.js} +2 -2
  27. notebook/static/{6008.b4fc0ceb2a3939eb8b68.js.map → 4951.d8baaf3632bee27d4888.js.map} +1 -1
  28. notebook/static/{5135.0ecfc3d3763bbc747bc9.js → 5135.6f146bc83223b0a367d6.js} +13 -13
  29. notebook/static/{5135.0ecfc3d3763bbc747bc9.js.map → 5135.6f146bc83223b0a367d6.js.map} +1 -1
  30. notebook/static/{5573.11c29f783f9d08a1ef3f.js → 5573.5f13d58b4fb49bd20e96.js} +19 -19
  31. notebook/static/{5573.11c29f783f9d08a1ef3f.js.map → 5573.5f13d58b4fb49bd20e96.js.map} +1 -1
  32. notebook/static/{5601.9d6cca9449dad4be2d59.js → 5601.67eaf59e4443e7464bbc.js} +5 -5
  33. notebook/static/{5601.9d6cca9449dad4be2d59.js.map → 5601.67eaf59e4443e7464bbc.js.map} +1 -1
  34. notebook/static/{6345.be41f5ff79cb9a9bcf3e.js → 6345.ca03ab559d7d152f0bcf.js} +5 -5
  35. notebook/static/{6345.be41f5ff79cb9a9bcf3e.js.map → 6345.ca03ab559d7d152f0bcf.js.map} +1 -1
  36. notebook/static/{7302.bae18f113fbc82bde8dd.js → 7302.384fc5f4283ea3aba3cf.js} +21 -21
  37. notebook/static/{3768.1c37846cbecbfb1cedf4.js.map → 7302.384fc5f4283ea3aba3cf.js.map} +1 -1
  38. notebook/static/{7369.a065dc2ed2f56a44cb0f.js → 7369.5b8c5f78b70096907327.js} +3 -3
  39. notebook/static/{7369.a065dc2ed2f56a44cb0f.js.map → 7369.5b8c5f78b70096907327.js.map} +1 -1
  40. notebook/static/{7811.4e69e9d0823ec9b2d218.js → 7811.fa11577c84ea92d4102c.js} +5 -5
  41. notebook/static/{7811.4e69e9d0823ec9b2d218.js.map → 7811.fa11577c84ea92d4102c.js.map} +1 -1
  42. notebook/static/{7906.4fc1485cef75bc0cbd28.js → 7906.0591558f697337e877b8.js} +3 -3
  43. notebook/static/{7906.4fc1485cef75bc0cbd28.js.map → 7906.0591558f697337e877b8.js.map} +1 -1
  44. notebook/static/{8579.a1fe3d6050e65996b704.js → 8579.75044552fbfae5d3e169.js} +14 -14
  45. notebook/static/{8579.a1fe3d6050e65996b704.js.map → 8579.75044552fbfae5d3e169.js.map} +1 -1
  46. notebook/static/{8781.99c47de7d954e7d24451.js → 8781.93ded0db04e1cace2f46.js} +58 -61
  47. notebook/static/8781.93ded0db04e1cace2f46.js.map +1 -0
  48. notebook/static/{8875.315376360b0527f2d92e.js → 8875.55554006d7836a7e9685.js} +4 -4
  49. notebook/static/{8875.315376360b0527f2d92e.js.map → 8875.55554006d7836a7e9685.js.map} +1 -1
  50. notebook/static/{8929.b5b29c25d0b317812054.js → 8929.52734b044aa837e7132d.js} +29 -3
  51. notebook/static/8929.52734b044aa837e7132d.js.map +1 -0
  52. notebook/static/{9068.b2842f92bbfa2dcb3045.js → 9068.903efe1a91c5838e0d91.js} +3 -3
  53. notebook/static/{9068.b2842f92bbfa2dcb3045.js.map → 9068.903efe1a91c5838e0d91.js.map} +1 -1
  54. notebook/static/{9380.5271a4f758251fe9bd9a.js → 9380.ed0becd75cac76b98c1a.js} +5 -5
  55. notebook/static/{9380.5271a4f758251fe9bd9a.js.map → 9380.ed0becd75cac76b98c1a.js.map} +1 -1
  56. notebook/static/main.65ae09d99829c70c593d.js +1179 -0
  57. notebook/static/main.65ae09d99829c70c593d.js.map +1 -0
  58. notebook/static/{notebook_core.0dfd038c4062400eb2f0.js → notebook_core.37d09340001fe2b154a6.js} +1387 -1055
  59. notebook/static/{notebook_core.0dfd038c4062400eb2f0.js.map → notebook_core.37d09340001fe2b154a6.js.map} +1 -1
  60. notebook/static/third-party-licenses.json +104 -104
  61. notebook/templates/consoles.html +1 -1
  62. notebook/templates/edit.html +1 -1
  63. notebook/templates/error.html +1 -1
  64. notebook/templates/notebooks.html +1 -1
  65. notebook/templates/terminals.html +1 -1
  66. notebook/templates/tree.html +1 -1
  67. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/application-extension/package.json.orig +15 -15
  68. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/documentsearch-extension/package.json.orig +5 -5
  69. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/help-extension/package.json.orig +7 -7
  70. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/notebook-extension/package.json.orig +10 -10
  71. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/tree-extension/package.json.orig +16 -16
  72. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/package.json +12 -12
  73. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/schemas/@jupyter-notebook/lab-extension/package.json.orig +11 -11
  74. notebook-7.4.0a2.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/534.b1feb1e5dee752bdfe43.js → notebook-7.4.0b0.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/507.64fd87004a86738ad850.js +1 -1
  75. notebook-7.4.0b0.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/568.ad0301c36223355b3801.js +1 -0
  76. notebook-7.4.0b0.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/928.2ba1817f535919acaab3.js +1 -0
  77. notebook-7.4.0b0.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/remoteEntry.8706c463a056a3aa7c83.js +1 -0
  78. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/third-party-licenses.json +2 -2
  79. {notebook-7.4.0a2.dist-info → notebook-7.4.0b0.dist-info}/METADATA +2 -2
  80. {notebook-7.4.0a2.dist-info → notebook-7.4.0b0.dist-info}/RECORD +104 -104
  81. notebook/static/8781.99c47de7d954e7d24451.js.map +0 -1
  82. notebook/static/8929.b5b29c25d0b317812054.js.map +0 -1
  83. notebook/static/main.d169897d1e63bbaa91cb.js +0 -1179
  84. notebook/static/main.d169897d1e63bbaa91cb.js.map +0 -1
  85. notebook-7.4.0a2.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/568.535717f1b07112110997.js +0 -1
  86. notebook-7.4.0a2.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/928.c9dae1baa4490d650ce9.js +0 -1
  87. notebook-7.4.0a2.data/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/remoteEntry.aa46dc8e35af2ba28d27.js +0 -1
  88. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/etc/jupyter/jupyter_server_config.d/notebook.json +0 -0
  89. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/applications/jupyter-notebook.desktop +0 -0
  90. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/icons/hicolor/scalable/apps/notebook.svg +0 -0
  91. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/application-extension/menus.json +0 -0
  92. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/application-extension/pages.json +0 -0
  93. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/application-extension/shell.json +0 -0
  94. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/application-extension/title.json +0 -0
  95. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/application-extension/top.json +0 -0
  96. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/application-extension/zen.json +0 -0
  97. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/help-extension/open.json +0 -0
  98. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/notebook-extension/checkpoints.json +0 -0
  99. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/notebook-extension/edit-notebook-metadata.json +0 -0
  100. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/notebook-extension/full-width-notebook.json +0 -0
  101. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/notebook-extension/kernel-logo.json +0 -0
  102. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/notebook-extension/scroll-output.json +0 -0
  103. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/tree-extension/file-actions.json +0 -0
  104. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/lab/schemas/@jupyter-notebook/tree-extension/widget.json +0 -0
  105. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/schemas/@jupyter-notebook/lab-extension/interface-switcher.json +0 -0
  106. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/schemas/@jupyter-notebook/lab-extension/launch-tree.json +0 -0
  107. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/93.eae3497dd223d842d198.js +0 -0
  108. {notebook-7.4.0a2.data → notebook-7.4.0b0.data}/data/share/jupyter/labextensions/@jupyter-notebook/lab-extension/static/style.js +0 -0
  109. {notebook-7.4.0a2.dist-info → notebook-7.4.0b0.dist-info}/WHEEL +0 -0
  110. {notebook-7.4.0a2.dist-info → notebook-7.4.0b0.dist-info}/entry_points.txt +0 -0
  111. {notebook-7.4.0a2.dist-info → notebook-7.4.0b0.dist-info}/licenses/LICENSE +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"8929.b5b29c25d0b317812054.js?v=b5b29c25d0b317812054","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,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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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,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 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 grid.resizeColumn(colRegion, colIndex, null);\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 */\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":""}