@ohif/app 3.7.0-beta.41 → 3.7.0-beta.43

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 (33) hide show
  1. package/dist/{204.bundle.f344a75f87137ea091fa.js → 150.bundle.94cbce497cafacd4a7d7.js} +69 -92
  2. package/dist/{195.bundle.b56618d38bc184f8ef78.js → 202.bundle.ac1e5e25d4daf54581b1.js} +3697 -972
  3. package/dist/{236.bundle.970ce03f811085367829.js → 236.bundle.3c5f844ce9de4ec0777d.js} +1 -1
  4. package/dist/{281.bundle.c6a26ea22a160a15da31.js → 281.bundle.ac92bd142441f317f308.js} +14 -10
  5. package/dist/{348.bundle.64c2bd15557b5aece504.js → 348.bundle.323f57efcc2239950451.js} +12 -8
  6. package/dist/{359.bundle.9fdd66fa9a9846c2d051.js → 359.bundle.3ae0f07b1c428eeb00a8.js} +2 -1
  7. package/dist/{663.bundle.8d2ec1533aa8e75019a4.js → 663.bundle.2dcb8a60d59464f4e563.js} +4 -4
  8. package/dist/{678.bundle.dcd50fd210e1d7e2efb1.js → 678.bundle.13062f7926c30056aee1.js} +32 -104
  9. package/dist/{754.bundle.36f6f0f1c2cad1ffeadc.js → 754.bundle.8a16fc8ad21fe00c2e15.js} +11928 -7138
  10. package/dist/{774.bundle.e2cf44623c1268d8433d.js → 774.bundle.8ba82ee206266eb2da5e.js} +55 -33
  11. package/dist/{821.bundle.3a7b408c415336b6a010.js → 821.bundle.d4120df6baeed120be9e.js} +5 -3
  12. package/dist/{869.bundle.51e2fc87fab5cb911ec1.js → 869.bundle.c9c018e6757410919ed8.js} +3 -2
  13. package/dist/{925.bundle.150debc1fe2cafa1e036.js → 925.bundle.a2f1103d968c53a2b8fb.js} +26 -20
  14. package/dist/{app.bundle.94979d10759d179bbd10.js → app.bundle.2905ffdd301e3c34286e.js} +44 -24
  15. package/dist/cornerstoneDICOMImageLoader.min.js +1 -1
  16. package/dist/cornerstoneDICOMImageLoader.min.js.map +1 -1
  17. package/dist/index.html +1 -1
  18. package/dist/{index.worker.17eee78bdafa44cbb47d.worker.js → index.worker.e62ecca63f1a2e124230.worker.js} +2 -2
  19. package/dist/index.worker.e62ecca63f1a2e124230.worker.js.map +1 -0
  20. package/dist/sw.js +1 -1
  21. package/package.json +19 -20
  22. package/dist/899.bundle.dc9c8c0729bf29173303.js +0 -4769
  23. package/dist/index.worker.17eee78bdafa44cbb47d.worker.js.map +0 -1
  24. /package/dist/{12.bundle.e63fa108deddf4b48ad1.js → 12.bundle.f46296f27a36e6b95f76.js} +0 -0
  25. /package/dist/{128.bundle.819cdd5927e7cf4a4f93.js → 128.bundle.963d34d21c01231fc804.js} +0 -0
  26. /package/dist/{181.bundle.3c90dbb782b783e30fd8.js → 181.bundle.817ca1ba6479fca5fd15.js} +0 -0
  27. /package/dist/{30.bundle.51b446a6388a463d9550.js → 30.bundle.8fb93818b3a58f29f7e3.js} +0 -0
  28. /package/dist/{378.bundle.14cdd6874c4d80de89e7.js → 378.bundle.c908a6194c50544b45db.js} +0 -0
  29. /package/dist/{410.bundle.dbedca0b114b39c355c9.js → 410.bundle.b3cbeff9c619149a2234.js} +0 -0
  30. /package/dist/{506.bundle.90338adba4235e1da9ad.js → 506.bundle.44629077a406500707ea.js} +0 -0
  31. /package/dist/{782.bundle.aff17622ba9137558582.js → 782.bundle.c511611d980f9aa6563b.js} +0 -0
  32. /package/dist/{814.bundle.a37a7407a6b4523f5057.js → 814.bundle.8391ddacf39d7c699c5f.js} +0 -0
  33. /package/dist/{822.bundle.83c544a4283056f1331d.js → 822.bundle.34b66f1c1b27e7884df7.js} +0 -0
@@ -412,35 +412,6 @@ class BaseStreamingImageVolume_BaseStreamingImageVolume extends esm.ImageVolume
412
412
  (0,esm.triggerEvent)(esm.eventTarget, esm.Enums.Events.IMAGE_VOLUME_LOADING_COMPLETED, eventDetail);
413
413
  }
414
414
  }
415
- const successCallback = (imageIdIndex, imageId, scalingParameters) => {
416
- const frameIndex = this._imageIdIndexToFrameIndex(imageIdIndex);
417
- const cachedImage = esm.cache.getCachedImageBasedOnImageURI(imageId);
418
- if (loadStatus.cancelled) {
419
- console.warn('volume load cancelled, returning for imageIdIndex: ', imageIdIndex);
420
- return;
421
- }
422
- if (!cachedImage || !cachedImage.image) {
423
- return updateTextureAndTriggerEvents(this, imageIdIndex, imageId);
424
- }
425
- const imageScalarData = this._scaleIfNecessary(cachedImage.image, scalingParameters);
426
- const { pixelsPerImage, bytesPerImage } = this.cornerstoneImageMetaData;
427
- const TypedArray = scalarData.constructor;
428
- let byteOffset = bytesPerImage * frameIndex;
429
- const bytePerPixel = bytesPerImage / pixelsPerImage;
430
- if (scalarData.BYTES_PER_ELEMENT !== bytePerPixel) {
431
- byteOffset *= scalarData.BYTES_PER_ELEMENT / bytePerPixel;
432
- }
433
- const volumeBufferView = new TypedArray(arrayBuffer, byteOffset, pixelsPerImage);
434
- cachedImage.imageLoadObject.promise
435
- .then((image) => {
436
- volumeBufferView.set(imageScalarData);
437
- updateTextureAndTriggerEvents(this, imageIdIndex, imageId);
438
- })
439
- .catch((err) => {
440
- errorCallback.call(this, err, imageIdIndex, imageId);
441
- });
442
- return;
443
- };
444
415
  const updateTextureAndTriggerEvents = (volume, imageIdIndex, imageId) => {
445
416
  const frameIndex = this._imageIdIndexToFrameIndex(imageIdIndex);
446
417
  cachedFrames[imageIdIndex] = true;
@@ -479,6 +450,22 @@ class BaseStreamingImageVolume_BaseStreamingImageVolume extends esm.ImageVolume
479
450
  });
480
451
  }
481
452
  };
453
+ const successCallback = (imageIdIndex, imageId, scalingParameters) => {
454
+ const frameIndex = this._imageIdIndexToFrameIndex(imageIdIndex);
455
+ const cachedImage = esm.cache.getCachedImageBasedOnImageURI(imageId);
456
+ const cachedVolume = esm.cache.getVolumeContainingImageId(imageId);
457
+ if (loadStatus.cancelled) {
458
+ console.warn('volume load cancelled, returning for imageIdIndex: ', imageIdIndex);
459
+ return;
460
+ }
461
+ if (!cachedImage?.image &&
462
+ !(cachedVolume && cachedVolume.volume !== this)) {
463
+ return updateTextureAndTriggerEvents(this, imageIdIndex, imageId);
464
+ }
465
+ const isFromImageCache = !!cachedImage;
466
+ const cachedImageOrVolume = cachedImage || cachedVolume.volume;
467
+ this.handleImageComingFromCache(cachedImageOrVolume, isFromImageCache, scalingParameters, scalarData, frameIndex, arrayBuffer, updateTextureAndTriggerEvents, imageIdIndex, imageId, errorCallback);
468
+ };
482
469
  function errorCallback(error, imageIdIndex, imageId) {
483
470
  this.framesProcessed++;
484
471
  if (this.framesProcessed === totalNumFrames) {
@@ -668,7 +655,7 @@ class BaseStreamingImageVolume_BaseStreamingImageVolume extends esm.ImageVolume
668
655
  rgba: false,
669
656
  spacing: this.spacing,
670
657
  dimensions: this.dimensions,
671
- PhotometricInterpretation,
658
+ photometricInterpretation: PhotometricInterpretation,
672
659
  voiLUTFunction: VOILUTFunction,
673
660
  invert: PhotometricInterpretation === 'MONOCHROME1',
674
661
  };
@@ -703,6 +690,28 @@ class BaseStreamingImageVolume_BaseStreamingImageVolume extends esm.ImageVolume
703
690
  clearLoadCallbacks() {
704
691
  this.loadStatus.callbacks = [];
705
692
  }
693
+ handleImageComingFromCache(cachedImageOrVolume, isFromImageCache, scalingParameters, scalarData, frameIndex, arrayBuffer, updateTextureAndTriggerEvents, imageIdIndex, imageId, errorCallback) {
694
+ const imageLoadObject = isFromImageCache
695
+ ? cachedImageOrVolume.imageLoadObject
696
+ : cachedImageOrVolume.convertToCornerstoneImage(imageId, imageIdIndex);
697
+ imageLoadObject.promise
698
+ .then((cachedImage) => {
699
+ const imageScalarData = this._scaleIfNecessary(cachedImage, scalingParameters);
700
+ const { pixelsPerImage, bytesPerImage } = this.cornerstoneImageMetaData;
701
+ const TypedArray = scalarData.constructor;
702
+ let byteOffset = bytesPerImage * frameIndex;
703
+ const bytePerPixel = bytesPerImage / pixelsPerImage;
704
+ if (scalarData.BYTES_PER_ELEMENT !== bytePerPixel) {
705
+ byteOffset *= scalarData.BYTES_PER_ELEMENT / bytePerPixel;
706
+ }
707
+ const volumeBufferView = new TypedArray(arrayBuffer, byteOffset, pixelsPerImage);
708
+ volumeBufferView.set(imageScalarData);
709
+ updateTextureAndTriggerEvents(this, imageIdIndex, imageId);
710
+ })
711
+ .catch((err) => {
712
+ errorCallback.call(this, err, imageIdIndex, imageId);
713
+ });
714
+ }
706
715
  getImageLoadRequests(_priority) {
707
716
  throw new Error('Abstract method');
708
717
  }
@@ -774,10 +783,10 @@ class BaseStreamingImageVolume_BaseStreamingImageVolume extends esm.ImageVolume
774
783
  _removeFromCache() {
775
784
  esm.cache.removeVolumeLoadObject(this.volumeId);
776
785
  }
777
- convertToCornerstoneImage(imageId, imageIdIndex) {
786
+ getCornerstoneImage(imageId, imageIdIndex) {
778
787
  const { imageIds } = this;
779
788
  const frameIndex = this._imageIdIndexToFrameIndex(imageIdIndex);
780
- const { bytesPerImage, pixelsPerImage, windowCenter, windowWidth, numComponents, color, dimensions, spacing, invert, voiLUTFunction, } = this.cornerstoneImageMetaData;
789
+ const { bytesPerImage, pixelsPerImage, windowCenter, windowWidth, numComponents, color, dimensions, spacing, invert, voiLUTFunction, photometricInterpretation, } = this.cornerstoneImageMetaData;
781
790
  const scalarData = this._getScalarDataByImageIdIndex(imageIdIndex);
782
791
  const volumeBuffer = scalarData.buffer;
783
792
  const TypedArray = scalarData.constructor;
@@ -795,7 +804,7 @@ class BaseStreamingImageVolume_BaseStreamingImageVolume extends esm.ImageVolume
795
804
  const intercept = modalityLutModule.rescaleIntercept
796
805
  ? modalityLutModule.rescaleIntercept
797
806
  : 0;
798
- const image = {
807
+ return {
799
808
  imageId,
800
809
  intercept,
801
810
  windowCenter,
@@ -819,12 +828,25 @@ class BaseStreamingImageVolume_BaseStreamingImageVolume extends esm.ImageVolume
819
828
  columnPixelSpacing: spacing[0],
820
829
  rowPixelSpacing: spacing[1],
821
830
  invert,
831
+ photometricInterpretation,
822
832
  };
833
+ }
834
+ convertToCornerstoneImage(imageId, imageIdIndex) {
835
+ return this.getCornerstoneImageLoadObject(imageId, imageIdIndex);
836
+ }
837
+ getCornerstoneImageLoadObject(imageId, imageIdIndex) {
838
+ const image = this.getCornerstoneImage(imageId, imageIdIndex);
823
839
  const imageLoadObject = {
824
840
  promise: Promise.resolve(image),
825
841
  };
826
842
  return imageLoadObject;
827
843
  }
844
+ getCornerstoneImages() {
845
+ const { imageIds } = this;
846
+ return imageIds.map((imageId, imageIdIndex) => {
847
+ return this.getCornerstoneImage(imageId, imageIdIndex);
848
+ });
849
+ }
828
850
  _convertToImages() {
829
851
  const byteLength = this.sizeInBytes;
830
852
  const numImages = this.imageIds.length;
@@ -2148,8 +2148,10 @@ function ViewerLayout(_ref) {
2148
2148
  // Todo: Handle parameters in a better way.
2149
2149
  const query = new URLSearchParams(window.location.search);
2150
2150
  const configUrl = query.get('configUrl');
2151
+ const dataSourceName = pathname.substring(dataSourceIdx + 1);
2152
+ const existingDataSource = extensionManager.getDataSources(dataSourceName);
2151
2153
  const searchQuery = new URLSearchParams();
2152
- if (dataSourceIdx !== -1) {
2154
+ if (dataSourceIdx !== -1 && existingDataSource) {
2153
2155
  searchQuery.append('datasources', pathname.substring(dataSourceIdx + 1));
2154
2156
  }
2155
2157
  if (configUrl) {
@@ -2175,8 +2177,8 @@ function ViewerLayout(_ref) {
2175
2177
  hotkeyDefinitions,
2176
2178
  hotkeyDefaults
2177
2179
  } = hotkeysManager;
2178
- const versionNumber = "3.7.0-beta.41";
2179
- const commitHash = "72207e6c785269db70d8f717c06ab3b27b1d0dd9";
2180
+ const versionNumber = "3.7.0-beta.43";
2181
+ const commitHash = "156c1ba60bbf3186bd6964e40a13e005fcebf5bc";
2180
2182
  const menuOptions = [{
2181
2183
  title: t('Header:About'),
2182
2184
  icon: 'info',
@@ -467,8 +467,9 @@ function OHIFCornerstoneSEGViewport(props) {
467
467
  patientSex: PatientSex || '',
468
468
  patientAge: PatientAge || '',
469
469
  MRN: PatientID || '',
470
- thickness: SliceThickness ? `${parseFloat(SliceThickness).toFixed(2)}mm` : '',
471
- spacing: SpacingBetweenSlices !== undefined ? `${parseFloat(SpacingBetweenSlices).toFixed(2)}mm` : '',
470
+ thickness: SliceThickness ? src.utils.roundNumber(SliceThickness, 2) : '',
471
+ thicknessUnits: SliceThickness !== undefined ? 'mm' : '',
472
+ spacing: SpacingBetweenSlices !== undefined ? src.utils.roundNumber(SpacingBetweenSlices, 2) : '',
472
473
  scanner: ManufacturerModelName || ''
473
474
  }
474
475
  }
@@ -144,6 +144,7 @@ __webpack_require__.d(segmentationState_namespaceObject, {
144
144
  addColorLUT: () => (addColorLUT),
145
145
  addSegmentation: () => (addSegmentation),
146
146
  addSegmentationRepresentation: () => (addSegmentationRepresentation),
147
+ getAllSegmentationRepresentations: () => (getAllSegmentationRepresentations),
147
148
  getColorLUT: () => (getColorLUT),
148
149
  getDefaultSegmentationStateManager: () => (getDefaultSegmentationStateManager),
149
150
  getGlobalConfig: () => (getGlobalConfig),
@@ -2649,6 +2650,14 @@ class SegmentationStateManager {
2649
2650
  }
2650
2651
  return toolGroupSegRepresentationsWithConfig.segmentationRepresentations;
2651
2652
  }
2653
+ getAllSegmentationRepresentations() {
2654
+ const toolGroupSegReps = {};
2655
+ Object.entries(this.state.toolGroups).forEach(([toolGroupId, toolGroupSegRepresentationsWithConfig]) => {
2656
+ toolGroupSegReps[toolGroupId] =
2657
+ toolGroupSegRepresentationsWithConfig.segmentationRepresentations;
2658
+ });
2659
+ return toolGroupSegReps;
2660
+ }
2652
2661
  addSegmentationRepresentation(toolGroupId, segmentationRepresentation) {
2653
2662
  if (!this.state.toolGroups[toolGroupId]) {
2654
2663
  this.state.toolGroups[toolGroupId] = {
@@ -2904,7 +2913,14 @@ function getSegmentationRepresentations(toolGroupId) {
2904
2913
  const segmentationStateManager = getDefaultSegmentationStateManager();
2905
2914
  return segmentationStateManager.getSegmentationRepresentations(toolGroupId);
2906
2915
  }
2916
+ function getAllSegmentationRepresentations() {
2917
+ const segmentationStateManager = getDefaultSegmentationStateManager();
2918
+ return segmentationStateManager.getAllSegmentationRepresentations();
2919
+ }
2907
2920
  function getToolGroupIdsWithSegmentation(segmentationId) {
2921
+ if (!segmentationId) {
2922
+ throw new Error('getToolGroupIdsWithSegmentation: segmentationId is empty');
2923
+ }
2908
2924
  const segmentationStateManager = getDefaultSegmentationStateManager();
2909
2925
  const state = segmentationStateManager.getState();
2910
2926
  const toolGroupIds = Object.keys(state.toolGroups);
@@ -6491,9 +6507,6 @@ function fillCircle(enabledElement, operationData, threshold = false) {
6491
6507
  fillCircle_transformWorldToIndex(imageData, bottomRightWorld),
6492
6508
  ];
6493
6509
  const boundsIJK = boundingBox_getBoundingBoxAroundShape(ellipsoidCornersIJK, dimensions);
6494
- if (boundsIJK.every(([min, max]) => min !== max)) {
6495
- throw new Error('Oblique segmentation tools are not supported yet');
6496
- }
6497
6510
  const ellipseObj = {
6498
6511
  center: center,
6499
6512
  xRadius: Math.abs(topLeftWorld[0] - bottomRightWorld[0]) / 2,
@@ -7064,9 +7077,7 @@ function registerCursor(toolName, iconContent, viewBox) {
7064
7077
  });
7065
7078
  }
7066
7079
  function getDefinedSVGCursorDescriptor(name) {
7067
- if (Object.prototype.hasOwnProperty.call(CursorSVG, name)) {
7068
- return CursorSVG[name];
7069
- }
7080
+ return CursorSVG[name];
7070
7081
  }
7071
7082
  const svgCursorNames = Object.keys(CursorSVG);
7072
7083
 
@@ -18409,9 +18420,6 @@ function fillRectangle(enabledElement, operationData, inside = true) {
18409
18420
  });
18410
18421
  });
18411
18422
  const boundsIJK = boundingBox_getBoundingBoxAroundShape(rectangleCornersIJK, dimensions);
18412
- if (boundsIJK.every(([min, max]) => min !== max)) {
18413
- throw new Error('Oblique segmentation tools are not supported yet');
18414
- }
18415
18423
  const pointInRectangle = () => true;
18416
18424
  const callback = ({ value, index, pointIJK }) => {
18417
18425
  if (segmentsLocked.includes(value)) {
@@ -18449,9 +18457,6 @@ function eraseRectangle(enabledElement, operationData, inside = true) {
18449
18457
  return eraseRectangle_transformWorldToIndex(imageData, world);
18450
18458
  });
18451
18459
  const boundsIJK = boundingBox_getBoundingBoxAroundShape(rectangleCornersIJK, dimensions);
18452
- if (boundsIJK.every(([min, max]) => min !== max)) {
18453
- throw new Error('Oblique segmentation tools are not supported yet');
18454
- }
18455
18460
  const pointInShape = () => true;
18456
18461
  const callback = ({ value, index }) => {
18457
18462
  if (segmentsLocked.includes(value)) {
@@ -22038,7 +22043,7 @@ function cancelActiveManipulations(element) {
22038
22043
  ;// CONCATENATED MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/store/SynchronizerManager/Synchronizer.js
22039
22044
 
22040
22045
  class Synchronizer {
22041
- constructor(synchronizerId, eventName, eventHandler) {
22046
+ constructor(synchronizerId, eventName, eventHandler, options) {
22042
22047
  this._viewportOptions = {};
22043
22048
  this._onEvent = (evt) => {
22044
22049
  if (this._ignoreFiredEvents === true) {
@@ -22066,6 +22071,7 @@ class Synchronizer {
22066
22071
  this._ignoreFiredEvents = false;
22067
22072
  this._sourceViewports = [];
22068
22073
  this._targetViewports = [];
22074
+ this._options = options || {};
22069
22075
  this.id = synchronizerId;
22070
22076
  }
22071
22077
  isDisabled() {
@@ -22154,7 +22160,7 @@ class Synchronizer {
22154
22160
  if (targetIsSource) {
22155
22161
  continue;
22156
22162
  }
22157
- this._eventHandler(this, sourceViewport, targetViewport, sourceEvent);
22163
+ this._eventHandler(this, sourceViewport, targetViewport, sourceEvent, this._options);
22158
22164
  }
22159
22165
  }
22160
22166
  catch (ex) {
@@ -22216,12 +22222,12 @@ function _getViewportElement(vp) {
22216
22222
  ;// CONCATENATED MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/store/SynchronizerManager/createSynchronizer.js
22217
22223
 
22218
22224
 
22219
- function createSynchronizer(synchronizerId, eventName, eventHandler) {
22225
+ function createSynchronizer(synchronizerId, eventName, eventHandler, options) {
22220
22226
  const synchronizerWithSameIdExists = state.synchronizers.some((sync) => sync.id === synchronizerId);
22221
22227
  if (synchronizerWithSameIdExists) {
22222
22228
  throw new Error(`Synchronizer with id '${synchronizerId}' already exists.`);
22223
22229
  }
22224
- const synchronizer = new SynchronizerManager_Synchronizer(synchronizerId, eventName, eventHandler);
22230
+ const synchronizer = new SynchronizerManager_Synchronizer(synchronizerId, eventName, eventHandler, options);
22225
22231
  state.synchronizers.push(synchronizer);
22226
22232
  return synchronizer;
22227
22233
  }
@@ -22920,7 +22926,7 @@ function createCameraPositionSynchronizer(synchronizerName) {
22920
22926
 
22921
22927
  ;// CONCATENATED MODULE: ../../../node_modules/@cornerstonejs/tools/dist/esm/synchronizers/callbacks/voiSyncCallback.js
22922
22928
 
22923
- function voiSyncCallback(synchronizerInstance, sourceViewport, targetViewport, voiModifiedEvent) {
22929
+ function voiSyncCallback(synchronizerInstance, sourceViewport, targetViewport, voiModifiedEvent, options) {
22924
22930
  const eventDetail = voiModifiedEvent.detail;
22925
22931
  const { volumeId, range, invertStateChanged, invert } = eventDetail;
22926
22932
  const renderingEngine = (0,esm.getRenderingEngine)(targetViewport.renderingEngineId);
@@ -22931,7 +22937,7 @@ function voiSyncCallback(synchronizerInstance, sourceViewport, targetViewport, v
22931
22937
  const tProperties = {
22932
22938
  voiRange: range,
22933
22939
  };
22934
- if (invertStateChanged) {
22940
+ if (options.syncInvertState && invertStateChanged) {
22935
22941
  tProperties.invert = invert;
22936
22942
  }
22937
22943
  if (tViewport instanceof esm.BaseVolumeViewport) {
@@ -22950,8 +22956,8 @@ function voiSyncCallback(synchronizerInstance, sourceViewport, targetViewport, v
22950
22956
 
22951
22957
 
22952
22958
 
22953
- function createVOISynchronizer(synchronizerName) {
22954
- const VOISynchronizer = SynchronizerManager_createSynchronizer(synchronizerName, esm.Enums.Events.VOI_MODIFIED, voiSyncCallback);
22959
+ function createVOISynchronizer(synchronizerName, options = { syncInvertState: true }) {
22960
+ const VOISynchronizer = SynchronizerManager_createSynchronizer(synchronizerName, esm.Enums.Events.VOI_MODIFIED, voiSyncCallback, options);
22955
22961
  return VOISynchronizer;
22956
22962
  }
22957
22963