NCBI C++ ToolKit
settings_set.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: settings_set.cpp 39666 2017-10-25 16:01:13Z katargir $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Robert G. Smith
27  *
28  * File Description:
29  * CSettingsSet is an adapter of CGuiRegistry.
30  *
31  */
32 
33 #include <ncbi_pch.hpp>
38 #include <algorithm>
39 
42 
43 /// must be the same used as a default in CGuiRegistry.
44 const string CSettingsSet::kDefaultDelim(".");
45 const string CSettingsSet::sm_DefaultValuesKey("default_values");
46 
47 static const string kSettingsHeadKey("GBPlugins");
48 static const string kStartupStyleKey("default_set");
49 static const string kCurrentSetKey("current");
50 static const string kNameKey("name");
51 static const string kFeatureSectionKey("feats");
52 
53 // a style with this name will not be shown in the list of styles.
54 // It can not be selected.
55 static const string kHiddenName("*");
56 
59 : m_Registry( registry ? registry : &CGuiRegistry::GetInstance()),
60  m_Type(key)
61 {
62  CRegistryReadView set_view =
64  // make sure we find what we expect in the registry.
65  if (set_view.IsEmpty()) {
67  "No type '" + m_Type + "' in settings.");
68  }
69  if (GetTypeDescription().empty()) {
71  "No '" + kNameKey + "' in settings: " + m_Type);
72  }
73  if (set_view.GetField(sm_DefaultValuesKey).IsNull()) {
75  "No '" + sm_DefaultValuesKey + "' in settings: " + m_Type);
76  }
77  string current_style = GetCurrentStyleKey();
78  if (current_style == sm_DefaultValuesKey) {
79  // in case we SetDefaultCurrentStyle() without RestoreCurrentStyle()
80  current_style = kStartupStyleKey;
81  }
82  SetCurrentStyleKey(current_style);
83 }
84 
85 
87 {
88 }
89 
90 
92 {
93  m_FieldDictionary.clear();
94  m_ColorDictionary.clear();
95 }
96 
97 
99 {
100  string sect(kSettingsHeadKey);
101  sect += kDefaultDelim;
102  sect += m_Type;
103  return sect;
104 }
105 
106 
108 {
109  string sect(x_GetSection());
110  sect += kDefaultDelim;
111  sect += GetCurrentStyleKey();
112  return sect;
113 }
114 
115 
116 const string& CSettingsSet::GetType(void) const
117 {
118  return m_Type;
119 }
120 
122 {
124 }
125 
126 
127 void CSettingsSet::SetCurrentStyleName(const string& new_style)
128 {
129  SetCurrentStyleKey(x_GetStyleKey(new_style));
130 }
131 
132 
134 {
135  return m_Registry->GetString
138 }
139 
140 
141 void CSettingsSet::SetCurrentStyleKey(const string& new_style_key)
142 {
143  m_Registry->Set
145  new_style_key);
146  if (new_style_key != sm_DefaultValuesKey) {
147  m_SavedStyle = new_style_key;
148  }
149  x_UncacheAll();
150 }
151 
152 
155 {
157  TFieldDictionary::iterator iter = m_FieldDictionary.find(key);
158  if (iter != m_FieldDictionary.end()) {
159  ref = iter->second;
160  } else {
162  m_FieldDictionary[key] = ref;
163  }
164  return ref;
165 }
166 
167 void CSettingsSet::x_Uncache(const string& key) const
168 {
169  m_FieldDictionary.erase(key);
170  m_ColorDictionary.erase(key);
171 }
172 
174 {
175  m_FieldDictionary.clear();
176  m_ColorDictionary.clear();
177 }
178 
180 {
182 }
183 
184 
185 
187 CSettingsSet::x_GetStyleView(const string& style_key) const
188 {
189  vector <string> keys;
190  keys.push_back(sm_DefaultValuesKey);
191  if (style_key != sm_DefaultValuesKey) {
192  keys.push_back(style_key);
193  }
194  return m_Registry->GetReadView(x_GetSection(), keys);
195 }
196 
197 
199 {
202 }
203 
204 
206 {
208 }
209 
210 
212 {
213  return m_Registry->GetString
215  kEmptyStr);
216 }
217 
218 
219 /// every style has a name and a key. Both should be unique within this Type.
220 /// translate between style names and keys.
221 string CSettingsSet::x_GetStyleName(const string& key) const
222 {
223  return m_Registry->GetString
226  kEmptyStr);
227 }
228 
229 
230 string CSettingsSet::x_GetStyleKey(const string& name) const
231 {
233  list <string> ret_list;
235  set_view.GetTopKeys(keys);
236  ITERATE(CRegistryReadView::TKeys, key_it, keys) {
237  if (key_it->type == CUser_field::TData::e_Fields &&
238  x_GetStyleName(key_it->key) == name ) {
239  return key_it->key;
240  }
241  }
242  return kEmptyStr;
243 }
244 
245 
246 /// make unique names and keys.
247 /// result may be different than the argument.
248 string CSettingsSet::x_MakeUniqueStyleName(const string& name) const
249 {
250  string uniq_name(name);
251  unsigned long suffix_number = 0;
252  list<string> names = GetStyleNames();
253  list<string>::iterator name_end = names.end();
254 
255  while (find(names.begin(), name_end, uniq_name) != name_end) {
256  uniq_name = name + " " + NStr::SizetToString(++suffix_number);
257  }
258  return uniq_name;
259 }
260 
261 
262 string CSettingsSet::x_MakeUniqueStyleKey(const string& key) const
263 {
264  string uniq_key(key);
265  unsigned long suffix_number = 0;
266  while ( m_Registry->HasField(x_GetSection() + kDefaultDelim + uniq_key) ) {
267  uniq_key = key + NStr::SizetToString(++suffix_number);
268  }
269  return uniq_key;
270 }
271 
272 
273 list<string> CSettingsSet::GetStyleNames() const
274 {
276  list <string> ret_list;
278  set_view.GetTopKeys(keys);
279  ITERATE(CRegistryReadView::TKeys, key_it, keys) {
280  if (key_it->type == CUser_field::TData::e_Fields) {
281  if (kStartupStyleKey != key_it->key) {
282  string name = x_GetStyleName(key_it->key);
283  if (name != kHiddenName )
284  ret_list.push_back(name);
285  }
286  }
287  }
288  ret_list.sort();
289  ret_list.push_front(x_GetStyleName(kStartupStyleKey));
290 
291  return ret_list;
292 }
293 
294 
295 
297 {
298  string new_key("custom style");
299  new_key = x_MakeUniqueStyleKey(new_key);
300  string new_name("New Default Values");
301  new_name = x_MakeUniqueStyleName(new_name);
303  new_key + kDefaultDelim + kNameKey,
304  new_name);
305  return new_name;
306 }
307 
308 
309 
310 string CSettingsSet::DuplicateStyle(const string& style)
311 {
312  // To do this need to be able to duplicate a User_field.
313  /*
314  // make new unique name.
315  string new_name(style + " copy");
316  new_name = x_MakeUniqueStyleName(new_name);
317 
318  // Some style names (default) may not actually exist
319  // so there is nothing to duplicate.
320  if (pcc.HasPCV(m_Type, style)) {
321  pcc.DupPCV(m_Type, style, new_name);
322  } else {
323  pcc.SetPCV(m_Type, new_name);
324  }
325  return new_name;
326  */
327  return kEmptyStr;
328 }
329 
330 
331 string CSettingsSet::RenameStyle(const string& old_style, const string& new_style)
332 {
333  if (new_style.empty() ||
334  old_style == new_style ) {
335  return kEmptyStr;
336  }
337  string style_key = x_GetStyleKey(old_style);
338  if (style_key.empty())
339  return kEmptyStr;
340 
341  string uniq_name = x_MakeUniqueStyleName(new_style);
343  style_key + kDefaultDelim + kNameKey, uniq_name);
344 
345  return uniq_name;
346 }
347 
348 
349 bool CSettingsSet::CanRenameStyle(const string& style)
350 {
351  return true;
352 }
353 
354 
355 bool CSettingsSet::DeleteStyle(const string& style)
356 {
357  string style_key = x_GetStyleKey(style);
358  if (style_key.empty() || style_key == sm_DefaultValuesKey)
359  return false;
360 
361  return m_Registry->DeleteField(x_GetSection() + kDefaultDelim + style_key);
362 }
363 
364 
365 string CSettingsSet::GetString(const string& key,
366  const string& default_val) const
367 {
369  if ( !ref ) {
370  return default_val;
371  }
372  return ref->GetData().GetStr();
373 }
374 
375 
376 int CSettingsSet::GetInt(const string& key,
377  int default_val) const
378 {
380  if ( !ref ) {
381  return default_val;
382  }
383  return ref->GetData().GetInt();
384 }
385 
386 
387 double CSettingsSet::GetReal(const string& key,
388  double default_val) const
389 {
391  if ( !ref ) {
392  return default_val;
393  }
394  return ref->GetData().GetReal();
395 }
396 
397 
398 bool CSettingsSet::GetBool(const string& key,
399  bool default_val) const
400 {
402  if ( !ref ) {
403  return default_val;
404  }
405  return ref->GetData().GetBool();
406 }
407 
408 
409 void CSettingsSet::GetIntVec(const string& key,
410  vector<int>& val) const
411 {
413  if (ref) {
414  val = ref->GetData().GetInts();
415  }
416 }
417 
418 
419 void CSettingsSet::GetRealVec(const string& key,
420  vector<double>& val) const
421 {
423  if (ref) {
424  val = ref->GetData().GetReals();
425  }
426 }
427 
428 
429 void CSettingsSet::GetStringVec(const string& key,
430  vector<string>& val) const
431 {
433  if (ref) {
434  const CUser_field_Base::C_Data::TStrs& src = ref->GetData().GetStrs();
435  val.clear();
436  copy( src.begin(), src.end(), back_inserter(val));
437  }
438 }
439 
441  const CRgbaColor& default_val) const
442 {
443  TColorDictionary::const_iterator iter = m_ColorDictionary.find(key);
444  if (iter != m_ColorDictionary.end()) {
445  return iter->second;
446  } else {
448  if ( !ref ) {
449  return default_val;
450  }
451  if (ref) {
452  CRgbaColor c;
453  if (UserFieldToColor(*ref, c)) {
454  m_ColorDictionary[key] = c;
455  return c;
456  }
457  }
458  return default_val;
459  }
460 }
461 
462 
463 /// Get sub-views of the settings.
464 CRegistryReadView CSettingsSet::x_GetReadView(const string& section) const
465 {
466  if (section.empty()) {
467  return x_GetCurrentStyleView();
468  }
469  return x_GetCurrentStyleView().GetReadView(section);
470 }
471 
472 
473 /// retrieve the key name for a given feature subtype
475  const string& section,
476  const string& subkey) const
477 {
478  string sect(section);
479  if (!sect.empty()) {
480  sect += kDefaultDelim;
481  }
482  sect += kFeatureSectionKey;
483  sect += kDefaultDelim;
484 
485  const CFeatList& feats(*CSeqFeatData::GetFeatList());
486  vector<string> feat_hierarchy = feats.GetStoragekeys(feat_subtype);
487 
488  // try them in reverse order so the more specific keys get tried first.
489  vector<string>::reverse_iterator riter(feat_hierarchy.end());
490  vector<string>::reverse_iterator rend(feat_hierarchy.begin());
491 
492  for ( ; riter != rend; ++riter) {
493  string s = sect + *riter;
494  if ( ! subkey.empty()) {
495  s += kDefaultDelim;
496  s += subkey;
497  }
499  if (f) {
500  return s;
501  }
502  }
503  // shouldn't get here.
504  // means that there wasn't a Master feature item in the global settings file.
505  _ASSERT(false);
506  return kEmptyStr;
507 }
508 
509 
511  const string& section)
512 {
513  string sect(section);
514  if (!sect.empty()) {
515  sect += kDefaultDelim;
516  }
517  sect += kFeatureSectionKey;
518  sect += kDefaultDelim;
519 
520  const CFeatList& feats(*CSeqFeatData::GetFeatList());
521  string feat_key = feats.GetStoragekey(feat_subtype);
522  sect += feat_key;
523  return sect;
524 }
525 
526 /// set specific values
527 void CSettingsSet::Set(const string& key, int val)
528 {
530  x_Uncache(key);
531 }
532 
533 
534 void CSettingsSet::Set(const string& key, double val)
535 {
537  x_Uncache(key);
538 }
539 
540 
541 void CSettingsSet::Set(const string& key, bool val)
542 {
544  x_Uncache(key);
545 }
546 
547 
548 void CSettingsSet::Set(const string& key, const string& val)
549 {
551  x_Uncache(key);
552 }
553 
554 
555 void CSettingsSet::Set(const string& key, const char* val)
556 {
558  x_Uncache(key);
559 }
560 
561 
562 void CSettingsSet::Set(const string& key, const vector<int>& val)
563 {
565  x_Uncache(key);
566 }
567 
568 
569 void CSettingsSet::Set(const string& key, const vector<double>& val)
570 {
572  x_Uncache(key);
573 }
574 
575 
576 void CSettingsSet::Set(const string& key, const vector<string>& val)
577 {
579  x_Uncache(key);
580 }
581 
582 
583 void CSettingsSet::Set(const string& key, const CRgbaColor& val)
584 {
588  x_Uncache(key);
589 }
590 
591 
592 bool CSettingsSet::Delete(const string& key)
593 {
595  //x_Uncache(key);
596 }
597 
598 
600 {
601  // store the color as a vector of ints.
602  vector<int> val;
603  val.push_back(c.GetRedUC());
604  val.push_back(c.GetGreenUC());
605  val.push_back(c.GetBlueUC());
606  val.push_back(c.GetAlphaUC());
607 
608  f.SetData().SetInts() = val;
609 }
610 
611 
613 {
614  switch(f.GetData().Which()) {
616  {{
617  vector<int> cvi = f.GetData().GetInts();
618  if (cvi.size() > 2 ) {
619  vector<int>::const_iterator cv_it = cvi.begin();
620  c.SetRed (static_cast<unsigned char>(*cv_it++));
621  c.SetGreen(static_cast<unsigned char>(*cv_it++));
622  c.SetBlue (static_cast<unsigned char>(*cv_it++));
623  if (cv_it != cvi.end()) {
624  c.SetAlpha(static_cast<unsigned char>(*cv_it));
625  }
626  } else {
627  return false;
628  }
629  break;
630  }}
632  vector<double> cvd = f.GetData().GetReals();
633  if (cvd.size() > 2 ) {
634  vector<double>::const_iterator cv_it = cvd.begin();
635  c.SetRed (static_cast<float>(*cv_it++));
636  c.SetGreen(static_cast<float>(*cv_it++));
637  c.SetBlue (static_cast<float>(*cv_it++));
638  if (cv_it != cvd.end()) {
639  c.SetAlpha(static_cast<float>(*cv_it));
640  }
641  } else {
642  return false;
643  }
644  break;
645  }}
647  string cs = f.GetData().GetStr();
648  c.FromString(cs);
649  break;
650  }}
651  default:
652  return false;
653  }
654 
655  return true;
656 }
657 
658 
659 
661 {
662  ostr << "Current style key : " << GetCurrentStyleKey() << endl;
663  ostr << "Current style name: " << GetCurrentStyleName() << endl;
665 }
666 
667 
CConfigurableItems - a static list of items that can be configured.
string GetStoragekey(int type, int subtype) const
Get the key used to store this type of feature.
vector< string > GetStoragekeys(int subtype) const
Get hierarchy of keys above this subtype, starting with "Master" example, eSubtype_gene,...
static string MakeKey(const string &section, const string &key, const string &delim=CGuiRegistry::kDecimalDot)
create a key from a section and a subkey
Definition: registry.cpp:504
CRef< objects::CUser_field > SetFieldToValue(const string &key)
same as SetField, but complain loudly if the field has subfields in it already.
Definition: registry.cpp:321
bool HasField(const string &key) const
Does a field with this section and key exist in this view?
Definition: registry.cpp:365
void Set(const string &key, int val)
set specific values
Definition: registry.cpp:178
CRegistryReadView GetReadView(const string &section) const
get a read-only view at a particular level.
Definition: registry.cpp:428
string GetString(const string &key, const string &default_val=kEmptyStr) const
Definition: registry.cpp:148
bool DeleteField(const string &key)
delete the specified field (and any of its subfields).
Definition: registry.cpp:333
class CRegistryReadView provides a nested hierarchical view at a particular key.
Definition: reg_view.hpp:58
void DumpAll(CNcbiOstream &ostr) const
Dump onto the stream all the keys in this view along with their types and data values.
Definition: reg_view.cpp:426
list< SKeyInfo > TKeys
retrieve information about all keys in the registry
Definition: reg_view.hpp:68
void GetTopKeys(TKeys &keys) const
Retrieve information about the top level keys in this view.
Definition: reg_view.cpp:278
CRegistryReadView GetReadView(const string &section) const
Definition: reg_view.cpp:74
CConstRef< objects::CUser_field > GetField(const string &key) const
provide raw field access
Definition: reg_view.cpp:104
bool IsEmpty()
There is nothing in this view.
Definition: reg_view.cpp:363
class CRgbaColor provides a simple abstraction for managing colors.
Definition: rgba_color.hpp:58
static const CFeatList * GetFeatList()
static void ColorToUserField(const CRgbaColor &c, objects::CUser_field &f)
convert a color into a vector of ints within a user field
CConstRef< objects::CUser_field > x_GetCurrentViewField(const string &key) const
retrieve (and cache) a field
string x_MakeUniqueStyleName(const string &name) const
make unique names and keys.
void DumpAll(CNcbiOstream &ostr)
write all keys and values we know about.
string AddStyle(void)
these all return the name of the style just added.
string x_GetStyleKey(const string &name) const
static string GetFeatWriteKey(TFeatSubtype feat_subtype, const string &section)
retrieve the key name to write values for a given feature subtype
void Set(const string &key, int val)
set a named integer value
string x_GetSection() const
get the full key string used to get this type's part of the registry.
string m_SavedStyle
> key used in cache.
bool Delete(const string &key)
Delete a key/value in the current settings.
string GetTypeDescription(void) const
void Uncache()
uncache any cached lookup data
void GetRealVec(const string &key, vector< double > &val) const
Retrieve a named real vector value from a section.key.
double GetReal(const string &key, double default_val=0) const
Retrieve a named double value from a section.key.
TFieldDictionary m_FieldDictionary
string x_GetStyleSection() const
get the full key string used to get the current style's part of the registry.
void SetCurrentStyleKey(const string &new_style_key)
int GetInt(const string &key, int default_val=0) const
Retrieve a named int value from a section.key.
static const string sm_DefaultValuesKey
the key for the default set of values.
bool DeleteStyle(const string &style)
static bool UserFieldToColor(const objects::CUser_field &f, CRgbaColor &c)
convert a user field into a color.
bool CanRenameStyle(const string &style)
CRgbaColor GetColor(const string &key, const CRgbaColor &default_val=CRgbaColor()) const
Retrieve a named color value from a section.key.
string RenameStyle(const string &old_style, const string &new_style)
static const string kDefaultDelim
must be the same used as a default in CGuiRegistry.
CRegistryReadView x_GetCurrentStyleView() const
get a view showing the values under the current style.
void RestoreCurrentStyle()
list< string > GetStyleNames(void) const
Methods to edit our list of valid styles.
CRegistryReadView x_GetStyleView(const string &style_key) const
get a view containing the values given a certain style.
string x_GetStyleName(const string &key) const
every style has a name and a key.
string GetCurrentStyleKey(void) const
style keys are only for internal use.
void x_UncacheAll() const
invalidate the entire cache
void GetStringVec(const string &key, vector< string > &val) const
Retrieve a named string vector value from a section.key.
int TFeatSubtype
we use int instead of CSeqFeatData::ESubtype for two reasons:
string x_MakeUniqueStyleKey(const string &key) const
string GetFeatReadKey(TFeatSubtype feat_subtype, const string &section, const string &subkey=kEmptyStr) const
retrieve the key name to read values for a given feature subtype
CRef< CGuiRegistry > m_Registry
string DuplicateStyle(const string &style)
virtual ~CSettingsSet()
TColorDictionary m_ColorDictionary
string GetCurrentStyleName(void) const
void x_Uncache(const string &key) const
uncache a given key
CSettingsSet(const string &type, CGuiRegistry *registry=0)
constructor
const string & GetType(void) const
Return the type passed in the constructor.
string m_Type
> the registry these views come from.
void GetIntVec(const string &key, vector< int > &val) const
Retrieve a named int vector value from a section.key.
string GetString(const string &key, const string &default_val=kEmptyStr) const
Retrieve a named string value from a section.key.
void SetCurrentStyleName(const string &new_style)
void SetDefaultCurrentStyle()
These are so that you can get data that is all default values.
CRegistryReadView x_GetReadView(const string &section) const
Retrieve a read-only view.
bool GetBool(const string &key, bool default_val=false) const
Retrieve a named bool value from a section.key.
static CMemoryRegistry registry
Definition: cn3d_tools.cpp:81
static const struct name_t names[]
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
unsigned char GetRedUC(void) const
Get specific channels in unsigned char values.
Definition: rgba_color.hpp:345
unsigned char GetGreenUC(void) const
Definition: rgba_color.hpp:351
unsigned char GetAlphaUC(void) const
Definition: rgba_color.hpp:363
void SetAlpha(float r)
Definition: rgba_color.cpp:287
void FromString(const string &str)
Assign color values encoded in a string.
Definition: rgba_color.cpp:363
void SetGreen(float r)
Definition: rgba_color.cpp:275
unsigned char GetBlueUC(void) const
Definition: rgba_color.hpp:357
void SetBlue(float r)
Definition: rgba_color.cpp:281
void SetRed(float r)
Set specific channels from floating point values.
Definition: rgba_color.cpp:269
bool IsNull(void) const THROWS_NONE
Check if pointer is null – same effect as Empty().
Definition: ncbiobj.hpp:1401
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
static string SizetToString(size_t value, TNumToStringFlags flags=0, int base=10)
Convert size_t to string.
Definition: ncbistr.cpp:2751
#define kEmptyStr
Definition: ncbistr.hpp:123
const TStr & GetStr(void) const
Get the variant data.
const TStrs & GetStrs(void) const
Get the variant data.
const TData & GetData(void) const
Get the Data member data.
TBool GetBool(void) const
Get the variant data.
TInt GetInt(void) const
Get the variant data.
TReal GetReal(void) const
Get the variant data.
const TReals & GetReals(void) const
Get the variant data.
vector< CStringUTF8 > TStrs
const TInts & GetInts(void) const
Get the variant data.
constexpr bool empty(list< Ts... >) noexcept
const struct ncbi::grid::netcache::search::fields::KEY key
const struct ncbi::grid::netcache::search::fields::SUBKEY subkey
void copy(Njn::Matrix< S > *matrix_, const Njn::Matrix< T > &matrix0_)
Definition: njn_matrix.hpp:613
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
USING_SCOPE(objects)
static const string kStartupStyleKey("default_set")
static const string kNameKey("name")
static const string kCurrentSetKey("current")
static const string kHiddenName("*")
static const string kSettingsHeadKey("GBPlugins")
static const string kFeatureSectionKey("feats")
#define _ASSERT
Modified on Thu Mar 28 17:13:10 2024 by modify_doxy.py rev. 669887