-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConnectedStandaloneRouting~IHEInvokeImageDisplay~ViewerRouting.bundle.60a45c773e1469a7f521.js.map
1 lines (1 loc) · 106 KB
/
ConnectedStandaloneRouting~IHEInvokeImageDisplay~ViewerRouting.bundle.60a45c773e1469a7f521.js.map
1
{"version":3,"sources":["webpack:///./connectedComponents/ConnectedCineDialog.js","webpack:///./connectedComponents/ConnectedLayoutButton.js","webpack:///./connectedComponents/ToolbarRow.js","webpack:///./connectedComponents/ConnectedStudyBrowser.js","webpack:///./connectedComponents/findDisplaySetByUID.js","webpack:///./components/ViewportGrid/ViewportPane.js","webpack:///./components/ViewportGrid/ViewportGrid.js","webpack:///./components/ViewportGrid/DefaultViewport.js","webpack:///./components/ViewportGrid/ConnectedViewportGrid.js","webpack:///./connectedComponents/ViewerMain.js","webpack:///./connectedComponents/ConnectedViewerMain.js","webpack:///./components/SidePanel.js","webpack:///./components/ErrorBoundaryDialog/ErrorBoundaryDialog.js","webpack:///./components/ErrorBoundaryDialog/index.js","webpack:///./connectedComponents/Viewer.js","webpack:///./connectedComponents/ConnectedViewer.js","webpack:///./customHooks/usePrevious.js","webpack:///./connectedComponents/ViewerRetrieveStudyData.js","webpack:///./connectedComponents/ConnectedViewerRetrieveStudyData.js"],"names":["scrollToIndex","toolImport","csTools","import","setViewportSpecificData","OHIF","redux","actions","ConnectedCineDialog","connect","state","viewports","cine","viewportSpecificData","activeViewportIndex","activeEnabledElement","commandsManager","runCommand","activeViewportCineData","isPlaying","cineFrameRate","dispatch","dispatchSetViewportSpecificData","viewportIndex","data","propsFromState","propsFromDispatch","ownProps","onPlayPauseChanged","cloneDeep","onFrameRateChanged","frameRate","onClickNextButton","stackData","getToolState","length","currentImageIdIndex","imageIds","onClickBackButton","onClickSkipToStart","onClickSkipToEnd","lastIndex","CineDialog","setLayout","setViewportActive","ConnectedLayoutButton","currentLayout","layout","onChange","selectedCell","numRows","row","numColumns","col","numViewports","i","viewport","plugin","vtk","push","onChangeFromDispatch","LayoutButton","ToolbarRow","props","dialog","dialogId","activeButtons","toolbarButtons","find","button","options","behavior","dismiss","id","filter","setState","toolbarButtonDefinitions","_getVisibleToolbarButtons","call","seriesPerStudyCount","_handleBuiltIn","bind","_onDerivedDisplaySetsLoadedAndCached","updateButtonGroups","panelModules","extensionManager","modules","MODULE_TYPES","PANEL","this","buttonGroups","left","right","forEach","panelExtension","panelModule","module","defaultContexts","Array","from","defaultContext","menuOptions","menuOption","contexts","context","hasActiveContext","activeContexts","some","actx","includes","isDisabled","studies","activeViewport","menuOptionEntry","value","target","icon","bottomLabel","label","unshift","t","document","addEventListener","removeEventListener","prevProps","activeContextsChanged","prevStudies","prevActiveViewport","shouldUpdate","series","closeCineDialogIfNotApplicable","buttonComponents","_getButtonComponents","onPress","side","handleSidePanelChange","onPressLeft","onPressRight","className","style","padding","selectedLeftSidePanel","onValueChanged","marginLeft","selectedRightSidePanel","Component","_getCustomButtonComponent","CustomComponent","activeButtonsIds","map","isActive","parentContext","toolbarClickCallback","_handleToolbarButtonClick","key","_getExpandableButtonComponent","activeCommand","childButtons","buttons","childButton","onClick","indexOf","_getDefaultButtonComponent","_this","hasCustomComponent","hasNestedButtonDefinitions","evt","commandName","Object","assign","commandOptions","type","toggables","togglable","toolbarModules","TOOLBAR","extension","definitions","definition","querySelector","getBoundingClientRect","x","y","newDialogId","create","content","defaultPosition","title","isLeftSidePanelOpen","PropTypes","bool","isRequired","isRightSidePanelOpen","string","func","arrayOf","array","any","modal","withTranslation","withModal","withDialog","withAppContext","utils","studyMetadataManager","setActiveViewportSpecificData","ConnectedStudyBrowser","stackLoadingProgressMap","loading","progress","studiesWithLoadingData","study","thumbnails","displaySetInstanceUID","stackId","stackProgressData","stackPercentComplete","percentComplete","onThumbnailClick","displaySet","studyMetadata","isArray","reduce","all","current","currentDisplaySet","displaySets","concat","ds","findDisplaySetByUID","isDerived","Modality","getSourceDisplaySet","Error","StudyBrowser","ViewportPane","children","onDrop","propClassName","useDrop","accept","drop","droppedItem","monitor","canDrop","isOver","StudyInstanceUID","collect","highlighted","hovered","classNames","ref","data-cy","propTypes","node","number","loadAndCacheDerivedDisplaySets","ViewportGrid","availablePlugins","defaultPluginName","defaultPlugin","setViewportData","viewportData","isStudyLoaded","rowSize","colSize","snackbar","useSnackbarContext","logger","useLogger","useEffect","promise","catch","error","message","show","autoClose","ViewportPanes","React","useMemo","pluginName","ViewportComponent","JSON","stringify","_getViewportComponent","active","display","gridTemplateRows","gridTemplateColumns","height","width","supportsDrop","object","defaultProps","DefaultViewport","getAvailableViewportModules","memoize","viewportModules","availableViewportModules","moduleDefinition","extensionId","ConnectedViewportGrid","VIEWPORT","values","_values","ViewerMain","dirtyViewportPanes","viewportPane","foundDisplaySet","v","vp","findDisplaySet","dSet","getDisplaySets","fillEmptyViewportPanes","prevViewportAmount","viewportAmount","isVtk","keys","clearViewportSpecificData","ConnectedViewerMain","SidePanel","isOpen","fromSideClass","styles","maxWidth","marginRight","Number","parseInt","UIModalService","servicesManager","services","ErrorBoundaryDialog","fallbackComponent","role","onError","componentStack","useState","open","setOpen","s","name","classnames","opened","Viewer","log","info","earliestDate","Date","toISOString","latestDate","StudyDate","moment","Promise","resolve","timepointType","timepointId","studyInstanceUIDs","PatientID","isLocked","timepointData","query","timepointIds","timepoints","onTimepointsUpdated","measurements","onMeasurementsUpdated","activeServer","server","MeasurementApi","setConfiguration","dataExchange","retrieve","DICOMSR","retrieveMeasurements","store","storeMeasurements","TimepointApi","retrieveTimepoints","storeTimepoints","remove","removeTimepoint","update","updateTimepoint","disassociate","disassociateStudy","_getActiveViewport","dismissAll","timepointApi","measurementApi","currentTimepointId","_mapStudiesToThumbnails","VisiblePanelLeft","VisiblePanelRight","panelExt","components","comp","component","WhiteLabelingContext","Consumer","whiteLabeling","UserManagerContext","userManager","AppContext","appContext","ConnectedHeader","linkText","appConfig","showStudyList","undefined","linkPath","createLogoComponentFn","isDerivedDisplaySetsLoaded","selectedPanel","sideClicked","toUpperCase","slice","openKey","selectedKey","updatedState","prevSelectedPanel","isSameSelectedPanel","activeIndex","getActiveViewport","shape","SeriesDescription","SeriesNumber","InstanceNumber","numImageFrames","images","getImageId","wadoRoot","_checkForSeriesInconsistencesWarnings","warningsList","warningIssues","warning","ReconstructionIssues","DATASET_4D","VARYING_IMAGESDIMENSIONS","VARYING_IMAGESCOMPONENTS","VARYING_IMAGESORIENTATION","IRREGULAR_SPACING","MULTIFFRAMES","missingFrames","warn","imageId","altImageText","imageIndex","Math","floor","hasWarnings","setTimepoints","setMeasurements","getActiveServer","servers","a","ConnectedViewer","usePrevious","useRef","OHIFStudyMetadata","metadata","OHIFSeriesMetadata","retrieveStudiesMetadata","deleteStudyMetadataPromise","makeCancelable","_promoteList","filters","isFilterStrategy","promoted","_promoteStudyDisplaySet","list","searchMethod","listCopy","response","promotedCount","arrayValues","seriesInstanceUID","promotedResponse","valueToCompare","SeriesInstanceUID","split","index","findIndex","itemToPromote","splice","_isQueryParamApplied","applied","seriesInstanceUIDs","validateFilterApplied","arrayToInspect","every","item","seriesInstanceUIDStr","validatePromoteApplied","isValid","resultSeries","validateMethod","_showUserMessage","queryParamApplied","showUserMessage","_addSeriesToStudy","sopClassHandlerModules","getData","seriesMetadata","getSeriesByUID","updateSeries","addSeries","createAndAddDisplaySetsForSeries","derivedDisplaySets","getDerivedDatasets","_updateStudyMetadataManager","get","add","_updateStudyDisplaySets","createDisplaySets","_addDerivedDisplaySets","_thinStudyData","ViewerRetrieveStudyData","cancelableSeriesPromises","cancelableStudiesPromises","setStudyData","setError","setStudies","setIsStudyLoaded","snackbarContext","useContext","filterQueryParam","maxConcurrentMetadataRequests","processStudies","studiesData","loadRemainingSeries","then","result","isCanceled","isQueryParamApplied","studyDidLoad","seriesLoader","loadNextSeries","hasNext","next","concurrentRequestsAllowed","getSeriesCount","promises","fill","loadStudies","retrieveParams","splitQueryParameterCalls","enableGoogleCloudAdapter","purgeCancellablePromises","useCallback","cancel","prevStudyInstanceUIDs","e","purge","NotFound","ConnectedViewerRetrieveStudyData"],"mappings":"gRAUMA,GAAgBC,EADHC,IAAQC,QACM,sBACzBC,EAA4BC,IAAKC,MAAMC,QAAvCH,wBA4FOI,EANaC,aAjFJ,SAAAC,GAAS,MAEuBA,EAAMC,UACpDC,GAHuB,EAEvBC,qBAFuB,EAEDC,sBACgC,IAAtDF,KASR,MAAO,CACLG,qBATUC,IAAgBC,WAAW,mCAUrCC,uBAReN,GAAQ,CACvBO,WAAW,EACXC,cAAe,IAOfN,oBAAqBJ,EAAMC,UAAUG,wBAId,SAAAO,GACzB,MAAO,CACLC,gCAAiC,SAACC,EAAeC,GAC/CH,EAASjB,EAAwBmB,EAAeC,SAKnC,SAACC,EAAgBC,EAAmBC,GAAa,IAEhEZ,EAGEU,EAHFV,qBACAG,EAEEO,EAFFP,uBACAJ,EACEW,EADFX,oBAGF,MAAO,CACLM,cAAeF,EAAuBE,cACtCD,UAAWD,EAAuBC,UAClCS,mBAAoB,SAAAT,GAClB,IAAMP,EAAOiB,IAAUX,GACvBN,EAAKO,WAAaP,EAAKO,UAEvBO,EAAkBJ,gCAAgCR,EAAqB,CACrEF,UAGJkB,mBAAoB,SAAAC,GAClB,IAAMnB,EAAOiB,IAAUX,GACvBN,EAAKQ,cAAgBW,EAErBL,EAAkBJ,gCAAgCR,EAAqB,CACrEF,UAGJoB,kBAAmB,WACjB,IAAMC,EAAY/B,IAAQgC,aAAanB,EAAsB,SAC7D,GAAKkB,GAAcA,EAAUT,MAASS,EAAUT,KAAKW,OAArD,CAFuB,MAGmBF,EAAUT,KAAK,GAAjDY,EAHe,EAGfA,oBACJA,GAJmB,EAGMC,SACOF,OAAS,GAC7CnC,EAAce,EAAsBqB,EAAsB,KAE5DE,kBAAmB,WACjB,IAAML,EAAY/B,IAAQgC,aAAanB,EAAsB,SAC7D,GAAKkB,GAAcA,EAAUT,MAASS,EAAUT,KAAKW,OAArD,CAFuB,IAGfC,EAAwBH,EAAUT,KAAK,GAAvCY,oBACoB,IAAxBA,GACJpC,EAAce,EAAsBqB,EAAsB,KAE5DG,mBAAoB,WAClB,IAAMN,EAAY/B,IAAQgC,aAAanB,EAAsB,SACxDkB,GAAcA,EAAUT,MAASS,EAAUT,KAAKW,QACrDnC,EAAce,EAAsB,IAEtCyB,iBAAkB,WAChB,IAAMP,EAAY/B,IAAQgC,aAAanB,EAAsB,SAC7D,GAAKkB,GAAcA,EAAUT,MAASS,EAAUT,KAAKW,OAArD,CACA,IAAMM,EAAYR,EAAUT,KAAK,GAAGa,SAASF,OAAS,EACtDnC,EAAce,EAAsB0B,QAKdhC,CAI1BiC,K,ECjGuCrC,IAAKC,MAAMC,QAA5CoC,E,EAAAA,UAAWC,E,EAAAA,kBA8DJC,EANepC,aAtDN,SAAAC,GACtB,MAAO,CACLoC,cAAepC,EAAMC,UAAUoC,OAC/BjC,oBAAqBJ,EAAMC,UAAUG,wBAId,SAAAO,GACzB,MAAO,CAEL2B,SAAU,SAACC,EAAcH,EAAehC,GAMtC,IALA,IAAMH,EAAY,GACZuC,EAAUD,EAAaE,IAAM,EAC7BC,EAAaH,EAAaI,IAAM,EAChCC,EAAeJ,EAAUE,EAEtBG,EAAI,EAAGA,EAAID,EAAcC,IAAK,CAErC,IAAMC,EAAWV,EAAcnC,UAAU4C,GACrCE,EAASD,GAAYA,EAASC,OAC9BD,GAAYA,EAASE,MACvBD,EAAS,eAGX9C,EAAUgD,KAAK,CACbF,WAGJ,IAAMV,EAAS,CACbG,UACAE,aACAzC,aAIEG,EADmBwC,EAAe,GAEpCjC,EAASuB,EAAkB,IAG7BvB,EAASsB,EAAUI,SAKN,SAACtB,EAAgBC,GAClC,IAAMkC,EAAuBlC,EAAkBsB,SACvCF,EAAuCrB,EAAvCqB,cAAehC,EAAwBW,EAAxBX,oBAEvB,MAAO,CACLkC,SAAU,SAAAC,GAAY,OACpBW,EAAqBX,EAAcH,EAAehC,OAI1BL,CAI5BoD,K,4rCC5CIC,E,YAqBJ,WAAYC,GAAO,M,iGAAA,S,EACjB,K,EAAA,eAAMA,GAAN,G,gDADiB,yCA6Ic,WAAM,IAC7BC,EAAW,EAAKD,MAAhBC,OAD6B,EAEa,EAAKtD,MAAjDuD,EAF+B,EAE/BA,SAAUC,EAFqB,EAErBA,cAAeC,EAFM,EAENA,eAC3BF,IACwBE,EAAeC,MACvC,SAAAC,GAAM,OAAIA,EAAOC,SAAuC,SAA5BD,EAAOC,QAAQC,cAG3CP,EAAOQ,QAAQ,CAAEC,GAAIR,IACrBC,EAAgBA,EAAcQ,QAC5B,SAAAL,GAAM,OAAIA,EAAOC,SAAuC,SAA5BD,EAAOC,QAAQC,YAE7C,EAAKI,SAAS,CAAEV,SAAU,KAAMC,uBAtJpC,IAAMU,EAA2BC,EAA0BC,KAA1B,MAHhB,OAYjB,EAAKpE,MAAQ,CACXyD,eAAgBS,EAChBV,cAAe,IAGjB,EAAKa,oBAAsB,GAE3B,EAAKC,eAAiBA,EAAeC,KAAf,MACtB,EAAKC,qCAAuC,EAAKA,qCAAqCD,KAA1C,MAI5C,EAAKE,qBAxBY,E,4SA2BE,WACbC,EAAeC,IAAiBC,QAAQC,IAAaC,OAE3DC,KAAKC,aAAe,CAClBC,KAAM,GACNC,MAAO,IAITR,EAAaS,SAAQ,SAAAC,GACnB,IAAMC,EAAcD,EAAeE,OAC7BC,EAAkBC,MAAMC,KAAKJ,EAAYK,gBAE/CL,EAAYM,YAAYR,SAAQ,SAAAS,GAC9B,IAAMC,EAAWL,MAAMC,KAAKG,EAAWE,SAAWP,GAC5CQ,EAAmB,EAAK1C,MAAM2C,eAAeC,MAAK,SAAAC,GAAI,OAC1DL,EAASM,SAASD,MAKdE,EAC6B,mBAA1BR,EAAWQ,YAClBR,EAAWQ,WAAW,EAAK/C,MAAMgD,QAAS,EAAKhD,MAAMiD,gBAEvD,GAAIP,IAAqBK,EAAY,CACnC,IAAMG,EAAkB,CACtBC,MAAOZ,EAAWa,OAClBC,KAAMd,EAAWc,KACjBC,YAAaf,EAAWgB,OAEpBnB,EAAOG,EAAWH,MAAQ,QAEhC,EAAKT,aAAaS,GAAMxC,KAAKsD,UAMnCxB,KAAKC,aAAaC,KAAK4B,QAAQ,CAC7BL,MAAO,UACPE,KAAM,WACNC,YAAa5B,KAAK1B,MAAMyD,EAAE,c,0CAU5BC,SAASC,iBACP,oCACAjC,KAAKP,wC,6CAKPuC,SAASE,oBACP,oCACAlC,KAAKP,wC,6DAKPO,KAAKN,qBACLM,KAAKd,SAAS,CACZR,eAAgBU,EAA0BC,KAAKW,U,yCAIhCmC,GACjB,IAAMC,EACJD,EAAUlB,iBAAmBjB,KAAK1B,MAAM2C,eAEpCoB,EAAcF,EAAUb,QACxBgB,EAAqBH,EAAUZ,eAC/BA,EAAiBvB,KAAK1B,MAAMiD,eAC5BD,EAAUtB,KAAK1B,MAAMgD,QACrBhC,EAAsBU,KAAKV,oBAE7BiD,GAAe,EAEnB,GACEF,EAAY3F,SAAW4E,EAAQ5E,QAC/B4F,IAAuBf,EAEvBgB,GAAe,OAEf,IAAK,IAAIzE,EAAI,EAAGA,EAAIwD,EAAQ5E,OAAQoB,IAClC,GAAIwD,EAAQxD,GAAG0E,OAAO9F,SAAW4C,EAAoBxB,GAAI,CACvDwB,EAAoBxB,GAAKwD,EAAQxD,GAAG0E,OAAO9F,OAE3C6F,GAAe,EACf,MAKFA,GACFvC,KAAKN,qBAGH0C,GACFpC,KAAKd,SACH,CACER,eAAgBU,EAA0BC,KAAKW,OAEjDA,KAAKyC,kC,+BAsBF,WACDC,EAAmBC,EAAqBtD,KAC5CW,KACAA,KAAK/E,MAAMyD,eACXsB,KAAK/E,MAAMwD,eAGPmE,EAAU,SAACC,EAAMpB,GACrB,EAAKnD,MAAMwE,sBAAsBD,EAAMpB,IAEnCsB,EAAcH,EAAQpD,KAAKQ,KAAM,QACjCgD,EAAeJ,EAAQpD,KAAKQ,KAAM,SAExC,OACE,oCACE,yBAAKiD,UAAU,cACb,yBAAKA,UAAU,wBAAwBC,MAAO,CAAEC,QAAS,SACvD,kBAAC,IAAD,CACEtE,QAASmB,KAAKC,aAAaC,KAC3BuB,MAAOzB,KAAK1B,MAAM8E,uBAAyB,GAC3CC,eAAgBN,KAGnBL,EACD,kBAAC,EAAD,MACA,yBACEO,UAAU,0BACVC,MAAO,CAAEI,WAAY,SAEpBtD,KAAKC,aAAaE,MAAMzD,QACvB,kBAAC,IAAD,CACEmC,QAASmB,KAAKC,aAAaE,MAC3BsB,MAAOzB,KAAK1B,MAAMiF,wBAA0B,GAC5CF,eAAgBL,Y,8BApNPQ,aA8NzB,SAASC,EAA0B7E,EAAQH,GACzC,IAAMiF,EAAkB9E,EAAO8E,gBAI/B,GAHoD,mBAApBA,EAGV,CACpB,IACMC,EAAmBlF,EAAcmF,KAAI,SAAAhF,GAAM,OAAIA,EAAOI,MACtD6E,EAAWF,EAAiBvC,SAASxC,EAAOI,IAElD,OACE,kBAAC0E,EAAD,CACEI,cANkB9D,KAOlB+D,qBAAsBC,EAA0BxE,KAAKQ,MACrDpB,OAAQA,EACRqF,IAAKrF,EAAOI,GACZP,cAAekF,EACfE,SAAUA,KAMlB,SAASK,EAA8BtF,EAAQH,GAAe,IAExD0F,EAFwD,OAGtDC,EAAexF,EAAOyF,QAAQT,KAAI,SAAAU,GAOtC,OANAA,EAAYC,QAAUP,EAA0BxE,KAAK,EAAM8E,GAEvD7F,EAAcmF,KAAI,SAAAhF,GAAM,OAAIA,EAAOI,MAAIwF,QAAQF,EAAYtF,KAAO,IACpEmF,EAAgBG,EAAYtF,IAGvBsF,KAGT,OACE,kBAAC,IAAD,CACEL,IAAKrF,EAAOI,GACZ6C,MAAOjD,EAAOiD,MACdF,KAAM/C,EAAO+C,KACb0C,QAASD,EACTD,cAAeA,IAKrB,SAASM,EAA2B7F,EAAQH,GAC1C,OACE,kBAAC,IAAD,CACEwF,IAAKrF,EAAOI,GACZ6C,MAAOjD,EAAOiD,MACdF,KAAM/C,EAAO+C,KACb4C,QAASP,EAA0BxE,KAAKQ,KAAMpB,GAC9CiF,SAAUpF,EAAcmF,KAAI,SAAAhF,GAAM,OAAIA,EAAOI,MAAIoC,SAASxC,EAAOI,MAQvE,SAAS2D,EAAqBjE,EAAgBD,GAC5C,IAAMiG,EAAQ1E,KACd,OAAOtB,EAAekF,KAAI,SAAAhF,GACxB,IAAM+F,EAAqB/F,EAAO8E,gBAC5BkB,EAA6BhG,EAAOyF,SAAWzF,EAAOyF,QAAQ3H,OAEpE,OAAIiI,EACKlB,EAA0BpE,KAAKqF,EAAO9F,EAAQH,GAGnDmG,EACKV,EAA8B7E,KAAKqF,EAAO9F,EAAQH,GAGpDgG,EAA2BpF,KAAKqF,EAAO9F,EAAQH,MAgB1D,SAASuF,EAA0BpF,EAAQiG,EAAKvG,GAAO,IAC7CG,EAAkBuB,KAAK/E,MAAvBwD,cAER,GAAIG,EAAOkG,YAAa,CACtB,IAAMjG,EAAUkG,OAAOC,OAAO,CAAEH,OAAOjG,EAAOqG,gBAC9C1J,IAAgBC,WAAWoD,EAAOkG,YAAajG,GAMjD,GAAoB,kBAAhBD,EAAOsG,KAA0B,CACnC,IAAMC,EAAY1G,EAAcQ,QAC9B,gBAAGJ,EAAH,EAAGA,QAAH,OAAiBA,IAAYA,EAAQuG,aAEvCpF,KAAKd,SAAS,CAAET,cAAe,GAAF,SAAM0G,GAAN,CAAiBvG,UACrB,YAAhBA,EAAOsG,MAChBlF,KAAKT,eAAeX,GAOxB,SAASQ,IAA4B,WAC7BiG,EAAiBzF,IAAiBC,QAAQC,IAAawF,SACvDnG,EAA2B,GAajC,OAXAkG,EAAejF,SAAQ,SAAAmF,GAAa,MACMA,EAAUhF,OAA1CiF,EAD0B,EAC1BA,YAAa7E,EADa,EACbA,eACrB6E,EAAYpF,SAAQ,SAAAqF,GAClB,IAAM1E,EAAU0E,EAAW1E,SAAWJ,EAElC,EAAKrC,MAAM2C,eAAeG,SAASL,IACrC5B,EAAyBjB,KAAKuH,SAK7BtG,EAGT,SAASI,EAAeX,GAAQ,MAERoB,KAAK1B,MAAnBC,EAFsB,EAEtBA,OAAQwD,EAFc,EAEdA,EACRvD,EAAawB,KAAK/E,MAAlBuD,SACAQ,EAAgBJ,EAAhBI,GAAIH,EAAYD,EAAZC,QAEZ,GAAyB,SAArBA,EAAQC,SACV,GAAIN,EACFD,EAAOQ,QAAQ,CAAEC,GAAIR,IACrBwB,KAAKd,UAAS,SAAAjE,GAAK,MAAK,CACtBuD,SAAU,KACVC,cAAe,EACVxD,EAAMwD,cAAcQ,QAAO,SAAAL,GAAM,OAAIA,EAAOI,KAAOA,cAGrD,CACL,IADK,EAEYgD,SACd0D,cADc,eAEdC,wBAFKC,EAFH,EAEGA,EAAGC,EAFN,EAEMA,EAGLC,EAAcvH,EAAOwH,OAAO,CAChCC,QAASjL,EACTkL,gBAAiB,CACfL,EAAGA,EAPS,IAOM,EAClBC,EAAGA,EARS,IAQM,KAGtB7F,KAAKd,UAAS,SAAAjE,GAAK,MAAK,CACtBuD,SAAUsH,EACVrH,cAAe,GAAF,SAAMxD,EAAMwD,eAAZ,CAA2BG,QAKrB,yBAArBC,EAAQC,UACVvD,IAAgBC,WAAW,4BAA6B,CACtD0K,MAAOnE,EAAE,iC,EAxYT1D,E,YAGe,CACjB8H,oBAAqBC,IAAUC,KAAKC,WACpCC,qBAAsBH,IAAUC,KAAKC,WACrClD,sBAAuBgD,IAAUI,OAAOF,WACxC/C,uBAAwB6C,IAAUI,OAAOF,WACzCxD,sBAAuBsD,IAAUK,KAAKH,WACtCrF,eAAgBmF,IAAUM,QAAQN,IAAUI,QAAQF,WACpDhF,QAAS8E,IAAUO,MACnB5E,EAAGqE,IAAUK,KAAKH,WAElB/H,OAAQ6H,IAAUQ,IAClBC,MAAOT,IAAUQ,M,EAdfvI,E,eAiBkB,CACpBiD,QAAS,KA2XEwF,kBAAgB,CAAC,SAAU,wBAA3BA,CACbC,YAAUC,YAAWC,YAAe5I,MC5ZLzD,IAAKsM,MAA9BC,qB,IAEAC,EAAkCxM,IAAKC,MAAMC,QAA7CsM,8BAkEOC,EALerM,aAxDN,SAACC,EAAOiB,GAI9B,IAAMoL,EAA0BrM,EAAMsM,QAAQC,SACxCC,EAAyBrL,IAAUF,EAASoF,SAiBlD,OAfAmG,EAAuBrH,SAAQ,SAAAsH,GAC7BA,EAAMC,WAAWvH,SAAQ,SAAArE,GAAQ,IACvB6L,EAA0B7L,EAA1B6L,sBACFC,EAAU,iBAAH,OAAoBD,GAC3BE,EAAoBR,EAAwBO,GAE9CE,EAAuB,EACvBD,IACFC,EAAuBD,EAAkBE,iBAG3CjM,EAAKgM,qBAAuBA,QAIzB,CACLzG,QAASmG,MAIc,SAAC7L,EAAUM,GACpC,MAAO,CACL+L,iBAAkB,SAAAL,GAChB,IAAIM,ECtCK,SACbC,EACAP,GAEA,OAAKnH,MAAM2H,QAAQD,IAEIA,EAAcE,QAAO,SAACC,EAAKC,GAChD,IAAIC,EAAoB,GAIxB,OAHID,GAAW9H,MAAM2H,QAAQG,EAAQE,eACnCD,EAAoBD,EAAQE,aAEvBH,EAAII,OAAOF,KACjB,IAK+B7J,MAHT,SAAAgK,GAAE,OACzBA,EAAGf,wBAA0BA,MAXW,KDkCrBgB,CACf1M,EAASiM,cACTP,GAGF,GAAIM,EAAWW,UAAW,KAChBC,EAAaZ,EAAbY,SAIR,KAFAZ,EAAaA,EAAWa,oBAAoB7M,EAASiM,gBAGnD,MAAM,IAAIa,MAAJ,gCACqBF,EADrB,0BAKR,IAAKZ,EACH,MAAM,IAAIc,MAAM,2BAIpBpN,EAASwL,EAA8Bc,QAKflN,CAG5BiO,K,kiBElEF,IAAMC,EAAe,SAAU5K,GAAO,IAC5B6K,EAA8D7K,EAA9D6K,SAAUC,EAAoD9K,EAApD8K,OAAQtN,EAA4CwC,EAA5CxC,cAA0BuN,EAAkB/K,EAA7B2E,UADL,IAEKqG,YAAQ,CAC/CC,OAAQ,YACRC,KAAM,SAACC,EAAaC,GAClB,IAAMC,EAAUD,EAAQC,UAClBC,EAASF,EAAQE,SAEvB,GAAID,GAAWC,GAAUR,EAAQ,KACvBS,EAA4CJ,EAA5CI,iBAAkBjC,EAA0B6B,EAA1B7B,sBAE1BwB,EAAO,CAAEtN,gBAAe+N,mBAAkBjC,4BAK9CkC,QAAS,SAAAJ,GAAO,MAAK,CACnBK,YAAaL,EAAQC,UACrBK,QAASN,EAAQE,aAlBe,UAE3BI,EAF2B,EAE3BA,QAASD,EAFkB,EAElBA,YAAeP,EAFG,KAsBpC,OACE,yBACEvG,UAAWgH,IACT,uBACA,CAAED,QAASA,GACX,CAAED,YAAaA,GACfV,GAEFa,IAAKV,EACLW,UAAA,6BAA+BrO,IAE9BqN,IAKPD,EAAakB,UAAY,CACvBjB,SAAU/C,IAAUiE,KAAK/D,WACzBxK,cAAesK,IAAUkE,OAAOhE,WAChC8C,OAAQhD,IAAUK,KAAKH,WACvBrD,UAAWmD,IAAUI,QAGR0C,Q,0BCvCPqB,GAAmCrD,IAAnCqD,+BAEFC,GAAe,SAASlM,GAAO,IAEjCjD,EAWEiD,EAXFjD,oBACAoP,EAUEnM,EAVFmM,iBACeC,EASbpM,EATFqM,cACArN,EAQEgB,EARFhB,OACAG,EAOEa,EAPFb,QACAE,EAMEW,EANFX,WACAiN,EAKEtM,EALFsM,gBACAtJ,EAIEhD,EAJFgD,QACAuJ,EAGEvM,EAHFuM,aACA1B,EAEE7K,EAFF6K,SACA2B,EACExM,EADFwM,cAGIC,EAAU,IAAMtN,EAChBuN,EAAU,IAAMrN,EAGtB,IAAKkN,IAAiBA,EAAanO,OACjC,OAAO,KAGT,IAAMuO,EAAWC,cACXC,EAASC,cAEfC,qBAAU,WACJP,GACFD,EAAazK,SAAQ,SAAA8H,GACFqC,GAA+BrC,EAAY5G,GACnDlB,SAAQ,SAAAkL,GACfA,EAAQC,OAAM,SAAAC,GACZL,EAAOK,MAAM,CAAEA,QAAOC,QAASD,EAAMC,UACrCR,EAASS,KAAK,CACZxF,MAAO,qCACPuF,QAASD,EAAMC,QACfvG,KAAM,QACNsG,QACAG,WAAW,eAMpB,CAACrK,EAASuJ,EAAcC,EAAeG,IAE1C,IAqDMW,EAAgBC,IAAMC,SArDH,kBACvBxO,EAAOpC,UAAU0I,KAAI,SAACtG,EAAQxB,GAC5B,IAAMoM,EAAa2C,EAAa/O,GAEhC,IAAKoM,EACH,OAAO,KAGT,IAAMnM,EAAO,CACXmM,aACA5G,WAeIyK,GACHzO,EAAOU,QAAUkK,GAAcA,EAAWlK,OACvCkK,EAAWlK,OACXV,EAAOU,OAEPgO,EAwFZ,SACEnB,EACA/O,EACAqN,EACAsB,EACAsB,EACArB,GAEA,GAAIG,EAAa3C,WAAY,CAE3B,IAAM8D,EAAoBvB,EAD1BsB,EAAaA,GAAcrB,GAG3B,IAAKsB,EACH,MAAM,IAAIhD,MAAJ,mDACwC+C,EADxC,0CAEkBE,KAAKC,UAAUzB,KAIzC,OACE,kBAACuB,EAAD,CACEnB,aAAcA,EACd/O,cAAeA,EACfqN,SAAU,CAACA,KAKjB,OAAO,kBAAC,KAAD,MApHuBgD,CACxBpQ,EACAD,EACAqN,EACAsB,EACAsB,EACArB,GAGF,OACE,kBAAC,EAAD,CACEtB,OAAQwB,EACR9O,cAAeA,EACfmH,UAAWgH,IAAW,qBAAsB,CAC1CmC,OAAQ/Q,IAAwBS,IAElCmI,IAAKnI,GAEJkQ,QAK6C,CACpD1O,EACAuN,EACAvJ,EACA6H,EACAsB,EACAC,EACAE,EACAvP,IAGF,OACE,yBACE8O,UAAQ,eACRjH,MAAO,CACLmJ,QAAS,OACTC,iBAAkB,UAAF,OAAY7O,EAAZ,aAAwBsN,EAAxB,MAChBwB,oBAAqB,UAAF,OAAY5O,EAAZ,aAA2BqN,EAA3B,MACnBwB,OAAQ,OACRC,MAAO,SAGRb,IAKPpB,GAAaJ,UAAY,CACvBS,aAAczE,IAAUO,MAAML,WAC9BoG,aAActG,IAAUC,KAAKC,WAC7BjL,oBAAqB+K,IAAUkE,OAAOhE,WACtChJ,OAAQ8I,IAAUuG,OAAOrG,WACzBmE,iBAAkBrE,IAAUuG,OAAOrG,WACnCsE,gBAAiBxE,IAAUK,KAAKH,WAChChF,QAAS8E,IAAUO,MACnBwC,SAAU/C,IAAUiE,KACpBM,cAAevE,IAAUI,OACzB/I,QAAS2I,IAAUkE,OAAOhE,WAC1B3I,WAAYyI,IAAUkE,OAAOhE,YAG/BkE,GAAaoC,aAAe,CAC1B/B,aAAc,GACdpN,QAAS,EACTE,WAAY,EACZL,OAAQ,CACNpC,UAAW,CAAC,KAEdG,oBAAqB,EACrBqR,cAAc,EACdjC,iBAAkB,CAChBoC,gBC7JW,SAAyBvO,GACtC,OAAO,+BAAM2N,KAAKC,UAAU5N,MD8J5BqM,cAAe,yBA2CFH,U,qBE3MTsC,GAA8BC,MAAQ,SAAAC,GAC1C,IAAMC,EAA2B,GAKjC,OAJAD,EAAgB5M,SAAQ,SAAA8M,GACtBD,EAAyBC,EAAiBC,aACxCD,EAAiB3M,UAEd0M,KAgCMG,GALepS,aAxBN,SAAAC,GACtB,IAII0P,EAJEqC,EAAkBpN,IAAiBC,QAAQC,IAAauN,UACxDJ,EAA2BH,GAA4BE,GAIzDA,EAAgBtQ,SAClBiO,EAAgBqC,EAAgB,GAAGG,aAPN,MAU8BlS,EAAMC,UAEnE,MAAO,CACLuC,QAb6B,EAUvBA,QAINE,WAd6B,EAUdA,WAKfL,OAf6B,EAUFA,OAM3BjC,oBAhB6B,EAUMA,oBAQnCoP,iBAAkBwC,EAElBtC,mBAMF,KAF4B3P,CAG5BwP,I,03BCjCF,IAAI8C,GAASP,KAAQQ,MAEfC,G,YAUJ,WAAYlP,GAAO,M,IAAA,O,4FAAA,S,EACjB,K,EAAA,gBAAMA,GAAN,G,kDADiB,mCA6DM,WAEvB,IAAMmP,EAAqB,GAFE,EAGY,EAAKnP,MAAtChB,EAHqB,EAGrBA,OAAQlC,EAHa,EAGbA,qBACRqN,EAAgB,EAAKxN,MAArBwN,YAER,GAAKA,GAAgBA,EAAY/L,OAAjC,CAIA,IAAK,IAAIoB,EAAI,EAAGA,EAAIR,EAAOpC,UAAUwB,OAAQoB,IAAK,CAChD,IAAM4P,EAAetS,EAAqB0C,GAM1C,GAJE4P,GACAA,EAAa7D,kBACb6D,EAAa9F,sBAGb6F,EAAmBvP,KAAK,CACtB2L,iBAAkB6D,EAAa7D,iBAC/BjC,sBAAuB8F,EAAa9F,4BAHxC,CASA,IAAM+F,EACJlF,EAAY9J,MACV,SAAAgK,GAAE,OACC8E,EAAmBvM,MAClB,SAAA0M,GAAC,OAAIA,EAAEhG,wBAA0Be,EAAGf,6BAErCa,EAAYA,EAAY/L,OAAS,GAExC+Q,EAAmBvP,KAAKyP,IAG1BF,EAAmBrN,SAAQ,SAACyN,EAAI/P,GAC1B+P,GAAMA,EAAGhE,kBACX,EAAKe,gBAAgB,CACnB9O,cAAegC,EACf+L,iBAAkBgE,EAAGhE,iBACrBjC,sBAAuBiG,EAAGjG,+BAvGf,4BA6GD,YAIZ,IAHJ9L,EAGI,EAHJA,cACA+N,EAEI,EAFJA,iBACAjC,EACI,EADJA,sBAEIM,EAAa,EAAK4F,eACpB,EAAKxP,MAAMgD,QACXuI,EACAjC,GAGF,GAAIM,EAAWW,UAAW,KAChBC,EAAaZ,EAAbY,SAGR,KAFAZ,EAAaA,EAAWa,oBAAoB,EAAKzK,MAAMgD,UAGrD,MAAM,IAAI0H,MAAJ,gCACqBF,EADrB,0BAMV,EAAKxK,MAAM3D,wBAAwBmB,EAAeoM,MAhIlD,EAAKjN,MAAQ,CACXwN,YAAa,IAJE,E,uSAQJnH,GACb,IAAMmH,EAAc,GAUpB,OATAnH,EAAQlB,SAAQ,SAAAsH,GACdA,EAAMe,YAAYrI,SAAQ,SAAA2N,GACnBA,EAAK/P,SACR+P,EAAK/P,OAAS,eAEhByK,EAAYvK,KAAK6P,SAIdtF,I,qCAGMnH,EAASuI,EAAkBjC,GACxC,IAAMF,EAAQpG,EAAQ3C,MAAK,SAAA+I,GACzB,OAAOA,EAAMmC,mBAAqBA,KAGpC,GAAKnC,EAIL,OAAOA,EAAMe,YAAY9J,MAAK,SAAAuJ,GAC5B,OAAOA,EAAWN,wBAA0BA,O,0CAS9C,GAAI5H,KAAK1B,MAAMgD,QAAS,CACtB,IAAMmH,EAAczI,KAAKgO,eAAehO,KAAK1B,MAAMgD,SACnDtB,KAAKd,SAAS,CAAEuJ,eAAezI,KAAKiO,2B,yCAIrB9L,GACjB,IAAM+L,EAAqB/L,EAAU7E,OAAOpC,UAAUwB,OAChDyR,EAAiBnO,KAAK1B,MAAMhB,OAAOpC,UAAUwB,OAC7C0R,EAAQpO,KAAK1B,MAAMhB,OAAOpC,UAAUgG,MAAK,SAAA2M,GAAE,QAAMA,EAAG5P,OAE1D,GACE+B,KAAK1B,MAAMgD,UAAYa,EAAUb,SAChC6M,IAAmBD,IAAuBE,EAC3C,CACA,IAAM3F,EAAczI,KAAKgO,eAAehO,KAAK1B,MAAMgD,SACnDtB,KAAKd,SAAS,CAAEuJ,eAAezI,KAAKiO,2B,+BA6E/B,IACC7S,EAAyB4E,KAAK1B,MAA9BlD,qBACFyP,EAAeyC,GAAOlS,GAE5B,OACE,yBAAK6H,UAAU,cACZjD,KAAK/E,MAAMwN,YAAY/L,QACtB,kBAAC,GAAD,CACEoO,cAAe9K,KAAK1B,MAAMwM,cAC1BxJ,QAAStB,KAAK1B,MAAMgD,QACpBuJ,aAAcA,EACdD,gBAAiB5K,KAAK4K,qB,6CAST,WAEbxP,EAAyB4E,KAAK1B,MAA9BlD,qBACR2J,OAAOsJ,KAAKjT,GAAsBgF,SAAQ,SAAAtE,GACxC,EAAKwC,MAAMgQ,0BAA0BxS,W,gCAxKlB0H,a,GAAnBgK,G,YACe,CACjBnS,oBAAqB+K,IAAUkE,OAAOhE,WACtChF,QAAS8E,IAAUO,MACnBvL,qBAAsBgL,IAAUuG,OAAOrG,WACvChJ,OAAQ8I,IAAUuG,OAAOrG,WACzB3L,wBAAyByL,IAAUK,KAAKH,WACxCgI,0BAA2BlI,IAAUK,KAAKH,aAyL/BkH,U,GCpMX5S,IAAKC,MAAMC,QAFbH,G,GAAAA,wBACA2T,G,GAAAA,0BA8BaC,GALavT,aAtBJ,SAAAC,GAAS,MAC+BA,EAAMC,UAEpE,MAAO,CACLG,oBAJ6B,EACvBA,oBAINiC,OAL6B,EACFA,OAK3BlC,qBAN6B,EACMA,qBAMnCF,UAAWD,EAAMC,cAIM,SAAAU,GACzB,MAAO,CACLjB,wBAAyB,SAACmB,EAAeC,GACvCH,EAASjB,GAAwBmB,EAAeC,KAElDuS,0BAA2B,WACzB1S,EAAS0S,UAKatT,CAG1BwS,IC5BIgB,I,QAAY,SAAC,GAAsC,IAApC9N,EAAoC,EAApCA,KAAM+N,EAA8B,EAA9BA,OAAQtF,EAAsB,EAAtBA,SAAUsD,EAAY,EAAZA,MACrCiC,EAAyB,UAAThO,EAAmB,aAAe,YAElDiO,EAASlC,EACX,CACEmC,SAAUnC,EACVoC,YAAaJ,EAAS,KAAgC,EAA1BK,OAAOC,SAAStC,IAE9C,GAEJ,OACE,6BACEvJ,MAAOyL,EACP1L,UAAWgH,IAAW,YAAayE,EAAe,CAChD,UAAWD,KAGZtF,KAKPqF,GAAUpE,UAAY,CACpB1J,KAAM0F,IAAUI,OAAOF,WACvBmI,OAAQrI,IAAUC,KAAKC,WACvB6C,SAAU/C,IAAUiE,KACpBoC,MAAOrG,IAAUI,QAGJgI,U,mgBC3BPQ,GAAmBC,IAAgBC,SAAnCF,eAEFG,GAAsB,SAAC,GAA0B,IAAxBpO,EAAwB,EAAxBA,QAASoI,EAAe,EAAfA,SA6CtC,OACE,kBAAC,IAAD,CACEiG,kBAXsB,kBACxB,yBAAKnM,UAAU,gBAAgBoM,KAAK,SAClC,8CACmBtO,EADnB,KAC6B,6BAD7B,kDAUAA,QAASA,EACTuO,QAhDkB,SAAC9D,EAAO+D,GA6B5BP,GAAetD,KAAK,CAClB1F,QA7BkB,WAAM,SACAwJ,oBAAS,GADT,GACjBC,EADiB,KACXC,EADW,KAGxB,OACE,yBAAKzM,UAAU,gBAAgBoM,KAAK,SAClC,yBAAKpM,UAAU,uBACb,wBAAIA,UAAU,4BACXlC,EADH,KACa,8BAAOyK,EAAMC,WAG5B,4BACExI,UAAU,mDACVsB,QAAS,kBAAMmL,GAAQ,SAAAC,GAAC,OAAKA,OAE7B,kBAAC,IAAD,CACEC,KAAK,eACL3M,UAAW4M,IAAW,0BAA2B,CAC/CC,OAAQL,MAPd,eAaCA,GAAQ,6BAAMF,KAOnBrJ,MAAO,2BAAF,OAA6BnF,OAmBjCoI,IAKPgG,GAAoB/E,UAAY,CAC9BrJ,QAASqF,IAAUI,OAAOF,WAC1B6C,SAAU/C,IAAUiE,KAAK/D,YAGZ6I,ICrEAA,GDqEAA,G,+gCE/CTY,G,YAuCJ,WAAYzR,GAAO,M,iGAAA,S,EACjB,K,EAAA,gBAAMA,GAAN,G,kDADiB,iBA2BX,CACN6H,qBAAqB,EACrBI,sBAAsB,EACtBhD,uBAAwB,GACxBH,sBAAuB,UACvBuE,WAAY,KAhCK,+BAyCE,SAAA1I,GACnBrE,IAAKoV,IAAIC,KAAK,sBAGd,IAAIC,GAAe,IAAIC,MAAOC,cAC1BC,GAAa,IAAIF,MAAOC,cAe5B,OAdI,EAAK9R,MAAMgD,UACb+O,EAAa,IAAIF,KAAK,cAAcC,cACpC,EAAK9R,MAAMgD,QAAQlB,SAAQ,SAAAsH,GACzB,IAAM4I,EAAYC,IAAO7I,EAAM4I,UAAW,YAAYF,cAClDE,EAAYJ,IACdA,EAAeI,GAEbA,EAAYD,IACdA,EAAaC,OAMZE,QAAQC,QAAQ,CACrB,CACEC,cAAe,WACfC,YAAa,cACbC,kBAAmB,EAAKtS,MAAMsS,kBAC9BC,UAAW5R,EAAO4R,UAClBX,eACAG,aACAS,UAAU,QArEG,4BA0ED,SAAAC,GAEhB,OADAnW,IAAKoV,IAAIC,KAAK,mBACPO,QAAQC,aA5EE,4BA+ED,SAACM,EAAeC,GAEhC,OADApW,IAAKoV,IAAIC,KAAK,mBACPO,QAAQC,aAjFE,4BAoFD,SAAAE,GAEhB,OADA/V,IAAKoV,IAAIC,KAAK,mBACPO,QAAQC,aAtFE,8BAyFC,SAACQ,EAAcpH,GAEjC,OADAjP,IAAKoV,IAAIC,KAAK,qBACPO,QAAQC,aA3FE,gCA8FG,SAAAS,GAChB,EAAK5S,MAAM6S,qBACb,EAAK7S,MAAM6S,oBAAoBD,MAhGhB,kCAoGK,SAAAE,GAClB,EAAK9S,MAAM+S,uBACb,EAAK/S,MAAM+S,sBAAsBD,MAtGlB,IAGTE,EAAiB,EAAKhT,MAAtBgT,aACFC,EAASxM,OAAOC,OAAO,GAAIsM,GAJhB,OAMjB1W,IAAKwW,aAAaI,eAAeC,iBAAiB,CAChDC,aAAc,CACZC,SAAUC,IAAQC,qBAClBC,MAAOF,IAAQG,mBAEjBR,WAGF3W,IAAKwW,aAAaY,aAAaP,iBAAiB,CAC9CC,aAAc,CACZC,SAAU,EAAKM,mBACfH,MAAO,EAAKI,gBACZC,OAAQ,EAAKC,gBACbC,OAAQ,EAAKC,gBACbC,aAAc,EAAKC,qBAIvB,EAAKC,mBAAqB,EAAKA,mBAAmBjT,KAAxB,OAxBT,E,+SAoCbQ,KAAK1B,MAAMC,QACbyB,KAAK1B,MAAMC,OAAOmU,e,0CAqEF,MACiB1S,KAAK1B,MAAhCgD,EADU,EACVA,QAASwJ,EADC,EACDA,cADC,EAEuBlQ,IAAKwW,aAAtCY,EAFU,EAEVA,aAAcR,EAFJ,EAEIA,eAGhBmB,EAAe,IAAIX,EAFE,cAE+B,CACxDb,oBAAqBnR,KAAKmR,sBAGtByB,EAAiB,IAAIpB,EAAemB,EAAc,CACtDtB,sBAAuBrR,KAAKqR,wBAO9B,GAJArR,KAAK6S,mBAVsB,cAW3B7S,KAAK2S,aAAeA,EACpB3S,KAAK4S,eAAiBA,EAElBtR,EAAS,CACX,IAAMuP,EAAYvP,EAAQ,IAAMA,EAAQ,GAAGuP,UAE3C8B,EAAaV,mBAAmB,CAAEpB,cAC9B/F,GACF9K,KAAK4S,eAAef,qBAAqBhB,EAAW,CAnB7B,gBAwBzB7Q,KAAKd,SAAS,CACZyI,WAAYmL,GAAwBxR,Q,yCAKvBa,GAAW,MACOnC,KAAK1B,MAAhCgD,EADoB,EACpBA,QAASwJ,EADW,EACXA,cAOjB,GALIxJ,IAAYa,EAAUb,SACxBtB,KAAKd,SAAS,CACZyI,WAAYmL,GAAwBxR,KAGpCwJ,GAAiBA,IAAkB3I,EAAU2I,cAAe,CAC9D,IAAM+F,EAAYvP,EAAQ,IAAMA,EAAQ,GAAGuP,UACnCgC,EAAuB7S,KAAvB6S,mBAER7S,KAAK2S,aAAaV,mBAAmB,CAAEpB,cACvC7Q,KAAK4S,eAAef,qBAAqBhB,EAAW,CAACgC,O,2CAKvD,OAAO7S,KAAK1B,MAAMpD,UAAU8E,KAAK1B,MAAMjD,uB,+BAGhC,IACH0X,EAAkBC,EADf,OAcP,OAZwBpT,IAAiBC,QAAQC,IAAaC,OAE9CK,SAAQ,SAAA6S,GACtBA,EAAS1S,OAAO2S,WAAW9S,SAAQ,SAAA+S,GAC7BA,EAAKnU,KAAO,EAAK/D,MAAMsI,uBACzByP,EAAoBG,EAAKC,UAChBD,EAAKnU,KAAO,EAAK/D,MAAMmI,wBAChC2P,EAAmBI,EAAKC,iBAM5B,oCAEE,kBAACC,GAAA,EAAqBC,SAAtB,MACG,SAAAC,GAAa,OACZ,kBAACC,GAAA,EAAmBF,SAApB,MACG,SAAAG,GAAW,OACV,kBAACC,EAAA,EAAWJ,SAAZ,MACG,SAAAK,GAAU,OACT,kBAACC,EAAA,EAAD,CACEC,SACEF,EAAWG,UAAUC,cACjB,kBACAC,EAENC,SACEN,EAAWG,UAAUC,cAAgB,SAAMC,EAE7CP,YAAaA,GAEZF,GACCA,EAAcW,uBACdX,EAAcW,sBAAsBrI,eAUpD,kBAAC,GAAD,CAAqB9K,QAAQ,cAC3B,kBAAC,EAAD,CACEQ,eACEvB,KAAK1B,MAAMpD,UAAU8E,KAAK1B,MAAMjD,qBAElC8Y,2BAA4BnU,KAAK1B,MAAM6V,2BACvChO,oBAAqBnG,KAAK/E,MAAMkL,oBAChCI,qBAAsBvG,KAAK/E,MAAMsL,qBACjCnD,sBACEpD,KAAK/E,MAAMkL,oBACPnG,KAAK/E,MAAMmI,sBACX,GAENG,uBACEvD,KAAK/E,MAAMsL,qBACPvG,KAAK/E,MAAMsI,uBACX,GAENT,sBAAuB,SAACD,EAAMuR,GAC5B,IAAMC,EAAcxR,GAAQA,EAAK,GAAGyR,cAAgBzR,EAAK0R,MAAM,GACzDC,EAAU,KAAH,OAAQH,EAAR,iBACPI,EAAc,WAAH,OAAcJ,EAAd,aACXK,EAAe3P,OAAOC,OAAO,GAAI,EAAK/J,OAEtCwT,EAASiG,EAAaF,GACtBG,EAAoBD,EAAaD,GAEjCG,EACJD,IAAsBP,GAAmC,OAAlBA,EAEzCM,EAAaD,GAAeL,GAAiBO,IAEdlG,GAAUmG,KAEvCF,EAAaF,IAAYE,EAAaF,IAGxC,EAAKtV,SAASwV,IAEhBpT,QAAStB,KAAK1B,MAAMgD,WAQxB,yBAAK2B,UAAU,iBAEb,kBAAC,GAAD,CAAqBlC,QAAQ,iBAC3B,kBAAC,GAAD,CAAWL,KAAK,OAAO+N,OAAQzO,KAAK/E,MAAMkL,qBACvC4M,EACC,kBAACA,EAAD,CACE7X,UAAW8E,KAAK1B,MAAMpD,UACtBoG,QAAStB,KAAK1B,MAAMgD,QACpBuT,YAAa7U,KAAK1B,MAAMjD,sBAG1B,kBAAC,EAAD,CACEiG,QAAStB,KAAK/E,MAAM0M,WACpBQ,cAAenI,KAAK1B,MAAMgD,YAOlC,yBAAK2B,UAAWgH,IAAW,iBACzB,kBAAC,GAAD,CAAqBlJ,QAAQ,cAC3B,kBAAC,GAAD,CACEO,QAAStB,KAAK1B,MAAMgD,QACpBwJ,cAAe9K,KAAK1B,MAAMwM,kBAMhC,kBAAC,GAAD,CAAqB/J,QAAQ,kBAC3B,kBAAC,GAAD,CAAWL,KAAK,QAAQ+N,OAAQzO,KAAK/E,MAAMsL,sBACxCyM,GACC,kBAACA,EAAD,CACEvE,OAAQzO,KAAK/E,MAAMsL,qBACnBrL,UAAW8E,KAAK1B,MAAMpD,UACtBoG,QAAStB,KAAK1B,MAAMgD,QACpBuT,YAAa7U,KAAK1B,MAAMjD,oBACxBkG,eACEvB,KAAK1B,MAAMpD,UAAU8E,KAAK1B,MAAMjD,qBAElCyZ,kBAAmB9U,KAAKyS,8B,gCA7UrBjP,a,GAAfuM,G,YACe,CACjBzO,QAAS8E,IAAUM,QACjBN,IAAU2O,MAAM,CACdlL,iBAAkBzD,IAAUI,OAAOF,WACnCgK,UAAWlK,IAAUI,OACrBqK,UAAWzK,IAAUI,OACrBiC,YAAarC,IAAUM,QACrBN,IAAU2O,MAAM,CACdnN,sBAAuBxB,IAAUI,OAAOF,WACxC0O,kBAAmB5O,IAAUI,OAC7ByO,aAAc7O,IAAUkE,OACxB4K,eAAgB9O,IAAUkE,OAC1B6K,eAAgB/O,IAAUkE,OAC1BxB,SAAU1C,IAAUI,OAAOF,WAC3B8O,OAAQhP,IAAUM,QAChBN,IAAU2O,MAAM,CACdM,WAAYjP,IAAUK,KAAKH,oBAOvCsK,kBAAmBxK,IAAUO,MAC7B2K,aAAclL,IAAU2O,MAAM,CAC5B7P,KAAMkB,IAAUI,OAChB8O,SAAUlP,IAAUI,SAEtB2K,oBAAqB/K,IAAUK,KAC/B4K,sBAAuBjL,IAAUK,KAEjCvL,UAAWkL,IAAUuG,OAAOrG,WAE5BjL,oBAAqB+K,IAAUkE,OAAOhE,WACtCwE,cAAe1E,IAAUC,KACzB9H,OAAQ6H,IAAUuG,SAoTP3F,mBAAW+I,IAepBwF,GAAqC,e,EAAA,G,EAAA,yBAAG,WAAgBrN,GAAhB,6FAKtCsN,EAAe,GACjBtN,EAAWuN,eAAqD,IAApCvN,EAAWuN,cAAc/Y,SACvDwL,EAAWuN,cAAcrV,SAAQ,SAAAsV,GAC/B,OAAQA,GACN,KAAKC,KAAqBC,WACxBJ,EAAatX,KAAK,sBAClB,MACF,KAAKyX,KAAqBE,yBACxBL,EAAatX,KAAK,iEAClB,MACF,KAAKyX,KAAqBG,yBACxBN,EAAatX,KAAK,oEAClB,MACF,KAAKyX,KAAqBI,0BACxBP,EAAatX,KAAK,kDAClB,MACF,KAAKyX,KAAqBK,kBACxBR,EAAatX,KAAK,oDAClB,MACF,KAAKyX,KAAqBM,aACxBT,EAAatX,KAAK,qCAMtBsX,EAAatX,KAAK,gFAGlBgK,EAAWgO,iBACXhO,EAAWuN,eACVvN,EAAWuN,gBAAkBvN,EAAWuN,cAAc9W,MAAK,SAAAwX,GAAI,OAAIA,IAASR,KAAqBC,gBACpGJ,EAAatX,KAAK,mCAAqCgK,EAAWgO,cAAgB,KArCxC,kBAwCrCV,GAxCqC,0C,iLAAH,sDAqDrC1C,GAA0B,SAASxR,GACvC,OAAOA,EAAQsC,KAAI,SAAA8D,GA0CjB,MAAO,CACLmC,iBA1C2BnC,EAArBmC,iBA2CNlC,WAzCiBD,EAAMe,YAAY7E,KAAI,SAAAsE,GAAc,IASjDkO,EACAC,EARFzO,EAKEM,EALFN,sBACAoN,EAIE9M,EAJF8M,kBACAE,EAGEhN,EAHFgN,eACAC,EAEEjN,EAFFiN,eACAF,EACE/M,EADF+M,aAMF,GAAI/M,EAAWY,UAAoC,QAAxBZ,EAAWY,SAIpCuN,EAAe,WACV,GAAInO,EAAWkN,QAAUlN,EAAWkN,OAAO1Y,OAAQ,CACxD,IAAM4Z,EAAaC,KAAKC,MAAMtO,EAAWkN,OAAO1Y,OAAS,GAEzD0Z,EAAUlO,EAAWkN,OAAOkB,GAAYjB,kBAExCgB,EAAenO,EAAWY,SAAWZ,EAAWY,SAAW,KAK7D,MAAO,CACLsN,UACAC,eACAzO,wBACAoN,oBACAE,iBACAC,iBACAF,eACAwB,YAVkBlB,GAAsCrN,Y,GC7crBtN,IAAKC,MAAMC,QAA9C4b,G,GAAAA,cAAeC,G,GAAAA,gBAEjBC,GAAkB,SAAAC,GAEtB,OAAOA,EAAQA,QAAQlY,MADN,SAAAmY,GAAC,OAAiB,IAAbA,EAAE1K,WAwBpB2K,GAAkB/b,aApBA,SAAAC,GAAS,IACvBC,EAAuBD,EAAvBC,UAAW2b,EAAY5b,EAAZ4b,QACnB,MAAO,CACL3b,UAAWA,EAAUE,qBACrBC,oBAAqBH,EAAUG,oBAC/BiW,aAAcsF,GAAgBC,OAIP,SAAAjb,GACzB,MAAO,CACLuV,oBAAqB,SAAAD,GACnBtV,EAAS8a,GAAcxF,KAEzBG,sBAAuB,SAAAD,GACrBxV,EAAS+a,GAAgBvF,QAKPpW,CAGtB+U,IAEagH,Q,wNCpCf,6CACe,SAASC,EAAYvV,GAClC,IAAMyI,EAAM+M,mBAKZ,OAJA5L,qBAAU,WACRnB,EAAI3B,QAAU9G,IACb,CAACA,IAEGyI,EAAI3B,U,01CCML2O,EAA0CC,IAA1CD,kBAAmBE,EAAuBD,IAAvBC,mBACnBC,EAAwD/V,IAAxD+V,wBAAyBC,EAA+BhW,IAA/BgW,2BACzBnQ,EAAyCD,IAAzCC,qBAAsBoQ,EAAmBrQ,IAAnBqQ,eA+BxBC,EAAe,SAAC9P,EAAOS,EAAesP,EAASC,GACnD,IAAIC,GAAW,EAMf,OAJKD,IACHC,EAAWC,EAAwBlQ,EAAOS,EAAesP,IAGpDE,GAGHC,EAA0B,SAAClQ,EAAOS,EAAesP,GACrD,IAxCuBI,EAAMvK,EAAQwK,EACjCC,EACAC,EACAC,EAEEC,EAmCFP,GAAW,EAIf,GAH0B5S,OAAOsJ,KAAKoJ,GAAS/a,OACE,EAEvB,KAChByb,EAAsBV,EAAtBU,kBAKFC,GAlDeP,EAmDnB1P,EAAc6F,iBAnDWV,EAoDzB6K,EApDiCL,EA+Cb,SAACO,EAAgBnQ,GACrC,OAAOA,EAAWoQ,oBAAsBD,GA/CxCN,EAAW,EAAIF,GACfG,EAAW,GACXC,EAAgB,GAEdC,EAAc5K,EAAOiL,MAAM,MACrBnY,SAAQ,SAAAqB,GAClB,IAAM+W,EAAQT,EAASU,UAAUX,EAAatY,UAAKwU,EAAWvS,IAE9D,GAAI+W,GAAS,EAAG,KACPE,EADO,EACUX,EAASY,OAAOH,EAAO,GADjC,MAEdR,EAASC,GAAiBS,EAC1BT,QAIG,CACLN,SAAUM,IAAkBC,EAAYxb,OACxCX,KAAM,GAAF,OAAMic,EAAN,EAAmBD,MAsCvBrQ,EAAMe,YAAc2P,EAAiBrc,KACrC4b,EAAWS,EAAiBT,SAG9B,OAAOA,GAUHiB,EAAuB,SAAClR,GAA0C,IAAnC+P,EAAmC,uDAAzB,GAAIC,EAAqB,uCAC9DS,EAAsBV,EAAtBU,kBACJU,GAAU,EAGd,IAAKV,EACH,OAAOU,EAET,IAAMC,EAAqBX,EAAkBI,MAAM,KAE/CQ,EAAwB,WAE1B,GADiBC,EAAetc,SAAWoc,EAAmBpc,OAK9D,OAAOsc,EAAeC,OAAM,SAAAC,GAAI,OAC9BJ,EAAmB5X,MACjB,SAAAiY,GAAoB,OAAIA,IAAyBD,EAAKZ,yBAKxDc,EAAyB,WAE3B,IADA,IAAIC,GAAU,EACLb,EAAQ,EAAGA,EAAQM,EAAmBpc,OAAQ8b,IAAS,CAC9D,IAAMW,EAAuBL,EAAmBN,GAC1Cc,EAAeN,EAAeR,GAEpC,IACGc,GACDA,EAAahB,oBAAsBa,EACnC,CACAE,GAAU,EACV,OAGJ,OAAOA,GArC6D,EAwC5B3R,EAAlClF,cAxC8D,MAwCrD,GAxCqD,IAwC5BkF,EAArBe,mBAxCiD,MAwCnC,GAxCmC,EAyChEuQ,EAAiBtB,EAAmBlV,EAASiG,EAC7C8Q,EAAiB7B,EACnBqB,EACAK,EAQJ,OAHEP,IAHGG,GAGOO,KAKRC,EAAmB,SAACC,EAAmBhO,GAAyB,IAAhBlN,EAAgB,uDAAP,GAC7D,IAAIkb,EAAJ,CADoE,MAKvBlb,EAArCmN,KAAMgO,OALsD,MAKpC,aALoC,EAMpEA,EAAgB,CACdjO,cAIEkO,EAAoB,SAACxR,EAAe3F,GACxC,IAAMoX,EACJha,IAAiBC,QAAjB,sBACI6H,EAAQS,EAAc0R,UACtBC,EAAiB,IAAI1C,EAAmB5U,EAAQkF,GAC/BS,EAAc4R,eAAevX,EAAO8V,mBAEzDnQ,EAAc6R,aAAaxX,EAAO8V,kBAAmBwB,GAErD3R,EAAc8R,UAAUH,GAG1B3R,EAAc+R,iCACZN,EACAE,GAGFpS,EAAMe,YAAcN,EAAc6F,iBAClCtG,EAAMyS,mBAAqBhS,EAAciS,mBAAmB,CAC1DtR,SAAUtG,EAAOsG,WAGnBuR,EAA4B3S,EAAOS,IAG/BkS,EAA8B,SAAC3S,EAAOS,GAAkB,IACpD0B,EAAqBnC,EAArBmC,iBAEH1C,EAAqBmT,IAAIzQ,IAC5B1C,EAAqBoT,IAAIpS,IAIvBqS,EAA0B,SAAC9S,EAAOS,GACtC,IAAMyR,EACJha,IAAiBC,QAAjB,sBAEG6H,EAAMe,cACTf,EAAMe,YAAcN,EAAcsS,kBAAkBb,IAGlDlS,EAAMyS,oBACRhS,EAAcuS,uBAAuBhT,EAAMyS,qBAIzCQ,EAAiB,SAAAjT,GACrB,MAAO,CACLmC,iBAAkBnC,EAAMmC,iBACxBrH,OAAQkF,EAAMlF,OAAOoB,KAAI,SAAAsV,GAAI,MAAK,CAChCZ,kBAAmBY,EAAKZ,wBAK9B,SAASsC,EAAT,GAMG,IAYGC,EACAC,EAlBJvJ,EAKC,EALDA,OACAX,EAIC,EAJDA,kBACAkI,EAGC,EAHDA,mBACAxK,EAEC,EAFDA,0BACAyM,EACC,EADDA,aACC,IAEyBvL,oBAAS,GAFlC,GAEMhE,EAFN,KAEawP,EAFb,SAG6BxL,mBAAS,IAHtC,GAGMlO,EAHN,KAGe2Z,EAHf,SAIyCzL,oBAAS,GAJlD,GAIM1E,EAJN,KAIqBoQ,EAJrB,KAKKC,EAAkBjQ,cALvB,EAM0BkQ,qBAAW1H,KAA9BI,iBANP,MAMmB,GANnB,IAUGA,EAFFuH,iBAAkB3D,OARnB,SASC4D,EACExH,EADFwH,8BAgDIC,EAAiB,SAACC,EAAa/D,GACnC,GAAIhX,MAAM2H,QAAQoT,IAAgBA,EAAY9e,OAAS,EAAG,CAExD,IAAM4E,EAAUka,EAAY5X,KAAI,SAAA8D,GAC9BqT,EAAarT,EAAMmC,iBAAkB8Q,EAAejT,IACpD,IAAMS,EAAgB,IAAI+O,EACxBxP,EACAA,EAAMmC,kBAsBR,OAnBA2Q,EAAwB9S,EAAOS,GAC/BkS,EAA4B3S,EAAOS,GAGnC0S,EAAyBnT,EAAMmC,kBAAoB0N,EACjDkE,EAAoBtT,IAEnBuT,MAAK,SAAAC,GACAA,IAAWA,EAAOC,YAtDX,SAAClU,EAAOS,EAAesP,GAEzBD,EACf9P,EACAS,EACAsP,EACAC,IAKApJ,EAA0B,GAG5B,IAAMuN,EAAsBjD,EAC1BlR,EACA+P,EACAC,GAGF8B,EACEqC,EACA,qGACAV,GAGFF,EAAW,GAAD,SAAK3Z,GAAL,CAAcoG,KACxBwT,GAAiB,GA4BPY,CAAapU,EAAOS,EAAesP,MAGtClM,OAAM,SAAAC,GACDA,IAAUA,EAAMoQ,aAClBZ,EAASxP,GACTwE,IAAIxE,MAAMA,OAIT9D,KAGTuT,EAAW3Z,GACX4Z,GAAiB,KAMfO,EAAmB,4CAAG,WAAMtT,GAAN,mGACDA,EAAc0R,UAA/BkC,EADkB,EAClBA,aADkB,wDAIpBC,EAJoB,4CAIH,sGAChBD,EAAaE,UADG,iEAEAF,EAAaG,OAFb,cAEf1Z,EAFe,OAGrBmX,EAAkBxR,EAAe3F,GATTyY,GAAW,SAAA3Z,GAAO,SAAQA,MAM7B,kBAKd0a,KALc,2CAJG,qDAYpBG,EACJb,GAAiCnT,EAAciU,iBAC3CC,EAAW5b,MAAM0b,GACpBG,KAAK,MACL1Y,IAAIoY,GAhBmB,SAkBbxL,QAAQlI,IAAI+T,GAlBC,mFAAH,sDAqBnBE,EAAW,4CAAG,uGAClB,IACQ9E,EAAU,GAEVU,EAAoBW,GAAsBA,EAAmB,GAC7D0D,EAAiB,CAACjL,EAAQX,GAE5BuH,IACFV,EAAQU,kBAAoBA,EAExBT,GACF8E,EAAete,KAAKuZ,KAKtB3D,EAAU2I,0BACV3I,EAAU4I,2BAEVF,EAAete,MAAK,GAGtB4c,EAA0BlK,GAAqB2G,EAC7CF,EAAuB,WAAvB,EAA2BmF,IAE1Bd,MAAK,SAAAC,GACAA,IAAWA,EAAOC,YACpBL,EAAeI,EAAQlE,MAG1BlM,OAAM,SAAAC,GACDA,IAAUA,EAAMoQ,aAClBZ,EAASxP,GACTwE,IAAIxE,MAAMA,OAGhB,MAAOA,GACHA,IACFwP,EAASxP,GACTwE,IAAIxE,MAAMA,IAvCI,2CAAH,qDA4CXmR,EAA2BC,uBAAY,WAC3C,IAAK,IAAIhM,KAAqBkK,EACxB,WAAYA,EAA0BlK,IACxCkK,EAA0BlK,GAAmBiM,SAIjD,IAAK,IAAIjM,KAAqBiK,EACxB,WAAYA,EAAyBjK,KACvCiK,EAAyBjK,GAAmBiM,SAC5CvF,EAA2B1G,GAC3BzJ,EAAqBgL,OAAOvB,OAK5BkM,EAAwB9F,YAAYpG,GAwB1C,GAtBAvF,qBAAU,aAENyR,GACAA,EAAsB7D,OAAM,SAAA8D,GAAC,OAAInM,EAAkBxP,SAAS2b,SAI5D5V,EAAqB6V,QACrBL,OAED,CAACG,EAAuBH,EAA0B/L,IAErDvF,qBAAU,WAKR,OAJAwP,EAA2B,GAC3BC,EAA4B,GAC5ByB,IAEO,WACLI,OAED,IAECnR,EAAO,CACT,IAAMxF,EAAUiG,KAAKC,UAAUV,GAC/B,OAAIxF,EAAQ5E,SAAS,QAAU4E,EAAQ5E,SAAS,aACvC,kBAAC6b,EAAA,EAAD,MAGF,kBAACA,EAAA,EAAD,CAAUxR,QAAQ,kCAG3B,OACE,kBAACsL,EAAA,EAAD,CACEzV,QAASA,EACTwJ,cAAeA,EACf8F,kBAAmBA,IAKzBgK,EAAwBxQ,UAAY,CAClCwG,kBAAmBxK,IAAUO,MAAML,WACnCwS,mBAAoB1S,IAAUO,MAC9B4K,OAAQnL,IAAUuG,OAClB2B,0BAA2BlI,IAAUK,KAAKH,WAC1CyU,aAAc3U,IAAUK,KAAKH,YAGhBsU,Q,QCpbqChgB,EAAKC,MAAMC,QAAvDwT,E,EAAAA,0BAA2ByM,E,EAAAA,aAC7BlX,EAAW,SAAAiT,GAAC,OAAiB,IAAbA,EAAE1K,QAoBlB8Q,EAAmCliB,aAlBjB,SAACC,EAAOiB,GAC9B,IAAMoV,EAAerW,EAAM4b,QAAQA,QAAQlY,KAAKkF,GAEhD,MAAO,CACL0N,OAAQrV,EAASqV,QAAUD,MAGJ,SAAA1V,GACzB,MAAO,CACLmf,aAAc,SAAClR,EAAkB9N,GAC/BH,EAASmf,EAAalR,EAAkB9N,KAE1CuS,0BAA2B,WACzB1S,EAAS0S,SAK0BtT,CAGvC4f,GAEasC","file":"ConnectedStandaloneRouting~IHEInvokeImageDisplay~ViewerRouting.bundle.60a45c773e1469a7f521.js","sourcesContent":["import { connect } from 'react-redux';\nimport { CineDialog } from '@ohif/ui';\nimport OHIF from '@ohif/core';\nimport csTools from 'cornerstone-tools';\nimport { commandsManager } from './../App.js';\n// Our target output kills the `as` and \"import\" throws a keyword error\n// import { import as toolImport, getToolState } from 'cornerstone-tools';\nimport cloneDeep from 'lodash.clonedeep';\n\nconst toolImport = csTools.import;\nconst scrollToIndex = toolImport('util/scrollToIndex');\nconst { setViewportSpecificData } = OHIF.redux.actions;\n\n// Why do I need or care about any of this info?\n// A dispatch action should be able to pull this at the time of an event?\n// `isPlaying` and `cineFrameRate` might matter, but I think we can prop pass for those.\nconst mapStateToProps = state => {\n // Get activeViewport's `cine` and `stack`\n const { viewportSpecificData, activeViewportIndex } = state.viewports;\n const { cine } = viewportSpecificData[activeViewportIndex] || {};\n const dom = commandsManager.runCommand('getActiveViewportEnabledElement');\n\n const cineData = cine || {\n isPlaying: false,\n cineFrameRate: 24,\n };\n\n // New props we're creating?\n return {\n activeEnabledElement: dom,\n activeViewportCineData: cineData,\n activeViewportIndex: state.viewports.activeViewportIndex,\n };\n};\n\nconst mapDispatchToProps = dispatch => {\n return {\n dispatchSetViewportSpecificData: (viewportIndex, data) => {\n dispatch(setViewportSpecificData(viewportIndex, data));\n },\n };\n};\n\nconst mergeProps = (propsFromState, propsFromDispatch, ownProps) => {\n const {\n activeEnabledElement,\n activeViewportCineData,\n activeViewportIndex,\n } = propsFromState;\n\n return {\n cineFrameRate: activeViewportCineData.cineFrameRate,\n isPlaying: activeViewportCineData.isPlaying,\n onPlayPauseChanged: isPlaying => {\n const cine = cloneDeep(activeViewportCineData);\n cine.isPlaying = !cine.isPlaying;\n\n propsFromDispatch.dispatchSetViewportSpecificData(activeViewportIndex, {\n cine,\n });\n },\n onFrameRateChanged: frameRate => {\n const cine = cloneDeep(activeViewportCineData);\n cine.cineFrameRate = frameRate;\n\n propsFromDispatch.dispatchSetViewportSpecificData(activeViewportIndex, {\n cine,\n });\n },\n onClickNextButton: () => {\n const stackData = csTools.getToolState(activeEnabledElement, 'stack');\n if (!stackData || !stackData.data || !stackData.data.length) return;\n const { currentImageIdIndex, imageIds } = stackData.data[0];\n if (currentImageIdIndex >= imageIds.length - 1) return;\n scrollToIndex(activeEnabledElement, currentImageIdIndex + 1);\n },\n onClickBackButton: () => {\n const stackData = csTools.getToolState(activeEnabledElement, 'stack');\n if (!stackData || !stackData.data || !stackData.data.length) return;\n const { currentImageIdIndex } = stackData.data[0];\n if (currentImageIdIndex === 0) return;\n scrollToIndex(activeEnabledElement, currentImageIdIndex - 1);\n },\n onClickSkipToStart: () => {\n const stackData = csTools.getToolState(activeEnabledElement, 'stack');\n if (!stackData || !stackData.data || !stackData.data.length) return;\n scrollToIndex(activeEnabledElement, 0);\n },\n onClickSkipToEnd: () => {\n const stackData = csTools.getToolState(activeEnabledElement, 'stack');\n if (!stackData || !stackData.data || !stackData.data.length) return;\n const lastIndex = stackData.data[0].imageIds.length - 1;\n scrollToIndex(activeEnabledElement, lastIndex);\n },\n };\n};\n\nconst ConnectedCineDialog = connect(\n mapStateToProps,\n mapDispatchToProps,\n mergeProps\n)(CineDialog);\n\nexport default ConnectedCineDialog;\n","import { LayoutButton } from '@ohif/ui';\nimport OHIF from '@ohif/core';\nimport { connect } from 'react-redux';\n\nconst { setLayout, setViewportActive } = OHIF.redux.actions;\n\nconst mapStateToProps = state => {\n return {\n currentLayout: state.viewports.layout,\n activeViewportIndex: state.viewports.activeViewportIndex,\n };\n};\n\nconst mapDispatchToProps = dispatch => {\n return {\n // TODO: Change if layout switched becomes more complex\n onChange: (selectedCell, currentLayout, activeViewportIndex) => {\n const viewports = [];\n const numRows = selectedCell.row + 1;\n const numColumns = selectedCell.col + 1;\n const numViewports = numRows * numColumns;\n\n for (let i = 0; i < numViewports; i++) {\n // Hacky way to allow users to exit MPR \"mode\"\n const viewport = currentLayout.viewports[i];\n let plugin = viewport && viewport.plugin;\n if (viewport && viewport.vtk) {\n plugin = 'cornerstone';\n }\n\n viewports.push({\n plugin,\n });\n }\n const layout = {\n numRows,\n numColumns,\n viewports,\n };\n\n const maxActiveIndex = numViewports - 1;\n if (activeViewportIndex > maxActiveIndex) {\n dispatch(setViewportActive(0));\n }\n\n dispatch(setLayout(layout));\n },\n };\n};\n\nconst mergeProps = (propsFromState, propsFromDispatch) => {\n const onChangeFromDispatch = propsFromDispatch.onChange;\n const { currentLayout, activeViewportIndex } = propsFromState;\n\n return {\n onChange: selectedCell =>\n onChangeFromDispatch(selectedCell, currentLayout, activeViewportIndex),\n };\n};\n\nconst ConnectedLayoutButton = connect(\n mapStateToProps,\n mapDispatchToProps,\n mergeProps\n)(LayoutButton);\n\nexport default ConnectedLayoutButton;\n","import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport { withTranslation } from 'react-i18next';\n\nimport { MODULE_TYPES } from '@ohif/core';\nimport {\n ExpandableToolMenu,\n RoundedButtonGroup,\n ToolbarButton,\n withModal,\n withDialog,\n} from '@ohif/ui';\n\nimport './ToolbarRow.css';\nimport { commandsManager, extensionManager } from './../App.js';\n\nimport ConnectedCineDialog from './ConnectedCineDialog';\nimport ConnectedLayoutButton from './ConnectedLayoutButton';\nimport { withAppContext } from '../context/AppContext';\n\nclass ToolbarRow extends Component {\n // TODO: Simplify these? isOpen can be computed if we say \"any\" value for selected,\n // closed if selected is null/undefined\n static propTypes = {\n isLeftSidePanelOpen: PropTypes.bool.isRequired,\n isRightSidePanelOpen: PropTypes.bool.isRequired,\n selectedLeftSidePanel: PropTypes.string.isRequired,\n selectedRightSidePanel: PropTypes.string.isRequired,\n handleSidePanelChange: PropTypes.func.isRequired,\n activeContexts: PropTypes.arrayOf(PropTypes.string).isRequired,\n studies: PropTypes.array,\n t: PropTypes.func.isRequired,\n // NOTE: withDialog, withModal HOCs\n dialog: PropTypes.any,\n modal: PropTypes.any,\n };\n\n static defaultProps = {\n studies: [],\n };\n\n constructor(props) {\n super(props);\n\n const toolbarButtonDefinitions = _getVisibleToolbarButtons.call(this);\n // TODO:\n // If it's a tool that can be active... Mark it as active?\n // - Tools that are on/off?\n // - Tools that can be bound to multiple buttons?\n\n // Normal ToolbarButtons...\n // Just how high do we need to hoist this state?\n // Why ToolbarRow instead of just Toolbar? Do we have any others?\n this.state = {\n toolbarButtons: toolbarButtonDefinitions,\n activeButtons: [],\n };\n\n this.seriesPerStudyCount = [];\n\n this._handleBuiltIn = _handleBuiltIn.bind(this);\n this._onDerivedDisplaySetsLoadedAndCached = this._onDerivedDisplaySetsLoadedAndCached.bind(\n this\n );\n\n this.updateButtonGroups();\n }\n\n updateButtonGroups() {\n const panelModules = extensionManager.modules[MODULE_TYPES.PANEL];\n\n this.buttonGroups = {\n left: [],\n right: [],\n };\n\n // ~ FIND MENU OPTIONS\n panelModules.forEach(panelExtension => {\n const panelModule = panelExtension.module;\n const defaultContexts = Array.from(panelModule.defaultContext);\n\n panelModule.menuOptions.forEach(menuOption => {\n const contexts = Array.from(menuOption.context || defaultContexts);\n const hasActiveContext = this.props.activeContexts.some(actx =>\n contexts.includes(actx)\n );\n\n // It's a bit beefy to pass studies; probably only need to be reactive on `studyInstanceUIDs` and activeViewport?\n // Note: This does not cleanly handle `studies` prop updating with panel open\n const isDisabled =\n typeof menuOption.isDisabled === 'function' &&\n menuOption.isDisabled(this.props.studies, this.props.activeViewport);\n\n if (hasActiveContext && !isDisabled) {\n const menuOptionEntry = {\n value: menuOption.target,\n icon: menuOption.icon,\n bottomLabel: menuOption.label,\n };\n const from = menuOption.from || 'right';\n\n this.buttonGroups[from].push(menuOptionEntry);\n }\n });\n });\n\n // TODO: This should come from extensions, instead of being baked in\n this.buttonGroups.left.unshift({\n value: 'studies',\n icon: 'th-large',\n bottomLabel: this.props.t('Series'),\n });\n }\n\n componentDidMount() {\n /*\n * TODO: Improve the way we notify parts of the app\n * that depends on derived display sets to be loaded.\n * (Implement pubsub for better tracking of derived display sets)\n */\n document.addEventListener(\n 'deriveddisplaysetsloadedandcached',\n this._onDerivedDisplaySetsLoadedAndCached\n );\n }\n\n componentWillUnmount() {\n document.removeEventListener(\n 'deriveddisplaysetsloadedandcached',\n this._onDerivedDisplaySetsLoadedAndCached\n );\n }\n\n _onDerivedDisplaySetsLoadedAndCached() {\n this.updateButtonGroups();\n this.setState({\n toolbarButtons: _getVisibleToolbarButtons.call(this),\n });\n }\n\n componentDidUpdate(prevProps) {\n const activeContextsChanged =\n prevProps.activeContexts !== this.props.activeContexts;\n\n const prevStudies = prevProps.studies;\n const prevActiveViewport = prevProps.activeViewport;\n const activeViewport = this.props.activeViewport;\n const studies = this.props.studies;\n const seriesPerStudyCount = this.seriesPerStudyCount;\n\n let shouldUpdate = false;\n\n if (\n prevStudies.length !== studies.length ||\n prevActiveViewport !== activeViewport\n ) {\n shouldUpdate = true;\n } else {\n for (let i = 0; i < studies.length; i++) {\n if (studies[i].series.length !== seriesPerStudyCount[i]) {\n seriesPerStudyCount[i] = studies[i].series.length;\n\n shouldUpdate = true;\n break;\n }\n }\n }\n\n if (shouldUpdate) {\n this.updateButtonGroups();\n }\n\n if (activeContextsChanged) {\n this.setState(\n {\n toolbarButtons: _getVisibleToolbarButtons.call(this),\n },\n this.closeCineDialogIfNotApplicable\n );\n }\n }\n\n closeCineDialogIfNotApplicable = () => {\n const { dialog } = this.props;\n let { dialogId, activeButtons, toolbarButtons } = this.state;\n if (dialogId) {\n const cineButtonPresent = toolbarButtons.find(\n button => button.options && button.options.behavior === 'CINE'\n );\n if (!cineButtonPresent) {\n dialog.dismiss({ id: dialogId });\n activeButtons = activeButtons.filter(\n button => button.options && button.options.behavior !== 'CINE'\n );\n this.setState({ dialogId: null, activeButtons });\n }\n }\n };\n\n render() {\n const buttonComponents = _getButtonComponents.call(\n this,\n this.state.toolbarButtons,\n this.state.activeButtons\n );\n\n const onPress = (side, value) => {\n this.props.handleSidePanelChange(side, value);\n };\n const onPressLeft = onPress.bind(this, 'left');\n const onPressRight = onPress.bind(this, 'right');\n\n return (\n <>\n <div className=\"ToolbarRow\">\n <div className=\"pull-left m-t-1 p-y-1\" style={{ padding: '10px' }}>\n <RoundedButtonGroup\n options={this.buttonGroups.left}\n value={this.props.selectedLeftSidePanel || ''}\n onValueChanged={onPressLeft}\n />\n </div>\n {buttonComponents}\n <ConnectedLayoutButton />\n <div\n className=\"pull-right m-t-1 rm-x-1\"\n style={{ marginLeft: 'auto' }}\n >\n {this.buttonGroups.right.length && (\n <RoundedButtonGroup\n options={this.buttonGroups.right}\n value={this.props.selectedRightSidePanel || ''}\n onValueChanged={onPressRight}\n />\n )}\n </div>\n </div>\n </>\n );\n }\n}\n\nfunction _getCustomButtonComponent(button, activeButtons) {\n const CustomComponent = button.CustomComponent;\n const isValidComponent = typeof CustomComponent === 'function';\n\n // Check if its a valid customComponent. Later on an CustomToolbarComponent interface could be implemented.\n if (isValidComponent) {\n const parentContext = this;\n const activeButtonsIds = activeButtons.map(button => button.id);\n const isActive = activeButtonsIds.includes(button.id);\n\n return (\n <CustomComponent\n parentContext={parentContext}\n toolbarClickCallback={_handleToolbarButtonClick.bind(this)}\n button={button}\n key={button.id}\n activeButtons={activeButtonsIds}\n isActive={isActive}\n />\n );\n }\n}\n\nfunction _getExpandableButtonComponent(button, activeButtons) {\n // Iterate over button definitions and update `onClick` behavior\n let activeCommand;\n const childButtons = button.buttons.map(childButton => {\n childButton.onClick = _handleToolbarButtonClick.bind(this, childButton);\n\n if (activeButtons.map(button => button.id).indexOf(childButton.id) > -1) {\n activeCommand = childButton.id;\n }\n\n return childButton;\n });\n\n return (\n <ExpandableToolMenu\n key={button.id}\n label={button.label}\n icon={button.icon}\n buttons={childButtons}\n activeCommand={activeCommand}\n />\n );\n}\n\nfunction _getDefaultButtonComponent(button, activeButtons) {\n return (\n <ToolbarButton\n key={button.id}\n label={button.label}\n icon={button.icon}\n onClick={_handleToolbarButtonClick.bind(this, button)}\n isActive={activeButtons.map(button => button.id).includes(button.id)}\n />\n );\n}\n/**\n * Determine which extension buttons should be showing, if they're\n * active, and what their onClick behavior should be.\n */\nfunction _getButtonComponents(toolbarButtons, activeButtons) {\n const _this = this;\n return toolbarButtons.map(button => {\n const hasCustomComponent = button.CustomComponent;\n const hasNestedButtonDefinitions = button.buttons && button.buttons.length;\n\n if (hasCustomComponent) {\n return _getCustomButtonComponent.call(_this, button, activeButtons);\n }\n\n if (hasNestedButtonDefinitions) {\n return _getExpandableButtonComponent.call(_this, button, activeButtons);\n }\n\n return _getDefaultButtonComponent.call(_this, button, activeButtons);\n });\n}\n\n/**\n * TODO: DEPRECATE\n * This is used exclusively in `extensions/cornerstone/src`\n * We have better ways with new UI Services to trigger \"builtin\" behaviors\n *\n * A handy way for us to handle different button types. IE. firing commands for\n * buttons, or initiation built in behavior.\n *\n * @param {*} button\n * @param {*} evt\n * @param {*} props\n */\nfunction _handleToolbarButtonClick(button, evt, props) {\n const { activeButtons } = this.state;\n\n if (button.commandName) {\n const options = Object.assign({ evt }, button.commandOptions);\n commandsManager.runCommand(button.commandName, options);\n }\n\n // TODO: Use Types ENUM\n // TODO: We can update this to be a `getter` on the extension to query\n // For the active tools after we apply our updates?\n if (button.type === 'setToolActive') {\n const toggables = activeButtons.filter(\n ({ options }) => options && !options.togglable\n );\n this.setState({ activeButtons: [...toggables, button] });\n } else if (button.type === 'builtIn') {\n this._handleBuiltIn(button);\n }\n}\n\n/**\n *\n */\nfunction _getVisibleToolbarButtons() {\n const toolbarModules = extensionManager.modules[MODULE_TYPES.TOOLBAR];\n const toolbarButtonDefinitions = [];\n\n toolbarModules.forEach(extension => {\n const { definitions, defaultContext } = extension.module;\n definitions.forEach(definition => {\n const context = definition.context || defaultContext;\n\n if (this.props.activeContexts.includes(context)) {\n toolbarButtonDefinitions.push(definition);\n }\n });\n });\n\n return toolbarButtonDefinitions;\n}\n\nfunction _handleBuiltIn(button) {\n /* TODO: Keep cine button active until its unselected. */\n const { dialog, t } = this.props;\n const { dialogId } = this.state;\n const { id, options } = button;\n\n if (options.behavior === 'CINE') {\n if (dialogId) {\n dialog.dismiss({ id: dialogId });\n this.setState(state => ({\n dialogId: null,\n activeButtons: [\n ...state.activeButtons.filter(button => button.id !== id),\n ],\n }));\n } else {\n const spacing = 20;\n const { x, y } = document\n .querySelector(`.ViewerMain`)\n .getBoundingClientRect();\n const newDialogId = dialog.create({\n content: ConnectedCineDialog,\n defaultPosition: {\n x: x + spacing || 0,\n y: y + spacing || 0,\n },\n });\n this.setState(state => ({\n dialogId: newDialogId,\n activeButtons: [...state.activeButtons, button],\n }));\n }\n }\n\n if (options.behavior === 'DOWNLOAD_SCREEN_SHOT') {\n commandsManager.runCommand('showDownloadViewportModal', {\n title: t('Download High Quality Image'),\n });\n }\n}\n\nexport default withTranslation(['Common', 'ViewportDownloadForm'])(\n withModal(withDialog(withAppContext(ToolbarRow)))\n);\n","import OHIF from '@ohif/core';\nimport { connect } from 'react-redux';\nimport { StudyBrowser } from '@ohif/ui';\nimport cloneDeep from 'lodash.clonedeep';\nimport findDisplaySetByUID from './findDisplaySetByUID';\n\nconst { studyMetadataManager } = OHIF.utils;\n\nconst { setActiveViewportSpecificData } = OHIF.redux.actions;\n\n// TODO\n// - Determine in which display set is active from Redux (activeViewportIndex and layout viewportData)\n// - Pass in errors and stack loading progress from Redux\nconst mapStateToProps = (state, ownProps) => {\n // If we know that the stack loading progress details have changed,\n // we can try to update the component state so that the thumbnail\n // progress bar is updated\n const stackLoadingProgressMap = state.loading.progress;\n const studiesWithLoadingData = cloneDeep(ownProps.studies);\n\n studiesWithLoadingData.forEach(study => {\n study.thumbnails.forEach(data => {\n const { displaySetInstanceUID } = data;\n const stackId = `StackProgress:${displaySetInstanceUID}`;\n const stackProgressData = stackLoadingProgressMap[stackId];\n\n let stackPercentComplete = 0;\n if (stackProgressData) {\n stackPercentComplete = stackProgressData.percentComplete;\n }\n\n data.stackPercentComplete = stackPercentComplete;\n });\n });\n\n return {\n studies: studiesWithLoadingData,\n };\n};\n\nconst mapDispatchToProps = (dispatch, ownProps) => {\n return {\n onThumbnailClick: displaySetInstanceUID => {\n let displaySet = findDisplaySetByUID(\n ownProps.studyMetadata,\n displaySetInstanceUID\n );\n\n if (displaySet.isDerived) {\n const { Modality } = displaySet;\n\n displaySet = displaySet.getSourceDisplaySet(ownProps.studyMetadata);\n\n if (!displaySet) {\n throw new Error(\n `Referenced series for ${Modality} dataset not present.`\n );\n }\n\n if (!displaySet) {\n throw new Error('Source data not present');\n }\n }\n\n dispatch(setActiveViewportSpecificData(displaySet));\n },\n };\n};\n\nconst ConnectedStudyBrowser = connect(\n mapStateToProps,\n mapDispatchToProps\n)(StudyBrowser);\n\nexport default ConnectedStudyBrowser;\n","/**\n * Finds displaySet by UID across all displaySets inside studyMetadata\n * @param {Array} studyMetadata\n * @param {string} displaySetInstanceUID\n */\nexport default function findDisplaySetByUID(\n studyMetadata,\n displaySetInstanceUID\n) {\n if (!Array.isArray(studyMetadata)) return null;\n\n const allDisplaySets = studyMetadata.reduce((all, current) => {\n let currentDisplaySet = [];\n if (current && Array.isArray(current.displaySets)) {\n currentDisplaySet = current.displaySets;\n }\n return all.concat(currentDisplaySet);\n }, []);\n\n const bySetInstanceUID = ds =>\n ds.displaySetInstanceUID === displaySetInstanceUID;\n\n const displaySet = allDisplaySets.find(bySetInstanceUID);\n return displaySet || null;\n}\n","import React from 'react';\nimport { useDrop } from 'react-dnd';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport './ViewportPane.css';\n\nconst ViewportPane = function (props) {\n const { children, onDrop, viewportIndex, className: propClassName } = props;\n const [{ hovered, highlighted }, drop] = useDrop({\n accept: 'thumbnail',\n drop: (droppedItem, monitor) => {\n const canDrop = monitor.canDrop();\n const isOver = monitor.isOver();\n\n if (canDrop && isOver && onDrop) {\n const { StudyInstanceUID, displaySetInstanceUID } = droppedItem;\n\n onDrop({ viewportIndex, StudyInstanceUID, displaySetInstanceUID });\n }\n },\n // Monitor, and collect props.\n // Returned as values by `useDrop`\n collect: monitor => ({\n highlighted: monitor.canDrop(),\n hovered: monitor.isOver(),\n }),\n });\n\n return (\n <div\n className={classNames(\n 'viewport-drop-target',\n { hovered: hovered },\n { highlighted: highlighted },\n propClassName\n )}\n ref={drop}\n data-cy={`viewport-container-${viewportIndex}`}\n >\n {children}\n </div>\n );\n};\n\nViewportPane.propTypes = {\n children: PropTypes.node.isRequired,\n viewportIndex: PropTypes.number.isRequired,\n onDrop: PropTypes.func.isRequired,\n className: PropTypes.string,\n};\n\nexport default ViewportPane;\n","import './ViewportGrid.css';\n\nimport React, { useEffect } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { utils } from '@ohif/core';\nimport { useSnackbarContext, useLogger } from '@ohif/ui';\n//\nimport ViewportPane from './ViewportPane.js';\nimport DefaultViewport from './DefaultViewport.js';\nimport EmptyViewport from './EmptyViewport.js';\n\nconst { loadAndCacheDerivedDisplaySets } = utils;\n\nconst ViewportGrid = function(props) {\n const {\n activeViewportIndex,\n availablePlugins,\n defaultPlugin: defaultPluginName,\n layout,\n numRows,\n numColumns,\n setViewportData,\n studies,\n viewportData,\n children,\n isStudyLoaded,\n } = props;\n\n const rowSize = 100 / numRows;\n const colSize = 100 / numColumns;\n\n // http://grid.malven.co/\n if (!viewportData || !viewportData.length) {\n return null;\n }\n\n const snackbar = useSnackbarContext();\n const logger = useLogger();\n\n useEffect(() => {\n if (isStudyLoaded) {\n viewportData.forEach(displaySet => {\n const promises = loadAndCacheDerivedDisplaySets(displaySet, studies);\n promises.forEach(promise => {\n promise.catch(error => {\n logger.error({ error, message: error.message });\n snackbar.show({\n title: 'Error loading derived display set:',\n message: error.message,\n type: 'error',\n error,\n autoClose: false,\n });\n });\n });\n });\n }\n }, [studies, viewportData, isStudyLoaded, snackbar]);\n\n const getViewportPanes = () =>\n layout.viewports.map((layout, viewportIndex) => {\n const displaySet = viewportData[viewportIndex];\n\n if (!displaySet) {\n return null;\n }\n\n const data = {\n displaySet,\n studies,\n };\n\n // JAMES TODO:\n\n // Use whichever plugin is currently in use in the panel\n // unless nothing is specified. If nothing is specified\n // and the display set has a plugin specified, use that.\n //\n // TODO: Change this logic to:\n // - Plugins define how capable they are of displaying a SopClass\n // - When updating a panel, ensure that the currently enabled plugin\n // in the viewport is capable of rendering this display set. If not\n // then use the most capable available plugin\n\n const pluginName =\n !layout.plugin && displaySet && displaySet.plugin\n ? displaySet.plugin\n : layout.plugin;\n\n const ViewportComponent = _getViewportComponent(\n data, // Why do we pass this as `ViewportData`, when that's not really what it is?\n viewportIndex,\n children,\n availablePlugins,\n pluginName,\n defaultPluginName\n );\n\n return (\n <ViewportPane\n onDrop={setViewportData}\n viewportIndex={viewportIndex} // Needed by `setViewportData`\n className={classNames('viewport-container', {\n active: activeViewportIndex === viewportIndex,\n })}\n key={viewportIndex}\n >\n {ViewportComponent}\n </ViewportPane>\n );\n });\n\n const ViewportPanes = React.useMemo(getViewportPanes, [\n layout,\n viewportData,\n studies,\n children,\n availablePlugins,\n defaultPluginName,\n setViewportData,\n activeViewportIndex,\n ]);\n\n return (\n <div\n data-cy=\"viewprt-grid\"\n style={{\n display: 'grid',\n gridTemplateRows: `repeat(${numRows}, ${rowSize}%)`,\n gridTemplateColumns: `repeat(${numColumns}, ${colSize}%)`,\n height: '100%',\n width: '100%',\n }}\n >\n {ViewportPanes}\n </div>\n );\n};\n\nViewportGrid.propTypes = {\n viewportData: PropTypes.array.isRequired,\n supportsDrop: PropTypes.bool.isRequired,\n activeViewportIndex: PropTypes.number.isRequired,\n layout: PropTypes.object.isRequired,\n availablePlugins: PropTypes.object.isRequired,\n setViewportData: PropTypes.func.isRequired,\n studies: PropTypes.array,\n children: PropTypes.node,\n defaultPlugin: PropTypes.string,\n numRows: PropTypes.number.isRequired,\n numColumns: PropTypes.number.isRequired,\n};\n\nViewportGrid.defaultProps = {\n viewportData: [],\n numRows: 1,\n numColumns: 1,\n layout: {\n viewports: [{}],\n },\n activeViewportIndex: 0,\n supportsDrop: true,\n availablePlugins: {\n DefaultViewport,\n },\n defaultPlugin: 'defaultViewportPlugin',\n};\n\n/**\n *\n *\n * @param {*} plugin\n * @param {*} viewportData\n * @param {*} viewportIndex\n * @param {*} children\n * @returns\n */\nfunction _getViewportComponent(\n viewportData,\n viewportIndex,\n children,\n availablePlugins,\n pluginName,\n defaultPluginName\n) {\n if (viewportData.displaySet) {\n pluginName = pluginName || defaultPluginName;\n const ViewportComponent = availablePlugins[pluginName];\n\n if (!ViewportComponent) {\n throw new Error(\n `No Viewport Component available for name ${pluginName}.\n Available plugins: ${JSON.stringify(availablePlugins)}`\n );\n }\n\n return (\n <ViewportComponent\n viewportData={viewportData}\n viewportIndex={viewportIndex}\n children={[children]}\n />\n );\n }\n\n return <EmptyViewport />;\n}\n\nexport default ViewportGrid;\n","/**\n *\n *\n * @export\n * @param {*} props\n * @returns\n */\nexport default function DefaultViewport(props) {\n return <div>{JSON.stringify(props)}</div>;\n}\n","import ViewportGrid from './ViewportGrid.js';\nimport { MODULE_TYPES } from '@ohif/core';\nimport { connect } from 'react-redux';\nimport { extensionManager } from './../../App.js';\nimport memoize from 'lodash/memoize';\n\nconst getAvailableViewportModules = memoize(viewportModules => {\n const availableViewportModules = {};\n viewportModules.forEach(moduleDefinition => {\n availableViewportModules[moduleDefinition.extensionId] =\n moduleDefinition.module;\n });\n return availableViewportModules;\n});\n\nconst mapStateToProps = state => {\n const viewportModules = extensionManager.modules[MODULE_TYPES.VIEWPORT];\n const availableViewportModules = getAvailableViewportModules(viewportModules);\n\n // TODO: Use something like state.plugins.defaultPlugin[MODULE_TYPES.VIEWPORT]\n let defaultPlugin;\n if (viewportModules.length) {\n defaultPlugin = viewportModules[0].extensionId;\n }\n\n const { numRows, numColumns, layout, activeViewportIndex } = state.viewports;\n\n return {\n numRows,\n numColumns,\n layout,\n activeViewportIndex,\n // TODO: rename `availableViewportModules`\n availablePlugins: availableViewportModules,\n // TODO: rename `defaultViewportModule`\n defaultPlugin,\n };\n};\n\nconst ConnectedViewportGrid = connect(\n mapStateToProps,\n null\n)(ViewportGrid);\n\nexport default ConnectedViewportGrid;\n","import './ViewerMain.css';\n\nimport { Component } from 'react';\nimport { ConnectedViewportGrid } from './../components/ViewportGrid/index.js';\nimport PropTypes from 'prop-types';\nimport React from 'react';\nimport memoize from 'lodash/memoize';\nimport _values from 'lodash/values';\n\nvar values = memoize(_values);\n\nclass ViewerMain extends Component {\n static propTypes = {\n activeViewportIndex: PropTypes.number.isRequired,\n studies: PropTypes.array,\n viewportSpecificData: PropTypes.object.isRequired,\n layout: PropTypes.object.isRequired,\n setViewportSpecificData: PropTypes.func.isRequired,\n clearViewportSpecificData: PropTypes.func.isRequired,\n };\n\n constructor(props) {\n super(props);\n\n this.state = {\n displaySets: [],\n };\n }\n\n getDisplaySets(studies) {\n const displaySets = [];\n studies.forEach(study => {\n study.displaySets.forEach(dSet => {\n if (!dSet.plugin) {\n dSet.plugin = 'cornerstone';\n }\n displaySets.push(dSet);\n });\n });\n\n return displaySets;\n }\n\n findDisplaySet(studies, StudyInstanceUID, displaySetInstanceUID) {\n const study = studies.find(study => {\n return study.StudyInstanceUID === StudyInstanceUID;\n });\n\n if (!study) {\n return;\n }\n\n return study.displaySets.find(displaySet => {\n return displaySet.displaySetInstanceUID === displaySetInstanceUID;\n });\n }\n\n componentDidMount() {\n // Add beforeUnload event handler to check for unsaved changes\n //window.addEventListener('beforeunload', unloadHandlers.beforeUnload);\n\n // Get all the display sets for the viewer studies\n if (this.props.studies) {\n const displaySets = this.getDisplaySets(this.props.studies);\n this.setState({ displaySets }, this.fillEmptyViewportPanes);\n }\n }\n\n componentDidUpdate(prevProps) {\n const prevViewportAmount = prevProps.layout.viewports.length;\n const viewportAmount = this.props.layout.viewports.length;\n const isVtk = this.props.layout.viewports.some(vp => !!vp.vtk);\n\n if (\n this.props.studies !== prevProps.studies ||\n (viewportAmount !== prevViewportAmount && !isVtk)\n ) {\n const displaySets = this.getDisplaySets(this.props.studies);\n this.setState({ displaySets }, this.fillEmptyViewportPanes);\n }\n }\n\n fillEmptyViewportPanes = () => {\n // TODO: Here is the entry point for filling viewports on load.\n const dirtyViewportPanes = [];\n const { layout, viewportSpecificData } = this.props;\n const { displaySets } = this.state;\n\n if (!displaySets || !displaySets.length) {\n return;\n }\n\n for (let i = 0; i < layout.viewports.length; i++) {\n const viewportPane = viewportSpecificData[i];\n const isNonEmptyViewport =\n viewportPane &&\n viewportPane.StudyInstanceUID &&\n viewportPane.displaySetInstanceUID;\n\n if (isNonEmptyViewport) {\n dirtyViewportPanes.push({\n StudyInstanceUID: viewportPane.StudyInstanceUID,\n displaySetInstanceUID: viewportPane.displaySetInstanceUID,\n });\n\n continue;\n }\n\n const foundDisplaySet =\n displaySets.find(\n ds =>\n !dirtyViewportPanes.some(\n v => v.displaySetInstanceUID === ds.displaySetInstanceUID\n )\n ) || displaySets[displaySets.length - 1];\n\n dirtyViewportPanes.push(foundDisplaySet);\n }\n\n dirtyViewportPanes.forEach((vp, i) => {\n if (vp && vp.StudyInstanceUID) {\n this.setViewportData({\n viewportIndex: i,\n StudyInstanceUID: vp.StudyInstanceUID,\n displaySetInstanceUID: vp.displaySetInstanceUID,\n });\n }\n });\n };\n\n setViewportData = ({\n viewportIndex,\n StudyInstanceUID,\n displaySetInstanceUID,\n }) => {\n let displaySet = this.findDisplaySet(\n this.props.studies,\n StudyInstanceUID,\n displaySetInstanceUID\n );\n\n if (displaySet.isDerived) {\n const { Modality } = displaySet;\n displaySet = displaySet.getSourceDisplaySet(this.props.studies);\n\n if (!displaySet) {\n throw new Error(\n `Referenced series for ${Modality} dataset not present.`\n );\n }\n }\n\n this.props.setViewportSpecificData(viewportIndex, displaySet);\n };\n\n render() {\n const { viewportSpecificData } = this.props;\n const viewportData = values(viewportSpecificData);\n\n return (\n <div className=\"ViewerMain\">\n {this.state.displaySets.length && (\n <ConnectedViewportGrid\n isStudyLoaded={this.props.isStudyLoaded}\n studies={this.props.studies}\n viewportData={viewportData}\n setViewportData={this.setViewportData}\n >\n {/* Children to add to each viewport that support children */}\n </ConnectedViewportGrid>\n )}\n </div>\n );\n }\n\n componentWillUnmount() {\n // Clear the entire viewport specific data\n const { viewportSpecificData } = this.props;\n Object.keys(viewportSpecificData).forEach(viewportIndex => {\n this.props.clearViewportSpecificData(viewportIndex);\n });\n\n // TODO: These don't have to be viewer specific?\n // Could qualify for other routes?\n // hotkeys.destroy();\n\n // Remove beforeUnload event handler...\n //window.removeEventListener('beforeunload', unloadHandlers.beforeUnload);\n // Destroy the synchronizer used to update reference lines\n //OHIF.viewer.updateImageSynchronizer.destroy();\n // TODO: Instruct all plugins to clean up themselves\n //\n // Clear references to all stacks in the StackManager\n //StackManager.clearStacks();\n // @TypeSafeStudies\n // Clears OHIF.viewer.Studies collection\n //OHIF.viewer.Studies.removeAll();\n // @TypeSafeStudies\n // Clears OHIF.viewer.StudyMetadataList collection\n //OHIF.viewer.StudyMetadataList.removeAll();\n }\n}\n\nexport default ViewerMain;\n","import OHIF from '@ohif/core';\nimport ViewerMain from './ViewerMain';\nimport { connect } from 'react-redux';\n\nconst {\n setViewportSpecificData,\n clearViewportSpecificData,\n} = OHIF.redux.actions;\n\nconst mapStateToProps = state => {\n const { activeViewportIndex, layout, viewportSpecificData } = state.viewports;\n\n return {\n activeViewportIndex,\n layout,\n viewportSpecificData,\n viewports: state.viewports,\n };\n};\n\nconst mapDispatchToProps = dispatch => {\n return {\n setViewportSpecificData: (viewportIndex, data) => {\n dispatch(setViewportSpecificData(viewportIndex, data));\n },\n clearViewportSpecificData: () => {\n dispatch(clearViewportSpecificData());\n },\n };\n};\n\nconst ConnectedViewerMain = connect(\n mapStateToProps,\n mapDispatchToProps\n)(ViewerMain);\n\nexport default ConnectedViewerMain;\n","import './SidePanel.css';\n\nimport React from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\n\nconst SidePanel = ({ from, isOpen, children, width }) => {\n const fromSideClass = from === 'right' ? 'from-right' : 'from-left';\n\n const styles = width\n ? {\n maxWidth: width,\n marginRight: isOpen ? '0' : Number.parseInt(width) * -1,\n }\n : {};\n\n return (\n <section\n style={styles}\n className={classNames('sidepanel', fromSideClass, {\n 'is-open': isOpen,\n })}\n >\n {children}\n </section>\n );\n};\n\nSidePanel.propTypes = {\n from: PropTypes.string.isRequired,\n isOpen: PropTypes.bool.isRequired,\n children: PropTypes.node,\n width: PropTypes.string,\n};\n\nexport default SidePanel;\n","import React, { useState } from 'react';\nimport classnames from 'classnames';\nimport PropTypes from 'prop-types';\nimport { ErrorBoundary, Icon } from '@ohif/ui';\nimport { servicesManager } from './../../App';\n\nimport './ErrorBoundaryDialog.css';\n\nconst { UIModalService } = servicesManager.services;\n\nconst ErrorBoundaryDialog = ({ context, children }) => {\n const handleOnError = (error, componentStack) => {\n const ErrorDialog = () => {\n const [open, setOpen] = useState(false);\n\n return (\n <div className=\"ErrorFallback\" role=\"alert\">\n <div className=\"ErrorBoundaryDialog\">\n <h3 className=\"ErrorBoundaryDialogTitle\">\n {context}: <span>{error.message}</span>\n </h3>\n </div>\n <button\n className=\"btn btn-primary btn-sm ErrorBoundaryDialogButton\"\n onClick={() => setOpen(s => !s)}\n >\n <Icon\n name=\"chevron-down\"\n className={classnames('ErrorBoundaryDialogIcon', {\n opened: open,\n })}\n />\n Stack Trace\n </button>\n\n {open && <pre>{componentStack}</pre>}\n </div>\n );\n };\n\n UIModalService.show({\n content: ErrorDialog,\n title: `Something went wrong in ${context}`,\n });\n };\n\n const fallbackComponent = () => (\n <div className=\"ErrorFallback\" role=\"alert\">\n <p>\n Error rendering {context}. <br /> Check the browser console for more\n details.\n </p>\n </div>\n );\n\n return (\n <ErrorBoundary\n fallbackComponent={fallbackComponent}\n context={context}\n onError={handleOnError}\n >\n {children}\n </ErrorBoundary>\n );\n};\n\nErrorBoundaryDialog.propTypes = {\n context: PropTypes.string.isRequired,\n children: PropTypes.node.isRequired,\n};\n\nexport default ErrorBoundaryDialog;\n","import ErrorBoundaryDialog from './ErrorBoundaryDialog';\n\nexport default ErrorBoundaryDialog;\n","import React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\n\nimport OHIF, { MODULE_TYPES, DICOMSR } from '@ohif/core';\nimport { withDialog } from '@ohif/ui';\nimport moment from 'moment';\nimport ConnectedHeader from './ConnectedHeader.js';\nimport ToolbarRow from './ToolbarRow.js';\nimport ConnectedStudyBrowser from './ConnectedStudyBrowser.js';\nimport ConnectedViewerMain from './ConnectedViewerMain.js';\nimport SidePanel from './../components/SidePanel.js';\nimport ErrorBoundaryDialog from './../components/ErrorBoundaryDialog';\nimport { extensionManager } from './../App.js';\nimport { ReconstructionIssues } from './../../../core/src/enums.js';\n\n// Contexts\nimport WhiteLabelingContext from '../context/WhiteLabelingContext.js';\nimport UserManagerContext from '../context/UserManagerContext';\nimport AppContext from '../context/AppContext';\n\nimport './Viewer.css';\nimport { finished } from 'stream';\n\nclass Viewer extends Component {\n static propTypes = {\n studies: PropTypes.arrayOf(\n PropTypes.shape({\n StudyInstanceUID: PropTypes.string.isRequired,\n StudyDate: PropTypes.string,\n PatientID: PropTypes.string,\n displaySets: PropTypes.arrayOf(\n PropTypes.shape({\n displaySetInstanceUID: PropTypes.string.isRequired,\n SeriesDescription: PropTypes.string,\n SeriesNumber: PropTypes.number,\n InstanceNumber: PropTypes.number,\n numImageFrames: PropTypes.number,\n Modality: PropTypes.string.isRequired,\n images: PropTypes.arrayOf(\n PropTypes.shape({\n getImageId: PropTypes.func.isRequired,\n })\n ),\n })\n ),\n })\n ),\n studyInstanceUIDs: PropTypes.array,\n activeServer: PropTypes.shape({\n type: PropTypes.string,\n wadoRoot: PropTypes.string,\n }),\n onTimepointsUpdated: PropTypes.func,\n onMeasurementsUpdated: PropTypes.func,\n // window.store.getState().viewports.viewportSpecificData\n viewports: PropTypes.object.isRequired,\n // window.store.getState().viewports.activeViewportIndex\n activeViewportIndex: PropTypes.number.isRequired,\n isStudyLoaded: PropTypes.bool,\n dialog: PropTypes.object,\n };\n\n constructor(props) {\n super(props);\n\n const { activeServer } = this.props;\n const server = Object.assign({}, activeServer);\n\n OHIF.measurements.MeasurementApi.setConfiguration({\n dataExchange: {\n retrieve: DICOMSR.retrieveMeasurements,\n store: DICOMSR.storeMeasurements,\n },\n server,\n });\n\n OHIF.measurements.TimepointApi.setConfiguration({\n dataExchange: {\n retrieve: this.retrieveTimepoints,\n store: this.storeTimepoints,\n remove: this.removeTimepoint,\n update: this.updateTimepoint,\n disassociate: this.disassociateStudy,\n },\n });\n\n this._getActiveViewport = this._getActiveViewport.bind(this);\n }\n\n state = {\n isLeftSidePanelOpen: true,\n isRightSidePanelOpen: false,\n selectedRightSidePanel: '',\n selectedLeftSidePanel: 'studies', // TODO: Don't hardcode this\n thumbnails: [],\n };\n\n componentWillUnmount() {\n if (this.props.dialog) {\n this.props.dialog.dismissAll();\n }\n }\n\n retrieveTimepoints = filter => {\n OHIF.log.info('retrieveTimepoints');\n\n // Get the earliest and latest study date\n let earliestDate = new Date().toISOString();\n let latestDate = new Date().toISOString();\n if (this.props.studies) {\n latestDate = new Date('1000-01-01').toISOString();\n this.props.studies.forEach(study => {\n const StudyDate = moment(study.StudyDate, 'YYYYMMDD').toISOString();\n if (StudyDate < earliestDate) {\n earliestDate = StudyDate;\n }\n if (StudyDate > latestDate) {\n latestDate = StudyDate;\n }\n });\n }\n\n // Return a generic timepoint\n return Promise.resolve([\n {\n timepointType: 'baseline',\n timepointId: 'TimepointId',\n studyInstanceUIDs: this.props.studyInstanceUIDs,\n PatientID: filter.PatientID,\n earliestDate,\n latestDate,\n isLocked: false,\n },\n ]);\n };\n\n storeTimepoints = timepointData => {\n OHIF.log.info('storeTimepoints');\n return Promise.resolve();\n };\n\n updateTimepoint = (timepointData, query) => {\n OHIF.log.info('updateTimepoint');\n return Promise.resolve();\n };\n\n removeTimepoint = timepointId => {\n OHIF.log.info('removeTimepoint');\n return Promise.resolve();\n };\n\n disassociateStudy = (timepointIds, StudyInstanceUID) => {\n OHIF.log.info('disassociateStudy');\n return Promise.resolve();\n };\n\n onTimepointsUpdated = timepoints => {\n if (this.props.onTimepointsUpdated) {\n this.props.onTimepointsUpdated(timepoints);\n }\n };\n\n onMeasurementsUpdated = measurements => {\n if (this.props.onMeasurementsUpdated) {\n this.props.onMeasurementsUpdated(measurements);\n }\n };\n\n componentDidMount() {\n const { studies, isStudyLoaded } = this.props;\n const { TimepointApi, MeasurementApi } = OHIF.measurements;\n const currentTimepointId = 'TimepointId';\n\n const timepointApi = new TimepointApi(currentTimepointId, {\n onTimepointsUpdated: this.onTimepointsUpdated,\n });\n\n const measurementApi = new MeasurementApi(timepointApi, {\n onMeasurementsUpdated: this.onMeasurementsUpdated,\n });\n\n this.currentTimepointId = currentTimepointId;\n this.timepointApi = timepointApi;\n this.measurementApi = measurementApi;\n\n if (studies) {\n const PatientID = studies[0] && studies[0].PatientID;\n\n timepointApi.retrieveTimepoints({ PatientID });\n if (isStudyLoaded) {\n this.measurementApi.retrieveMeasurements(PatientID, [\n currentTimepointId,\n ]);\n }\n\n this.setState({\n thumbnails: _mapStudiesToThumbnails(studies),\n });\n }\n }\n\n componentDidUpdate(prevProps) {\n const { studies, isStudyLoaded } = this.props;\n\n if (studies !== prevProps.studies) {\n this.setState({\n thumbnails: _mapStudiesToThumbnails(studies),\n });\n }\n if (isStudyLoaded && isStudyLoaded !== prevProps.isStudyLoaded) {\n const PatientID = studies[0] && studies[0].PatientID;\n const { currentTimepointId } = this;\n\n this.timepointApi.retrieveTimepoints({ PatientID });\n this.measurementApi.retrieveMeasurements(PatientID, [currentTimepointId]);\n }\n }\n\n _getActiveViewport() {\n return this.props.viewports[this.props.activeViewportIndex];\n }\n\n render() {\n let VisiblePanelLeft, VisiblePanelRight;\n const panelExtensions = extensionManager.modules[MODULE_TYPES.PANEL];\n\n panelExtensions.forEach(panelExt => {\n panelExt.module.components.forEach(comp => {\n if (comp.id === this.state.selectedRightSidePanel) {\n VisiblePanelRight = comp.component;\n } else if (comp.id === this.state.selectedLeftSidePanel) {\n VisiblePanelLeft = comp.component;\n }\n });\n });\n\n return (\n <>\n {/* HEADER */}\n <WhiteLabelingContext.Consumer>\n {whiteLabeling => (\n <UserManagerContext.Consumer>\n {userManager => (\n <AppContext.Consumer>\n {appContext => (\n <ConnectedHeader\n linkText={\n appContext.appConfig.showStudyList\n ? 'Study List'\n : undefined\n }\n linkPath={\n appContext.appConfig.showStudyList ? '/' : undefined\n }\n userManager={userManager}\n >\n {whiteLabeling &&\n whiteLabeling.createLogoComponentFn &&\n whiteLabeling.createLogoComponentFn(React)}\n </ConnectedHeader>\n )}\n </AppContext.Consumer>\n )}\n </UserManagerContext.Consumer>\n )}\n </WhiteLabelingContext.Consumer>\n\n {/* TOOLBAR */}\n <ErrorBoundaryDialog context=\"ToolbarRow\">\n <ToolbarRow\n activeViewport={\n this.props.viewports[this.props.activeViewportIndex]\n }\n isDerivedDisplaySetsLoaded={this.props.isDerivedDisplaySetsLoaded}\n isLeftSidePanelOpen={this.state.isLeftSidePanelOpen}\n isRightSidePanelOpen={this.state.isRightSidePanelOpen}\n selectedLeftSidePanel={\n this.state.isLeftSidePanelOpen\n ? this.state.selectedLeftSidePanel\n : ''\n }\n selectedRightSidePanel={\n this.state.isRightSidePanelOpen\n ? this.state.selectedRightSidePanel\n : ''\n }\n handleSidePanelChange={(side, selectedPanel) => {\n const sideClicked = side && side[0].toUpperCase() + side.slice(1);\n const openKey = `is${sideClicked}SidePanelOpen`;\n const selectedKey = `selected${sideClicked}SidePanel`;\n const updatedState = Object.assign({}, this.state);\n\n const isOpen = updatedState[openKey];\n const prevSelectedPanel = updatedState[selectedKey];\n // RoundedButtonGroup returns `null` if selected button is clicked\n const isSameSelectedPanel =\n prevSelectedPanel === selectedPanel || selectedPanel === null;\n\n updatedState[selectedKey] = selectedPanel || prevSelectedPanel;\n\n const isClosedOrShouldClose = !isOpen || isSameSelectedPanel;\n if (isClosedOrShouldClose) {\n updatedState[openKey] = !updatedState[openKey];\n }\n\n this.setState(updatedState);\n }}\n studies={this.props.studies}\n />\n </ErrorBoundaryDialog>\n\n {/*<ConnectedStudyLoadingMonitor studies={this.props.studies} />*/}\n {/*<StudyPrefetcher studies={this.props.studies} />*/}\n\n {/* VIEWPORTS + SIDEPANELS */}\n <div className=\"FlexboxLayout\">\n {/* LEFT */}\n <ErrorBoundaryDialog context=\"LeftSidePanel\">\n <SidePanel from=\"left\" isOpen={this.state.isLeftSidePanelOpen}>\n {VisiblePanelLeft ? (\n <VisiblePanelLeft\n viewports={this.props.viewports}\n studies={this.props.studies}\n activeIndex={this.props.activeViewportIndex}\n />\n ) : (\n <ConnectedStudyBrowser\n studies={this.state.thumbnails}\n studyMetadata={this.props.studies}\n />\n )}\n </SidePanel>\n </ErrorBoundaryDialog>\n\n {/* MAIN */}\n <div className={classNames('main-content')}>\n <ErrorBoundaryDialog context=\"ViewerMain\">\n <ConnectedViewerMain\n studies={this.props.studies}\n isStudyLoaded={this.props.isStudyLoaded}\n />\n </ErrorBoundaryDialog>\n </div>\n\n {/* RIGHT */}\n <ErrorBoundaryDialog context=\"RightSidePanel\">\n <SidePanel from=\"right\" isOpen={this.state.isRightSidePanelOpen}>\n {VisiblePanelRight && (\n <VisiblePanelRight\n isOpen={this.state.isRightSidePanelOpen}\n viewports={this.props.viewports}\n studies={this.props.studies}\n activeIndex={this.props.activeViewportIndex}\n activeViewport={\n this.props.viewports[this.props.activeViewportIndex]\n }\n getActiveViewport={this._getActiveViewport}\n />\n )}\n </SidePanel>\n </ErrorBoundaryDialog>\n </div>\n </>\n );\n }\n}\n\nexport default withDialog(Viewer);\n\n/**\n * Async function to check if there are any inconsistences in the series\n * (i.e. reconstructable to a 3D volume). If not reconstructable MPR is disabled.\n * The actual computations are done in isDisplaySetReconstructable.\n *\n * 1) Is series multiframe?\n * 2) Do the frames have different dimensions/numer of components/orientations?\n * 3) Has the series any missing frames or irregular spacing?\n * 4) Is the series 4D?\n *\n * @param {*object} displaySet\n * @returns {[string]} an array of strings containing the warnings\n */\nconst _checkForSeriesInconsistencesWarnings = async function (displaySet) {\n // NOTE: at the moment this function is async even if it does not perfom any heavy calculation.\n // We may add or move here some of the computations\n // done when creating the displaySet (see makeDisplaySet and isDisplaySetReconstructable).\n // the thumbnail footnotes warning react element is already set up to handle a promise.\n const warningsList = [];\n if (displaySet.warningIssues && displaySet.warningIssues.length !== 0) {\n displaySet.warningIssues.forEach(warning => {\n switch (warning) {\n case ReconstructionIssues.DATASET_4D:\n warningsList.push(\"The dataset is 4D.\");\n break;\n case ReconstructionIssues.VARYING_IMAGESDIMENSIONS:\n warningsList.push(\"The dataset frames have different dimensions (rows, columns).\");\n break;\n case ReconstructionIssues.VARYING_IMAGESCOMPONENTS:\n warningsList.push(\"The dataset frames have different components (Sample per pixel).\");\n break;\n case ReconstructionIssues.VARYING_IMAGESORIENTATION:\n warningsList.push(\"The dataset frames have different orientation.\");\n break;\n case ReconstructionIssues.IRREGULAR_SPACING:\n warningsList.push(\"The dataset frames have different pixel spacing.\");\n break;\n case ReconstructionIssues.MULTIFFRAMES:\n warningsList.push(\"The dataset is a multiframes.\");\n break;\n default:\n break;\n }\n });\n warningsList.push('The datasets is not a reconstructable 3D volume. MPR mode is not available.');\n }\n\n if (displaySet.missingFrames &&\n (!displaySet.warningIssues ||\n (displaySet.warningIssues && !displaySet.warningIssues.find(warn => warn === ReconstructionIssues.DATASET_4D)))) {\n warningsList.push('The datasets is missing frames: ' + displaySet.missingFrames + '.');\n }\n\n return warningsList\n}\n\n/**\n * What types are these? Why do we have \"mapping\" dropped in here instead of in\n * a mapping layer?\n *\n * TODO[react]:\n * - Add showStackLoadingProgressBar option\n *\n * @param {Study[]} studies\n * @param {DisplaySet[]} studies[].displaySets\n */\nconst _mapStudiesToThumbnails = function(studies) {\n return studies.map(study => {\n const { StudyInstanceUID } = study;\n\n const thumbnails = study.displaySets.map(displaySet => {\n const {\n displaySetInstanceUID,\n SeriesDescription,\n InstanceNumber,\n numImageFrames,\n SeriesNumber,\n } = displaySet;\n\n let imageId;\n let altImageText;\n\n if (displaySet.Modality && displaySet.Modality === 'SEG') {\n // TODO: We want to replace this with a thumbnail showing\n // the segmentation map on the image, but this is easier\n // and better than what we have right now.\n altImageText = 'SEG';\n } else if (displaySet.images && displaySet.images.length) {\n const imageIndex = Math.floor(displaySet.images.length / 2);\n\n imageId = displaySet.images[imageIndex].getImageId();\n } else {\n altImageText = displaySet.Modality ? displaySet.Modality : 'UN';\n }\n\n const hasWarnings = _checkForSeriesInconsistencesWarnings(displaySet)\n\n return {\n imageId,\n altImageText,\n displaySetInstanceUID,\n SeriesDescription,\n InstanceNumber,\n numImageFrames,\n SeriesNumber,\n hasWarnings,\n };\n });\n\n return {\n StudyInstanceUID,\n thumbnails,\n };\n });\n};\n","import { connect } from 'react-redux';\nimport Viewer from './Viewer.js';\nimport OHIF from '@ohif/core';\n\nconst { setTimepoints, setMeasurements } = OHIF.redux.actions;\n\nconst getActiveServer = servers => {\n const isActive = a => a.active === true;\n return servers.servers.find(isActive);\n};\n\nconst mapStateToProps = state => {\n const { viewports, servers } = state;\n return {\n viewports: viewports.viewportSpecificData,\n activeViewportIndex: viewports.activeViewportIndex,\n activeServer: getActiveServer(servers),\n };\n};\n\nconst mapDispatchToProps = dispatch => {\n return {\n onTimepointsUpdated: timepoints => {\n dispatch(setTimepoints(timepoints));\n },\n onMeasurementsUpdated: measurements => {\n dispatch(setMeasurements(measurements));\n },\n };\n};\n\nconst ConnectedViewer = connect(\n mapStateToProps,\n mapDispatchToProps\n)(Viewer);\n\nexport default ConnectedViewer;\n","import React, { useEffect, useRef } from 'react';\nexport default function usePrevious(value) {\n const ref = useRef();\n useEffect(() => {\n ref.current = value;\n }, [value]);\n\n return ref.current;\n}\n","import React, { useState, useEffect, useContext, useCallback } from 'react';\nimport { metadata, studies, utils, log } from '@ohif/core';\nimport usePrevious from '../customHooks/usePrevious';\n\nimport ConnectedViewer from './ConnectedViewer.js';\nimport PropTypes from 'prop-types';\nimport { extensionManager } from './../App.js';\nimport { useSnackbarContext, ErrorPage } from '@ohif/ui';\n\n// Contexts\nimport AppContext from '../context/AppContext';\nimport NotFound from '../routes/NotFound';\n\nconst { OHIFStudyMetadata, OHIFSeriesMetadata } = metadata;\nconst { retrieveStudiesMetadata, deleteStudyMetadataPromise } = studies;\nconst { studyMetadataManager, makeCancelable } = utils;\n\nconst _promoteToFront = (list, values, searchMethod) => {\n let listCopy = [...list];\n let response = [];\n let promotedCount = 0;\n\n const arrayValues = values.split(',');\n arrayValues.forEach(value => {\n const index = listCopy.findIndex(searchMethod.bind(undefined, value));\n\n if (index >= 0) {\n const [itemToPromote] = listCopy.splice(index, 1);\n response[promotedCount] = itemToPromote;\n promotedCount++;\n }\n });\n\n return {\n promoted: promotedCount === arrayValues.length,\n data: [...response, ...listCopy],\n };\n};\n\n/**\n * Promote series to front if find found equivalent on filters object\n * @param {Object} study - study reference to promote series against\n * @param {Object} [filters] - Object containing filters to be applied\n * @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against\n * @param {boolean} isFilterStrategy - if filtering by query param strategy ON\n */\nconst _promoteList = (study, studyMetadata, filters, isFilterStrategy) => {\n let promoted = false;\n // Promote only if no filter should be applied\n if (!isFilterStrategy) {\n promoted = _promoteStudyDisplaySet(study, studyMetadata, filters);\n }\n\n return promoted;\n};\n\nconst _promoteStudyDisplaySet = (study, studyMetadata, filters) => {\n let promoted = false;\n const queryParamsLength = Object.keys(filters).length;\n const shouldPromoteToFront = queryParamsLength > 0;\n\n if (shouldPromoteToFront) {\n const { seriesInstanceUID } = filters;\n\n const _seriesLookup = (valueToCompare, displaySet) => {\n return displaySet.SeriesInstanceUID === valueToCompare;\n };\n const promotedResponse = _promoteToFront(\n studyMetadata.getDisplaySets(),\n seriesInstanceUID,\n _seriesLookup\n );\n\n study.displaySets = promotedResponse.data;\n promoted = promotedResponse.promoted;\n }\n\n return promoted;\n};\n\n/**\n * Method to identify if query param (from url) was applied to given list\n * @param {Object} study - study reference to promote series against\n * @param {Object} [filters] - Object containing filters to be applied\n * @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against\n * @param {boolean} isFilterStrategy - if filtering by query param strategy ON\n */\nconst _isQueryParamApplied = (study, filters = {}, isFilterStrategy) => {\n const { seriesInstanceUID } = filters;\n let applied = true;\n // skip in case no filter or no toast manager\n\n if (!seriesInstanceUID) {\n return applied;\n }\n const seriesInstanceUIDs = seriesInstanceUID.split(',');\n\n let validateFilterApplied = () => {\n const sameSize = arrayToInspect.length === seriesInstanceUIDs.length;\n if (!sameSize) {\n return;\n }\n\n return arrayToInspect.every(item =>\n seriesInstanceUIDs.some(\n seriesInstanceUIDStr => seriesInstanceUIDStr === item.SeriesInstanceUID\n )\n );\n };\n\n let validatePromoteApplied = () => {\n let isValid = true;\n for (let index = 0; index < seriesInstanceUIDs.length; index++) {\n const seriesInstanceUIDStr = seriesInstanceUIDs[index];\n const resultSeries = arrayToInspect[index];\n\n if (\n !resultSeries ||\n resultSeries.SeriesInstanceUID !== seriesInstanceUIDStr\n ) {\n isValid = false;\n break;\n }\n }\n return isValid;\n };\n\n const { series = [], displaySets = [] } = study;\n const arrayToInspect = isFilterStrategy ? series : displaySets;\n const validateMethod = isFilterStrategy\n ? validateFilterApplied\n : validatePromoteApplied;\n\n if (!arrayToInspect) {\n applied = false;\n } else {\n applied = validateMethod();\n }\n\n return applied;\n};\nconst _showUserMessage = (queryParamApplied, message, dialog = {}) => {\n if (queryParamApplied) {\n return;\n }\n\n const { show: showUserMessage = () => {} } = dialog;\n showUserMessage({\n message,\n });\n};\n\nconst _addSeriesToStudy = (studyMetadata, series) => {\n const sopClassHandlerModules =\n extensionManager.modules['sopClassHandlerModule'];\n const study = studyMetadata.getData();\n const seriesMetadata = new OHIFSeriesMetadata(series, study);\n const existingSeries = studyMetadata.getSeriesByUID(series.SeriesInstanceUID);\n if (existingSeries) {\n studyMetadata.updateSeries(series.SeriesInstanceUID, seriesMetadata);\n } else {\n studyMetadata.addSeries(seriesMetadata);\n }\n\n studyMetadata.createAndAddDisplaySetsForSeries(\n sopClassHandlerModules,\n seriesMetadata\n );\n\n study.displaySets = studyMetadata.getDisplaySets();\n study.derivedDisplaySets = studyMetadata.getDerivedDatasets({\n Modality: series.Modality,\n });\n\n _updateStudyMetadataManager(study, studyMetadata);\n};\n\nconst _updateStudyMetadataManager = (study, studyMetadata) => {\n const { StudyInstanceUID } = study;\n\n if (!studyMetadataManager.get(StudyInstanceUID)) {\n studyMetadataManager.add(studyMetadata);\n }\n};\n\nconst _updateStudyDisplaySets = (study, studyMetadata) => {\n const sopClassHandlerModules =\n extensionManager.modules['sopClassHandlerModule'];\n\n if (!study.displaySets) {\n study.displaySets = studyMetadata.createDisplaySets(sopClassHandlerModules);\n }\n\n if (study.derivedDisplaySets) {\n studyMetadata._addDerivedDisplaySets(study.derivedDisplaySets);\n }\n};\n\nconst _thinStudyData = study => {\n return {\n StudyInstanceUID: study.StudyInstanceUID,\n series: study.series.map(item => ({\n SeriesInstanceUID: item.SeriesInstanceUID,\n })),\n };\n};\n\nfunction ViewerRetrieveStudyData({\n server,\n studyInstanceUIDs,\n seriesInstanceUIDs,\n clearViewportSpecificData,\n setStudyData,\n}) {\n // hooks\n const [error, setError] = useState(false);\n const [studies, setStudies] = useState([]);\n const [isStudyLoaded, setIsStudyLoaded] = useState(false);\n const snackbarContext = useSnackbarContext();\n const { appConfig = {} } = useContext(AppContext);\n const {\n filterQueryParam: isFilterStrategy = false,\n maxConcurrentMetadataRequests,\n } = appConfig;\n\n let cancelableSeriesPromises;\n let cancelableStudiesPromises;\n /**\n * Callback method when study is totally loaded\n * @param {object} study study loaded\n * @param {object} studyMetadata studyMetadata for given study\n * @param {Object} [filters] - Object containing filters to be applied\n * @param {string} [filter.seriesInstanceUID] - series instance uid to filter results against\n */\n const studyDidLoad = (study, studyMetadata, filters) => {\n // User message\n const promoted = _promoteList(\n study,\n studyMetadata,\n filters,\n isFilterStrategy\n );\n\n // Clear viewport to allow new promoted one to be displayed\n if (promoted) {\n clearViewportSpecificData(0);\n }\n\n const isQueryParamApplied = _isQueryParamApplied(\n study,\n filters,\n isFilterStrategy\n );\n // Show message in case not promoted neither filtered but should to\n _showUserMessage(\n isQueryParamApplied,\n 'Query parameters were not totally applied. It might be using original series list for given study.',\n snackbarContext\n );\n\n setStudies([...studies, study]);\n setIsStudyLoaded(true);\n };\n\n /**\n * Method to process studies. It will update displaySet, studyMetadata, load remaining series, ...\n * @param {Array} studiesData Array of studies retrieved from server\n * @param {Object} [filters] - Object containing filters to be applied\n * @param {string} [filters.seriesInstanceUID] - series instance uid to filter results against\n */\n const processStudies = (studiesData, filters) => {\n if (Array.isArray(studiesData) && studiesData.length > 0) {\n // Map studies to new format, update metadata manager?\n const studies = studiesData.map(study => {\n setStudyData(study.StudyInstanceUID, _thinStudyData(study));\n const studyMetadata = new OHIFStudyMetadata(\n study,\n study.StudyInstanceUID\n );\n\n _updateStudyDisplaySets(study, studyMetadata);\n _updateStudyMetadataManager(study, studyMetadata);\n\n // Attempt to load remaning series if any\n cancelableSeriesPromises[study.StudyInstanceUID] = makeCancelable(\n loadRemainingSeries(studyMetadata)\n )\n .then(result => {\n if (result && !result.isCanceled) {\n studyDidLoad(study, studyMetadata, filters);\n }\n })\n .catch(error => {\n if (error && !error.isCanceled) {\n setError(error);\n log.error(error);\n }\n });\n\n return study;\n });\n\n setStudies(studies);\n setIsStudyLoaded(true);\n }\n };\n\n const forceRerender = () => setStudies(studies => [...studies]);\n\n const loadRemainingSeries = async studyMetadata => {\n const { seriesLoader } = studyMetadata.getData();\n if (!seriesLoader) return;\n\n const loadNextSeries = async () => {\n if (!seriesLoader.hasNext()) return;\n const series = await seriesLoader.next();\n _addSeriesToStudy(studyMetadata, series);\n forceRerender();\n return loadNextSeries();\n };\n\n const concurrentRequestsAllowed =\n maxConcurrentMetadataRequests || studyMetadata.getSeriesCount();\n const promises = Array(concurrentRequestsAllowed)\n .fill(null)\n .map(loadNextSeries);\n\n return await Promise.all(promises);\n };\n\n const loadStudies = async () => {\n try {\n const filters = {};\n // Use the first, discard others\n const seriesInstanceUID = seriesInstanceUIDs && seriesInstanceUIDs[0];\n const retrieveParams = [server, studyInstanceUIDs];\n\n if (seriesInstanceUID) {\n filters.seriesInstanceUID = seriesInstanceUID;\n // Query param filtering controlled by appConfig property\n if (isFilterStrategy) {\n retrieveParams.push(filters);\n }\n }\n\n if (\n appConfig.splitQueryParameterCalls ||\n appConfig.enableGoogleCloudAdapter\n ) {\n retrieveParams.push(true); // Seperate SeriesInstanceUID filter calls.\n }\n\n cancelableStudiesPromises[studyInstanceUIDs] = makeCancelable(\n retrieveStudiesMetadata(...retrieveParams)\n )\n .then(result => {\n if (result && !result.isCanceled) {\n processStudies(result, filters);\n }\n })\n .catch(error => {\n if (error && !error.isCanceled) {\n setError(error);\n log.error(error);\n }\n });\n } catch (error) {\n if (error) {\n setError(error);\n log.error(error);\n }\n }\n };\n\n const purgeCancellablePromises = useCallback(() => {\n for (let studyInstanceUIDs in cancelableStudiesPromises) {\n if ('cancel' in cancelableStudiesPromises[studyInstanceUIDs]) {\n cancelableStudiesPromises[studyInstanceUIDs].cancel();\n }\n }\n\n for (let studyInstanceUIDs in cancelableSeriesPromises) {\n if ('cancel' in cancelableSeriesPromises[studyInstanceUIDs]) {\n cancelableSeriesPromises[studyInstanceUIDs].cancel();\n deleteStudyMetadataPromise(studyInstanceUIDs);\n studyMetadataManager.remove(studyInstanceUIDs);\n }\n }\n });\n\n const prevStudyInstanceUIDs = usePrevious(studyInstanceUIDs);\n\n useEffect(() => {\n const hasStudyInstanceUIDsChanged = !(\n prevStudyInstanceUIDs &&\n prevStudyInstanceUIDs.every(e => studyInstanceUIDs.includes(e))\n );\n\n if (hasStudyInstanceUIDsChanged) {\n studyMetadataManager.purge();\n purgeCancellablePromises();\n }\n }, [prevStudyInstanceUIDs, purgeCancellablePromises, studyInstanceUIDs]);\n\n useEffect(() => {\n cancelableSeriesPromises = {};\n cancelableStudiesPromises = {};\n loadStudies();\n\n return () => {\n purgeCancellablePromises();\n };\n }, []);\n\n if (error) {\n const content = JSON.stringify(error);\n if (content.includes('404') || content.includes('NOT_FOUND')) {\n return <NotFound />;\n }\n\n return <NotFound message=\"Failed to retrieve study data\" />;\n }\n\n return (\n <ConnectedViewer\n studies={studies}\n isStudyLoaded={isStudyLoaded}\n studyInstanceUIDs={studyInstanceUIDs}\n />\n );\n}\n\nViewerRetrieveStudyData.propTypes = {\n studyInstanceUIDs: PropTypes.array.isRequired,\n seriesInstanceUIDs: PropTypes.array,\n server: PropTypes.object,\n clearViewportSpecificData: PropTypes.func.isRequired,\n setStudyData: PropTypes.func.isRequired,\n};\n\nexport default ViewerRetrieveStudyData;\n","import { connect } from 'react-redux';\nimport ViewerRetrieveStudyData from './ViewerRetrieveStudyData.js';\nimport OHIF from '@ohif/core';\n\nconst { clearViewportSpecificData, setStudyData } = OHIF.redux.actions;\nconst isActive = a => a.active === true;\n\nconst mapStateToProps = (state, ownProps) => {\n const activeServer = state.servers.servers.find(isActive);\n\n return {\n server: ownProps.server || activeServer,\n };\n};\nconst mapDispatchToProps = dispatch => {\n return {\n setStudyData: (StudyInstanceUID, data) => {\n dispatch(setStudyData(StudyInstanceUID, data));\n },\n clearViewportSpecificData: () => {\n dispatch(clearViewportSpecificData());\n },\n };\n};\n\nconst ConnectedViewerRetrieveStudyData = connect(\n mapStateToProps,\n mapDispatchToProps\n)(ViewerRetrieveStudyData);\n\nexport default ConnectedViewerRetrieveStudyData;\n"],"sourceRoot":""}