VR-Forces 5.0.2 Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
templateUtil.h
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright (c) 2022 MAK Technologies, Inc.
3  * All rights reserved.
4  *****************************************************************************/
5 
9 
10 #pragma once
11 
12 #include <vlutil/vlExceptions.h>
13 #include <functional>
14 #include <vector>
15 #include <map>
16 
17 // Expand the provide macro.
18 #define DO_PP(MACRO) MACRO
19 
20 // Theses macros make it easy to define VAR-ARG template classes.
21 
22 // Make stream puts an 'word' with the index prepended separated by "<<"
23 // Example MAKE_STREAM_1(A) output A1
24 // Example MAKE_STREAM_2(A) output A1 << A2
25 #define MAKE_STREAM_1(word) word##1
26 #define MAKE_STREAM_2(word) MAKE_STREAM_1(word)<<word##2
27 #define MAKE_STREAM_3(word) MAKE_STREAM_2(word)<<word##3
28 #define MAKE_STREAM_4(word) MAKE_STREAM_3(word)<<word##4
29 #define MAKE_STREAM_5(word) MAKE_STREAM_4(word)<<word##5
30 #define MAKE_STREAM_6(word) MAKE_STREAM_5(word)<<word##6
31 #define MAKE_STREAM_7(word) MAKE_STREAM_6(word)<<word##7
32 #define MAKE_STREAM_8(word) MAKE_STREAM_7(word)<<word##8
33 #define MAKE_STREAM_9(word) MAKE_STREAM_8(word)<<word##9
34 #define MAKE_STREAM_10(word) MAKE_STREAM_9(word)<<word##10
35 
36 #define MAKE_STREAM(word,count) DO_PP(MAKE_STREAM_##count(word))
37 
38 
39 // Make stream puts an 'word' with the index prepended separated by ">>"
40 // Example MAKE_STREAMOUT_1(A) output A1
41 // Example MAKE_STREAMOUT_2(A) output A1 >> A2
42 #define MAKE_STREAMOUT_1(word) word##1
43 #define MAKE_STREAMOUT_2(word) MAKE_STREAMOUT_1(word)>>word##2
44 #define MAKE_STREAMOUT_3(word) MAKE_STREAMOUT_2(word)>>word##3
45 #define MAKE_STREAMOUT_4(word) MAKE_STREAMOUT_3(word)>>word##4
46 #define MAKE_STREAMOUT_5(word) MAKE_STREAMOUT_4(word)>>word##5
47 #define MAKE_STREAMOUT_6(word) MAKE_STREAMOUT_5(word)>>word##6
48 #define MAKE_STREAMOUT_7(word) MAKE_STREAMOUT_6(word)>>word##7
49 #define MAKE_STREAMOUT_8(word) MAKE_STREAMOUT_7(word)>>word##8
50 #define MAKE_STREAMOUT_9(word) MAKE_STREAMOUT_8(word)>>word##9
51 #define MAKE_STREAMOUT_10(word) MAKE_STREAMOUT_9(word)>>word##10
52 
53 #define MAKE_STREAMOUT(word,count) DO_PP(MAKE_STREAMOUT_##count(word))
54 
55 
56 
57 //Make list puts an 'word' with the index prepended separated by ","
58 //Example MAKE_LIST_1(A) output A1
59 //Example MAKE_LIST_2(A) output A1,A2
60 #define MAKE_LIST_1(word) word##1
61 #define MAKE_LIST_2(word) MAKE_LIST_1(word),word##2
62 #define MAKE_LIST_3(word) MAKE_LIST_2(word),word##3
63 #define MAKE_LIST_4(word) MAKE_LIST_3(word),word##4
64 #define MAKE_LIST_5(word) MAKE_LIST_4(word),word##5
65 #define MAKE_LIST_6(word) MAKE_LIST_5(word),word##6
66 #define MAKE_LIST_7(word) MAKE_LIST_6(word),word##7
67 #define MAKE_LIST_8(word) MAKE_LIST_7(word),word##8
68 #define MAKE_LIST_9(word) MAKE_LIST_8(word),word##9
69 #define MAKE_LIST_10(word) MAKE_LIST_9(word),word##10
70 
71 #define MAKE_LIST(word,count) DO_PP(MAKE_LIST_##count(word))
72 
73 //Make multilist puts two words 'first' then 'second' each with the index of the
74 //pair, prepended separated by ","
75 //Example MAKE_MULTILIST_1(A,::B) output A1::B1
76 //Example MAKE_MULTILIST_2(A,::B) output A1::B1,A2::B2
77 #define MAKE_MULTILIST_1(first,second) first##1 second##1
78 #define MAKE_MULTILIST_2(first,second) MAKE_MULTILIST_1(first,second),first##2 second##2
79 #define MAKE_MULTILIST_3(first,second) MAKE_MULTILIST_2(first,second),first##3 second##3
80 #define MAKE_MULTILIST_4(first,second) MAKE_MULTILIST_3(first,second),first##4 second##4
81 #define MAKE_MULTILIST_5(first,second) MAKE_MULTILIST_4(first,second),first##5 second##5
82 #define MAKE_MULTILIST_6(first,second) MAKE_MULTILIST_5(first,second),first##6 second##6
83 #define MAKE_MULTILIST_7(first,second) MAKE_MULTILIST_6(first,second),first##7 second##7
84 #define MAKE_MULTILIST_8(first,second) MAKE_MULTILIST_7(first,second),first##8 second##8
85 #define MAKE_MULTILIST_9(first,second) MAKE_MULTILIST_8(first,second),first##9 second##9
86 #define MAKE_MULTILIST_10(first,second) MAKE_MULTILIST_9(first,second),first##10 second##10
87 
88 #define MAKE_MULTILIST(first,second,count) DO_PP(MAKE_MULTILIST_##count(first,second))
89 
90 
91 //A slightly odd macro, needed to for a series of inline functions.
92 //pair, prepended separated by ","
93 //Example MAKE_CAST_CALL_1(A,B,C,D) output A1B(C,D1)
94 //Example MAKE_CAST_CALL_2(A,::B,C)output A1B(C,D1),A2B(C,D2)
95 #define MAKE_CAST_CALL_1(first,second,third,forth) first##1 second(third,forth##1)
96 #define MAKE_CAST_CALL_2(first,second,third,forth) MAKE_CAST_CALL_1(first,second,third,forth),first##2 second(third,forth##2)
97 #define MAKE_CAST_CALL_3(first,second,third,forth) MAKE_CAST_CALL_2(first,second,third,forth),first##3 second(third,forth##3)
98 #define MAKE_CAST_CALL_4(first,second,third,forth) MAKE_CAST_CALL_3(first,second,third,forth),first##4 second(third,forth##4)
99 #define MAKE_CAST_CALL_5(first,second,third,forth) MAKE_CAST_CALL_4(first,second,third,forth),first##5 second(third,forth##5)
100 #define MAKE_CAST_CALL_6(first,second,third,forth) MAKE_CAST_CALL_5(first,second,third,forth),first##6 second(third,forth##6)
101 #define MAKE_CAST_CALL_7(first,second,third,forth) MAKE_CAST_CALL_6(first,second,third,forth),first##7 second(third,forth##7)
102 #define MAKE_CAST_CALL_8(first,second,third,forth) MAKE_CAST_CALL_7(first,second,third,forth),first##8 second(third,forth##8)
103 #define MAKE_CAST_CALL_9(first,second,third,forth) MAKE_CAST_CALL_8(first,second,third,forth),first##9 second(third,forth##9)
104 #define MAKE_CAST_CALL_10(first,second,third,forth) MAKE_CAST_CALL_9(first,second,third,forth),first##10 second(third,forth##10)
105 
106 #define MAKE_CAST_CALL(first,second,third,forth,count) DO_PP(MAKE_CAST_CALL_##count(first,second,third,forth))
107 
108 
109 //Make list puts an 'word' with the index prepended separated by ";"
110 //Example MAKE_DECL_LIST_1(int A) output int A
111 //Example MAKE_DECL_LIST_1(int A) output int A1; int A2
112 #define MAKE_DECL_LIST_1(word) word##1
113 #define MAKE_DECL_LIST_2(word) MAKE_DECL_LIST_1(word);word##2
114 #define MAKE_DECL_LIST_3(word) MAKE_DECL_LIST_2(word);word##3
115 #define MAKE_DECL_LIST_4(word) MAKE_DECL_LIST_3(word);word##4
116 #define MAKE_DECL_LIST_5(word) MAKE_DECL_LIST_4(word);word##5
117 #define MAKE_DECL_LIST_6(word) MAKE_DECL_LIST_5(word);word##6
118 #define MAKE_DECL_LIST_7(word) MAKE_DECL_LIST_6(word);word##7
119 #define MAKE_DECL_LIST_8(word) MAKE_DECL_LIST_7(word);word##8
120 #define MAKE_DECL_LIST_9(word) MAKE_DECL_LIST_8(word);word##9
121 #define MAKE_DECL_LIST_10(word) MAKE_DECL_LIST_9(word);word##10
122 
123 #define MAKE_DECL_LIST(word,count) DO_PP(MAKE_DECL_LIST_##count(word))
124 
125 //Make list puts an 'word' with the index prepended separated by ";"
126 //Example MAKE_DECL_LIST_1(int A) output int A
127 //Example MAKE_DECL_LIST_1(int A) output int A1; int A2
128 #define MAKE_DECL_MULTILIST_1(first,second) first##1 second##1
129 #define MAKE_DECL_MULTILIST_2(first,second) MAKE_DECL_MULTILIST_1(first,second);first##2 second##2
130 #define MAKE_DECL_MULTILIST_3(first,second) MAKE_DECL_MULTILIST_2(first,second);first##3 second##3
131 #define MAKE_DECL_MULTILIST_4(first,second) MAKE_DECL_MULTILIST_3(first,second);first##4 second##4
132 #define MAKE_DECL_MULTILIST_5(first,second) MAKE_DECL_MULTILIST_4(first,second);first##5 second##5
133 #define MAKE_DECL_MULTILIST_6(first,second) MAKE_DECL_MULTILIST_5(first,second);first##6 second##6
134 #define MAKE_DECL_MULTILIST_7(first,second) MAKE_DECL_MULTILIST_6(first,second);first##7 second##7
135 #define MAKE_DECL_MULTILIST_8(first,second) MAKE_DECL_MULTILIST_7(first,second);first##8 second##8
136 #define MAKE_DECL_MULTILIST_9(first,second) MAKE_DECL_MULTILIST_8(first,second);first##9 second##9
137 #define MAKE_DECL_MULTILIST_10(first,second) MAKE_DECL_MULTILIST_9(first,second);first##10 second##10
138 
139 #define MAKE_DECL_MULTILIST(first,second,count) DO_PP(MAKE_DECL_MULTILIST_##count(first,second))
140 
141 #ifdef _WIN32
142 #define EXPORT_TEMPLATE_TYPEDEF(C,TD)\
143  typedef C TD;
144 #else
145 #define EXPORT_TEMPLATE_TYPEDEF(C,TD)\
146  typedef C TD;\
147  template class C;
148 #endif
149 
150 // FAST_REPEATED_CALL implements/mimics Duff's Device.
151 // A Google search will provide examples and explanations.
152 #define FAST_REPEATED_CALL(count,x) \
153 { \
154  if(count > 0) \
155  { \
156  size_t __FAST_ITERATE_count = count;\
157  size_t __FAST_ITERATE_n = (__FAST_ITERATE_count + 7) >> 3; \
158  switch (__FAST_ITERATE_count & 7) \
159  { \
160  case 0: do { x;\
161  case 7: x; \
162  case 6: x; \
163  case 5: x; \
164  case 4: x; \
165  case 3: x; \
166  case 2: x; \
167  case 1: x; \
168  } while (--__FAST_ITERATE_n > 0);\
169  }\
170  }\
171 }
172 
173 
174 namespace makVrv
175 {
176 
177 //Used to search a key in a map, and return NULL if it is not found.
178 template <typename K,typename V, typename Pr,typename Alloc>
179 V* DtFindPointerInMap(const std::map<K,V,Pr,Alloc>& map,K key)
180 {
181  typename std::map<K,V,Pr,Alloc>::const_iterator iter = map.find(key);
182  if(iter == map.end())
183  {
184  return 0;
185  }
186  else
187  {
188  return const_cast<V*>(&iter->second);
189  }
190 }
191 
197 template <typename M>
199 {
200  typename M::mapped_type ptr;
201  typename M::iterator curIter = map.begin();
202  typename M::const_iterator endIter = map.end();
203  for ( ; curIter != endIter; ++curIter )
204  {
205  ptr = curIter->second;
206  curIter->second = 0;
207  delete ptr;
208  }
209  map.clear();
210 }
211 
217 template <typename V>
219 {
220  typename V::value_type ptr;
221  typename V::iterator curIter = vec.begin();
222  typename V::iterator endIter = vec.end();
223  for ( ; curIter != endIter; ++curIter )
224  {
225  ptr = *curIter;
226  (*curIter) = 0;
227  delete ptr;
228  }
229  vec.clear();
230 }
231 
232 template <typename Iter>
233 void DtDeletePointersInIterators(Iter begin, Iter end)
234 {
235  for(Iter cur = begin;cur != end;++cur)
236  {
237  delete *cur;
238  }
239 }
240 
241 template <typename Key, typename Value>
243 {
244  inline bool operator()(const std::pair<Key,Value>& a, const std::pair<Key,Value>& b) const
245  {
246  return a.first < b.first;
247  }
248 };
249 
250 
251 template <typename T,typename R,typename A,typename Col>
252 void forEachCallMember( T* _this, R (T::*memfun)(A),Col& col)
253 {
254  typename Col::iterator curIter = col.begin();
255  typename Col::iterator endIter = col.end();
256  for(;curIter != endIter;++curIter)
257  {
258  (_this->*memfun)(*curIter);
259  }
260 }
261 
262 template <typename Ret,typename AT,typename Class>
263 Ret callConstFunction1(const Class* _this,
264  const Ret (Class::* memberPtr)(AT) const,
265  AT param)
266 {
267  return const_cast<Ret>(_this->*(memberPtr)(param));
268 }
269 
270 class DtDe;
271 
272 template <typename T, void(T::*MF)()>
273 void DtMemberFunctionCallback(DtDe* de,void* data)
274 {
275  (((T*)data)->*MF)();
276 }
277 
278 template <class InputIterator1, class InputIterator2, class OutputIterator1,class OutputIterator2>
279 void set_split_difference ( InputIterator1 first1, InputIterator1 last1,
280  InputIterator2 first2, InputIterator2 last2,
281  OutputIterator1 result1,
282  OutputIterator2 result2 )
283 {
284  while (first1!=last1 && first2!=last2)
285  {
286  if (*first1<*first2)
287  {
288  *result1++ = *first1++;
289  }
290  else if (*first2<*first1)
291  {
292  *result2++ = *first2++;
293  }
294  else
295  {
296  first1++;
297  first2++;
298  }
299 
300  }
301  copy(first1,last1,result1);
302  copy(first2,last2,result2);
303 }
304 
305 //#include <boost/bind.hpp>
306 //#include <vrvUtil/signalslib.h>
307 //
308 //template <typename Argument>
309 //void forwardSignal(boost::signalslib::signal<void (Argument)>& emitter,
311 //{
317 //}
318 //
319 //template <typename Argument,typename Argument2>
320 //void forwardSignal(boost::signalslib::signal<void (Argument,Argument2)>& emitter,
322 //{
328 //}
329 
330 template <typename iter, typename T>
331 iter fasterFind(size_t size, iter begin, iter end,const T& value)
332 {
333  FAST_REPEATED_CALL(size, {if(*begin == value) return begin; else ++begin;} )
334  return end;
335 }
336 
337 template <typename iter, typename F>
338 iter fastFindPred(size_t size, iter begin, iter end,const F& pred)
339 {
340  FAST_REPEATED_CALL(size, {if(pred(*begin)) return begin; else ++begin;} )
341  return end;
342 }
343 
344 template <typename T, typename Ax >
345 void fastEraseFromUnsortedVector(std::vector<T,Ax>& list, const T& value)
346 {
347  size_t size = list.size();
348  if(size == 0)
349  {
350  return;
351  }
352  else
353  {
354  typename std::vector<T,Ax>::iterator i = fasterFind(size,list.begin(),list.end(),value);
355  if(i != list.end())
356  {
357  if(size == 1)
358  {
359  list.resize(0);
360  }
361  else
362  {
363  if(&(*i) != &list.back())
364  {
365  *i = list.back();
366  }
367  list.resize(size - 1);
368  }
369  }
370  }
371 }
372 
373 template <typename T, typename Ax >
374 void fastEraseFromUnsortedVector(std::vector<T*,Ax>& list, const T* value)
375 {
376  size_t size = list.size();
377  if(size == 0)
378  {
379  return;
380  }
381  else if(size == 1)
382  {
383  list.resize(0);
384  }
385  else
386  {
387  typename std::vector<T*,Ax>::iterator i = fasterFind(size,list.begin(),list.end(),value);
388  if(i != list.end())
389  {
390  if(&(*i) != &list.back())
391  {
392  *i = list.back();
393  }
394  list.resize(size - 1);
395  }
396  }
397 }
398 
399 template <typename T, typename Ax, typename Function >
400 void fastEraseFromUnsortedVectorPred(std::vector<T,Ax>& list, const Function& f)
401 {
402  size_t size = list.size();
403  if(size == 0)
404  {
405  return;
406  }
407  else if(size == 1)
408  {
409  list.resize(0);
410  }
411  else
412  {
413  typename std::vector<T,Ax>::iterator i = fastFindPred(size,list.begin(),list.end(),f);
414  if(i != list.end())
415  {
416  if(&(*i) != &list.back())
417  {
418  *i = list.back();
419  }
420  list.resize(size - 1);
421  }
422  }
423 }
424 
425 template <typename T, typename Ax, typename Function>
426 void fastEraseFromUnsortedVectorPred(std::vector<T*,Ax>& list, const Function& f)
427 {
428  size_t size = list.size();
429  if(size == 0)
430  {
431  return;
432  }
433  else if(size == 1)
434  {
435  list.resize(0);
436  }
437  else
438  {
439  typename std::vector<T*,Ax>::iterator i =fastFindPred(size,list.begin(),list.end(), f );
440  if(i != list.end())
441  {
442  if(&(*i) != &list.back())
443  {
444  *i = list.back();
445  }
446  list.resize(size - 1);
447  }
448  }
449 }
450 
451 template <typename Ret, typename T>
453 {
454  typedef Ret (T::*MemberFnPtr)() const;
456 
458  : myPtr(memFun)
459  {
460  }
461 
463  : myPtr(second.myPtr)
464  {
465  }
466 
467  bool operator()(const T* a, const T* b) const
468  {
469  return (a->*myPtr)() < (b->*myPtr)();
470  }
471 };
472 
473 template <typename Ret, typename T>
475 {
477 }
478 
479 template <typename Ret, typename T>
481 {
482  typedef Ret (T::*MemberFnPtr)() const;
484  Ret myValue;
485 
487  : myPtr(memFun)
488  , myValue(value)
489  {
490  }
491 
493  : myPtr(second.myPtr)
494  , myValue(second.myValue)
495  {
496  }
497 
498  bool operator()(const T* a) const
499  {
500  return (a->*myPtr)() == myValue;
501  }
502 };
503 
504 template <typename Ret, typename T>
505 inline EqualPointerByFunction_T<Ret,T> EqualPointerByFunction(Ret (T::*ptr)() const,Ret value)
506 {
507  return EqualPointerByFunction_T<Ret,T>(ptr,value);
508 }
509 
511 template <typename K,typename V>
512 const V& findOrThrow(const std::map<K,V,std::less<K>, std::allocator<std::pair<const K, V> > >& map, K key)
513 {
514  typename std::map<K,V>::const_iterator iter = map.find(key);
515  if(iter == map.end())
516  {
517  DtTHROW_NEW(DtInvalidInput,"Unable to find key");
518  }
519  return iter->second;
520 }
521 
523 template <typename K,typename V>
524 const V& findByIndexOrThrow(const std::map<K,V,std::less<K>, std::allocator<std::pair<const K, V> > >& map, int index)
525 {
526  if(index >= (int)map.size())
527  {
528  DtTHROW_NEW(DtInvalidInput,"Index out of range.");
529  }
530  typename std::map<K,V>::const_iterator i = map.begin();
531  std::advance(i,index);
532  return i->second;
533 }
534 
536 template <typename V>
537 const V& findByIndexOrThrow(const std::vector<V>& vec, int index)
538 {
539  if(index >= (int)vec.size())
540  {
541  DtTHROW_NEW(DtInvalidInput,"Index out of range.");
542  }
543  typename std::vector<V>::const_iterator i = vec.begin();
544  std::advance(i,index);
545  return *i;
546 }
547 
548 
549 }
Ret myValue
Definition: templateUtil.h:484
bool operator()(const T *a, const T *b) const
Definition: templateUtil.h:467
voidpf void uLong size
Definition: ioapi.h:39
void DtMemberFunctionCallback(DtDe *de, void *data)
Definition: templateUtil.h:273
EqualPointerByFunction_T< Ret, T > EqualPointerByFunction(Ret(T::*ptr)() const, Ret value)
Definition: templateUtil.h:505
const V & findByIndexOrThrow(const std::map< K, V, std::less< K >, std::allocator< std::pair< const K, V > > > &map, int index)
Find a value by index in a map, or throw an DtInvalidInput exception.
Definition: templateUtil.h:524
Ret callConstFunction1(const Class *_this, const Ret(Class::*memberPtr)(AT) const, AT param)
Definition: templateUtil.h:263
const V & findOrThrow(const std::map< K, V, std::less< K >, std::allocator< std::pair< const K, V > > > &map, K key)
Find a value in a map, or throw an DtInvalidInput exception.
Definition: templateUtil.h:512
void DtClearAndDeletePointersInMap(M &map)
Deletes all pointers in a map then clears it.
Definition: templateUtil.h:198
Definition: templateUtil.h:480
bool operator()(const T *a) const
Definition: templateUtil.h:498
SortPointersByFunction_T< Ret, T > SortPointersByFunction(Ret(T::*ptr)() const)
Definition: templateUtil.h:474
bool operator()(const std::pair< Key, Value > &a, const std::pair< Key, Value > &b) const
Definition: templateUtil.h:244
Definition: templateUtil.h:242
#define FAST_REPEATED_CALL(count, x)
Definition: templateUtil.h:152
SortPointersByFunction_T(MemberFnPtr memFun)
Definition: templateUtil.h:457
EqualPointerByFunction_T(MemberFnPtr memFun, Ret value)
Definition: templateUtil.h:486
MemberFnPtr myPtr
Definition: templateUtil.h:455
Definition: templateUtil.h:452
void DtDeletePointersInIterators(Iter begin, Iter end)
Definition: templateUtil.h:233
void DtClearAndDeletePointersInVector(V &vec)
Deletes all pointers in a vector then clears it.
Definition: templateUtil.h:218
SortPointersByFunction_T(const SortPointersByFunction_T< Ret, T > &second)
Definition: templateUtil.h:462
iter fastFindPred(size_t size, iter begin, iter end, const F &pred)
Definition: templateUtil.h:338
MemberFnPtr myPtr
Definition: templateUtil.h:483
V * DtFindPointerInMap(const std::map< K, V, Pr, Alloc > &map, K key)
Definition: templateUtil.h:179
void fastEraseFromUnsortedVectorPred(std::vector< T, Ax > &list, const Function &f)
Definition: templateUtil.h:400
EqualPointerByFunction_T(const SortPointersByFunction_T< Ret, T > &second)
Definition: templateUtil.h:492
Ret(T::* MemberFnPtr)() const
Definition: templateUtil.h:454
void forEachCallMember(T *_this, R(T::*memfun)(A), Col &col)
Definition: templateUtil.h:252
The DtDe is the core component of any VR-Vantage application. It owns a DtRenderer, DtDeCommunicator, as well as a DtDisplay and other things.
Definition: DtDe.h:70
iter fasterFind(size_t size, iter begin, iter end, const T &value)
boost::signalslib::signal&lt;void (Argument)&gt;&amp; forwarder)
Definition: templateUtil.h:331
void fastEraseFromUnsortedVector(std::vector< T, Ax > &list, const T &value)
Definition: templateUtil.h:345
Ret(T::* MemberFnPtr)() const
Definition: templateUtil.h:482
void set_split_difference(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator1 result1, OutputIterator2 result2)
Definition: templateUtil.h:279

Document ID: Generated on Sun Dec 4 20:22:03 EST 2022 from SVN revision 249613
Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)