Mercurial > hg > orthanc
annotate OrthancServer/OrthancFindRequestHandler.cpp @ 1859:4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 02 Dec 2015 11:22:05 +0100 |
parents | 36ab170733d6 |
children | 512b6e76f531 |
rev | line source |
---|---|
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
1 /** |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
2 * Orthanc - A Lightweight, RESTful DICOM Store |
1288
6e7e5ed91c2d
upgrade to year 2015
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1162
diff
changeset
|
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics |
6e7e5ed91c2d
upgrade to year 2015
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1162
diff
changeset
|
4 * Department, University Hospital of Liege, Belgium |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
5 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
6 * This program is free software: you can redistribute it and/or |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
7 * modify it under the terms of the GNU General Public License as |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
8 * published by the Free Software Foundation, either version 3 of the |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
9 * License, or (at your option) any later version. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
10 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
11 * In addition, as a special exception, the copyright holders of this |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
12 * program give permission to link the code of its release with the |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
14 * that use the same license as the "OpenSSL" library), and distribute |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
15 * the linked executables. You must obey the GNU General Public License |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
16 * in all respects for all of the code used other than "OpenSSL". If you |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
17 * modify file(s) with this exception, you may extend this exception to |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
18 * your version of the file(s), but you are not obligated to do so. If |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
19 * you do not wish to do so, delete this exception statement from your |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
20 * version. If you delete this exception statement from all source files |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
21 * in the program, then also delete it here. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
22 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
23 * This program is distributed in the hope that it will be useful, but |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
24 * WITHOUT ANY WARRANTY; without even the implied warranty of |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
26 * General Public License for more details. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
27 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
28 * You should have received a copy of the GNU General Public License |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
30 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
31 |
824
a811bdf8b8eb
precompiled headers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
810
diff
changeset
|
32 |
831
84513f2ee1f3
pch for unit tests and server
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
824
diff
changeset
|
33 #include "PrecompiledHeadersServer.h" |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
34 #include "OrthancFindRequestHandler.h" |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
35 |
1759
e268412adcf1
removal of old implementation of search
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1758
diff
changeset
|
36 #include "../Core/DicomFormat/DicomArray.h" |
1486
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1429
diff
changeset
|
37 #include "../Core/Logging.h" |
795 | 38 #include "FromDcmtkBridge.h" |
1759
e268412adcf1
removal of old implementation of search
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1758
diff
changeset
|
39 #include "OrthancInitialization.h" |
1751
fb569ee09a69
LookupResource complete
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1737
diff
changeset
|
40 #include "Search/LookupResource.h" |
1759
e268412adcf1
removal of old implementation of search
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1758
diff
changeset
|
41 #include "ServerToolbox.h" |
608 | 42 |
1486
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1429
diff
changeset
|
43 #include <boost/regex.hpp> |
f967bdf8534e
refactoring to Logging.h
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1429
diff
changeset
|
44 |
608 | 45 |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
46 namespace Orthanc |
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
47 { |
608 | 48 static void AddAnswer(DicomFindAnswers& answers, |
49 const Json::Value& resource, | |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
50 const DicomArray& query, |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
51 const std::list<DicomTag>& sequencesToReturn) |
608 | 52 { |
53 DicomMap result; | |
54 | |
55 for (size_t i = 0; i < query.GetSize(); i++) | |
56 { | |
1346 | 57 if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL) |
58 { | |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
59 // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052)) |
1346 | 60 result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue()); |
61 } | |
62 else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
63 { | |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
64 // Do not include the encoding, this is handled by class ParsedDicomFile |
1346 | 65 } |
66 else | |
608 | 67 { |
68 std::string tag = query.GetElement(i).GetTag().Format(); | |
69 std::string value; | |
70 if (resource.isMember(tag)) | |
71 { | |
72 value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); | |
73 result.SetValue(query.GetElement(i).GetTag(), value); | |
74 } | |
722 | 75 else |
76 { | |
77 result.SetValue(query.GetElement(i).GetTag(), ""); | |
78 } | |
608 | 79 } |
80 } | |
81 | |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
82 if (result.GetSize() == 0 && |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
83 sequencesToReturn.empty()) |
1331
77e129ba64e4
Prevent freeze on C-FIND if no DICOM tag is to be returned
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
84 { |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
85 LOG(WARNING) << "The C-FIND request does not return any DICOM tag"; |
1331
77e129ba64e4
Prevent freeze on C-FIND if no DICOM tag is to be returned
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
86 } |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
87 else if (sequencesToReturn.empty()) |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
88 { |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
89 answers.Add(result); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
90 } |
1331
77e129ba64e4
Prevent freeze on C-FIND if no DICOM tag is to be returned
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
91 else |
77e129ba64e4
Prevent freeze on C-FIND if no DICOM tag is to be returned
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
92 { |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
93 ParsedDicomFile dicom(result); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
94 |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
95 for (std::list<DicomTag>::const_iterator tag = sequencesToReturn.begin(); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
96 tag != sequencesToReturn.end(); ++tag) |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
97 { |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
98 std::cout << tag->Format(); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
99 |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
100 const Json::Value& source = resource[tag->Format()]; |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
101 |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
102 if (source.type() == Json::objectValue && |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
103 source.isMember("Type") && |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
104 source.isMember("Value") && |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
105 source["Type"].asString() == "Sequence" && |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
106 source["Value"].type() == Json::arrayValue) |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
107 { |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
108 Json::Value content = Json::arrayValue; |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
109 |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
110 for (Json::Value::ArrayIndex i = 0; i < source["Value"].size(); i++) |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
111 { |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
112 Json::Value item; |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
113 Toolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
114 content.append(item); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
115 } |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
116 |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
117 dicom.Replace(*tag, content, false); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
118 } |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
119 } |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
120 |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
121 answers.Add(dicom); |
1331
77e129ba64e4
Prevent freeze on C-FIND if no DICOM tag is to be returned
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1288
diff
changeset
|
122 } |
608 | 123 } |
124 | |
125 | |
1851
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
126 |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
127 bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */, |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
128 ResourceType level, |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
129 const DicomTag& tag, |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
130 ModalityManufacturer manufacturer) |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
131 { |
1853
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
132 switch (manufacturer) |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
133 { |
1856
36ab170733d6
Made eFilm version explicit
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1853
diff
changeset
|
134 case ModalityManufacturer_EFilm2: |
1853
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
135 // Following Denis Nesterov's mail on 2015-11-30 |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
136 if (tag == DicomTag(0x0008, 0x0000) || // "GenericGroupLength" |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
137 tag == DicomTag(0x0010, 0x0000) || // "GenericGroupLength" |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
138 tag == DicomTag(0x0020, 0x0000)) // "GenericGroupLength" |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
139 { |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
140 return false; |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
141 } |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
142 |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
143 break; |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
144 |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
145 case ModalityManufacturer_Vitrea: |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
146 // Following Denis Nesterov's mail on 2015-11-30 |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
147 if (tag == DicomTag(0x5653, 0x0010)) // "PrivateCreator = Vital Images SW 3.4" |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
148 { |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
149 return false; |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
150 } |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
151 |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
152 break; |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
153 |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
154 default: |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
155 break; |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
156 } |
b7d3d3b182cf
two patches for manufacturers Efilm and Vitrea
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1851
diff
changeset
|
157 |
1851
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
158 return true; |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
159 } |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
160 |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
161 |
1800
30e97a1f4093
callback for handling worklists with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1799
diff
changeset
|
162 void OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, |
665 | 163 const DicomMap& input, |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
164 const std::list<DicomTag>& sequencesToReturn, |
1573
3309878b3e16
more information about the origin of requests submitted to the DICOM handlers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1486
diff
changeset
|
165 const std::string& remoteIp, |
1799
4f01c9d73f02
calledAet made available to all the handlers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1759
diff
changeset
|
166 const std::string& remoteAet, |
4f01c9d73f02
calledAet made available to all the handlers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1759
diff
changeset
|
167 const std::string& calledAet) |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
168 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
169 /** |
1799
4f01c9d73f02
calledAet made available to all the handlers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1759
diff
changeset
|
170 * Ensure that the remote modality is known to Orthanc. |
665 | 171 **/ |
172 | |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
173 RemoteModalityParameters modality; |
665 | 174 |
1573
3309878b3e16
more information about the origin of requests submitted to the DICOM handlers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1486
diff
changeset
|
175 if (!Configuration::LookupDicomModalityUsingAETitle(modality, remoteAet)) |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
176 { |
1582
bd1889029cbb
encoding of exceptions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1573
diff
changeset
|
177 throw OrthancException(ErrorCode_UnknownModality); |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
178 } |
806 | 179 |
1382
1cd2e09cb0e5
case insensitive search by default
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1374
diff
changeset
|
180 bool caseSensitivePN = Configuration::GetGlobalBoolParameter("CaseSensitivePN", false); |
1374
a1745d9be6e9
CaseSensitivePN configuration option
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1361
diff
changeset
|
181 |
665 | 182 |
183 /** | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
184 * Retrieve the query level. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
185 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
186 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
187 const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); |
1737
ec66a16aa398
removal of DicomStringValue and DicomNullValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1582
diff
changeset
|
188 if (levelTmp == NULL || |
ec66a16aa398
removal of DicomStringValue and DicomNullValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1582
diff
changeset
|
189 levelTmp->IsNull() || |
ec66a16aa398
removal of DicomStringValue and DicomNullValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1582
diff
changeset
|
190 levelTmp->IsBinary()) |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
191 { |
1851
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
192 LOG(ERROR) << "C-FIND request without the tag 0008,0052 (QueryRetrieveLevel)"; |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
193 throw OrthancException(ErrorCode_BadRequest); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
194 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
195 |
1737
ec66a16aa398
removal of DicomStringValue and DicomNullValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1582
diff
changeset
|
196 ResourceType level = StringToResourceType(levelTmp->GetContent().c_str()); |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
197 |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
198 if (level != ResourceType_Patient && |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
199 level != ResourceType_Study && |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
200 level != ResourceType_Series && |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
201 level != ResourceType_Instance) |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
202 { |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
203 throw OrthancException(ErrorCode_NotImplemented); |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
204 } |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
205 |
665 | 206 |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
207 DicomArray query(input); |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
208 LOG(INFO) << "DICOM C-Find request at level: " << EnumerationToString(level); |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
209 |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
210 for (size_t i = 0; i < query.GetSize(); i++) |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
211 { |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
212 if (!query.GetElement(i).GetValue().IsNull()) |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
213 { |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
214 LOG(INFO) << " " << query.GetElement(i).GetTag() |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
215 << " " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag()) |
1737
ec66a16aa398
removal of DicomStringValue and DicomNullValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1582
diff
changeset
|
216 << " = " << query.GetElement(i).GetValue().GetContent(); |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
217 } |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
218 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
219 |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
220 for (std::list<DicomTag>::const_iterator it = sequencesToReturn.begin(); |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
221 it != sequencesToReturn.end(); ++it) |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
222 { |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
223 LOG(INFO) << " (" << it->Format() |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
224 << ") " << FromDcmtkBridge::GetName(*it) |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
225 << " : sequence tag whose content will be copied"; |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
226 } |
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
227 |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
228 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
229 /** |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
230 * Build up the query object. |
608 | 231 **/ |
232 | |
1751
fb569ee09a69
LookupResource complete
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1737
diff
changeset
|
233 LookupResource finder(level); |
1759
e268412adcf1
removal of old implementation of search
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1758
diff
changeset
|
234 |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
235 for (size_t i = 0; i < query.GetSize(); i++) |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
236 { |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
237 const DicomTag tag = query.GetElement(i).GetTag(); |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
238 |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
239 if (query.GetElement(i).GetValue().IsNull() || |
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
240 tag == DICOM_TAG_QUERY_RETRIEVE_LEVEL || |
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
241 tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
242 { |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
243 continue; |
714
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
244 } |
6a1dbba0cca7
new implementation of C-Find handler
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
690
diff
changeset
|
245 |
1737
ec66a16aa398
removal of DicomStringValue and DicomNullValue
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1582
diff
changeset
|
246 std::string value = query.GetElement(i).GetValue().GetContent(); |
1429
7366a0bdda6a
attempt of fix for Syngo.Via
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1383
diff
changeset
|
247 if (value.size() == 0) |
7366a0bdda6a
attempt of fix for Syngo.Via
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1383
diff
changeset
|
248 { |
7366a0bdda6a
attempt of fix for Syngo.Via
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1383
diff
changeset
|
249 // An empty string corresponds to a "*" wildcard constraint, so we ignore it |
7366a0bdda6a
attempt of fix for Syngo.Via
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1383
diff
changeset
|
250 continue; |
7366a0bdda6a
attempt of fix for Syngo.Via
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1383
diff
changeset
|
251 } |
611
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
252 |
1851
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
253 if (FilterQueryTag(value, level, tag, modality.GetManufacturer())) |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
254 { |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
255 ValueRepresentation vr = FromDcmtkBridge::GetValueRepresentation(tag); |
1758 | 256 |
1851
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
257 // DICOM specifies that searches must be case sensitive, except |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
258 // for tags with a PN value representation |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
259 bool sensitive = true; |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
260 if (vr == ValueRepresentation_PatientName) |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
261 { |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
262 sensitive = caseSensitivePN; |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
263 } |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
264 |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
265 finder.AddDicomConstraint(tag, value, sensitive); |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
266 } |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
267 else |
1758 | 268 { |
1851
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
269 LOG(INFO) << "Because of a patch for the manufacturer of the remote modality, " |
d364926389e0
OrthancFindRequestHandler::FilterQueryTag
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1800
diff
changeset
|
270 << "ignoring constraint on tag (" << tag.Format() << ") " << FromDcmtkBridge::GetName(tag); |
1759
e268412adcf1
removal of old implementation of search
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1758
diff
changeset
|
271 } |
611
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
272 } |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
273 |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
274 |
608 | 275 /** |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
276 * Run the query. |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
277 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
278 |
1753 | 279 size_t maxResults = (level == ResourceType_Instance) ? maxInstances_ : maxResults_; |
941
83489fddd8c5
Options to limit the number of results for an incoming C-FIND query
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
831
diff
changeset
|
280 |
1753 | 281 std::vector<std::string> resources, instances; |
282 context_.GetIndex().FindCandidates(resources, instances, finder); | |
1752 | 283 |
1753 | 284 assert(resources.size() == instances.size()); |
1800
30e97a1f4093
callback for handling worklists with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1799
diff
changeset
|
285 bool complete = true; |
1753 | 286 |
287 for (size_t i = 0; i < instances.size(); i++) | |
1752 | 288 { |
1753 | 289 Json::Value dicom; |
290 context_.ReadJson(dicom, instances[i]); | |
291 | |
292 if (finder.IsMatch(dicom)) | |
293 { | |
294 if (maxResults != 0 && | |
295 answers.GetSize() >= maxResults) | |
296 { | |
1800
30e97a1f4093
callback for handling worklists with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1799
diff
changeset
|
297 complete = false; |
1753 | 298 break; |
299 } | |
300 else | |
301 { | |
1859
4e7c318a3f69
C-FIND SCP will return tags with sequence value representation
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1856
diff
changeset
|
302 AddAnswer(answers, dicom, query, sequencesToReturn); |
1753 | 303 } |
304 } | |
1752 | 305 } |
306 | |
1753 | 307 LOG(INFO) << "Number of matching resources: " << answers.GetSize(); |
1361
94ffb597d297
refactoring of C-Find SCP
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1354
diff
changeset
|
308 |
1800
30e97a1f4093
callback for handling worklists with plugins
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1799
diff
changeset
|
309 answers.SetComplete(complete); |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
310 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
311 } |