cubevis 1.0.35__tar.gz → 1.0.44__tar.gz

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.
Files changed (165) hide show
  1. {cubevis-1.0.35 → cubevis-1.0.44}/PKG-INFO +1 -1
  2. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__js__/bokeh-3.8/cubevisjs.min.js +5 -5
  3. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/_showable.py +0 -4
  4. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/sources/_data_pipe.py +17 -26
  5. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/sources/_updatable_data_source.py +2 -2
  6. cubevis-1.0.44/cubevis/bokeh/sources/transport/__init__.py +12 -0
  7. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/toolbox/_cube.py +3 -3
  8. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/toolbox/_interactive_clean_ui.mustache +10 -10
  9. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/toolbox/_interactive_clean_ui.py +10 -10
  10. {cubevis-1.0.35 → cubevis-1.0.44}/pyproject.toml +1 -1
  11. {cubevis-1.0.35 → cubevis-1.0.44}/LICENSE +0 -0
  12. {cubevis-1.0.35 → cubevis-1.0.44}/README.rst +0 -0
  13. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/LICENSE.rst +0 -0
  14. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/20px/fast-backward.svg +0 -0
  15. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/20px/fast-forward.svg +0 -0
  16. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/20px/step-backward.svg +0 -0
  17. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/20px/step-forward.svg +0 -0
  18. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/add-chan.png +0 -0
  19. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/add-chan.svg +0 -0
  20. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/add-cube.png +0 -0
  21. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/add-cube.svg +0 -0
  22. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/drag.png +0 -0
  23. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/drag.svg +0 -0
  24. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/mask-selected.png +0 -0
  25. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/mask.png +0 -0
  26. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/mask.svg +0 -0
  27. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/new-layer-sm-selected.png +0 -0
  28. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/new-layer-sm-selected.svg +0 -0
  29. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/new-layer-sm.png +0 -0
  30. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/new-layer-sm.svg +0 -0
  31. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/reset.png +0 -0
  32. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/reset.svg +0 -0
  33. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/sub-chan.png +0 -0
  34. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/sub-chan.svg +0 -0
  35. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/sub-cube.png +0 -0
  36. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/sub-cube.svg +0 -0
  37. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/trash.png +0 -0
  38. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/trash.svg +0 -0
  39. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/trash_full.png +0 -0
  40. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/trash_full.svg +0 -0
  41. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/trash_full_raw.png +0 -0
  42. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/zoom-to-fit.png +0 -0
  43. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__icons__/zoom-to-fit.svg +0 -0
  44. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__init__.py +0 -0
  45. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__js__/bokeh-3.6/cubevisjs.min.js +0 -0
  46. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__js__/bokeh-3.7/cubevisjs.min.js +0 -0
  47. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/__js__/casalib.min.js +0 -0
  48. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/__init__.py +0 -0
  49. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/annotations/__init__.py +0 -0
  50. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/annotations/_ev_poly_annotation.py +0 -0
  51. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/components/__init__.py +0 -0
  52. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/format/__init__.py +0 -0
  53. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/format/_time_ticks.py +0 -0
  54. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/format/_wcs_ticks.py +0 -0
  55. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/__init__.py +0 -0
  56. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/_bokeh_app_context.py +0 -0
  57. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/_edit_span.py +0 -0
  58. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/_ev_text_input.py +0 -0
  59. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/_shared_dict.py +0 -0
  60. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/_tip.py +0 -0
  61. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/models/_tip_button.py +0 -0
  62. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/sources/__init__.py +0 -0
  63. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/sources/_image_data_source.py +0 -0
  64. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/sources/_image_pipe.py +0 -0
  65. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/sources/_spectra_data_source.py +0 -0
  66. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/__init__.py +0 -0
  67. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/_current.py +0 -0
  68. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/_initialize.py +0 -0
  69. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/_javascript.py +0 -0
  70. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/_palette.py +0 -0
  71. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/_session.py +0 -0
  72. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/bokeh-2.4.1.min.js +0 -0
  73. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/bokeh-gl-2.4.1.min.js +0 -0
  74. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/bokeh-tables-2.4.1.min.js +0 -0
  75. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/bokeh-widgets-2.4.1.min.js +0 -0
  76. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/casaguijs-v0.0.4.0-b2.4.min.js +0 -0
  77. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/casaguijs-v0.0.5.0-b2.4.min.js +0 -0
  78. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/casaguijs-v0.0.6.0-b2.4.min.js +0 -0
  79. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/state/js/casalib-v0.0.1.min.js +0 -0
  80. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/tools/__init__.py +0 -0
  81. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/tools/_cbreset_tool.py +0 -0
  82. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/tools/_drag_tool.py +0 -0
  83. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/utils/__init__.py +0 -0
  84. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/utils/_axes_labels.py +0 -0
  85. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/bokeh/utils/_svg_icon.py +0 -0
  86. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/data/__init__.py +0 -0
  87. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/data/casaimage/__init__.py +0 -0
  88. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/exe/__init__.py +0 -0
  89. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/exe/_context.py +0 -0
  90. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/exe/_mode.py +0 -0
  91. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/exe/_setting.py +0 -0
  92. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/exe/_task.py +0 -0
  93. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/_gclean.py +0 -0
  94. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/__init__.py +0 -0
  95. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_createmask.py +0 -0
  96. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_createregion.py +0 -0
  97. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_interactiveclean.mustache +0 -0
  98. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_interactiveclean.py +0 -0
  99. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_interactivecleannotebook.mustache +0 -0
  100. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_interactivecleannotebook.py +0 -0
  101. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_plotants.py +0 -0
  102. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/apps/_plotbandpass.py +0 -0
  103. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/casashell/createmask.py +0 -0
  104. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/casashell/iclean.py +0 -0
  105. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/casatasks/__init__.py +0 -0
  106. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/casatasks/createmask.py +0 -0
  107. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/casatasks/createregion.py +0 -0
  108. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/casatasks/iclean.py +0 -0
  109. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/private/casatasks/iclean_notebook.py +0 -0
  110. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/readme.rst +0 -0
  111. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/remote/__init__.py +0 -0
  112. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/remote/_gclean.py +0 -0
  113. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/remote/_local.py +0 -0
  114. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/remote/_remote_kernel.py +0 -0
  115. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/toolbox/__init__.py +0 -0
  116. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/toolbox/_app_context.py +0 -0
  117. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/toolbox/_interactiveclean_wrappers.py +0 -0
  118. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/toolbox/_region_list.py +0 -0
  119. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_ResourceManager.py +0 -0
  120. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/__init__.py +0 -0
  121. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_browser.py +0 -0
  122. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_contextmgrchain.py +0 -0
  123. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_conversion.py +0 -0
  124. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_copydoc.py +0 -0
  125. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_docenum.py +0 -0
  126. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_git.py +0 -0
  127. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_import_protected_module.py +0 -0
  128. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_jupyter.py +0 -0
  129. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_logging.py +0 -0
  130. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_mutual_exclusion.py +0 -0
  131. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_pkgs.py +0 -0
  132. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_regions.py +0 -0
  133. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_static.py +0 -0
  134. {cubevis-1.0.35 → cubevis-1.0.44}/cubevis/utils/_tiles.py +0 -0
  135. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/alma-many-chan/alma-many-chan.py +0 -0
  136. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/basic-websockets-demo/client.html +0 -0
  137. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/basic-websockets-demo/client.py +0 -0
  138. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/basic-websockets-demo/server.py +0 -0
  139. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/createmask-demo/run-createmask.py +0 -0
  140. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/createregion-demo/run-createregion.py +0 -0
  141. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/cubemask-demo/image-slider-spectra-done-stats.py +0 -0
  142. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/cubemask-demo/image-slider-spectra-done.py +0 -0
  143. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/cubemask-demo/image-slider-spectra.py +0 -0
  144. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/cubemask-demo/image-slider.py +0 -0
  145. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/cubemask-demo/image.py +0 -0
  146. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-demo/iclean-demo.ipynb +0 -0
  147. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-demo/m100_interactive.py +0 -0
  148. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-demo/mask0-iclean.py +0 -0
  149. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-demo/run-gclean.py +0 -0
  150. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-demo/run-iclean-obj.py +0 -0
  151. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-demo/run-iclean.py +0 -0
  152. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-demo/vla-sim-jet-iclean.py +0 -0
  153. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-first-look/run-fl-cont.py +0 -0
  154. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-first-look/run-fl-line.py +0 -0
  155. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-outlier/run-iclean.py +0 -0
  156. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-outlier/test_outlier.txt +0 -0
  157. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/iclean-remote/iclean_remote_webserver.py +0 -0
  158. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/large-cube/run-largecube.py +0 -0
  159. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/svg-test.py +0 -0
  160. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/updatable-data-source/direct-plot.py +0 -0
  161. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/updatable-data-source/simple-update.py +0 -0
  162. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/updatable-data-source/updated-plot.py +0 -0
  163. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/uranus-demo/uranus-iclean.py +0 -0
  164. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/websocket-reconnect/client.html +0 -0
  165. {cubevis-1.0.35 → cubevis-1.0.44}/tests/manual/websocket-reconnect/server.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cubevis
3
- Version: 1.0.35
3
+ Version: 1.0.44
4
4
  Summary: visualization toolkit and apps for casa
5
5
  License: LGPL
6
6
  Author-email: Darrell Schiebel <darrell@schiebel.us>,Pam Harris <pharris@nrao.edu>
@@ -42,15 +42,15 @@
42
42
  }
43
43
  })
44
44
  ({
45
- "07c9fde72b": function _(e,a,t,o,c){o();const i=e("tslib"),n=e("31b6f4b4a1");c("DataPipe",n.DataPipe);c("activeDataPipes",e("5179d11e71").activeDataPipes);const p=e("2889e0dd45");c("ImagePipe",p.ImagePipe);const s=e("de65005924");c("ImageDataSource",s.ImageDataSource);const r=e("02e3c3e46c");c("SpectraDataSource",r.SpectraDataSource);const S=e("64b16deff9");c("UpdatableDataSource",S.UpdatableDataSource);const d=e("b6ae454f0d");c("WcsTicks",d.WcsTicks);const l=e("cb7d28d6b3");c("DragTool",l.DragTool);const D=e("9d3c34ff8e");c("CBResetTool",D.CBResetTool);const T=e("e3901fa9f2");c("serialize",T.serialize),c("deserialize",T.deserialize);const b=e("9f961622ce");c("TipButton",b.TipButton);const u=e("ca4c845905");c("Tip",u.Tip);const f=e("a6e757a69a");c("Showable",f.Showable);const P=e("467d2716b0");c("BokehAppContext",P.BokehAppContext);const g=e("50a1e32f01");c("SharedDict",g.SharedDict);const h=e("b55081402e");c("EditSpan",h.EditSpan);const B=e("9144bfc7a5");c("EvTextInput",B.EvTextInput);const E=e("74e0abef8a");c("EvPolyAnnotation",E.EvPolyAnnotation);const I=i.__importStar(e("484bb85d20"));t.find=I;(0,e("@bokehjs/base").register_models)({DataPipe:n.DataPipe,ImagePipe:p.ImagePipe,ImageDataSource:s.ImageDataSource,SpectraDataSource:r.SpectraDataSource,UpdatableDataSource:S.UpdatableDataSource,WcsTicks:d.WcsTicks,DragTool:l.DragTool,CBResetTool:D.CBResetTool,Tip:u.Tip,TipButton:b.TipButton,SharedDict:g.SharedDict,Showable:f.Showable,BokehAppContext:P.BokehAppContext,EditSpan:h.EditSpan,EvTextInput:B.EvTextInput,EvPolyAnnotation:E.EvPolyAnnotation})},
46
- "31b6f4b4a1": function _(e,s,t,o,i){var n;o();const c=e("@bokehjs/models/sources/data_source"),a=e("e3901fa9f2"),l=e("@bokehjs/core/util/callbacks"),r=e("5179d11e71");class d extends c.DataSource{constructor(e){super(e),this.send_queue={},this.connection_queue=[],this.pending={},this.incoming_callbacks={},this.session_id=casalib.object_id(this)}isColab(){return void 0!==window.google&&void 0!==window.google.colab&&void 0!==window.google.colab.kernel}async getWebSocketUrl(){const[e,s]=this.address;if(this.isColab())try{const e=window.google,t=(await e.colab.kernel.proxyPort(s,{cache:!0})).replace(/^https:/,"wss:");return console.log(`Colab proxy URL for port ${s}: ${t}`),t}catch(t){return console.error("Error getting Colab proxy URL:",t),`ws://${e}:${s}`}return`ws://${e}:${s}`}checkSessionConflict(){try{if("undefined"==typeof Storage)return console.warn("localStorage not available, skipping session conflict detection"),!0;const e=localStorage.getItem(this.session_storage_key);if(e){const s=JSON.parse(e);if(s.sessionId!==this.session_id&&Date.now()-s.timestamp<12e4){if(this.conflict_check){const e=`CubeVis DataPipe (${this.instance_key}) is already running in another browser window or tab.\n\nPlease close other instances and refresh this page, or\nclose this window to continue using the other instance.`;return alert(e),window.opener||1===window.history.length?window.close():window.location.href="about:blank",!1}console.group(`DataPipe ${this.instance_key} conflict detected in Jupyter context`),console.log("Current session ID:",this.session_id),console.log("Existing session ID:",s.sessionId),console.log("Existing timestamp:",new Date(s.timestamp).toISOString()),console.log("Age of existing session (ms):",Date.now()-s.timestamp),console.log("Address:",this.address),console.log("Instance key:",this.instance_key),console.log("Storage key:",this.session_storage_key),console.log("Existing data:",s),console.log("All localStorage keys:",Object.keys(localStorage).filter((e=>e.startsWith("cubevis_datapipe_")))),console.groupEnd()}}return this.updateSessionHeartbeat(),!0}catch(e){return console.warn("Session conflict detection failed:",e),!0}}updateSessionHeartbeat(){try{"undefined"!=typeof Storage&&localStorage.setItem(this.session_storage_key,JSON.stringify({sessionId:this.session_id,timestamp:Date.now(),instanceKey:this.instance_key}))}catch(e){console.warn("Session heartbeat update failed:",e)}}startHeartbeat(){this.heartbeat_interval=window.setInterval((()=>{this.updateSessionHeartbeat()}),3e4)}stopHeartbeat(){this.heartbeat_interval&&(clearInterval(this.heartbeat_interval),this.heartbeat_interval=void 0)}cleanupSession(){try{if("undefined"!=typeof Storage){const e=localStorage.getItem(this.session_storage_key);if(e){JSON.parse(e).sessionId===this.session_id&&localStorage.removeItem(this.session_storage_key)}}}catch(e){console.warn("Session cleanup failed:",e)}this.stopHeartbeat()}handleSessionConflictMessage(e){console.error("Session conflict detected by server:",e);let s="Session conflict detected by server.";"session_conflict"===e.type?s=e.error||s:"session_corruption"===e.type&&(s=`Session corruption detected.\nExpected: ${e.expected}\nReceived: ${e.received}`),alert(s+"\n\nThis window will be closed to prevent data corruption."),this.cleanupSession();const t=new CustomEvent("cubevis_session_conflict",{detail:{message:e,sessionId:this.session_id}});window.dispatchEvent(t),setTimeout((()=>{window.opener||1===window.history.length?window.close():window.location.href="about:blank"}),2e3)}generateInstanceKey(){const e=`${this.address[0]}_${this.address[1]}`;return`${this.instance_id}_${e}`}async initializeWebSocket(){let e;if(this.isColab()){const[s,t]=this.address;console.log("=== Colab WebSocket Debug ==="),console.log("Port:",t);try{let s=null;const o=document.referrer;console.log("Referrer:",o),window.colab&&window.colab.global&&window.colab.global.config&&console.log("Colab config:",window.colab.global.config);try{window.parent&&window.parent.location&&console.log("Parent location:",window.parent.location.href)}catch(e){console.log("Cannot access parent location (CORS)")}const i=window.location.hostname.match(/([^-]+)-([^-]+)-\d+-colab/);if(i){const e=i[1],s=i[2];console.log("Session ID:",e,"Hash:",s)}const n=window.google;if(n&&n.colab&&n.colab.kernel&&(console.log("Available kernel properties:",Object.keys(n.colab.kernel)),n.colab.kernel.websocketUrl&&(console.log("Kernel WebSocket URL:",n.colab.kernel.websocketUrl),s=n.colab.kernel.websocketUrl)),s){const o=s.match(/wss?:\/\/([^\/]+)/);o?(e=`wss://${o[1]}/_proxy/${t}/`,console.log("Constructed kernel proxy URL:",e)):e=`wss://${s}/_proxy/${t}/`}else{console.log("Could not determine kernel domain, trying message passing..."),window.parent.postMessage({type:"request_kernel_domain"},"*");const s=await n.colab.kernel.proxyPort(t,{cache:!0});e=s.replace(/^https:/,"wss:"),console.log("Using googleusercontent proxy (may not work):",e)}}catch(o){console.error("Error in Colab proxy detection:",o),e=`ws://${s}:${t}`}console.log("=== End Debug ===")}else e=`ws://${this.address[0]}:${this.address[1]}`;console.log("Final datapipe url:",e);var s=void 0;document.shutdown_in_progress_=!1;var t=()=>{void 0!==this.websocket&&this.websocket.close(),this.websocket=new WebSocket(e),this.websocket.binaryType="arraybuffer",this.websocket.addEventListener("error",(e=>{console.log("error encountered:",e)})),this.websocket.onmessage=e=>{if("string"==typeof e.data||e.data instanceof String){let s=(0,a.deserialize)(e.data);if("id"in s&&"direction"in s&&"message"in s){let{id:e,message:t,direction:o}=s;if("error"===o&&("session_conflict"===e||e===this.session_id)&&t&&("session_conflict"===t.type||"session_corruption"===t.type||"close_duplicate"===t.action))return void this.handleSessionConflictMessage(t);if(void 0===t&&console.log("Error, event failure",s),"j2p"==o)if(e in this.pending){let{cb:o}=this.pending[e];if(delete this.pending[e],e in this.send_queue&&this.send_queue[e].length>0){let{cb:s,msg:t}=this.send_queue[e].shift();this.pending[e]={cb:s},this.websocket.send((0,a.serialize)(t))}void 0===t?console.log("DROPPING ERROR FOR NOW (maybe need error callbacks)",s):o(t)}else console.log("message received but could not find id");else if(e in this.incoming_callbacks){let s=this.incoming_callbacks[e](t);this.websocket.send((0,a.serialize)({id:e,direction:o,message:s,session:this.session_id}))}}else console.log(`datapipe received message without one of 'id', 'message' or 'direction': ${s}`)}else console.log("datapipe received binary data",e.data.byteLength,"bytes")},this.websocket.onopen=()=>{for(s?0==s.connected&&console.log(`connection reestablished at ${new Date}`):(this.websocket.send((0,a.serialize)({id:"initialize",direction:"j2p",session:this.session_id})),this.startHeartbeat()),s=new casalib.ReconnectState;this.connection_queue.length>0;){let e=this.connection_queue.shift();this.send.apply(e[0],e[1])}},this.websocket.onclose=()=>{if(s&&1==s.connected&&(console.log(`connection lost at ${new Date}`),s.connected=!1,!document.shutdown_in_progress_)){console.log(`connection lost at ${new Date}`);var e=s;function o(i){0==s.connected&&(console.log(`${i+1}\treconnection attempt ${new Date}`),t(),e.backoff(),e.retries>0?setTimeout(o,e.timeout,i+1):0==s.connected&&console.log(`aborting reconnection after ${i} attempts ${new Date}`))}o(0)}}};window.addEventListener("beforeunload",(()=>{this.cleanupSession()})),document.addEventListener("visibilitychange",(()=>{"hidden"===document.visibilityState?this.stopHeartbeat():"visible"===document.visibilityState&&(this.updateSessionHeartbeat(),this.startHeartbeat())})),t()}initialize(){if(super.initialize(),r.activeDataPipes.register(this),this.instance_key=this.generateInstanceKey(),this.session_storage_key=`cubevis_datapipe_${this.instance_key}`,!this.checkSessionConflict())return;this.initializeWebSocket();(()=>{null!=this.init_script&&(0,l.execute)(this.init_script,this)})()}destroy(){r.activeDataPipes.unregister(this),super.destroy()}register(e,s){this.incoming_callbacks[e]=s}send(e,s,t,o=!1){let i={id:e,message:s,direction:"j2p",session:this.session_id};if(!this.websocket||e in this.pending)if(e in this.send_queue)if("boolean"==typeof o&&o&&this.send_queue[e].length>0)this.send_queue[e][0].msg=i,this.send_queue[e][0].cb=t;else if("function"==typeof o&&this.send_queue[e].length>0){let n=!1;for(const c of this.send_queue[e])o(c.msg.message)&&(c.msg=i,c.cb=t,n=!0);n||this.send_queue[e].push({cb:t,msg:i})}else this.send_queue[e].push({cb:t,msg:i});else this.send_queue[e]=[{cb:t,msg:i}];else if(this.websocket.readyState===WebSocket.CONNECTING)this.connection_queue.push([this,[e,s,t]]);else if(e in this.send_queue&&this.send_queue[e].length>0){this.send_queue[e].push({cb:t,msg:i});{let{cb:l,msg:r}=this.send_queue[e].shift();if(this.pending[e]={cb:l},this.websocket.readyState===WebSocket.OPEN)this.websocket.send((0,a.serialize)(r));else{let d=20,h=this;function g(){h.websocket.readyState===WebSocket.OPEN?h.websocket.send((0,a.serialize)(r)):(d-=1,d>0&&setTimeout(g,3e3))}setTimeout(g,3e3)}}}else if(this.websocket.readyState===WebSocket.OPEN)this.pending[e]={cb:t},this.websocket.send((0,a.serialize)(i));else{let u=20,b=this;function p(){b.websocket.readyState===WebSocket.OPEN?(b.pending[e]={cb:t},b.websocket.send((0,a.serialize)(i))):(u-=1,u>0&&setTimeout(p,3e3))}setTimeout(p,3e3)}}}t.DataPipe=d,n=d,d.__name__="DataPipe",d.__module__="cubevis.bokeh.sources._data_pipe",n.define((({Any:e,Tuple:s,String:t,Number:o,Bool:i})=>({init_script:[e,null],address:[s(t,o)],instance_id:[t],conflict_check:[i,!0]})))},
45
+ "07c9fde72b": function _(e,a,t,o,c){o();const i=e("tslib"),n=e("7a1eeba81e");c("DataPipe",n.DataPipe);c("activeDataPipes",e("5179d11e71").activeDataPipes);const p=e("2889e0dd45");c("ImagePipe",p.ImagePipe);const s=e("de65005924");c("ImageDataSource",s.ImageDataSource);const r=e("02e3c3e46c");c("SpectraDataSource",r.SpectraDataSource);const S=e("64b16deff9");c("UpdatableDataSource",S.UpdatableDataSource);const d=e("b6ae454f0d");c("WcsTicks",d.WcsTicks);const l=e("cb7d28d6b3");c("DragTool",l.DragTool);const D=e("9d3c34ff8e");c("CBResetTool",D.CBResetTool);const T=e("e3901fa9f2");c("serialize",T.serialize),c("deserialize",T.deserialize);const b=e("9f961622ce");c("TipButton",b.TipButton);const u=e("ca4c845905");c("Tip",u.Tip);const P=e("a6e757a69a");c("Showable",P.Showable);const f=e("467d2716b0");c("BokehAppContext",f.BokehAppContext);const g=e("50a1e32f01");c("SharedDict",g.SharedDict);const h=e("b55081402e");c("EditSpan",h.EditSpan);const B=e("9144bfc7a5");c("EvTextInput",B.EvTextInput);const E=e("74e0abef8a");c("EvPolyAnnotation",E.EvPolyAnnotation);const I=i.__importStar(e("484bb85d20"));t.find=I;(0,e("@bokehjs/base").register_models)({DataPipe:n.DataPipe,ImagePipe:p.ImagePipe,ImageDataSource:s.ImageDataSource,SpectraDataSource:r.SpectraDataSource,UpdatableDataSource:S.UpdatableDataSource,WcsTicks:d.WcsTicks,DragTool:l.DragTool,CBResetTool:D.CBResetTool,Tip:u.Tip,TipButton:b.TipButton,SharedDict:g.SharedDict,Showable:P.Showable,BokehAppContext:f.BokehAppContext,EditSpan:h.EditSpan,EvTextInput:B.EvTextInput,EvPolyAnnotation:E.EvPolyAnnotation})},
46
+ "7a1eeba81e": function _(e,t,s,i,n){var o;i();const a=e("@bokehjs/models/sources/data_source"),c=e("e3901fa9f2"),r=e("@bokehjs/core/util/callbacks"),l=e("5179d11e71");class d extends a.DataSource{constructor(e){super(e),this.send_queue={},this.connection_queue=[],this.pending={},this.incoming_callbacks={},this.session_id=casalib.object_id(this)}checkSessionConflict(){try{if("undefined"==typeof Storage)return console.warn("localStorage not available, skipping session conflict detection"),!0;const e=localStorage.getItem(this.session_storage_key);if(e){const t=JSON.parse(e);if(t.sessionId!==this.session_id&&Date.now()-t.timestamp<12e4){if(this.conflict_check){const e=`CubeVis DataPipe (${this.instance_key}) is already running in another browser window or tab.\n\nPlease close other instances and refresh this page, or\nclose this window to continue using the other instance.`;return alert(e),window.opener||1===window.history.length?window.close():window.location.href="about:blank",!1}console.group(`DataPipe ${this.instance_key} conflict detected in Jupyter context`),console.log("Current session ID:",this.session_id),console.log("Existing session ID:",t.sessionId),console.log("Existing timestamp:",new Date(t.timestamp).toISOString()),console.log("Age of existing session (ms):",Date.now()-t.timestamp),console.log("Backend IP:",this.backend_ip),console.log("Backend Port:",this.backend_port),console.log("Backend URL:",this.backend_url),console.log("Instance key:",this.instance_key),console.log("Storage key:",this.session_storage_key),console.log("Existing data:",t),console.log("All localStorage keys:",Object.keys(localStorage).filter((e=>e.startsWith("cubevis_datapipe_")))),console.groupEnd()}}return this.updateSessionHeartbeat(),!0}catch(e){return console.warn("Session conflict detection failed:",e),!0}}updateSessionHeartbeat(){try{"undefined"!=typeof Storage&&localStorage.setItem(this.session_storage_key,JSON.stringify({sessionId:this.session_id,timestamp:Date.now(),instanceKey:this.instance_key}))}catch(e){console.warn("Session heartbeat update failed:",e)}}startHeartbeat(){this.heartbeat_interval=window.setInterval((()=>{this.updateSessionHeartbeat()}),3e4)}stopHeartbeat(){this.heartbeat_interval&&(clearInterval(this.heartbeat_interval),this.heartbeat_interval=void 0)}cleanupSession(){try{if("undefined"!=typeof Storage){const e=localStorage.getItem(this.session_storage_key);if(e){JSON.parse(e).sessionId===this.session_id&&localStorage.removeItem(this.session_storage_key)}}}catch(e){console.warn("Session cleanup failed:",e)}this.stopHeartbeat()}handleSessionConflictMessage(e){console.error("Session conflict detected by server:",e);let t="Session conflict detected by server.";"session_conflict"===e.type?t=e.error||t:"session_corruption"===e.type&&(t=`Session corruption detected.\nExpected: ${e.expected}\nReceived: ${e.received}`),alert(t+"\n\nThis window will be closed to prevent data corruption."),this.cleanupSession();const s=new CustomEvent("cubevis_session_conflict",{detail:{message:e,sessionId:this.session_id}});window.dispatchEvent(s),setTimeout((()=>{window.opener||1===window.history.length?window.close():window.location.href="about:blank"}),2e3)}generateInstanceKey(){return`${this.instance_id}_${this.backend_port}`}async initializeWebSocket(){console.log(" datapipe url:",this.backend_url),console.log(`datapipe ip/port: ${this.backend_ip}/${this.backend_port}`);var e=void 0;document.shutdown_in_progress_=!1;var t=async()=>{void 0!==this.websocket&&this.websocket.close();const s=this.backend_url,i=s.replace("wss://","https://");try{console.log(" priming proxy session..."),await fetch(i,{mode:"no-cors"}),this.websocket=new WebSocket(s),this.websocket.binaryType="arraybuffer"}catch(e){console.error("Proxy wake-up failed",e),this.websocket=new WebSocket(s),this.websocket.binaryType="arraybuffer"}this.websocket.addEventListener("error",(e=>{console.log("error encountered:",e)})),this.websocket.onmessage=e=>{if("string"==typeof e.data||e.data instanceof String){let t=(0,c.deserialize)(e.data);if("id"in t&&"direction"in t&&"message"in t){let{id:e,message:s,direction:i}=t;if("error"===i&&("session_conflict"===e||e===this.session_id)&&s&&("session_conflict"===s.type||"session_corruption"===s.type||"close_duplicate"===s.action))return void this.handleSessionConflictMessage(s);if(void 0===s&&console.log("Error, event failure",t),"j2p"==i)if(e in this.pending){let{cb:i}=this.pending[e];if(delete this.pending[e],e in this.send_queue&&this.send_queue[e].length>0){let{cb:t,msg:s}=this.send_queue[e].shift();this.pending[e]={cb:t},this.websocket.send((0,c.serialize)(s))}void 0===s?console.log("DROPPING ERROR FOR NOW (maybe need error callbacks)",t):i(s)}else console.log("message received but could not find id");else if(e in this.incoming_callbacks){let t=this.incoming_callbacks[e](s);this.websocket.send((0,c.serialize)({id:e,direction:i,message:t,session:this.session_id}))}}else console.log(`datapipe received message without one of 'id', 'message' or 'direction': ${t}`)}else console.log("datapipe received binary data",e.data.byteLength,"bytes")},this.websocket.onopen=()=>{for(console.log(">>> DATAPIPE CONNECTED"),e?0==e.connected&&console.log(`connection reestablished at ${new Date}`):(this.websocket.send((0,c.serialize)({id:"initialize",direction:"j2p",session:this.session_id})),this.startHeartbeat()),e=new casalib.ReconnectState;this.connection_queue.length>0;){let e=this.connection_queue.shift();this.send.apply(e[0],e[1])}},this.websocket.onclose=()=>{if(e&&1==e.connected&&(console.log(`connection lost at ${new Date}`),e.connected=!1,!document.shutdown_in_progress_)){console.log(`connection lost at ${new Date}`);var s=e;function i(n){0==e.connected&&(console.log(`${n+1}\treconnection attempt ${new Date}`),t(),s.backoff(),s.retries>0?setTimeout(i,s.timeout,n+1):0==e.connected&&console.log(`aborting reconnection after ${n} attempts ${new Date}`))}i(0)}}};window.addEventListener("beforeunload",(()=>{this.cleanupSession()})),document.addEventListener("visibilitychange",(()=>{"hidden"===document.visibilityState?this.stopHeartbeat():"visible"===document.visibilityState&&(this.updateSessionHeartbeat(),this.startHeartbeat())})),t()}initialize(){if(super.initialize(),l.activeDataPipes.register(this),this.instance_key=this.generateInstanceKey(),this.session_storage_key=`cubevis_datapipe_${this.instance_key}`,!this.checkSessionConflict())return;this.initializeWebSocket();(()=>{null!=this.init_script&&(0,r.execute)(this.init_script,this)})()}destroy(){l.activeDataPipes.unregister(this),super.destroy()}register(e,t){this.incoming_callbacks[e]=t}send(e,t,s,i=!1){let n={id:e,message:t,direction:"j2p",session:this.session_id};if(!this.websocket||e in this.pending)if(e in this.send_queue)if("boolean"==typeof i&&i&&this.send_queue[e].length>0)this.send_queue[e][0].msg=n,this.send_queue[e][0].cb=s;else if("function"==typeof i&&this.send_queue[e].length>0){let o=!1;for(const a of this.send_queue[e])i(a.msg.message)&&(a.msg=n,a.cb=s,o=!0);o||this.send_queue[e].push({cb:s,msg:n})}else this.send_queue[e].push({cb:s,msg:n});else this.send_queue[e]=[{cb:s,msg:n}];else if(this.websocket.readyState===WebSocket.CONNECTING)this.connection_queue.push([this,[e,t,s]]);else if(e in this.send_queue&&this.send_queue[e].length>0){this.send_queue[e].push({cb:s,msg:n});{let{cb:r,msg:l}=this.send_queue[e].shift();if(this.pending[e]={cb:r},this.websocket.readyState===WebSocket.OPEN)this.websocket.send((0,c.serialize)(l));else{let d=20,h=this;function u(){h.websocket.readyState===WebSocket.OPEN?h.websocket.send((0,c.serialize)(l)):(d-=1,d>0&&setTimeout(u,3e3))}setTimeout(u,3e3)}}}else if(this.websocket.readyState===WebSocket.OPEN)this.pending[e]={cb:s},this.websocket.send((0,c.serialize)(n));else{let b=20,g=this;function p(){g.websocket.readyState===WebSocket.OPEN?(g.pending[e]={cb:s},g.websocket.send((0,c.serialize)(n))):(b-=1,b>0&&setTimeout(p,3e3))}setTimeout(p,3e3)}}}s.DataPipe=d,o=d,d.__name__="DataPipe",d.__module__="cubevis.bokeh.sources._data_pipe",o.define((({Any:e,Str:t,Int:s,Bool:i,Nullable:n})=>({init_script:[n(e),null],backend_ip:[t,"127.0.0.1"],backend_port:[s],backend_url:[t],instance_id:[t],conflict_check:[i,!0]})))},
47
47
  "e3901fa9f2": function _(e,r,s,i,o){i();const l=e("@bokehjs/base"),a=e("@bokehjs/core/resolvers"),t=e("@bokehjs/core/serialization/deserializer"),n=e("@bokehjs/core/serialization/serializer"),{deserialize:c}=new class{constructor(){this.resolver=new a.ModelResolver(l.default_resolver),this.deserializer=new t.Deserializer(this.resolver),this.deserialize=e=>{try{return this.deserializer.decode(JSON.parse(e))}catch(r){return console.group("deserialize error"),console.log(e),console.log(r),console.groupEnd(),{}}}}};s.deserialize=c;const{serialize:z}=new class{constructor(){this.serializer=new n.Serializer,this.serialize=e=>JSON.stringify(this.serializer.encode(e))}};s.serialize=z},
48
48
  "5179d11e71": function _(a,e,n,c,t){c();const i=a("30b45c52a1");n.activeDataPipes=new i.ModelManager},
49
49
  "30b45c52a1": function _(e,n,s,t,i){t();class r{constructor(){this.instances=new Map}register(e){this.instances.set(e.id,e),console.log(`registered instance ${e.id}`)}unregister(e){this.instances.delete(e.id),console.log(`unregistered instance ${e.id}`)}getInstances(){return Array.from(this.instances.values())}getInstance(e){return this.instances.get(e)}}s.ModelManager=r,r.__name__="ModelManager"},
50
- "2889e0dd45": function _(i,s,e,t,n){var a;t();const o=i("@bokehjs/models/sources/column_data_source"),d=i("31b6f4b4a1");class r extends d.DataPipe{constructor(i){super(i),this.position={},this._wcs=null}initialize(){super.initialize(),this.fits_header_json&&(this._wcs=new casalib.coordtxl.WCSTransform(new casalib.coordtxl.MapKeywordProvider(JSON.parse(this.fits_header_json))))}channel(i,s,e){this.position[e]={index:i};let t={action:"channel",index:i,id:e};super.send(this.dataid,t,(i=>{null!=this._histogram_source&&"hist"in i&&"top"in i.hist&&"bottom"in i.hist&&"left"in i.hist&&"right"in i.hist&&(this._histogram_source.data=i.hist),s(i)}))}spectrum(i,s,e,t=!1){let n={action:"spectrum",index:i,id:e};super.send(this.dataid,n,s,t)}adjust_colormap(i,s,e,t,n=!1){const a={action:"adjust-colormap",bounds:i,transfer:s,id:t};super.send(this.dataid,a,e,n)}refresh(i,s,e=[0,0]){let{index:t}=s in this.position?this.position[s]:{index:e};if(2===t.length){let e={action:"channel",index:t,id:s};super.send(this.dataid,e,i)}else if(3===t.length){let e={action:"spectrum",index:t,id:s};super.send(this.dataid,e,i)}}wcs(){return this._wcs}}e.ImagePipe=r,a=r,r.__name__="ImagePipe",r.__module__="cubevis.bokeh.sources._image_pipe",a.define((({Number:i,Nullable:s,String:e,Tuple:t,Ref:n})=>({dataid:[e],shape:[t(i,i,i,i)],fits_header_json:[s(e),null],_histogram_source:[s(n(o.ColumnDataSource)),null]})))},
50
+ "2889e0dd45": function _(i,e,s,t,n){var a;t();const o=i("@bokehjs/models/sources/column_data_source"),d=i("7a1eeba81e");class r extends d.DataPipe{constructor(i){super(i),this.position={},this._wcs=null}initialize(){super.initialize(),this.fits_header_json&&(this._wcs=new casalib.coordtxl.WCSTransform(new casalib.coordtxl.MapKeywordProvider(JSON.parse(this.fits_header_json))))}channel(i,e,s){this.position[s]={index:i};let t={action:"channel",index:i,id:s};super.send(this.dataid,t,(i=>{null!=this._histogram_source&&"hist"in i&&"top"in i.hist&&"bottom"in i.hist&&"left"in i.hist&&"right"in i.hist&&(this._histogram_source.data=i.hist),e(i)}))}spectrum(i,e,s,t=!1){let n={action:"spectrum",index:i,id:s};super.send(this.dataid,n,e,t)}adjust_colormap(i,e,s,t,n=!1){const a={action:"adjust-colormap",bounds:i,transfer:e,id:t};super.send(this.dataid,a,s,n)}refresh(i,e,s=[0,0]){let{index:t}=e in this.position?this.position[e]:{index:s};if(2===t.length){let s={action:"channel",index:t,id:e};super.send(this.dataid,s,i)}else if(3===t.length){let s={action:"spectrum",index:t,id:e};super.send(this.dataid,s,i)}}wcs(){return this._wcs}}s.ImagePipe=r,a=r,r.__name__="ImagePipe",r.__module__="cubevis.bokeh.sources._image_pipe",a.define((({Number:i,Nullable:e,String:s,Tuple:t,Ref:n})=>({dataid:[s],shape:[t(i,i,i,i)],fits_header_json:[e(s),null],_histogram_source:[e(n(o.ColumnDataSource)),null]})))},
51
51
  "de65005924": function _(s,a,t,c,i){var o;c();const e=s("@bokehjs/models/sources/column_data_source"),n=s("@bokehjs/core/util/string"),u=s("2889e0dd45"),h=s("@bokehjs/core/util/callbacks");class r extends e.ColumnDataSource{constructor(s){super(s),this.imid=(0,n.uuid4)()}_mask_contour(s){const a=casalib.d3.contours().size(this.image_source.shape.slice(0,2)).thresholds([1])(s[0])[0].coordinates.map((s=>s.map((s=>s.reduce(((s,a)=>(s[0].push(a[0]),s[1].push(a[1]),s)),[[],[]])))));return{xs:[a.map((s=>s.map((s=>s[0]))))],ys:[a.map((s=>s.map((s=>s[1]))))]}}initialize(){if(super.initialize(),null!=this._mask_contour_source&&"msk"in this.data&&this.data.msk.length>0&&this.data.msk[0].length>0){const s=this.data.msk;this._mask_contour_source.data=this._mask_contour(s)}void 0===this.last_chan&&(this.last_chan=[this.cur_chan[0].valueOf(),this.cur_chan[1].valueOf()]);(()=>{null!=this.init_script&&(0,h.execute)(this.init_script,this)})()}channel(s,a=0,t){this.image_source.channel([a,s],(c=>{void 0!==c&&void 0!==c.chan||console.log("ImageDataSource ERROR ENCOUNTERED <1>",c),this.last_chan=[this.cur_chan[0].valueOf(),this.cur_chan[1].valueOf()],this.cur_chan=[a,s],null!=this._mask_contour_source&&"chan"in c&&"msk"in c.chan&&(c.msk_contour=this._mask_contour(c.chan.msk),this._mask_contour_source.data=c.msk_contour),t&&t(c),this.data=c.chan}),this.imid)}adjust_colormap(s,a,t){this.image_source.adjust_colormap(s,a,t,this.imid,!0)}signal_change(){this.change.emit()}refresh(s){this.image_source.refresh((a=>{void 0!==a&&void 0!==a.chan||console.log("ImageDataSource ERROR ENCOUNTERED <2>",a),null!=this._mask_contour_source&&"chan"in a&&"msk"in a.chan&&(a.msk_contour=this._mask_contour(a.chan.msk),this._mask_contour_source.data=a.msk_contour),s&&s(a),this.data=a.chan}),this.imid,[0,0])}wcs(){return this.image_source.wcs()}}t.ImageDataSource=r,o=r,r.__name__="ImageDataSource",r.__module__="cubevis.bokeh.sources._image_data_source",o.define((({Tuple:s,Number:a,Ref:t,Nullable:c,Any:i})=>({init_script:[i,null],image_source:[t(u.ImagePipe)],_mask_contour_source:[c(t(e.ColumnDataSource)),null],num_chans:[s(a,a)],cur_chan:[s(a,a)]})))},
52
52
  "02e3c3e46c": function _(e,s,i,t,r){var a;t();const c=e("@bokehjs/models/sources/column_data_source"),u=e("@bokehjs/core/util/string"),o=e("2889e0dd45");class _ extends c.ColumnDataSource{constructor(e){super(e),this.imid=(0,u.uuid4)()}initialize(){super.initialize()}spectra(e,s,i=0,t=!1){this.image_source.spectrum([e,s,i],(e=>this.data=e.spectrum),this.imid,t)}refresh(){this.image_source.refresh((e=>this.data=e.spectrum),this.imid,[0,0,0])}}i.SpectraDataSource=_,a=_,_.__name__="SpectraDataSource",_.__module__="cubevis.bokeh.sources._spectra_data_source",a.define((({Ref:e})=>({image_source:[e(o.ImagePipe)]})))},
53
- "64b16deff9": function _(e,s,i,t,a){var n;t();const u=e("@bokehjs/models/sources/column_data_source"),l=e("31b6f4b4a1"),o=e("@bokehjs/core/util/callbacks");class c extends u.ColumnDataSource{constructor(e){super(e)}send(e,s){this.pipe.send(this.session_id.valueOf(),{action:"callback",message:e},(e=>{s("result"in e?e.result:{error:`expected to find a "result" in "${e}"`,msg:e})}))}initialize(){super.initialize();(()=>{null!=this.js_init&&(0,o.execute)(this.js_init,this)})()}}i.UpdatableDataSource=c,n=c,c.__name__="UpdatableDataSource",c.__module__="cubevis.bokeh.sources._updatable_data_source",n.define((({Ref:e,Any:s,String:i})=>({js_init:[s,null],js_update:[s,null],pipe:[e(l.DataPipe)],session_id:[i]})))},
53
+ "64b16deff9": function _(e,s,i,a,t){var n;a();const u=e("@bokehjs/models/sources/column_data_source"),l=e("7a1eeba81e"),o=e("@bokehjs/core/util/callbacks");class c extends u.ColumnDataSource{constructor(e){super(e)}send(e,s){this.pipe.send(this.session_id.valueOf(),{action:"callback",message:e},(e=>{s("result"in e?e.result:{error:`expected to find a "result" in "${e}"`,msg:e})}))}initialize(){super.initialize();(()=>{null!=this.js_init&&(0,o.execute)(this.js_init,this)})()}}i.UpdatableDataSource=c,n=c,c.__name__="UpdatableDataSource",c.__module__="cubevis.bokeh.sources._updatable_data_source",n.define((({Ref:e,Any:s,String:i})=>({js_init:[s,null],js_update:[s,null],pipe:[e(l.DataPipe)],session_id:[i]})))},
54
54
  "b6ae454f0d": function _(s,i,o,t,e){var r;t();const a=s("@bokehjs/models/formatters/tick_formatter"),c=s("de65005924");class l extends a.TickFormatter{constructor(s){super(s),this._axis=null,this._coord="world"}initialize(){super.initialize(),"x"==this.axis||"X"==this.axis||"y"==this.axis||"Y"==this.axis?this._axis="x"==this.axis||"X"==this.axis?"x":"y":console.log("ERROR: WcsTicks formatter created with invalid axis:",this.axis)}doFormat(s){const i=[];if(this._axis&&this.image_source.wcs()&&"world"==this._coord)for(let o=0,t=s.length;o<t;o++)if("x"==this._axis){const t=new casalib.coordtxl.Point2D(Number(s[o]),0);this.image_source.wcs().imageToWorldCoords(t,!1),i.push(new casalib.coordtxl.WorldCoords(t.getX(),t.getY()).format(2e3)[0])}else{const t=new casalib.coordtxl.Point2D(0,Number(s[o]));this.image_source.wcs().imageToWorldCoords(t,!1),i.push(new casalib.coordtxl.WorldCoords(t.getX(),t.getY()).format(2e3)[1])}else for(let o=0,t=s.length;o<t;o++)i.push(""+s[o]);return i}coordinates(s){return s!=this._coord&&("world"!=s&&"pixel"!=s||(this._coord=s)),this._coord}}o.WcsTicks=l,r=l,l.__name__="WcsTicks",l.__module__="cubevis.bokeh.format._wcs_ticks",r.define((({Ref:s,String:i})=>({axis:[i],image_source:[s(c.ImageDataSource)]})))},
55
55
  "cb7d28d6b3": function _(i,e,t,o,s){var d;o();const l=i("@bokehjs/models/tools/gestures/gesture_tool"),r=i("8fc7a9e935"),_=i("484bb85d20"),m=i("@bokehjs/core/util/callbacks");class a extends l.GestureToolView{_pan_start(i){var e;null===(e=this.model.document)||void 0===e||e.interactive_start(this.plot_view.model);const t=(0,_.px_from_sx)(this.plot_view,i.sx),o=(0,_.py_from_sy)(this.plot_view,i.sy),s=(0,_.dx_from_px)(this.plot_view,t),d=(0,_.dy_from_py)(this.plot_view,o),{start:l}=this.model;l?(0,m.execute)(l,this.model,{sx:t,sy:o,x:s,y:d,delta_x:i.dx,delta_y:-i.dy,shift:"modifiers"in i?i.modifiers.shift:void 0,ctrl:"modifiers"in i?i.modifiers.ctrl:void 0,alt:"modifiers"in i?i.modifiers.alt:void 0}):this.model.trigger_event(new r.DragStart(t,o,s,d,i.dx,-i.dy,i.modifiers))}_pan(i){var e;null===(e=this.model.document)||void 0===e||e.interactive_start(this.plot_view.model);const t=(0,_.px_from_sx)(this.plot_view,i.sx),o=(0,_.py_from_sy)(this.plot_view,i.sy),s=(0,_.dx_from_px)(this.plot_view,t),d=(0,_.dy_from_py)(this.plot_view,o),{move:l}=this.model;l?(0,m.execute)(l,this.model,{sx:t,sy:o,x:s,y:d,delta_x:i.dx,delta_y:-i.dy,shift:"modifiers"in i?i.modifiers.shift:void 0,ctrl:"modifiers"in i?i.modifiers.ctrl:void 0,alt:"modifiers"in i?i.modifiers.alt:void 0}):this.model.trigger_event(new r.Drag(t,o,s,d,i.dx,-i.dy,i.modifiers))}_pan_end(i){const e=(0,_.px_from_sx)(this.plot_view,i.sx),t=(0,_.py_from_sy)(this.plot_view,i.sy),o=(0,_.dx_from_px)(this.plot_view,e),s=(0,_.dy_from_py)(this.plot_view,t),{end:d}=this.model;d?(0,m.execute)(d,this.model,{sx:e,sy:t,x:o,y:s,delta_x:i.dx,delta_y:-i.dy,shift:"modifiers"in i?i.modifiers.shift:void 0,ctrl:"modifiers"in i?i.modifiers.ctrl:void 0,alt:"modifiers"in i?i.modifiers.alt:void 0}):this.model.trigger_event(new r.DragEnd(e,t,o,s,i.dx,-i.dy,i.modifiers))}}t.DragToolView=a,a.__name__="DragToolView";class n extends l.GestureTool{constructor(i){super(i),this.tool_name="Drag",this.event_type="pan",this.default_order=10}}t.DragTool=n,d=n,n.__name__="DragTool",n.__module__="cubevis.bokeh.tools._drag_tool",d.prototype.default_view=a,d.define((({Any:i,Nullable:e})=>({start:[e(i),null],move:[e(i),null],end:[e(i),null]})))},
56
56
  "8fc7a9e935": function _(e,t,a,s,_){s();const n=e("@bokehjs/core/bokeh_events");class r extends n.Pan{}a.Drag=r,r.__name__="Drag";class l extends n.PanStart{constructor(e,t,a,s,_,n,r){super(e,t,a,s,r),this.delta_x=_,this.delta_y=n}get event_values(){const{delta_x:e,delta_y:t}=this;return{...super.event_values,delta_x:e,delta_y:t}}}a.DragStart=l,l.__name__="DragStart";class d extends n.PanEnd{constructor(e,t,a,s,_,n,r){super(e,t,a,s,r),this.delta_x=_,this.delta_y=n}get event_values(){const{delta_x:e,delta_y:t}=this;return{...super.event_values,delta_x:e,delta_y:t}}}a.DragEnd=d,d.__name__="DragEnd"},
@@ -64,4 +64,4 @@
64
64
  "b55081402e": function _(e,n,t,_,s){var a;_();const o=e("@bokehjs/models/annotations/span"),p=e("@bokehjs/core/bokeh_events");class r extends o.SpanView{on_pan_start(e){const n=super.on_pan_start(e);return this.model.trigger_event(new p.LODStart),n}on_pan(e){super.on_pan(e)}on_pan_end(e){super.on_pan_end(e),this.model.trigger_event(new p.LODEnd)}}t.EditSpanView=r,r.__name__="EditSpanView";class d extends o.Span{constructor(e){super(e)}}t.EditSpan=d,a=d,d.__name__="EditSpan",d.__module__="cubevis.bokeh.models._edit_span",a.prototype.default_view=r},
65
65
  "9144bfc7a5": function _(e,t,s,n,r){var i;n();const l=e("@bokehjs/models/widgets/text_input"),o=e("@bokehjs/core/dom"),u=e("@bokehjs/core/bokeh_events");class _ extends l.TextInputView{stylesheets(){return[...super.stylesheets(),new o.InlineStyleSheet(".bk-input-prefix { padding: 0 var(--padding-vertical); }")]}connect_signals(){super.connect_signals(),this.el.addEventListener("mouseenter",(e=>{this.model.trigger_event(new u.MouseEnter(e.screenX,e.screenY,e.x,e.y,{shift:e.shiftKey,ctrl:e.ctrlKey,alt:e.altKey}))})),this.el.addEventListener("mouseleave",(e=>{this.model.trigger_event(new u.MouseLeave(e.screenX,e.screenY,e.x,e.y,{shift:e.shiftKey,ctrl:e.ctrlKey,alt:e.altKey}))}))}render(){super.render()}}s.EvTextInputView=_,_.__name__="EvTextInputView";class c extends l.TextInput{constructor(e){super(e)}}s.EvTextInput=c,i=c,c.__name__="EvTextInput",c.__module__="cubevis.bokeh.models._ev_text_input",i.prototype.default_view=_},
66
66
  "74e0abef8a": function _(e,t,n,s,o){var i;s();const r=e("@bokehjs/models/annotations/poly_annotation"),a=e("@bokehjs/core/bokeh_events");class _ extends r.PolyAnnotationView{on_enter(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.MouseEnter(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt}),o=super.on_enter(e);return this.model.trigger_event(s),o}on_leave(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.MouseLeave(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt});super.on_leave(e),this.model.trigger_event(s)}on_pan_start(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.PanStart(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt}),o=super.on_pan_start(e);return this.model.trigger_event(s),o}on_pan_end(e){const{x_scale:t,y_scale:n}=this.plot_view.frame,s=new a.PanEnd(e.sx,e.sy,t.invert(e.sx),n.invert(e.sy),{shift:e.modifiers.shift,ctrl:e.modifiers.ctrl,alt:e.modifiers.alt});super.on_pan_end(e),this.model.trigger_event(s)}on_pan(e){super.on_pan(e);const t=new a.RangesUpdate(e.sx,e.sx+e.dx,e.sy,e.sy+e.dy);this.model.trigger_event(t)}}n.EvPolyAnnotationView=_,_.__name__="EvPolyAnnotationView";class l extends r.PolyAnnotation{constructor(e){super(e)}}n.EvPolyAnnotation=l,i=l,l.__name__="EvPolyAnnotation",l.__module__="cubevis.bokeh.annotations._ev_poly_annotation",i.prototype.default_view=_},
67
- }, "07c9fde72b", {"index":"07c9fde72b","src/bokeh/sources/data_pipe":"31b6f4b4a1","src/bokeh/util/conversions":"e3901fa9f2","src/bokeh/sources/active_data_pipes":"5179d11e71","src/bokeh/util/model_manager":"30b45c52a1","src/bokeh/sources/image_pipe":"2889e0dd45","src/bokeh/sources/image_data_source":"de65005924","src/bokeh/sources/spectra_data_source":"02e3c3e46c","src/bokeh/sources/updatable_data_source":"64b16deff9","src/bokeh/format/wcs_ticks":"b6ae454f0d","src/bokeh/tools/drag_tool":"cb7d28d6b3","src/bokeh/events":"8fc7a9e935","src/bokeh/util/find":"484bb85d20","src/bokeh/tools/cbreset_tool":"9d3c34ff8e","src/bokeh/models/tip_button":"9f961622ce","src/bokeh/models/tip":"ca4c845905","src/bokeh/models/showable":"a6e757a69a","src/bokeh/models/bokeh_app_context":"467d2716b0","src/bokeh/models/shared_dict":"50a1e32f01","src/bokeh/models/edit_span":"b55081402e","src/bokeh/models/ev_text_input":"9144bfc7a5","src/bokeh/annotations/ev_poly_annotation":"74e0abef8a"}, {});});
67
+ }, "07c9fde72b", {"index":"07c9fde72b","src/bokeh/sources/data_pipe":"7a1eeba81e","src/bokeh/util/conversions":"e3901fa9f2","src/bokeh/sources/active_data_pipes":"5179d11e71","src/bokeh/util/model_manager":"30b45c52a1","src/bokeh/sources/image_pipe":"2889e0dd45","src/bokeh/sources/image_data_source":"de65005924","src/bokeh/sources/spectra_data_source":"02e3c3e46c","src/bokeh/sources/updatable_data_source":"64b16deff9","src/bokeh/format/wcs_ticks":"b6ae454f0d","src/bokeh/tools/drag_tool":"cb7d28d6b3","src/bokeh/events":"8fc7a9e935","src/bokeh/util/find":"484bb85d20","src/bokeh/tools/cbreset_tool":"9d3c34ff8e","src/bokeh/models/tip_button":"9f961622ce","src/bokeh/models/tip":"ca4c845905","src/bokeh/models/showable":"a6e757a69a","src/bokeh/models/bokeh_app_context":"467d2716b0","src/bokeh/models/shared_dict":"50a1e32f01","src/bokeh/models/edit_span":"b55081402e","src/bokeh/models/ev_text_input":"9144bfc7a5","src/bokeh/annotations/ev_poly_annotation":"74e0abef8a"}, {});});
@@ -314,10 +314,6 @@ class Showable(LayoutDOM,BokehInit):
314
314
  for url in js_paths
315
315
  ])
316
316
 
317
- print( "-----scripts-being-used-----------------------------------------------" )
318
- print( all_scripts )
319
- print( "----------------------------------------------------------------------" )
320
-
321
317
  # Use json_item approach which is more reliable in iframes
322
318
  item = json_item(self, target=f"bokeh-{self.id}")
323
319
  item_json = json_lib.dumps(item)
@@ -71,7 +71,9 @@ class DataPipe(DataSource,BokehInit):
71
71
  JavaScript to be run during initialization of an instance of an DataPipe object.
72
72
  """)
73
73
 
74
- address = Tuple( String, Int, help="two integer sequence representing the address and port to use for the websocket" )
74
+ backend_ip = String(default="127.0.0.1", help="the IP address that the Python server binds to locally" )
75
+ backend_port = Int( help="the port that the Python server listens on" )
76
+ backend_url = String( help="the full URL used by the browser to connect to the Python server" )
75
77
 
76
78
  instance_id = String( help="Unique ID for each DataPipe object" )
77
79
 
@@ -86,34 +88,17 @@ class DataPipe(DataSource,BokehInit):
86
88
  ###################################################################
87
89
  #__javascript__ = [ casalib_url( ), cubevisjs_url( ) ]
88
90
 
89
- def _expose_colab_port(self):
90
- """Expose the WebSocket port through Colab's proxy"""
91
- try:
92
- from google.colab import output
93
- port = self.address[1]
94
-
95
- # Use serve_kernel_port_as_iframe for newer Colab
96
- # This doesn't open a popup, just registers the port
97
- try:
98
- output.serve_kernel_port_as_iframe(port)
99
- print(f"✓ Colab: Exposed WebSocket port {port} via iframe proxy")
100
- except AttributeError:
101
- # Fallback to older method
102
- output.serve_kernel_port_as_window(port)
103
- print(f"✓ Colab: Exposed WebSocket port {port} via window proxy")
104
-
105
- except Exception as e:
106
- print(f"⚠ Warning: Could not expose port {port} in Colab: {e}")
107
- import traceback
108
- traceback.print_exc()
109
-
110
- def __init__( self, *args, abort=None, **kwargs ):
91
+ def __init__( self, *args, abort=None, address=None, **kwargs ):
111
92
 
112
93
  if 'conflict_check' not in kwargs:
113
94
  kwargs['conflict_check'] = not is_interactive_jupyter( )
114
95
  if 'instance_id' not in kwargs:
115
96
  kwargs['instance_id'] = str(uuid4( ))
116
97
 
98
+ if address is not None:
99
+ kwargs['backend_ip'] = address[0]
100
+ kwargs['backend_port'] = address[1]
101
+
117
102
  super( ).__init__( *args, **kwargs )
118
103
 
119
104
  self.__send_queue = { }
@@ -127,9 +112,15 @@ class DataPipe(DataSource,BokehInit):
127
112
  if self.__abort is not None and not callable(self.__abort):
128
113
  raise RuntimeError(f'abort function must be callable ({type(self.__abort)} is not)')
129
114
 
130
- # Expose port in Colab
115
+ # Fetch URL in Colab
131
116
  if is_colab( ):
132
- self._expose_colab_port()
117
+ from google.colab.output import eval_js
118
+ # Colab maps the internal port to a secure external URL
119
+ external_https = eval_js(f"google.colab.kernel.proxyPort({self.backend_port})")
120
+ self.backend_url = external_https.replace("https://", "wss://")
121
+ else:
122
+ # Standard local/remote access
123
+ self.backend_url = f"ws://{self.backend_ip}:{self.backend_port}"
133
124
 
134
125
  def __enqueue_send( self, ident, msg, callback ):
135
126
  ### it is assumed that this is called AFTER the lock has been aquired
@@ -291,7 +282,7 @@ class DataPipe(DataSource,BokehInit):
291
282
  self.__websocket = websocket
292
283
  session_established = False
293
284
 
294
- print(f"✓ WebSocket server received connection on port {self.address[1]}")
285
+ print(f"✓ WebSocket server received connection on port {self.backend_port}")
295
286
 
296
287
  async for message in websocket:
297
288
  msg = deserialize(message)
@@ -34,10 +34,10 @@ from bokeh.plotting import ColumnDataSource
34
34
  from bokeh.core.properties import Instance, String, Nullable
35
35
  from bokeh.models.callbacks import Callback
36
36
  from bokeh.models import CustomJS
37
- import websockets
38
37
  from ._data_pipe import DataPipe
39
38
  from ..state import casalib_url, cubevisjs_url
40
39
  from ...utils import find_ws_address
40
+ from .transport import create_ws_server
41
41
  from .. import BokehInit
42
42
 
43
43
  class UpdatableDataSource(ColumnDataSource,BokehInit):
@@ -189,5 +189,5 @@ class UpdatableDataSource(ColumnDataSource,BokehInit):
189
189
  raise RuntimeError( 'UpdatableDataSource.serve should only be called for when a "pipe" is NOT supplied as part of initialization' )
190
190
 
191
191
  self._stop_serving_function = stop_function
192
- async with websockets.serve( self.pipe.process_messages, self.pipe.address[0], self.pipe.address[1] ) as msgpipe:
192
+ async with create_ws_server( self.pipe.process_messages, self.pipe.backend_ip, self.pipe.backend_port ) as msgpipe:
193
193
  yield { 'msgpipe': msgpipe }
@@ -0,0 +1,12 @@
1
+ import websockets
2
+ from cubevis.utils import is_colab
3
+
4
+ def create_ws_server(callback, ip_address, port):
5
+ """
6
+ Uniform wrapper for creating a WebSocket server.
7
+ """
8
+ if is_colab( ):
9
+ print( f"websocket startup: {ip_address}/{port} (bind IP 0.0.0.0)" )
10
+ return websockets.serve( callback, "0.0.0.0", port, origins=None )
11
+ else:
12
+ return websockets.serve( callback, ip_address, port )
@@ -38,7 +38,6 @@ import asyncio
38
38
  from uuid import uuid4
39
39
  from sys import platform
40
40
  from os.path import dirname, join
41
- import websockets
42
41
  from contextlib import asynccontextmanager
43
42
  from bokeh.core.enums import HatchPattern as _hatch_patterns
44
43
  from bokeh.core.enums import DashPattern as _dash_patterns
@@ -59,6 +58,7 @@ from ..bokeh.models import EvTextInput, SharedDict
59
58
  from ..bokeh.tools import CBResetTool
60
59
  from ..bokeh.state import available_palettes, find_palette, default_palette
61
60
  from ..bokeh.annotations import EvPolyAnnotation
61
+ from ..bokeh.sources.transport import create_ws_server
62
62
  from bokeh.layouts import row, column
63
63
  from bokeh.models.dom import HTML
64
64
  from bokeh.models import Tooltip
@@ -2301,8 +2301,8 @@ class CubeMask:
2301
2301
  @asynccontextmanager
2302
2302
  async def serve( self, stop_function ):
2303
2303
  self._stop_serving_function = stop_function
2304
- async with websockets.serve( self._pipe['image'].process_messages, self._pipe['image'].address[0], self._pipe['image'].address[1] ) as im, \
2305
- websockets.serve( self._pipe['control'].process_messages, self._pipe['control'].address[0], self._pipe['control'].address[1] ) as ctrl:
2304
+ async with create_ws_server( self._pipe['image'].process_messages, self._pipe['image'].backend_ip, self._pipe['image'].backend_port ) as im, \
2305
+ create_ws_server( self._pipe['control'].process_messages, self._pipe['control'].backend_ip, self._pipe['control'].backend_port ) as ctrl:
2306
2306
  yield { 'im': im, 'ctrl': ctrl }
2307
2307
  #pass
2308
2308
 
@@ -34,7 +34,6 @@ import sys
34
34
  import copy
35
35
  import asyncio
36
36
  import shutil
37
- import websockets
38
37
  from os.path import basename, abspath, exists, join
39
38
  import numpy as np
40
39
  from uuid import uuid4
@@ -65,6 +64,7 @@ from cubevis.utils import find_ws_address, convert_masks
65
64
  from cubevis.toolbox import CubeMask
66
65
  from cubevis.bokeh.utils import svg_icon
67
66
  from cubevis.bokeh.sources import DataPipe
67
+ from cubevis.bokeh.sources.transport import create_ws_server
68
68
  from cubevis.utils import DocEnum
69
69
  from cubevis import exe
70
70
 
@@ -142,11 +142,11 @@ class InteractiveCleanUI:
142
142
  ###
143
143
  ### need to add extra cube ports here for multifield imaging
144
144
  ###
145
- ports = [ self._pipe['control'].address[1], self._clean['converge']['pipe'].address[1] ]
145
+ ports = [ self._pipe['control'].backend_port, self._clean['converge']['pipe'].backend_port ]
146
146
 
147
147
  for imid, imdetails in self._clean_targets.items( ):
148
- ports.append( imdetails['gui']['cube']._pipe['image'].address[1] )
149
- ports.append( imdetails['gui']['cube']._pipe['control'].address[1] )
148
+ ports.append( imdetails['gui']['cube']._pipe['image'].backend_port )
149
+ ports.append( imdetails['gui']['cube']._pipe['control'].backend_port )
150
150
 
151
151
  # Also forward http port if serving webpage
152
152
  #if not self._is_notebook:
@@ -1155,12 +1155,12 @@ class InteractiveCleanUI:
1155
1155
  [
1156
1156
  self._clean_targets[img]['gui']['cube'].serve(self.__stop),
1157
1157
  ]
1158
- ] + [ websockets.serve( self._pipe['control'].process_messages,
1159
- self._pipe['control'].address[0],
1160
- self._pipe['control'].address[1] ),
1161
- websockets.serve( self._clean['converge']['pipe'].process_messages,
1162
- self._clean['converge']['pipe'].address[0],
1163
- self._clean['converge']['pipe'].address[1] ) ]
1158
+ ] + [ create_ws_server( self._pipe['control'].process_messages,
1159
+ self._pipe['control'].backend_ip,
1160
+ self._pipe['control'].backend_port ),
1161
+ create_ws_server( self._clean['converge']['pipe'].process_messages,
1162
+ self._clean['converge']['pipe'].backend_ip,
1163
+ self._clean['converge']['pipe'].backend_port ) ]
1164
1164
  ) ):
1165
1165
  self.__result_future = asyncio.Future( )
1166
1166
  yield self.__result_future
@@ -33,7 +33,6 @@ import sys
33
33
  import copy
34
34
  import asyncio
35
35
  import shutil
36
- import websockets
37
36
  from os.path import basename, abspath, exists, join
38
37
  import numpy as np
39
38
  from uuid import uuid4
@@ -64,6 +63,7 @@ from cubevis.utils import find_ws_address, convert_masks
64
63
  from cubevis.toolbox import CubeMask
65
64
  from cubevis.bokeh.utils import svg_icon
66
65
  from cubevis.bokeh.sources import DataPipe
66
+ from cubevis.bokeh.sources.transport import create_ws_server
67
67
  from cubevis.utils import DocEnum
68
68
  from cubevis import exe
69
69
 
@@ -141,11 +141,11 @@ class InteractiveCleanUI:
141
141
  ###
142
142
  ### need to add extra cube ports here for multifield imaging
143
143
  ###
144
- ports = [ self._pipe['control'].address[1], self._clean['converge']['pipe'].address[1] ]
144
+ ports = [ self._pipe['control'].backend_port, self._clean['converge']['pipe'].backend_port ]
145
145
 
146
146
  for imid, imdetails in self._clean_targets.items( ):
147
- ports.append( imdetails['gui']['cube']._pipe['image'].address[1] )
148
- ports.append( imdetails['gui']['cube']._pipe['control'].address[1] )
147
+ ports.append( imdetails['gui']['cube']._pipe['image'].backend_port )
148
+ ports.append( imdetails['gui']['cube']._pipe['control'].backend_port )
149
149
 
150
150
  # Also forward http port if serving webpage
151
151
  #if not self._is_notebook:
@@ -1154,12 +1154,12 @@ class InteractiveCleanUI:
1154
1154
  [
1155
1155
  self._clean_targets[img]['gui']['cube'].serve(self.__stop),
1156
1156
  ]
1157
- ] + [ websockets.serve( self._pipe['control'].process_messages,
1158
- self._pipe['control'].address[0],
1159
- self._pipe['control'].address[1] ),
1160
- websockets.serve( self._clean['converge']['pipe'].process_messages,
1161
- self._clean['converge']['pipe'].address[0],
1162
- self._clean['converge']['pipe'].address[1] ) ]
1157
+ ] + [ create_ws_server( self._pipe['control'].process_messages,
1158
+ self._pipe['control'].backend_ip,
1159
+ self._pipe['control'].backend_port ),
1160
+ create_ws_server( self._clean['converge']['pipe'].process_messages,
1161
+ self._clean['converge']['pipe'].backend_ip,
1162
+ self._clean['converge']['pipe'].backend_port ) ]
1163
1163
  ) ):
1164
1164
  self.__result_future = asyncio.Future( )
1165
1165
  yield self.__result_future
@@ -16,7 +16,7 @@ dependencies = [
16
16
  ]
17
17
  requires-python = ">=3.11"
18
18
  readme = "README.rst"
19
- version = "1.0.35"
19
+ version = "1.0.44"
20
20
 
21
21
  [project.license]
22
22
  text = "LGPL"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes