Bug Summary

File:/home/sdobbs/work/clang/halld_recon/src/libraries/DAQ/Df250EmulatorAlgorithm_v2.cc
Warning:line 255, column 10
Division by zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -main-file-name Df250EmulatorAlgorithm_v2.cc -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /w/halld-scifs17exp/home/sdobbs/clang/llvm-project/install/lib/clang/12.0.0 -D HAVE_EVIO -D HAVE_TMVA=1 -I .Linux_CentOS7.7-x86_64-gcc4.8.5/libraries/DAQ -I libraries/DAQ -I . -I libraries -I libraries/include -I /w/halld-scifs17exp/home/sdobbs/clang/halld_recon/Linux_CentOS7.7-x86_64-gcc4.8.5/include -I libraries -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/evio/evio-4.4.6/Linux-x86_64/include -I /w/halld-scifs17exp/halld2/home/sdobbs/Software/jana/jana_0.8.2/Linux_CentOS7.7-x86_64-gcc4.8.5/include -I /group/halld/Software/builds/Linux_CentOS7.7-x86_64-gcc4.8.5/root/root-6.08.06/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward -internal-isystem /usr/local/include -internal-isystem /w/halld-scifs17exp/home/sdobbs/clang/llvm-project/install/lib/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /home/sdobbs/work/clang/halld_recon/src -ferror-limit 19 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-01-21-110224-160369-1 -x c++ libraries/DAQ/Df250EmulatorAlgorithm_v2.cc

libraries/DAQ/Df250EmulatorAlgorithm_v2.cc

1#include <DAQ/Df250EmulatorAlgorithm_v2.h>
2
3// corresponds to version 0x0C0C or 0x0C0D of the fADC250 firmwarer
4
5Df250EmulatorAlgorithm_v2::Df250EmulatorAlgorithm_v2(JEventLoop *loop){
6 // Enables forced use of default values
7 FORCE_DEFAULT = 0;
8 // Default values for the essential parameters
9 NSA_DEF = 20;
10 NSB_DEF = 5;
11 THR_DEF = 120;
12 NPED_DEF = 4;
13 MAXPED_DEF = 512;
14 NSAT_DEF = 2;
15
16 // DEBUG
17 NSA_DEF = 15;
18 NSB_DEF = 1;
19 THR_DEF = 108;
20 NPED_DEF = 4;
21 MAXPED_DEF = 512;
22 NSAT_DEF = 2;
23
24
25 // Set verbosity
26 VERBOSE = 0;
27
28 if(gPARMS){
29 gPARMS->SetDefaultParameter("EMULATION250:FORCE_DEFAULT", FORCE_DEFAULT,"Set to >0 to force use of default values");
30 gPARMS->SetDefaultParameter("EMULATION250:NSA", NSA_DEF,"Set NSA for firmware emulation, will be overwritten by BORConfig if present");
31 gPARMS->SetDefaultParameter("EMULATION250:NSB", NSB_DEF,"Set NSB for firmware emulation, will be overwritten by BORConfig if present");
32 gPARMS->SetDefaultParameter("EMULATION250:THR", THR_DEF,"Set threshold for firmware emulation, will be overwritten by BORConfig if present");
33 gPARMS->SetDefaultParameter("EMULATION250:NPED", NPED_DEF,"Set NPED for firmware emulation, will be overwritten by BORConfig if present");
34 gPARMS->SetDefaultParameter("EMULATION250:MAXPED", MAXPED_DEF,"Set MAXPED for firmware emulation, will be overwritten by BORConfig if present");
35 gPARMS->SetDefaultParameter("EMULATION250:NSAT", NSAT_DEF,"Set NSAT for firmware emulation, will be overwritten by BORConfig if present");
36 gPARMS->SetDefaultParameter("EMULATION250:VERBOSE", VERBOSE,"Set verbosity for f250 emulation");
37 }
38}
39
40void Df250EmulatorAlgorithm_v2::EmulateFirmware(const Df250WindowRawData* rawData,
41 std::vector<Df250PulseData*> &pdat_objs)
42{
43 // This is the main routine called by JEventSource_EVIO::GetObjects() and serves as the entry point for the code.
44 if (VERBOSE > 0) {
1
Assuming field 'VERBOSE' is <= 0
2
Taking false branch
45 jout << " Df250EmulatorAlgorithm_v2::EmulateFirmware ==> Starting emulation <==" << endl;
46 jout << "rocid : " << rawData->rocid << " slot: " << rawData->slot << " channel: " << rawData->channel << endl;
47 }
48
49 // First check that we have window raw data available
50 if (rawData == NULL__null) {
3
Assuming 'rawData' is not equal to NULL
4
Taking false branch
51 jerr << " ERROR: Df250EmulatorAlgorithm_v2::EmulateFirmware - raw sample data is missing" << endl;
52 jerr << " Contact mstaib@jlab.org" << endl;
53 return;
54 }
55
56 // We need the channel number to get the threshold
57 uint32_t channel = rawData->channel;
58
59 // First grab the config objects from the raw data and get the quantities we need from them
60 // The only things we need for this version of the f250 firmware are NSB, NSA, and the threshold.
61 // These are all stored in the BOR config. We can grab this from the raw data since that was already associated in JEventSource_EVIO::GetObjects.
62 const Df250BORConfig *f250BORConfig = NULL__null;
63 rawData->GetSingle(f250BORConfig);
5
Calling 'JObject::GetSingle'
10
Returning from 'JObject::GetSingle'
64
65 uint32_t NSA;
66 int32_t NSB;
67 uint32_t NPED, MAXPED;
68 uint16_t THR;
69 uint16_t NSAT;
70 //If this does not exist, or we force it, use the default values
71 if (f250BORConfig
10.1
'f250BORConfig' is not equal to NULL
10.1
'f250BORConfig' is not equal to NULL
== NULL__null || FORCE_DEFAULT){
11
Assuming field 'FORCE_DEFAULT' is 0
12
Taking false branch
72 static int counter = 0;
73 NSA = NSA_DEF;
74 NSB = NSB_DEF;
75 THR = THR_DEF;
76 NPED = NPED_DEF;
77 MAXPED = MAXPED_DEF;
78 NSAT = NSAT_DEF;
79 if (counter < 10){
80 counter++;
81 if (counter == 10) jout << " WARNING Df250EmulatorAlgorithm_v2::EmulateFirmware No Df250BORConfig == Using default values == LAST WARNING" << endl;
82 else jout << " WARNING Df250EmulatorAlgorithm_v2::EmulateFirmware No Df250BORConfig == Using default values " << endl;
83 //<< rawData->rocid << "/" << rawData->slot << "/" << rawData->channel << endl;
84 }
85 }
86 else{
87 NSA = f250BORConfig->NSA;
88 NSB = f250BORConfig->NSB;
89 THR = f250BORConfig->adc_thres[channel];
90 NPED = f250BORConfig->NPED;
13
Value assigned to 'NPED'
91 MAXPED = f250BORConfig->MaxPed;
92 NSAT = f250BORConfig->NSAT;
93 //if (VERBOSE > 0) jout << "Df250EmulatorAlgorithm_v2::EmulateFirmware NSA: " << NSA << " NSB: " << NSB << " THR: " << THR << endl;
94 }
95
96 if (VERBOSE
13.1
Field 'VERBOSE' is <= 0
13.1
Field 'VERBOSE' is <= 0
> 0) jout << "Df250EmulatorAlgorithm_v2::EmulateFirmware NSA: " << NSA << " NSB: " << NSB << " THR: " << THR << endl;
14
Taking false branch
97
98 // Note that in principle we could get this information from the Df250Config objects as well, but generally only NPED and the value of NSA+NSB are saved
99 // not the individual NSA and NSB values
100
101 /*
102 // TEST
103 if( (rawData->rocid >= 31) || (rawData->rocid <= 46) ) {
104 NSA = NSA_DEF;
105 NSB = NSB_DEF;
106 }
107 */
108
109 // quality bits
110 bool bad_pedestal = false;
111 bool bad_timing_pedestal = false;
112 bool no_timing_calculation = false;
113
114 // Now we can start to loop over the raw data
115 // This requires a few passes due to some features in the way the quantities are calculated...
116 // The first step is to scan the samples for TC (threshold crossing sample) and compute the
117 // integrals of all pulses found.
118
119 vector<uint16_t> samples = rawData->samples;
120 uint16_t NW = samples.size();
121 uint32_t npulses = 0;
122 const int max_pulses = 3;
123 uint32_t TC[max_pulses] = {};
124 uint32_t TMIN[max_pulses] = {3};
125 //uint32_t TNSAT[max_pulses] = {};
126 uint32_t pulse_integral[max_pulses] = {};
127 bool has_overflow_samples[max_pulses] = {false};
128 bool has_underflow_samples[max_pulses] = {false};
129 uint32_t number_samples_above_threshold[max_pulses] = {0};
130 bool NSA_beyond_PTW[max_pulses] = {false};
131 bool vpeak_beyond_NSA[max_pulses] = {false};
132 bool vpeak_not_found[max_pulses] = {false};
133
134 // some verbose debugging output
135 if(VERBOSE
14.1
Field 'VERBOSE' is <= 0
14.1
Field 'VERBOSE' is <= 0
> 0) {
15
Taking false branch
136 for (unsigned int i=0; i < NW; i++) {
137 if(VERBOSE > 2) {
138 if(samples[i] == 0x1fff)
139 jout << "Overflow at sample " << i << endl;
140 if(samples[i] == 0x1000)
141 jout << "Underflow at sample " << i << endl;
142 }
143 if (VERBOSE > 5) jout << "Df250EmulatorAlgorithm_v2::EmulateFirmware samples[" << i << "]: " << samples[i] << endl;
144 }
145 }
146
147
148 // look for the threhold crossings and compute the integrals
149 //unsigned int MAX_SAMPLE = (NSB>0) ? (NW-NSAT) : (NW-NSAT+NSB-1)); // check this
150 unsigned int MAX_SAMPLE = NW-NSAT;
151 for (unsigned int i=0; i < MAX_SAMPLE; i++) {
16
Assuming 'i' is >= 'MAX_SAMPLE'
17
Loop condition is false. Execution continues on line 231
152 if ((samples[i] & 0xfff) > THR) {
153 if (VERBOSE > 1) {
154 jout << "threshold crossing at " << i << endl;
155 }
156
157 // save threshold crossing - could be overwritten
158 TC[npulses] = i+1;
159
160 // check that we have more than NSAT samples over threshold
161 if( NSAT>1 ){
162 int samples_over_threshold = 1;
163
164 if(i==0) {
165 // the algorithm only terminates if we dip below threshold...
166 for(unsigned int j=i+1; ((samples[j]&0xfff)>=THR) && (j<MAX_SAMPLE+1); j++) {
167 // only count samples actually above threshold
168 if ((samples[j] & 0xfff) > THR)
169 samples_over_threshold++;
170
171 if( samples_over_threshold == NSAT ) {
172 //TC[npulses] = j+1;
173 //i=j;
174 break;
175 }
176
177 }
178 } else {
179 for(unsigned int j=i+1; ((samples[j]&0xfff)>THR) && (j<MAX_SAMPLE+1); j++) {
180 samples_over_threshold++;
181
182 if( samples_over_threshold == NSAT )
183 break;
184 }
185 }
186
187 // if we couldn't find NSAT samples above threshold, move on...
188 if( samples_over_threshold != NSAT )
189 continue;
190 }
191 //else {
192 //TNSAT[npulses] = TC[npulses];
193 //}
194
195
196 // calculate integral
197 unsigned int ibegin;
198 if(NSB > 0)
199 ibegin = i > uint32_t(NSB) ? (i - NSB) : 0; // Set to beginning of window if too early
200 else {
201 ibegin = i - NSB;
202 if(ibegin > uint32_t(NW)) // make sure we don't start looking outside the window
203 break;
204 }
205 unsigned int iend = (i + NSA) < uint32_t(NW) ? (i + NSA) : NW; // Set to last sample if too late
206 // check to see if NSA extends beyond the end of the window
207 NSA_beyond_PTW[npulses] = (i + NSA - 1) >= uint32_t(NW);
208 for (i = ibegin; i < iend; ++i) {
209 pulse_integral[npulses] += (samples[i] & 0xfff);
210 // quality monitoring
211 if(samples[i] == 0x1fff) {
212 has_overflow_samples[npulses] = true;
213 }
214 if(samples[i] == 0x1000) {
215 has_underflow_samples[npulses] = true;
216 }
217 // count number of samples within NSA that are above thresholds
218 if( (i+1>=TC[npulses]) && ((samples[i] & 0xfff) > THR) )
219 number_samples_above_threshold[npulses]++;
220 }
221 for (; i < NW && (samples[i] & 0xfff) >= THR; ++i) {}
222 if (++npulses == max_pulses)
223 break;
224 TMIN[npulses] = i;
225 }
226 }
227
228 // That concludes the first pass over the data.
229 // Now we can head into the fine timing pass over the data.
230
231 uint32_t VPEAK[max_pulses] = {};
232 uint32_t TPEAK[max_pulses] = {};
233 uint16_t TMID[max_pulses] = {};
234 uint16_t VMID[max_pulses] = {};
235 uint16_t TFINE[max_pulses] = {};
236 uint32_t pulse_time[max_pulses] = {};
237
238 // The pulse pedestal is the sum of NPED (4-15) samples at the beginning of the window
239 uint32_t pedestal = 0;
240 uint32_t VMIN = 0; // VMIN is just the average of the first 4 samples, needed for timing algorithm
241 for (unsigned int i=0; i < NPED; i++) {
18
Assuming 'i' is >= 'NPED'
19
Loop condition is false. Execution continues on line 255
242 pedestal += (samples[i] & 0xfff);
243 if(i<4)
244 VMIN += (samples[i] & 0xfff);
245 // error conditions
246 // sample larger than MaxPed
247 if ((samples[i] & 0xfff) > MAXPED) {
248 bad_pedestal = true;
249 }
250 // samples with underflow/overflow
251 if( (samples[i] == 0x1fff) || (samples[i] == 0x1000) ) {
252 bad_pedestal = true;
253 }
254 }
255 VMIN /= NPED; // compute average
20
Division by zero
256
257 // error conditions for timing algorithm
258 //bool pedestal_underflow = false;
259 //for (unsigned int i=0; i < 5; i++) {
260 for (unsigned int i=0; i < 4; i++) {
261 // We set the "Time Quality bit 0" to 1 if any of the first 5 samples is greated than MaxPed or TET...
262 if ( ((samples[i] & 0xfff) > MAXPED) || ((samples[i] & 0xfff) > THR) ) {
263 bad_timing_pedestal = true;
264 }
265 // ... or is overflow or underflow
266 if ( (samples[i] == 0x1000) || (samples[i] == 0x1fff) ) {
267 bad_timing_pedestal = true;
268 }
269 //}
270
271 // TEST
272 //for (unsigned int i=0; i < 4; i++) {
273
274 // "If any of the first 5 samples is greater than TET the TDC will NOT proceed..."
275 // Waiit for iiit...
276 if( (samples[i] & 0xfff) > THR ) {
277 no_timing_calculation = true;
278 }
279 }
280
281
282 for (unsigned int p=0; p < npulses; ++p) {
283 // TEST
284 //TC[p] = TNSAT[p];
285
286 // "If any of the first 5 samples is greater than TET or underflow the TDC will NOT proceed
287 // 1. pulse time is set to TC
288 // 2. pulse peak is set to zero
289 // 3. Time quality bits 0 and 1 are set to 1"
290 if(no_timing_calculation) {
291 TMID[p] = TC[p];
292 TFINE[p] = 0;
293 VPEAK[p] = 0;
294 vpeak_not_found[p] = true; // this is "time quality bit 1"
295 // "Time Quality bit 0" should already be set
296 } // should just put an else here...
297
298 // we set up a loop so that we can break out of it at appropriate times...
299 // note that currently the timing algorithm is run when the pedestal has underflow samples,
300 // but according to the documentation, it shouldn't...
301 //while ( (!no_timing_calculation || pedestal_underflow) && true) {
302 while ( (!no_timing_calculation) && true) {
303 //if (VMIN == 99999) {
304 // VPEAK[p] = 0;
305 // reportTC[p] = true;
306 // pulse_time[p] = (TC[p] << 6);
307 // break;
308 // }
309
310 // search for the peak of the pulse
311 // has to be after the threshold crossing (NO?)
312 // has to be before the last sample
313 unsigned int ipeak;
314 for (ipeak = TC[p]; (int)ipeak < NW-1; ++ipeak) {
315 //for (ipeak = TC[p]+1; ipeak < NW-1; ++ipeak) {
316 if ((samples[ipeak] & 0xfff) < (samples[ipeak-1] & 0xfff)) {
317 VPEAK[p] = (samples[ipeak-1] & 0xfff);
318 TPEAK[p] = ipeak-1;
319 break;
320 }
321 }
322
323 // check to see if the peak is beyond the NSA
324 if(ipeak > TC[p]+NSA)
325 vpeak_beyond_NSA[p] = true;
326
327 if (VERBOSE > 1) {
328 jout << " pulse " << p << ": VMIN: " << VMIN
329 << " TC: " << TC[p] << " VPEAK: " << VPEAK[p] << endl;
330 }
331
332 // set error conditions in case we didn't find the peak
333 if (VPEAK[p] == 0) {
334 TMID[p] = TC[p];
335 TFINE[p] = 0;
336 VPEAK[p] = 0;
337 vpeak_beyond_NSA[p] = true;
338 vpeak_not_found[p] = true;
339 break;
340 }
341
342 // VMID is the half amplitude
343 VMID[p] = (VMIN + VPEAK[p]) >> 1;
344
345 /*
346 for (unsigned int i = TMIN[p] + 1; i < (uint32_t)ipeak; ++i) { // old
347 if ((samples[i] & 0xfff) > VMID[p]) {
348 TMID[p] = i;
349 break;
350 }
351 }
352 */
353
354 // look down the leading edge for the sample that satisfies V(N1) <= VMID < V(N+1)
355 // N1 is then the coarse time
356 // note that when analyzing pulses after the first, we could end up with a time for the
357 // second pulse that is before the first one! this is a little crazy, but is how
358 // the algorithm is currently implemented
359 for (unsigned int i = TPEAK[p]; i >= 1; --i) {
360 if ( ((samples[i-1] & 0xfff) <= VMID[p]) && ((samples[i] & 0xfff) > VMID[p]) ) { // V(N1) <= VMID < V(N+1)
361 // if ( ((samples[i-1] & 0xfff) <= VMID[p]) // V(N1) <= VMID < V(N+1)
362 // || ( (samples[i-1] & 0xfff) > (samples[i] & 0xfff) ) ) { // we aren't on the leading edge anymore
363 TMID[p] = i;
364 break;
365 }
366 }
367
368 if (TMID[p] == 0) { // handle the case where we couldn't find a coarse time - redundant?
369 TFINE[p] = 0;
370 }
371 else {
372 // fine timing algorithm (see documentation)
373 int Vnext = (samples[TMID[p]] & 0xfff);
374 int Vlast = (samples[TMID[p]-1] & 0xfff);
375 if (VERBOSE > 2) {
376 jout << " TMIN = " << TMIN[p] << " TMID = " << TMID[p] << " TPEAK = " << TPEAK[p] << endl
377 << " VMID = " << VMID[p] << " Vnext = " << Vnext << " Vlast = " << Vlast << endl;
378 }
379 if (Vnext > Vlast && VMID[p] >= Vlast)
380 TFINE[p] = 64 * (VMID[p] - Vlast) / (Vnext - Vlast);
381 else
382 TFINE[p] = 62;
383 if(TFINE[p] == 64)
384 TFINE[p] = 0;
385 }
386 pulse_time[p] = ((TMID[p]-1) << 6) + TFINE[p];
387 break;
388 }
389 VMIN = (VMIN < 99999)? VMIN : 0; // deprecated?
390
391 if (VERBOSE > 1) {
392 jout << " pulse " << p << ": VMID: " << VMID[p] << " TMID: " << TMID[p]
393 << " TFINE: " << TFINE[p] << " time: " << pulse_time[p]
394 << " integral: " << pulse_integral[p] << endl;
395 if (VERBOSE > 2) {
396 jout << " TMIN = " << TMIN[p] << " TMID = " << TMID[p] << " TPEAK = " << TPEAK[p] << endl;
397 //<< " VMID = " << VMID[p] << " Vnext = " << Vnext << " Vlast = " << Vlast << endl;
398 }
399 }
400
401 // algorithm is finished, fill the information
402 Df250PulseData* f250PulseData;
403 if( p < pdat_objs.size() ) {
404 f250PulseData = pdat_objs[p];
405
406 if(f250PulseData == NULL__null) {
407 jerr << " NULL f250PulseData object!" << endl;
408 continue;
409 }
410 } else {
411 // make a fresh object if one does not exist
412 f250PulseData = new Df250PulseData;
413
414 f250PulseData->rocid = rawData->rocid;
415 f250PulseData->slot = rawData->slot;
416 f250PulseData->channel = rawData->channel;
417 f250PulseData->itrigger = rawData->itrigger;
418 // word 1
419 f250PulseData->event_within_block = 1;
420 f250PulseData->QF_pedestal = bad_pedestal;
421 f250PulseData->pedestal = pedestal;
422 // word 2
423 f250PulseData->integral = pulse_integral[p];
424 f250PulseData->QF_NSA_beyond_PTW = NSA_beyond_PTW[p];
425 f250PulseData->QF_overflow = has_overflow_samples[p];
426 f250PulseData->QF_underflow = has_underflow_samples[p];
427 f250PulseData->nsamples_over_threshold = number_samples_above_threshold[p];
428 // word 3
429 f250PulseData->course_time = TMID[p];
430 f250PulseData->fine_time = TFINE[p];
431 f250PulseData->QF_vpeak_beyond_NSA = vpeak_beyond_NSA[p];
432 f250PulseData->QF_vpeak_not_found = vpeak_not_found[p];
433 f250PulseData->QF_bad_pedestal = bad_timing_pedestal;
434 // other information
435 f250PulseData->pulse_number = p;
436 f250PulseData->nsamples_integral = NSA + NSB;
437 f250PulseData->nsamples_pedestal = NPED;
438 f250PulseData->emulated = true;
439
440 f250PulseData->AddAssociatedObject(rawData);
441 const_cast<Df250WindowRawData*>(rawData)->AddAssociatedObject(f250PulseData);
442 pdat_objs.push_back(f250PulseData);
443 }
444
445 // copy over emulated values
446 f250PulseData->integral_emulated = pulse_integral[p];
447 f250PulseData->pedestal_emulated = pedestal;
448 f250PulseData->pulse_peak_emulated = VPEAK[p];
449 f250PulseData->course_time_emulated = TMID[p];
450 f250PulseData->fine_time_emulated = TFINE[p];
451
452 // check the emulated quality factors as well
453 uint32_t QF = 0; // make single quality factor number for compactness
454 if( bad_pedestal ) QF |= (1<<0);
455 if( NSA_beyond_PTW[p] ) QF |= (1<<1);
456 if( has_overflow_samples[p] ) QF |= (1<<2);
457 if( has_underflow_samples[p] ) QF |= (1<<3);
458 if( vpeak_beyond_NSA[p] ) QF |= (1<<4);
459 if( vpeak_not_found[p] ) QF |= (1<<5);
460 if( bad_timing_pedestal ) QF |= (1<<6);
461 f250PulseData->QF_emulated = QF;
462
463 if(VERBOSE > 3) {
464 cout << boolalpha;
465 cout << "bad_pedestal = " << bad_pedestal << endl;
466 cout << "NSA_beyond_PTW = " << NSA_beyond_PTW[p] << endl;
467 cout << "has_overflow_samples = " << has_overflow_samples[p] << endl;
468 cout << "has_underflow_samples = " << has_underflow_samples[p] << endl;
469 cout << "vpeak_beyond_NSA = " << vpeak_beyond_NSA[p] << endl;
470 cout << "vpeak_not_found = " << vpeak_not_found[p] << endl;
471 cout << "bad_timing_pedestal = " << bad_timing_pedestal << endl;
472 cout << "total QF = " << QF << endl;
473 }
474
475 // if we are using the emulated values, copy them
476 if( f250PulseData->emulated ) {
477 f250PulseData->integral = f250PulseData->integral_emulated;
478 f250PulseData->pedestal = f250PulseData->pedestal_emulated;
479 f250PulseData->pulse_peak = f250PulseData->pulse_peak_emulated;
480 f250PulseData->course_time = f250PulseData->course_time_emulated;
481 f250PulseData->fine_time = f250PulseData->fine_time_emulated;
482
483 /*
484 if( (rawData->rocid >= 31) || (rawData->rocid <= 46) ) {
485 f250PulseData->nsamples_integral = NSA + NSB;
486 }
487 */
488
489 }
490
491 }
492
493 if (VERBOSE > 0) jout << " Df250EmulatorAlgorithm_v2::EmulateFirmware ==> Emulation complete <==" << endl;
494 return;
495}

/w/halld-scifs17exp/halld2/home/sdobbs/Software/jana/jana_0.8.2/Linux_CentOS7.7-x86_64-gcc4.8.5/include/JANA/JObject.h

1// $Id: JObject.h 1709 2006-04-26 20:34:03Z davidl $
2//
3// File: JObject.h
4// Created: Wed Aug 17 10:57:09 EDT 2005
5// Creator: davidl (on Darwin wire129.jlab.org 7.8.0 powerpc)
6//
7
8#ifndef _JObject_
9#define _JObject_
10
11#include <cstdio>
12#include <sstream>
13#include <cassert>
14#include <map>
15#include <vector>
16#include <set>
17#include <string>
18#include <cstdint>
19#include <type_traits>
20#include <typeinfo>
21#include <stdint.h>
22using std::pair;
23using std::map;
24using std::set;
25using std::vector;
26using std::string;
27using std::stringstream;
28
29// The following is here just so we can use ROOT's THtml class to generate documentation.
30#include "cint.h"
31
32
33/// The JObject class is a base class for all data classes.
34/// (See JFactory and JFactory_base for algorithm classes.)
35///
36///
37/// The following line should be included in the public definition of all
38/// classes which inherit from JObject with the argument being the name of the
39/// class without any quotes.
40/// e.g. for a class named "MyClass" :
41///
42/// public:
43/// JOBJECT_PUBLIC(MyClass);
44///
45/// This will define a virtual method <i>className()</i> and a static
46/// method <i>static_className()</i> that are used by JANA to identify
47/// the object's last generation in the inheritance chain by name. This
48/// also allows for possible upgrades to JANA in the future without
49/// requiring classes that inherit from JObject to be redefined explicity.
50#define JOBJECT_PUBLIC(T)virtual const char* className(void) const {return static_className
();} static const char* static_className(void) {return "T";} virtual
JObject* Clone() const {return CloneObject<T>( *this )
;}
\
51 virtual const char* className(void) const {return static_className();} \
52 static const char* static_className(void) {return #T;} \
53 virtual JObject* Clone() const {return CloneObject<T>( *this );}
54
55
56
57// Place everything in JANA namespace
58namespace jana{
59
60class JFactory_base;
61class JEventLoop;
62
63class JObject{
64
65 public:
66 JOBJECT_PUBLIC(JObject)virtual const char* className(void) const {return static_className
();} static const char* static_className(void) {return "JObject"
;} virtual JObject* Clone() const {return CloneObject<JObject
>( *this );}
;
67
68 typedef unsigned long long oid_t;
69
70 JObject() : id((oid_t)this),append_types(false),factory(NULL__null) {}
71 JObject( oid_t aId ) : id( aId ),append_types(false),factory(NULL__null) {}
72
73 virtual ~JObject(){
74 for(unsigned int i=0; i<auto_delete.size(); i++)delete auto_delete[i];
75 }
76
77 // Copy constructor
78 JObject(const JObject& o) :
79 id( (oid_t)this ), append_types(o.append_types), associated(
80 o.associated), auto_delete(), messagelog(
81 o.messagelog), factory(o.factory) {
82 // Deep copy the objects in auto_delete vector
83 for( auto obj : o.auto_delete ) {
84 auto_delete.push_back( obj->Clone() );
85 }
86 }
87
88 // Move constructor
89 JObject( const JObject&& o ) : id( (oid_t)this ), append_types(o.append_types), associated(
90 std::move(o.associated)), auto_delete(std::move(o.auto_delete)), messagelog( std::move(
91 o.messagelog)), factory(o.factory) {
92 factory = nullptr;
93 }
94
95 // Assignment operator
96 JObject& operator=( const JObject& o) {
97 if( this == &o ) return *this;
98 append_types = o.append_types;
99 associated = o.associated;
100 messagelog = o.messagelog;
101 factory = o.factory;
102 auto_delete.clear();
103 for( auto obj : o.auto_delete ) {
104 auto_delete.push_back( obj->Clone() );
105 }
106 return *this;
107 }
108
109 // Define template static method for cloning the object of this type. This would get called from a
110 // virtual method define for each subclass to polymorphically clone the objects.
111 template<typename TYPE>
112 static typename std::enable_if<
113 (std::is_abstract <TYPE>::value || !std::is_copy_constructible<TYPE>::value), JObject*>::type CloneObject(
114 const TYPE& obj) {
115 // For abstract method it will return null pointer, and probably will cause problems. But
116 // there sohuld not be any object of abstract class to start with.
117 return nullptr;
118 }
119 template<typename TYPE>
120 static typename std::enable_if<
121 (!std::is_abstract <TYPE>::value
122 && std::is_copy_constructible <TYPE>::value ), JObject*>::type CloneObject(
123 const TYPE& obj) {
124 // For non-abstract class create a new object using the copy constructor of the class
125 // given in the template argument.
126 return new TYPE(obj);
127 }
128
129 /// Test if this object is of type T by checking its className() against T::static_className()
130 template<typename T> bool IsA(const T *t) const {return dynamic_cast<const T*>(this)!=0L;}
131
132 /// Test if this object is of type T (or a descendant) by attempting a dynamic cast
133 template<typename T> bool IsAT(const T *t) const {return dynamic_cast<const T*>(this)!=0L;}
134
135 // Methods for handling associated objects
136 inline void AddAssociatedObject(const JObject *obj);
137 inline void AddAssociatedObjectAutoDelete(JObject *obj, bool auto_delete=true);
138 inline void RemoveAssociatedObject(const JObject *obj);
139 inline void ClearAssociatedObjects(void);
140 inline bool IsAssociated(const JObject* locObject) const {return (associated.find(locObject) != associated.end());}
141 template<typename T> void Get(vector<const T*> &ptrs, string classname="", int max_depth=1000000) const ;
142 template<typename T> void GetT(vector<const T*> &ptrs) const ;
143 template<typename T> void GetSingle(const T* &ptrs, string classname="") const ;
144 template<typename T> void GetSingleT(const T* &ptrs) const ;
145 template<typename T> void GetAssociatedAncestors(set<const JObject*> &already_checked, int &max_depth, set<const T*> &objs_found, string classname="") const;
146 template<typename T> void GetAssociatedDescendants(JEventLoop *loop, vector<const T*> &associatedTo, int max_depth=1000000);
147 void GetAssociatedDescendants(JEventLoop *loop, vector<const JObject*> &associatedTo, int max_depth=1000000);
148
149 template<typename T,typename S> void CopyToVector(T itbegin, T itend, vector<const S*> &v) const;
150
151 // Methods for handling pretty formatting for dumping to the screen or file
152 virtual void toStrings(vector<pair<string,string> > &items)const;
153 template<typename T> void AddString(vector<pair<string,string> > &items, const char *name, const char *format, const T &val) const;
154
155 // Methods for attaching and retrieving log messages to/from object
156 void AddLog(string &message) const {messagelog.push_back(message);}
157 void AddLog(vector<string> &messages) const {messagelog.insert(messagelog.end(), messages.begin(), messages.end());}
158 void GetLog(vector<string> &messagelog) const {messagelog = this->messagelog;}
159
160 // Misc methods
161 bool GetAppendTypes(void) const {return append_types;} ///< Get state of append_types flag (for AddString)
162 void SetAppendTypes(bool append_types){this->append_types=append_types;} ///< Set state of append_types flag (for AddString)
163 void SetFactoryPointer(JFactory_base *factory){this->factory=factory;}
164 JFactory_base * GetFactoryPointer(void) const {return factory;}
165 string GetName(void) const {return string(className());}
166 string GetTag(void) const ;
167 string GetNameTag(void) const {return GetName() + (GetTag()=="" ? "":":") + GetTag();}
168
169 oid_t id;
170
171 private:
172
173 bool append_types;
174 set<const JObject*> associated;
175 // map<const JObject*, string> associated; replaced with set in jana 0.7.7
176 vector<JObject*> auto_delete;
177 mutable vector<string> messagelog;
178 JFactory_base *factory;
179
180};
181
182#if !defined(__CINT__) && !defined(__CLING__)
183
184
185//--------------------------
186// AddAssociatedObject
187//--------------------------
188void JObject::AddAssociatedObject(const JObject *obj)
189{
190 /// Add a JObject to the list of associated objects
191
192 assert(obj!=NULL)((obj!=__null) ? static_cast<void> (0) : __assert_fail (
"obj!=__null", "/w/halld-scifs17exp/halld2/home/sdobbs/Software/jana/jana_0.8.2/Linux_CentOS7.7-x86_64-gcc4.8.5/include/JANA/JObject.h"
, 192, __PRETTY_FUNCTION__))
;
193
194 associated.insert(obj);
195 //associated[obj] = obj->className();
196}
197
198//--------------------------
199// AddAssociatedObjectAutoDelete
200//--------------------------
201void JObject::AddAssociatedObjectAutoDelete(JObject *obj, bool auto_delete)
202{
203 /// Add a JObject to the list of associated objects. If the auto_delete
204 /// flag is true, then automatically delete it when this object is
205 /// deleted. Otherwise, this behaves identically to the AddAssociatedObject
206 /// method.
207 ///
208 /// Note that if the object is removed via RemoveAssociatedObject(...)
209 /// then the object is NOT deleted. BUT, if the entire list of associated
210 /// objects is cleared via ClearAssociatedObjects, then the object will
211 /// be deleted.
212
213 AddAssociatedObject(obj);
214
215 if(auto_delete)this->auto_delete.push_back(obj);
216}
217
218//--------------------------
219// RemoveAssociatedObject
220//--------------------------
221void JObject::RemoveAssociatedObject(const JObject *obj)
222{
223 /// Remove the specified JObject from the list of associated
224 /// objects. This will NOT delete the object even if the
225 /// object was added with the AddAssociatedObjectAutoDelete(...)
226 /// method with the auto_delete flag set.
227
228 // map<const JObject*, string>::iterator iter = associated.find(obj);
229 auto iter = associated.find(obj);
230
231 if(iter!=associated.end()){
232 associated.erase(iter);
233 }
234}
235
236//--------------------------
237// ClearAssociatedObjects
238//--------------------------
239void JObject::ClearAssociatedObjects(void)
240{
241 /// Remove all associated objects from the associated objects list.
242 /// This will also delete any objects that were added via the
243 /// AddAssociatedObjectAutoDelete(...) method with the auto_delete
244 /// flag set.
245
246 // Clear pointers to associated objects
247 associated.clear();
248
249 // Delete objects in the auto_delete list
250 for(unsigned int i=0; i<auto_delete.size(); i++)delete auto_delete[i];
251 auto_delete.clear();
252}
253
254//--------------------------
255// CopyToVector
256//
257// This litte utility method is here because the g++ 4.4.7
258// compiler was complaining about the declaration of
259// set<const T*>::iterator it; in the Get method. Very strange
260// but this at least avoids ever having to declare the variable.
261//--------------------------
262template<typename T,typename S>
263void JObject::CopyToVector(T itbegin, T itend, vector<const S*> &v) const
264{
265 for(T it=itbegin; it!=itend; it++) v.push_back(*it);
266}
267
268//--------------------------
269// Get
270//--------------------------
271template<typename T>
272void JObject::Get(vector<const T*> &ptrs, string classname, int max_depth) const
273{
274 /// Fill the given vector with pointers to the associated objects of the
275 /// type on which the vector is based. The objects are chosen by matching
276 /// their class names (obtained via JObject::className()) either to the
277 /// one provided in classname or to T::static_className() if classname is
278 /// an empty string. Associations will be searched to a level of max_depth
279 /// to find all objects of the requested type. By default, max_depth is
280 /// set to a very large number so that all associations are found. To
281 /// limit the search to only objects directly associated with this one,
282 /// set max_depth to either "0" or "1".
283 ///
284 /// The contents of ptrs are cleared upon entry.
285
286 if(classname=="")classname=T::static_className();
287
288 // Use the GetAssociatedAncestors method which may call itself
289 // recursively to search all levels of association (at or
290 // below this object. Objects for which this is an associated
291 // object are not checked for).
292 set<const JObject*> already_checked;
293 set<const T*> objs_found;
294 int my_max_depth = max_depth;
295 GetAssociatedAncestors(already_checked, my_max_depth, objs_found, classname);
296
297 // Copy results into caller's container
298 ptrs.clear();
299 CopyToVector(objs_found.begin(), objs_found.end(), ptrs);
300// set<const T*>::iterator it;
301// for(it=objs_found.begin(); it!=objs_found.end(); it++){
302// ptrs.push_back(*it);
303// }
304}
305
306//--------------------------
307// GetAssociatedAncestors
308//--------------------------
309template<typename T>
310void JObject::GetAssociatedAncestors(set<const JObject*> &already_checked, int &max_depth, set<const T*> &objs_found, string classname) const
311{
312 /// Get associated objects of the specified type (either "T" or classname).
313 /// Check also for associated objects of any associated objects
314 /// to a level of max_depth associations. This method calls itself
315 /// recursively so care is taken to only check the associated objects
316 /// of each object encountered only once.
317 ///
318 /// The "already_checked" parameter should be passed in as an empty container
319 /// that is used to keep track of which objects had their direct associations
320 /// checked. "max_depth" indicates the maximum level of associations to check
321 /// (n.b. both "0" and "1" means only check direct associations.) This must
322 /// be passed as a reference to an existing int since it is modified in order
323 /// to keep track of the current depth in the recursive calls. Set max_depth
324 /// to a very high number (like 1000000) to check all associations. The
325 /// "objs_found" container will contain the actual associated objects found.
326 /// The objects are chosen by matching their class names (obtained via
327 /// JObject::className()) either to the one provided in "classname" or to
328 /// T::static_className() if classname is an empty string.
329
330 if(already_checked.find(this) == already_checked.end()) already_checked.insert(this);
331
332 if(classname=="")classname=T::static_className();
333 max_depth--;
334
335 //map<const JObject*, string>::const_iterator iter = associated.begin();
336 for( auto obj : associated ){
337
338 // Add to list if appropriate
339 if( classname == obj->className() ){
340 objs_found.insert( dynamic_cast<const T*>(obj) );
341 }
342
343 // Check this object's associated objects if appropriate
344 if(max_depth<=0) continue;
345 if(already_checked.find(obj) != already_checked.end()) continue;
346 already_checked.insert(obj);
347 obj->GetAssociatedAncestors(already_checked, max_depth, objs_found, classname);
348 }
349
350 max_depth++;
351}
352
353//--------------------------
354// GetAssociatedDescendants
355//--------------------------
356template<typename T>
357void GetAssociatedDescendants(JEventLoop *loop, vector<const T*> &associatedTo, int max_depth=1000000)
358{
359 /// Find objects of type "T" for which this object appears in its
360 /// associated ancestors list. (This is kind of the opposite of
361 /// the "Get()" method.)
362 ///
363 /// WARNING: this must build and search the ancestor list of EVERY
364 /// object produced by EVERY factory. It is an expensive method
365 /// to call. Use it with great caution!
366 ///
367 /// WARNING: this only searches objects that have already been
368 /// created. It will not activate factories they may eventually
369 /// claim this as an associated object so the list returned may
370 /// be incomplete.
371 ///
372 /// WARNING: this templated method works by first calling the
373 /// JObject form and then dynamically casting each of those to see
374 /// if they of type "T". This makes this an even more expensive
375 /// call. Again, use with great caution!!
376
377 vector<const JObject*> ajobjs;
378 GetAssociatedDescendants(loop, ajobjs, max_depth);
379 for(uint32_t i=0; i<ajobjs.size(); i++){
380 const T *ptr = dynamic_cast<const T*>(ajobjs[i]);
381 if(ptr != NULL__null) associatedTo.push_back(ptr);
382 }
383}
384
385//--------------------------
386// GetT
387//--------------------------
388template<typename T>
389void JObject::GetT(vector<const T*> &ptrs) const
390{
391 /// Fill the given vector with pointers to the associated
392 /// JObjects of the type on which the vector is based. This is
393 /// similar to the Get() method except objects are selected
394 /// by attempting a dynamic_cast to type const T*. This allows
395 /// one to select a list of all objects who have a type T
396 /// somewhere in their inheritance chain.
397 ///
398 /// A potential issue with this method is that the dynamic_cast
399 /// does not always work correctly for objects created via a
400 /// plugin when the cast occurs outside of the plugin or
401 /// vice versa.
402 ///
403 /// The contents of ptrs are cleared upon entry.
404
405 ptrs.clear();
406
407 //map<const JObject*, string>::const_iterator iter = associated.begin();
408 //for(; iter!=associated.end(); iter++){
409 for( auto obj : associated ){
410 const T *ptr = dynamic_cast<const T*>(obj);
411 if(ptr != NULL__null)ptrs.push_back(ptr);
412 }
413}
414
415//-------------
416// GetSingle
417//-------------
418template<class T>
419void JObject::GetSingle(const T* &t, string classname) const
420{
421 /// This is a convenience method that can be used to get a pointer to the single
422 /// associate object of type T.
423 ///
424 /// The objects are chosen by matching their class names
425 /// (obtained via JObject::className()) either
426 /// to the one provided in classname or to T::static_className()
427 /// if classname is an empty string.
428 ///
429 /// If no object of the specified type is found, a NULL pointer is
430 /// returned.
431
432 t = NULL__null;
433
434 if(classname=="")classname=T::static_className();
6
Taking false branch
435
436 //map<const JObject*, string>::const_iterator iter = associated.begin();
437 //for(; iter!=associated.end(); iter++){
438 for( auto obj : associated ){
439 if( classname == obj->className() ){
7
Value assigned to field 'NPED'
8
Taking true branch
440 t = dynamic_cast<const T*>(obj);
441 if(t
8.1
't' is not equal to NULL
8.1
't' is not equal to NULL
!=NULL__null)return;
9
Taking true branch
442 }
443 }
444}
445
446//-------------
447// GetSingleT
448//-------------
449template<class T>
450void JObject::GetSingleT(const T* &t) const
451{
452 /// This is a convenience method that can be used to get a pointer to the single
453 /// associate object of type T.
454 ///
455 /// This is similar to the GetSingle() method except objects are selected
456 /// by attempting a dynamic_cast to type const T*. This allows
457 /// one to select a list of all objects who have a type T
458 /// somewhere in their inheritance chain.
459 /// The objects are chosen by matching their class names
460 /// (obtained via JObject::className()) either
461 /// to the one provided in classname or to T::static_className()
462 /// if classname is an empty string.
463 ///
464 /// If no object of the specified type is found, a NULL pointer is
465 /// returned.
466
467 t = NULL__null;
468
469 //map<const JObject*, string>::const_iterator iter = associated.begin();
470 //for(; iter!=associated.end(); iter++){
471 for( auto obj : associated ){
472 t = dynamic_cast<const T*>(obj);
473 if(t!=NULL__null)return;
474 }
475}
476
477//--------------------------
478// toStrings
479//--------------------------
480inline void JObject::toStrings(vector<pair<string,string> > &items) const
481{
482 /// Fill the given "items" vector with items representing the (important)
483 /// data members of this object. The structure of "items" is a vector
484 /// of pairs. The "first" element of the pair is the name of the item
485 /// as it should be displayed when dumping the item to the screen. For
486 /// example, one may wish to include units using a string like "r (cm)".
487 /// The "second" element of the pair is a formatted string containing the
488 /// value as it should be displayed.
489 ///
490 /// To facilitate this, the AddString() method exists which allows
491 /// items to be added with the desired formatting using a single line.
492 ///
493 /// This is a virtual method that is expected (but not required)
494 /// to be implemented by all classes that inherit from JObject.
495
496 AddString(items, "JObject", "0x%08x", (unsigned long)this);
497}
498
499//--------------------------
500// AddString
501//--------------------------
502template<typename T>
503void JObject::AddString(vector<pair<string,string> > &items, const char *name, const char *format, const T &val) const
504{
505 /// Write the given value (val) to a string using the sprintf style formatting
506 /// string (format) and add it to the given vector (items) with the column
507 /// name "name". This is intended for use in the toStrings() method of
508 /// classes that inherit from JObject.
509 ///
510 /// The append_type flag provides a facility for recording the data type
511 /// and value with default formatting into items. This can be used
512 /// by a generic convertor (not part of JANA) to auto-generate a
513 /// representation of this object for use in some other persistence
514 /// package (e.g. ROOT files).
515 ///
516 /// If the append_types flag is set then the data type of "val" is
517 /// automatically appended with a colon (:) separator to the
518 /// name (first) part of the pair. In addition, "val" is converted
519 /// using stringstream and appended as well, also with a colon (:)
520 /// separator. For example, if the value of name passed in is "px"
521 /// and T is of type double, then the first member of the pair
522 /// appended to items will be something like "px:double:1.23784"
523 /// which can be decifered later to get the name, type, and value
524 /// of the data member.
525 ///
526 /// By default, the append_types flag is not set and the name part
527 /// of the pair is a straight copy of the name argument that is
528 /// passed in.
529
530 char str[256];
531 sprintf(str, format, val);
532
533 stringstream ss;
534 ss<<name;
535 if(append_types){
536 if(typeid(T)==typeid(int)){
537 ss<<":int:"<<val;
538 }else if(typeid(T)==typeid(int32_t)){
539 ss<<":int:"<<val;
540 }else if(typeid(T)==typeid(unsigned int)){
541 ss<<":uint:"<<val;
542 }else if(typeid(T)==typeid(uint32_t)){
543 ss<<":uint:"<<val;
544 }else if(typeid(T)==typeid(long)){
545 ss<<":long:"<<val;
546 }else if(typeid(T)==typeid(int64_t)){
547 ss<<":long:"<<val;
548 }else if(typeid(T)==typeid(unsigned long)){
549 ss<<":ulong:"<<val;
550 }else if(typeid(T)==typeid(uint64_t)){
551 ss<<":ulong:"<<val;
552 }else if(typeid(T)==typeid(short)){
553 ss<<":short:"<<val;
554 }else if(typeid(T)==typeid(int16_t)){
555 ss<<":short:"<<val;
556 }else if(typeid(T)==typeid(unsigned short)){
557 ss<<":ushort:"<<val;
558 }else if(typeid(T)==typeid(uint16_t)){
559 ss<<":ushort:"<<val;
560 }else if(typeid(T)==typeid(float)){
561 ss<<":float:"<<val;
562 }else if(typeid(T)==typeid(double)){
563 ss<<":double:"<<val;
564 }else if(typeid(T)==typeid(string)){
565 ss<<":string:"<<val;
566 }else if(typeid(T)==typeid(const char*)){
567 ss<<":string:"<<val;
568 }else if(typeid(T)==typeid(char*)){
569 ss<<":string:"<<val;
570 }else{
571 ss<<":unknown:"<<str;
572 }
573 }
574
575 pair<string, string> item;
576 item.first = ss.str();
577 item.second = string(str);
578 items.push_back(item);
579}
580
581#endif // __CINT__ __CLING__
582
583
584} // Close JANA namespace
585
586#endif // _JObject_
587