/// <summary> /// Overridden N-ACTION-RQ message handler. Return an N-EVENT-REPORT-RQ /// after the N-ACTION-RSP. /// </summary> /// <param name="dicomMessage">N-ACTION-RQ and Dataset.</param> /// <returns>Boolean - true if dicomMessage handled here.</returns> public override bool HandleNActionRequest(DicomMessage dicomMessage) { // Validate the received message // System.String iodName = DicomThread.GetIodNameFromDefinition(dicomMessage); // DicomThread.Validate(dicomMessage, iodName); // set up the default N-ACTION-RSP with a successful status DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.NACTIONRSP); responseMessage.Set("0x00000900", VR.US, 0); // send the response this.Send(responseMessage); // delay before generating the N-EVENT-REPORT-RQ System.Threading.Thread.Sleep(_eventDelay); // create the N-EVENT-REPORT-RQ based in the contents of the N-ACTION-RQ DicomMessage requestMessage = GenerateTriggers.MakeStorageCommitEvent(_informationModels, dicomMessage); // send the request this.Send(requestMessage); // message handled return true; }
public override bool HandleNSetRequest(DicomMessage dicomMessage) { // Try to get the IOD Name System.String iodName = DicomThread.GetIodNameFromDefinition(dicomMessage); System.String messsage = String.Format("Processed N-SET-RQ {0}", iodName); WriteInformation(messsage); DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.NSETRSP); responseMessage.Set("0x00000900", VR.US, 0); this.Send(responseMessage); return true; }
/// <summary> /// Overridden N-ACTION-RQ message handler. /// </summary> /// <param name="dicomMessage">N-ACTION-RQ and Dataset.</param> /// <returns>Boolean - true if dicomMessage handled here.</returns> public override bool HandleNActionRequest(DicomMessage dicomMessage) { // Validate the received message // System.String iodName = DicomThread.GetIodNameFromDefinition(dicomMessage); // DicomThread.Validate(dicomMessage, iodName); // set up the default N-ACTION-RSP with a successful status DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.NACTIONRSP); responseMessage.Set("0x00000900", VR.US, 0); // send the response this.Send(responseMessage); // message handled return true; }
public override bool HandleNCreateRequest(DicomMessage dicomMessage) { // Try to get the IOD Name System.String iodName = DicomThread.GetIodNameFromDefinition(dicomMessage); // Try to get the Patient Name DvtkHighLevelInterface.Dicom.Other.Values attributeValues = dicomMessage["0x00100010"].Values; System.String patientName = attributeValues[0]; System.String messsage = String.Format("Processed N-CREATE-RQ {0}: \"{1}\"", iodName, patientName); WriteInformation(messsage); DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.NCREATERSP); responseMessage.Set("0x00000900", VR.US, 0); this.Send(responseMessage); return true; }
/// <summary> /// Applies this filter to a DICOM message. /// </summary> /// <param name="dicomMessage">The DICOM message.</param> public void Apply(DicomMessage dicomMessage) { dicomMessage.Set(tagSequence, vR, this.values.ToArray()); }
/// <summary> /// Overridden C-FIND-RQ message handler that makes use of the appropriate Information Model to handle the query. /// </summary> /// <param name="queryMessage">C-FIND-RQ Identifier (Dataset) containing query attributes.</param> /// <returns>Boolean - true if dicomMessage handled here.</returns> public override bool HandleCFindRequest(DicomMessage queryMessage) { // Validate the received message //System.String iodName = DicomThread.GetIodNameFromDefinition(queryMessage); //DicomThread.Validate(queryMessage, iodName); // perform query DicomMessageCollection responseMessages = _modalityWorklistInformationModel.QueryInformationModel(queryMessage); if(responseMessages.Count > 1) { WriteInformation(string.Format("Sending {0} C-FIND responses after performing query.\r\n",responseMessages.Count)); } else { WriteWarning("No response from MWL information model after performing query.\r\n"); } // handle responses foreach (DicomMessage responseMessage in responseMessages) { int waitedTime = 0; // Check for cancel message from SCU if (WaitForPendingDataInNetworkInputBuffer(100, ref waitedTime)) { DicomMessage cancelRq = ReceiveDicomMessage(); if (cancelRq.CommandSet.DimseCommand == DvtkData.Dimse.DimseCommand.CCANCELRQ) { // set up the C-FIND-RSP with cancel status DicomMessage respMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); respMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0xFE00); // send the response this.Send(respMessage); break; } } this.Send(responseMessage); } // message handled return true; }
/// <summary> /// Generate a Modality Worklist Item from the user defined tags provided and /// the Default Value Manager. /// </summary> /// <param name="defaultValueManager">Default Value Manager.</param> /// <param name="userDefinedTags">User defined Tags.</param> /// <returns>CFind Modality Worklist Response message.</returns> public static DvtkHighLevelInterface.Dicom.Messages.DicomMessage MakeModalityWorklistItem(Dvtk.Dicom.InformationEntity.DefaultValues.DefaultValueManager defaultValueManager, TagValueCollection userDefinedTags) { DvtkHighLevelInterface.Dicom.Messages.DicomMessage worklistResponseMessage = new DvtkHighLevelInterface.Dicom.Messages.DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); worklistResponseMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.31"); DvtkData.Dimse.DataSet worklistItemDataset = Dvtk.Dicom.InformationEntity.Worklist.WorklistQueryDataset.CreateWorklistItemDataset(userDefinedTags); worklistResponseMessage.DataSet.DvtkDataDataSet = worklistItemDataset; // Add the default values AddDefaultWorklistResponseValues(defaultValueManager, worklistItemDataset); return worklistResponseMessage; }
/// <summary> /// Cretae a storage commitment event. /// </summary> /// <param name="informationModels">The information models.</param> /// <param name="actionMessage">The action message.</param> /// <returns>The created event.</returns> public static DvtkHighLevelInterface.Dicom.Messages.DicomMessage MakeStorageCommitEvent(QueryRetrieveInformationModels informationModels, DvtkHighLevelInterface.Dicom.Messages.DicomMessage actionMessage) { // refresh the information models informationModels.Refresh(); DvtkHighLevelInterface.Dicom.Messages.DicomMessage eventMessage = new DvtkHighLevelInterface.Dicom.Messages.DicomMessage(DvtkData.Dimse.DimseCommand.NEVENTREPORTRQ); eventMessage.Set("0x00000002", VR.UI, "1.2.840.10008.1.20.1"); eventMessage.Set("0x00001000", VR.UI, "1.2.840.10008.1.20.1.1"); DvtkData.Dimse.DataSet actionDataset = actionMessage.DataSet.DvtkDataDataSet; DvtkData.Dimse.DataSet eventDataset = new DvtkData.Dimse.DataSet(); DvtkData.Dimse.Attribute eventReferenceSopSequence = new DvtkData.Dimse.Attribute(0x00081199, DvtkData.Dimse.VR.SQ); SequenceOfItems eventReferenceSopSequenceOfItems = new SequenceOfItems(); eventReferenceSopSequence.DicomValue = eventReferenceSopSequenceOfItems; DvtkData.Dimse.Attribute eventFailedSopSequence = new DvtkData.Dimse.Attribute(0x00081198, DvtkData.Dimse.VR.SQ); SequenceOfItems eventFailedSopSequenceOfItems = new SequenceOfItems(); eventFailedSopSequence.DicomValue = eventFailedSopSequenceOfItems; if (actionDataset != null) { DvtkData.Dimse.Attribute transactionUid = actionDataset.GetAttribute(DvtkData.Dimse.Tag.TRANSACTION_UID); if (transactionUid != null) { eventDataset.Add(transactionUid); } DvtkData.Dimse.Attribute referencedSopSequence = actionDataset.GetAttribute(DvtkData.Dimse.Tag.REFERENCED_SOP_SEQUENCE); if (referencedSopSequence != null) { SequenceOfItems sequenceOfItems = (SequenceOfItems)referencedSopSequence.DicomValue; foreach(DvtkData.Dimse.SequenceItem item in sequenceOfItems.Sequence) { System.String sopClassUid = ""; System.String sopInstanceUid = ""; DvtkData.Dimse.Attribute attribute = item.GetAttribute(DvtkData.Dimse.Tag.REFERENCED_SOP_CLASS_UID); if (attribute != null) { UniqueIdentifier uniqueIdentifier = (UniqueIdentifier)attribute.DicomValue; if (uniqueIdentifier.Values.Count > 0) { sopClassUid = uniqueIdentifier.Values[0]; } } attribute = item.GetAttribute(DvtkData.Dimse.Tag.REFERENCED_SOP_INSTANCE_UID); if (attribute != null) { UniqueIdentifier uniqueIdentifier = (UniqueIdentifier)attribute.DicomValue; if (uniqueIdentifier.Values.Count > 0) { sopInstanceUid = uniqueIdentifier.Values[0]; } } if (informationModels.PatientRoot.IsInstanceInInformationModel(sopClassUid, sopInstanceUid)) { DvtkData.Dimse.SequenceItem itemOk = new DvtkData.Dimse.SequenceItem(); itemOk.AddAttribute(0x00081150, DvtkData.Dimse.VR.UI, sopClassUid); itemOk.AddAttribute(0x00081155, DvtkData.Dimse.VR.UI, sopInstanceUid); // add instance to committed list eventReferenceSopSequenceOfItems.Sequence.Add(itemOk); } else { DvtkData.Dimse.SequenceItem itemNotOk = new DvtkData.Dimse.SequenceItem(); itemNotOk.AddAttribute(0x00081150, DvtkData.Dimse.VR.UI, sopClassUid); itemNotOk.AddAttribute(0x00081155, DvtkData.Dimse.VR.UI, sopInstanceUid); itemNotOk.AddAttribute(0x00081197, DvtkData.Dimse.VR.US, 0x0110); // add instance to failed list eventFailedSopSequenceOfItems.Sequence.Add(itemNotOk); } } } if (eventReferenceSopSequenceOfItems.Sequence.Count > 0) { eventMessage.Set("0x00001002", VR.US, 1); eventDataset.Add(eventReferenceSopSequence); } if (eventFailedSopSequenceOfItems.Sequence.Count > 0) { eventMessage.Set("0x00001002", VR.US, 2); eventDataset.Add(eventFailedSopSequence); } } eventMessage.DataSet.DvtkDataDataSet = eventDataset; return eventMessage; }
public override bool HandleCMoveRequest(DicomMessage retrieveMessage) { // try to get the SOP Class Uid so that we know which Information Model to use. DvtkHighLevelInterface.Dicom.Other.Values values = retrieveMessage.CommandSet["0x00000002"].Values; System.String sopClassUid = values[0]; DvtkData.Dul.AbstractSyntax abstractSyntax = new DvtkData.Dul.AbstractSyntax(sopClassUid); // try to get the Move Destination AE. values = retrieveMessage.CommandSet["0x00000600"].Values; string vr = retrieveMessage.CommandSet["0x00000600"].VR.ToString(); System.String moveDestinationAE = values[0]; string hexString = moveDestinationAE; System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (DicomThread.Options.LoadedDefinitionFileNames.Length < 10) WriteWarning("Some of the definition files is not loaded properly."); if (vr == "UN") { for (int i = 0; i <= hexString.Length - 2; i += 2) { sb.Append(Convert.ToString(Convert.ToChar(Int32.Parse(hexString.Substring(i, 2), System.Globalization.NumberStyles.HexNumber)))); } } else if (vr == "AE") { sb.Append(moveDestinationAE); } if (moveDestinationAE == null || moveDestinationAE=="") { DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CMOVERSP); responseMessage.Set("0x00000900", VR.US, 0xA801); responseMessage.Set("0x00000902", VR.LO, "Unknown Move Destination"); this.Send(responseMessage); return(true); } MoveAEdetailsIndex=FindMoveAEDetails(sb.ToString()); if (IsHaveMoveDestinations && MoveAEdetailsIndex == -1) { DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CMOVERSP); responseMessage.Set("0x00000900", VR.US, 0xA801); responseMessage.Set("0x00000902", VR.LO, "Move Destination not registered in SCP"); this.Send(responseMessage); WriteWarning("Move destination is not registered in SCP"); return (true); } DvtkData.Collections.StringCollection retrieveList = null; // check if we should use the Patient Root Information Model if ((abstractSyntax.UID == DvtkData.Dul.AbstractSyntax.Patient_Root_Query_Retrieve_Information_Model_MOVE.UID) && (PatientRootInformationModel != null)) { // check if the information model should be refreshed before retrieving if (RefreshInformationModelBeforeUse == true) { PatientRootInformationModel.RefreshInformationModel(); } // perform retrieve retrieveList = PatientRootInformationModel.RetrieveInformationModel(retrieveMessage); } // check if we should use the Study Root Information Model else if ((abstractSyntax.UID == DvtkData.Dul.AbstractSyntax.Study_Root_Query_Retrieve_Information_Model_MOVE.UID) && (StudyRootInformationModel != null)) { // check if the information model should be refreshed before retrieving if (RefreshInformationModelBeforeUse == true) { StudyRootInformationModel.RefreshInformationModel(); } // perform retrieve retrieveList = StudyRootInformationModel.RetrieveInformationModel(retrieveMessage); } // check if we should use the Patient Study Only Information Model else if ((abstractSyntax.UID == DvtkData.Dul.AbstractSyntax.Patient_Study_Only_Query_Retrieve_Information_Model_MOVE.UID) && (PatientStudyOnlyInformationModel != null)) { // check if the information model should be refreshed before retrieving if (RefreshInformationModelBeforeUse == true) { PatientStudyOnlyInformationModel.RefreshInformationModel(); } // perform retrieve retrieveList = PatientStudyOnlyInformationModel.RetrieveInformationModel(retrieveMessage); } // process the retrieve list return ProcessRetrieveList(moveDestinationAE, retrieveList); }
public void Ticket788_1_1() { DicomFile dicomFile = null; QueryRetrievePatientStudyOnlyInformationModel queryRetrievePatientStudyOnlyInformationModel = new QueryRetrievePatientStudyOnlyInformationModel(); dicomFile = new DicomFile(); dicomFile.DataSet.Set("0x00100020", VR.LO, "1"); dicomFile.DataSet.Set("0x0020000D", VR.UI, "1.1"); dicomFile.DataSet.Set("0x0020000E", VR.UI, "1.1.1"); dicomFile.DataSet.Set("0x00080018", VR.UI, "1.1.1.1"); queryRetrievePatientStudyOnlyInformationModel.AddToInformationModel(dicomFile); dicomFile = new DicomFile(); dicomFile.DataSet.Set("0x00100020", VR.LO, "2"); dicomFile.DataSet.Set("0x0020000D", VR.UI, "2.1"); dicomFile.DataSet.Set("0x0020000E", VR.UI, "2.1.1"); dicomFile.DataSet.Set("0x00080018", VR.UI, "2.1.1.1"); queryRetrievePatientStudyOnlyInformationModel.AddToInformationModel(dicomFile); dicomFile = new DicomFile(); dicomFile.DataSet.Set("0x00100020", VR.LO, "3"); dicomFile.DataSet.Set("0x0020000D", VR.UI, "3.1"); dicomFile.DataSet.Set("0x0020000E", VR.UI, "3.1.1"); dicomFile.DataSet.Set("0x00080018", VR.UI, "3.1.1.1"); queryRetrievePatientStudyOnlyInformationModel.AddToInformationModel(dicomFile); DicomMessage cMoveRequest = new DicomMessage(Dimse.CMOVERQ); cMoveRequest.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.3.2"); cMoveRequest.Set("0x00000600", VR.AE, "MOVE_DESTINATION"); cMoveRequest.Set("0x00080052", VR.CS, "PATIENT"); cMoveRequest.Set("0x00100020", VR.LO, "2"); DvtkData.Collections.StringCollection fileNames = queryRetrievePatientStudyOnlyInformationModel.RetrieveInformationModel(cMoveRequest); Assert.That(fileNames.Count, Is.EqualTo(1)); }
/// <summary> /// Generate a CFind Modality Worklist Query trigger from the given queryTags. /// All other return keys are taken from the supported return key attributes /// in the Worklist Information Model. /// </summary> /// <param name="queryTags">List of Query Tags.</param> /// <returns>CFind Modality Worklist Query trigger.</returns> public static DvtkHighLevelInterface.Dicom.Messages.DicomMessage MakeCFindModalityWorklist(TagValueCollection queryTags) { DvtkHighLevelInterface.Dicom.Messages.DicomMessage queryMessage = new DvtkHighLevelInterface.Dicom.Messages.DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRQ); queryMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.31"); DvtkData.Dimse.DataSet queryDataset = Dvtk.Dicom.InformationEntity.Worklist.WorklistQueryDataset.CreateWorklistQueryDataset(queryTags); queryMessage.DataSet.DvtkDataDataSet = queryDataset; return queryMessage; }
protected override void Execute() { PresentationContext presentationContext = new PresentationContext("1.2.840.10008.1.20.1", // Abstract Syntax Name "1.2.840.10008.1.2"); // Transfer Syntax Name(s) PresentationContext[] presentationContexts = new PresentationContext[1]; presentationContexts[0] = presentationContext; SendAssociateRq(presentationContexts); ReceiveAssociateAc(); if (_nActionMessage != null) { WriteInformation("N-Action Request Information"+"\n"+_nActionMessage.DataSet.Dump("")); Send(_nActionMessage); } ReceiveDicomMessage(); if (_Delay < 0) { // Async storage commitment SendReleaseRq(); ReceiveReleaseRp(); // Start the Storage commit SCP for receiving N-EVENTREPORT EmulateStorageCommitSCP(); } else { string info; if (_Delay == 0) { //Wait for 24 hrs(infinite) int waitingTime = 24 * 60 * 60; _Delay = (short)waitingTime; info = "Waiting forever for N-Event-Report."; } else { info = string.Format("Waiting for N-Event-Report for {0} secs", _Delay); } WriteInformation(info); int waitedTime = 0; if (WaitForPendingDataInNetworkInputBuffer(_Delay * 1000, ref waitedTime)) { DicomMessage nEventReportResponse = ReceiveDicomMessage(); if (nEventReportResponse.CommandSet.DimseCommand == DvtkData.Dimse.DimseCommand.NEVENTREPORTRQ) { // set up the default N-EVENT-REPORT-RSP with a successful status DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.NEVENTREPORTRSP); responseMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0); // send the response this.Send(responseMessage); string msg = "N-Event-Report is received from PACS."; WriteInformation(msg); WriteInformation("N-Event-Report Information\n"+nEventReportResponse.DataSet.Dump("")); SendReleaseRq(); ReceiveReleaseRp(); return; } } else { SendReleaseRq(); ReceiveReleaseRp(); // Start the Storage commit SCP for receiving N-EVENTREPORT EmulateStorageCommitSCP(); } } }
private void menuItemStorageCommit_Click(object sender, System.EventArgs e) { toolBarButtonStoreCommit.Enabled = false; menuItemStorageCommit.Enabled = false; toolBarButtonResult.Enabled = false; //If result tab is present, remove it if(tabControlStorageSCU.Controls.Contains(tabPageResults)) { tabControlStorageSCU.Controls.Remove(tabPageResults); } tabControlStorageSCU.SelectedTab = tabPageLogging; //Update DVT & SUT settings UpdateConfig(); this.storageCommitSCUOptions.ResultsDirectory = validationResultsFileGroup.Directory; this.storageCommitSCUOptions.DataDirectory = this.storageOptions.DataDirectory; toolBarButtonAbort.Enabled = false; CommitScu commitScuThread = new CommitScu(this); if (isStopped) { this.overviewThread = new OverviewThread(); this.overviewThread.Initialize(threadManager); this.overviewThread.Options.ResultsDirectory = validationResultsFileGroup.Directory; this.overviewThread.Options.Identifier = "Storage_SCU_Emulator"; this.overviewThread.Options.AttachChildsToUserInterfaces = true; this.overviewThread.Options.LogThreadStartingAndStoppingInParent = false; this.overviewThread.Options.LogWaitingForCompletionChildThreads = false; this.userControlActivityLogging.Attach(overviewThread); String resultsFileName = "StoreSCUEmulator_" + System.DateTime.Now.ToString("yyyyMMddHHmmss", System.Globalization.CultureInfo.InvariantCulture); this.overviewThread.Options.ResultsFileNameOnlyWithoutExtension = resultsFileName; // // Start the Dicom Overview Thread // this.overviewThread.Start(); isStopped = false; } commitScuThread.Initialize(this.overviewThread); commitScuThread.Options.CopyFrom(this.storageCommitSCUOptions); String resultsFileBaseName = "StorageCommitOperationAsSCU_" + System.DateTime.Now.ToString("yyyyMMddHHmmss", System.Globalization.CultureInfo.InvariantCulture); commitScuThread.Options.ResultsFileNameOnlyWithoutExtension = resultsFileBaseName; commitScuThread.Options.Identifier = resultsFileBaseName; commitScuThread.Options.LogThreadStartingAndStoppingInParent = false; commitScuThread.Options.LogWaitingForCompletionChildThreads = false; commitScuThread.Options.AutoValidate = false; DicomMessage nActionStorageCommitment = new DicomMessage(DvtkData.Dimse.DimseCommand.NACTIONRQ); nActionStorageCommitment.Set("0x00000003", DvtkData.Dimse.VR.UI, "1.2.840.10008.1.20.1"); nActionStorageCommitment.Set("0x00001001", DvtkData.Dimse.VR.UI, "1.2.840.10008.1.20.1.1"); // Well known Instance UID nActionStorageCommitment.Set("0x00001008", DvtkData.Dimse.VR.US, 1); DvtkData.Dimse.SequenceItem referencedStudyComponentSequenceItem = new DvtkData.Dimse.SequenceItem(); referencedStudyComponentSequenceItem.AddAttribute(DvtkData.Dimse.Tag.REFERENCED_SOP_CLASS_UID.GroupNumber, DvtkData.Dimse.Tag.REFERENCED_SOP_CLASS_UID.ElementNumber, DvtkData.Dimse.VR.UI, "1.2.840.10008.3.1.2.3.3"); string refSopInstanceUID = UID.Create(); referencedStudyComponentSequenceItem.AddAttribute(DvtkData.Dimse.Tag.REFERENCED_SOP_INSTANCE_UID.GroupNumber, DvtkData.Dimse.Tag.REFERENCED_SOP_INSTANCE_UID.ElementNumber, DvtkData.Dimse.VR.UI, refSopInstanceUID); nActionStorageCommitment.DataSet.DvtkDataDataSet.AddAttribute(DvtkData.Dimse.Tag.REFERENCED_STUDY_COMPONENT_SEQUENCE.GroupNumber, DvtkData.Dimse.Tag.REFERENCED_STUDY_COMPONENT_SEQUENCE.ElementNumber, DvtkData.Dimse.VR.SQ, referencedStudyComponentSequenceItem); AddReferencedSopSequence(storageCommitItems, 0x00081199, nActionStorageCommitment.DataSet.DvtkDataDataSet, InstanceStateEnum.InstanceStorageCommitRequested); string transUID = UID.Create(); nActionStorageCommitment.DataSet.DvtkDataDataSet.AddAttribute(DvtkData.Dimse.Tag.TRANSACTION_UID.GroupNumber, DvtkData.Dimse.Tag.TRANSACTION_UID.ElementNumber, DvtkData.Dimse.VR.UI, transUID); if (delay < 0) { //toolBarButtonStop.Enabled = true; commitScuThread.setSupportedTS(selectedTS); } commitScuThread.ThreadSettings = this.storageCommitSCUOptions; commitScuThread.Timeout = delay; commitScuThread.NActionMessage = nActionStorageCommitment; commitScuThread.Start(); }
/// <summary> /// Overridden N-ACTION-RQ message handler. Return an N-EVENT-REPORT-RQ /// after the N-ACTION-RSP. /// </summary> /// <param name="queryMessage">N-ACTION-RQ and Dataset.</param> /// <returns>Boolean - true if dicomMessage handled here.</returns> protected override void AfterHandlingNActionRequest(DicomMessage dicomMessage) { isEventSent = false; // set up the default N-ACTION-RSP with a successful status DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.NACTIONRSP); responseMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0); // send the response this.Send(responseMessage); IsMessageHandled = true; // creating information model QueryRetrieveInformationModels qrInfoModels = CreateQueryRetrieveInformationModels(true, _dataDirectory); // delay before generating the N-EVENT-REPORT-RQ WriteInformation(string.Format("Delaying the N-EVENT-REPORT by {0} secs", _eventDelay / 1000)); isAssociated = true; int waitedTime = 0; if (WaitForPendingDataInNetworkInputBuffer(_eventDelay, ref waitedTime)) { ReleaseRq releaseRq = ReceiveReleaseRq(); if (releaseRq != null) { SendReleaseRp(); isAssociated = false; } } if (!isAssociated) { string info = "Sending the N-Event-Report asynchronously."; WriteInformation(info); SCU commitScu = new SCU(); commitScu.Initialize(this.Parent); // Set the correct settings for the overview DicomThread. // commitScu.Options.Identifier = "Storage_Commitment_SCU_association_" + storageCommitmentScuIndex.ToString(); commitScu.Options.ResultsFileNameOnlyWithoutExtension = (this.overviewThread as StoreCommitScp).startDateTime + "_Storage_Commitment_SCU_association_" + storageCommitmentScuIndex.ToString(); storageCommitmentScuIndex++; commitScu.Options.LocalAeTitle = this.Options.LocalAeTitle; commitScu.Options.RemoteAeTitle = _remoteAETitle; commitScu.Options.RemotePort = _port; commitScu.Options.RemoteHostName = _remoteHostName; commitScu.Options.RemoteRole = Dvtk.Sessions.SutRole.Requestor; commitScu.Options.ResultsDirectory = this.Options.ResultsDirectory; commitScu.Options.DataDirectory = this.Options.DataDirectory; commitScu.Options.StorageMode = Dvtk.Sessions.StorageMode.NoStorage; commitScu.Options.LogThreadStartingAndStoppingInParent = false; commitScu.Options.LogWaitingForCompletionChildThreads = false; commitScu.Options.AutoValidate = false; PresentationContext presentationContext = new PresentationContext("1.2.840.10008.1.20.1", // Abstract Syntax Name "1.2.840.10008.1.2"); // Transfer Syntax Name(s) PresentationContext[] presentationContexts = new PresentationContext[1]; presentationContexts[0] = presentationContext; // create the N-EVENT-REPORT-RQ based in the contents of the N-ACTION-RQ DicomMessage requestMessage = GenerateTriggers.MakeStorageCommitEvent(qrInfoModels, dicomMessage); if (waitedTime < _eventDelay) Sleep(_eventDelay - waitedTime); commitScu.Start(); isEventSent = commitScu.TriggerSendAssociationAndWait(requestMessage, presentationContexts); } else { string info = "Sending the N-Event-Report synchronously."; WriteInformation(info); if (!isEventSent) SendNEventReport(qrInfoModels, dicomMessage); } }
/// <summary> /// Overridden C-FIND-RQ message handler that makes use of the appropriate Information Model to handle the query. /// </summary> /// <param name="queryMessage">C-FIND-RQ Identifier (Dataset) containing query attributes.</param> /// <returns>Boolean - true if dicomMessage handled here.</returns> public override bool HandleCFindRequest(DicomMessage queryMessage) { // Validate the received message //System.String iodName = DicomThread.GetIodNameFromDefinition(queryMessage); //DicomThread.Validate(queryMessage, iodName); // try to get the SOP Class Uid so that we know which Information Model to use. DvtkHighLevelInterface.Dicom.Other.Values values = queryMessage.CommandSet["0x00000002"].Values; System.String sopClassUid = values[0]; DvtkData.Dul.AbstractSyntax abstractSyntax = new DvtkData.Dul.AbstractSyntax(sopClassUid); // check if we should use the Patient Root Information Model if ((abstractSyntax.UID == DvtkData.Dul.AbstractSyntax.Patient_Root_Query_Retrieve_Information_Model_FIND.UID) && (PatientRootInformationModel != null)) { // check if the information model should be refreshed before querying if (RefreshInformationModelBeforeUse == true) { PatientRootInformationModel.RefreshInformationModel(); } // perform query DicomMessageCollection responseMessages = PatientRootInformationModel.QueryInformationModel(queryMessage); // handle responses foreach (DicomMessage responseMessage in responseMessages) { int waitedTime = 0; // Check for cancel message from SCU if (WaitForPendingDataInNetworkInputBuffer(100, ref waitedTime)) { DicomMessage cancelRq = ReceiveDicomMessage(); if (cancelRq.CommandSet.DimseCommand == DvtkData.Dimse.DimseCommand.CCANCELRQ) { // set up the C-FIND-RSP with cancel status DicomMessage respMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); respMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0xFE00); // send the response this.Send(respMessage); break; } } this.Send(responseMessage); } } // check if we should use the Study Root Information Model else if ((abstractSyntax.UID == DvtkData.Dul.AbstractSyntax.Study_Root_Query_Retrieve_Information_Model_FIND.UID) && (StudyRootInformationModel != null)) { // check if the information model should be refreshed before querying if (RefreshInformationModelBeforeUse == true) { StudyRootInformationModel.RefreshInformationModel(); } // perform query DicomMessageCollection responseMessages = StudyRootInformationModel.QueryInformationModel(queryMessage); // handle responses foreach (DicomMessage responseMessage in responseMessages) { int waitedTime = 0; // Check for cancel message from SCU if (WaitForPendingDataInNetworkInputBuffer(100, ref waitedTime)) { DicomMessage cancelRq = ReceiveDicomMessage(); if (cancelRq.CommandSet.DimseCommand == DvtkData.Dimse.DimseCommand.CCANCELRQ) { // set up the C-FIND-RSP with cancel status DicomMessage respMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); respMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0xFE00); // send the response this.Send(respMessage); break; } } this.Send(responseMessage); } } // check if we should use the Patient Study Only Information Model else if ((abstractSyntax.UID == DvtkData.Dul.AbstractSyntax.Patient_Study_Only_Query_Retrieve_Information_Model_FIND.UID) && (PatientStudyOnlyInformationModel != null)) { // check if the information model should be refreshed before querying if (RefreshInformationModelBeforeUse == true) { PatientStudyOnlyInformationModel.RefreshInformationModel(); } // perform query DicomMessageCollection responseMessages = PatientStudyOnlyInformationModel.QueryInformationModel(queryMessage); // handle responses foreach (DicomMessage responseMessage in responseMessages) { int waitedTime = 0; // Check for cancel message from SCU if (WaitForPendingDataInNetworkInputBuffer(100, ref waitedTime)) { DicomMessage cancelRq = ReceiveDicomMessage(); if (cancelRq.CommandSet.DimseCommand == DvtkData.Dimse.DimseCommand.CCANCELRQ) { // set up the C-FIND-RSP with cancel status DicomMessage respMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); respMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0xFE00); // send the response this.Send(respMessage); break; } } this.Send(responseMessage); } } else { // should never get here - but send a final CFINDRSP anyway DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); this.Send(responseMessage); } // message handled return true; }
protected override void AfterHandlingCEchoRequest(DicomMessage dicomMessage) { if (!IsMessageHandled) { DicomMessage CEchoRsp = new DicomMessage(DimseCommand.CECHORSP); CEchoRsp.Set("0x00000002", VR.UI, "1.2.840.10008.1.1"); CEchoRsp.Set("0x00000900", VR.US, 0); Send(CEchoRsp); IsMessageHandled = true; } }
/// <summary> /// Overridden C-STORE-RQ message handler. /// </summary> /// <param name="dicomMessage">C-STORE-RQ and Dataset.</param> /// <returns>Boolean - true if dicomMessage handled here.</returns> protected override void AfterHandlingCStoreRequest(DicomMessage dicomMessage) { // set up the default C-STORE-RSP with a successful status DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CSTORERSP); responseMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0); // send the response this.Send(responseMessage); // message handled IsMessageHandled = true; }
private bool ProcessRetrieveList(System.String moveDestinationAE, DvtkData.Collections.StringCollection retrieveList) { UInt16 status = 0x0000; UInt16 remainingSubOperations = (UInt16)retrieveList.Count; UInt16 completeSubOperations = 0; UInt16 failedSubOperations = 0; UInt16 warningSubOperations = 0; int subOperationIndex = 0; bool isCancelRecd = false; foreach (System.String dcmFilename in retrieveList) { status = 0xFF00; SendCMoveRsp(status, remainingSubOperations, completeSubOperations, failedSubOperations, warningSubOperations); if (HandleSubOperation(moveDestinationAE, dcmFilename, subOperationIndex) == true && cStoreStatusVal == 0x0000) { completeSubOperations++; } else if (cStoreStatusVal == 0xB007 || cStoreStatusVal == 0xB000 || cStoreStatusVal == 0xB006) { warningSubOperations += 1; } else { failedSubOperations++; } remainingSubOperations--; subOperationIndex++; int waitedTime = 0; // Check for cancel message from SCU if (WaitForPendingDataInNetworkInputBuffer(100, ref waitedTime)) { DicomMessage cancelRq = ReceiveDicomMessage(); if (cancelRq.CommandSet.DimseCommand == DvtkData.Dimse.DimseCommand.CCANCELRQ) { // set up the C-FIND-RSP with cancel status DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CMOVERSP); responseMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0xFE00); // send the response this.Send(responseMessage); isCancelRecd = true; break; } } } if (!isCancelRecd) { if ((failedSubOperations > 0) || (warningSubOperations > 0)) { status = 0xB000; } //else if ((failedSubOperations == 0) && (completeSubOperations==0) && (remainingSubOperations==0) &&(warningSubOperations==0)) //{ // status = 0xA702; //} else { status = 0x0000; } SendCMoveRsp(status, remainingSubOperations, completeSubOperations, failedSubOperations, warningSubOperations); } // message handled return true; }
protected override void AfterHandlingNEventReportRequest(DicomMessage dicomMessage) { base.AfterHandlingNEventReportRequest(dicomMessage); IsMessageHandled = true; // set up the default N-EVENT-REPORT-RSP with a successful status DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.NEVENTREPORTRSP); responseMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0); // send the response this.Send(responseMessage); }
private void SendCMoveRsp(UInt16 status, UInt16 remainingSubOperations, UInt16 completeSubOperations, UInt16 failedSubOperations, UInt16 warningSubOperations) { DicomMessage responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CMOVERSP); responseMessage.Set("0x00000900", VR.US, status); responseMessage.Set("0x00001020", VR.US, remainingSubOperations); responseMessage.Set("0x00001021", VR.US, completeSubOperations); responseMessage.Set("0x00001022", VR.US, failedSubOperations); responseMessage.Set("0x00001023", VR.US, warningSubOperations); this.Send(responseMessage); }
/// <summary> /// Returns number of responses. /// </summary> /// <param name="studyTime"></param> /// <param name="StydyTimeRange"></param> /// <param name="?"></param> /// <returns></returns> private int Ticket788CommonCode2(String studyTime, String StydyTimeRange) { QueryRetrievePatientRootInformationModel queryRetrievePatientRootInformationModel = new QueryRetrievePatientRootInformationModel(); DicomFile dicomFile = new DicomFile(); dicomFile.DataSet.Set("0x00100020", VR.LO, "1"); dicomFile.DataSet.Set("0x0020000D", VR.UI, "1.1"); dicomFile.DataSet.Set("0x0020000E", VR.UI, "1.1.1"); dicomFile.DataSet.Set("0x00080018", VR.UI, "1.1.1.1"); dicomFile.DataSet.Set("0x00080020", VR.DA, "20090225"); // Study date. dicomFile.DataSet.Set("0x00080030", VR.TM, studyTime); // Study time. queryRetrievePatientRootInformationModel.AddToInformationModel(dicomFile); DicomMessage cFindRequest = new DicomMessage(DimseCommand.CFINDRQ); cFindRequest.CommandSet.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.1.1"); // Set Affected SOP class to Patient Root Query/Retrieve Information Model – FIND cFindRequest.DataSet.Set("0x00100020", VR.LO, "1"); // Patient ID. cFindRequest.DataSet.Set("0x0020000D", VR.UI); // Study instance UID. cFindRequest.Set("0x00080030", VR.TM, StydyTimeRange); // Study time. cFindRequest.DataSet.Set("0x00080052", VR.CS, "STUDY"); // Query Retrieve Level. DicomMessageCollection cFindResponses = queryRetrievePatientRootInformationModel.QueryInformationModel(cFindRequest); return (cFindResponses.Count); }
/// <summary> /// Generate a CFind Modality Worklist Query trigger by reading the query /// dataset from the given mwlQueryDcmFilename. If the scheduledProcedureStepStartDate /// is defined (not string empty) then if a value for this attribute is present in the /// read datset it will be overwritten by the scheduledProcedureStepStartDate value. /// </summary> /// <param name="mwlQueryDcmFilename">DCM file containing the MWL Query Dataset.</param> /// <param name="scheduledProcedureStepStartDate">Optional (not sting empty) start date to overwrite dataset value.</param> /// <returns>CFind Modality Worklist Query trigger.</returns> public static DvtkHighLevelInterface.Dicom.Messages.DicomMessage MakeCFindModalityWorklist(System.String mwlQueryDcmFilename, System.String scheduledProcedureStepStartDate) { DvtkHighLevelInterface.Dicom.Messages.DicomMessage queryMessage = new DvtkHighLevelInterface.Dicom.Messages.DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRQ); queryMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.31"); DvtkData.Dimse.DataSet queryDataset = Dvtk.Dicom.InformationEntity.Worklist.WorklistQueryDataset.CreateWorklistQueryDataset(mwlQueryDcmFilename, scheduledProcedureStepStartDate); queryMessage.DataSet.DvtkDataDataSet = queryDataset; return queryMessage; }
public void Ticket1361_4_1() { DicomFile dicomFile = null; QueryRetrievePatientRootInformationModel queryRetrievePatientRootInformationModel = new QueryRetrievePatientRootInformationModel(); dicomFile = new DicomFile(); dicomFile.DataSet.Set("0x00100020", VR.LO, "1"); dicomFile.DataSet.Set("0x0020000D", VR.UI, "1.1"); dicomFile.DataSet.Set("0x0020000E", VR.UI, "1.1.1"); dicomFile.DataSet.Set("0x00080018", VR.UI, "1.1.1.1"); queryRetrievePatientRootInformationModel.AddToInformationModel(dicomFile, false); dicomFile = new DicomFile(); dicomFile.DataSet.Set("0x00100020", VR.LO, "1"); dicomFile.DataSet.Set("0x0020000D", VR.UI, "1.1"); dicomFile.DataSet.Set("0x0020000E", VR.UI, "1.1.1"); dicomFile.DataSet.Set("0x00080018", VR.UI, "1.1.1.2"); queryRetrievePatientRootInformationModel.AddToInformationModel(dicomFile, false); dicomFile = new DicomFile(); dicomFile.DataSet.Set("0x00100020", VR.LO, "1"); dicomFile.DataSet.Set("0x0020000D", VR.UI, "1.1"); dicomFile.DataSet.Set("0x0020000E", VR.UI, "1.1.1"); dicomFile.DataSet.Set("0x00080018", VR.UI, "1.1.1.3"); queryRetrievePatientRootInformationModel.AddToInformationModel(dicomFile, false); DicomMessage cMoveRequest = new DicomMessage(DimseCommand.CMOVERQ); cMoveRequest.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.1.2"); cMoveRequest.Set("0x00000600", VR.AE, "MOVE_DESTINATION"); cMoveRequest.Set("0x00080052", VR.CS, "IMAGE"); cMoveRequest.Set("0x00100020", VR.LO, "1"); cMoveRequest.Set("0x0020000D", VR.UI, "1.1"); cMoveRequest.Set("0x0020000E", VR.UI, "1.1.1"); cMoveRequest.Set("0x00080018", VR.UI, "1.1.1.1", "1.1.1.3"); DvtkData.Collections.StringCollection fileNames = queryRetrievePatientRootInformationModel.RetrieveInformationModel(cMoveRequest); Assert.That(fileNames.Count, Is.EqualTo(0)); }
/// <summary> /// Method to handle the workflow after receiving a C-EHO-RQ. /// </summary> /// <param name="dicomMessage">C-ECHO-RQ message.</param> protected override void AfterHandlingCEchoRequest(DicomMessage dicomMessage) { if (IsMessageHandled == false) { DicomMessage dicomMessageToSend = new DicomMessage(DvtkData.Dimse.DimseCommand.CECHORSP); dicomMessageToSend.Set("0x00000002", DvtkData.Dimse.VR.UI, "1.2.840.10008.1.1"); dicomMessageToSend.Set("0x00000900", DvtkData.Dimse.VR.US, 0); Send(dicomMessageToSend); // message has now been handled IsMessageHandled = true; } }
/// <summary> /// Make C-FIND query. /// </summary> /// <param name="informationModel">The information model.</param> /// <param name="queryTags">The query tags.</param> /// <returns>The create C-FIND message.</returns> public static DvtkHighLevelInterface.Dicom.Messages.DicomMessage MakeCFindQuery(QueryRetrieveInformationModelEnum informationModel, TagValueCollection queryTags) { DvtkHighLevelInterface.Dicom.Messages.DicomMessage queryMessage = new DvtkHighLevelInterface.Dicom.Messages.DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRQ); DvtkData.Dimse.DataSet queryDataset = null; switch(informationModel) { case QueryRetrieveInformationModelEnum.PatientRootQueryRetrieveInformationModel: default: queryMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.1.1"); queryDataset = new DvtkData.Dimse.DataSet("Patient Root Query/Retrieve Information Model - FIND SOP Class"); break; case QueryRetrieveInformationModelEnum.StudyRootQueryRetrieveInformationModel: queryMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.2.1"); queryDataset = new DvtkData.Dimse.DataSet("Study Root Query/Retrieve Information Model - FIND SOP Class"); break; case QueryRetrieveInformationModelEnum.PatientStudyOnlyQueryRetrieveInformationModel: queryMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.3.1"); queryDataset = new DvtkData.Dimse.DataSet("Patient/Study Only Query/Retrieve Info. Model - FIND SOP Class"); break; } // add the query keys AddQueryRetrieveKeys(queryTags, queryDataset); queryMessage.DataSet.DvtkDataDataSet = queryDataset; return queryMessage; }
/// <summary> /// Create C-Move retrieve. /// </summary> /// <param name="informationModel">The information model.</param> /// <param name="moveDestination">The move destination.</param> /// <param name="retrieveTags">The retrieve tags.</param> /// <returns>teh C-MOVE message.</returns> public static DvtkHighLevelInterface.Dicom.Messages.DicomMessage MakeCMoveRetrieve(QueryRetrieveInformationModelEnum informationModel, System.String moveDestination, TagValueCollection retrieveTags) { DvtkHighLevelInterface.Dicom.Messages.DicomMessage retrieveMessage = new DvtkHighLevelInterface.Dicom.Messages.DicomMessage(DvtkData.Dimse.DimseCommand.CMOVERQ); DvtkData.Dimse.DataSet retrieveDataset = null; switch(informationModel) { case QueryRetrieveInformationModelEnum.PatientRootQueryRetrieveInformationModel: default: retrieveMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.1.2"); retrieveDataset = new DvtkData.Dimse.DataSet("Patient Root Query/Retrieve Information Model - MOVE SOP Class"); break; case QueryRetrieveInformationModelEnum.StudyRootQueryRetrieveInformationModel: retrieveMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.2.2"); retrieveDataset = new DvtkData.Dimse.DataSet("Study Root Query/Retrieve Information Model - MOVE SOP Class"); break; case QueryRetrieveInformationModelEnum.PatientStudyOnlyQueryRetrieveInformationModel: retrieveMessage.Set("0x00000002", VR.UI, "1.2.840.10008.5.1.4.1.2.3.2"); retrieveDataset = new DvtkData.Dimse.DataSet("Patient/Study Only Query/Retrieve Info. Model - MOVE SOP Class"); break; } retrieveMessage.Set("0x00000600", VR.AE, moveDestination); // add the query keys AddQueryRetrieveKeys(retrieveTags, retrieveDataset); retrieveMessage.DataSet.DvtkDataDataSet = retrieveDataset; return retrieveMessage; }
/// <summary> /// Overridden C-FIND-RQ message handler that makes use of the appropriate Information Model to handle the query. /// </summary> /// <param name="queryMessage">C-FIND-RQ Identifier (Dataset) containing query attributes.</param> /// <returns>Boolean - true if dicomMessage handled here.</returns> public override bool HandleCFindRequest(DicomMessage queryMessage) { // Query response messages DicomMessageCollection responseMessages = new DicomMessageCollection(); DvtkHighLevelInterface.Dicom.Other.Values values = queryMessage.CommandSet["0x00000002"].Values; System.String sopClassUid = values[0]; DicomMessage responseMessage = null; foreach (DataSet randomDataset in randomizedDatasets) { responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); responseMessage.CommandSet.Set("0x00000002", DvtkData.Dimse.VR.UI, sopClassUid); responseMessage.CommandSet.Set("0x00000900", DvtkData.Dimse.VR.US, 0xFF00); responseMessage.DataSet.CloneFrom(randomDataset); responseMessages.Add(responseMessage); } responseMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); responseMessage.CommandSet.Set("0x00000002", DvtkData.Dimse.VR.UI, sopClassUid); responseMessage.CommandSet.Set("0x00000900", DvtkData.Dimse.VR.US, 0x0000); responseMessages.Add(responseMessage); // handle responses foreach (DicomMessage rspMessage in responseMessages) { try { int waitedTime = 0; // Check for cancel message from SCU if (WaitForPendingDataInNetworkInputBuffer(100, ref waitedTime)) { DicomMessage cancelRq = ReceiveDicomMessage(); if (cancelRq.CommandSet.DimseCommand == DvtkData.Dimse.DimseCommand.CCANCELRQ) { // set up the C-FIND-RSP with cancel status DicomMessage respMessage = new DicomMessage(DvtkData.Dimse.DimseCommand.CFINDRSP); respMessage.Set("0x00000900", DvtkData.Dimse.VR.US, 0xFE00); // send the response this.Send(respMessage); break; } } this.Send(rspMessage); } catch(Exception) { string theErrorText = "DICOM Connection Error: RIS Emulator is failed to send the C-FIND-RSP."; WriteError(theErrorText); } } // message handled return true; }