ROOT logo
/**
 * @file   Option.C
 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
 * @date   Tue Oct 16 18:59:04 2012
 * 
 * @brief  
 * 
 * 
 * @ingroup pwglf_forward_trains_util
 */
#ifndef OPTION_C
#define OPTION_C
#include <TNamed.h>
#include <iomanip>
#ifndef __CINT__
# include <TString.h>
# include <TList.h>
# include <TObjArray.h>
# include <TObjString.h>
# include <TMath.h>
# include <iostream>
# include <iomanip>
# include <cstdarg>
# include <cstdio>
#else
class TString;
class TList;
class TObjArray;
#endif

/** 
 * An option.  The value is stored as a string 
 *
 * @ingroup pwglf_forward_trains_util
 */
struct Option /* : public TNamed */
{
  /** 
   * Constructor 
   * 
   * @param name           Name of option
   * @param arg            Dummy argument (possibly null)
   * @param description    Description
   * @param value          Default value 
   */
  Option(const TString& name, 
	 const TString& arg, 
	 const TString& description,
	 const TString& value)
    : fName(name), fDescription(description), 
      fValue(value), fArg(arg), fIsSet(false)
  {}
  /** 
   * Copy constructor 
   * 
   * @param other Object to copy from 
   */
  Option(const Option& other)
    : fName(other.fName), 
      fDescription(other.fDescription),
      fValue(other.fValue), 
      fArg(other.fArg), 
      fIsSet(other.fIsSet)
  {}
  /** 
   * Assignment operator 
   * 
   * @param other Object to assign from 
   *
   * @return Reference to this object
   */
  Option& operator=(const Option& other)
  {
    if (&other == this) return *this;
    
    fName        = other.fName;
    fDescription = other.fDescription;
    fValue       = other.fValue;
    fArg         = other.fArg;
    fIsSet       = other.fIsSet;
    
    return *this;
  }
  /** 
   * Set the value 
   * 
   * @param val New value 
   */
  void Set(const TString& val) 
  { 
    if (HasArg()) {
      fIsSet = true;
      fValue = val;
      // Info("Set", "Setting option %s with arg %s to %s", 
      // fName.Data(), fArg.Data(), fValue.Data());
      return;
    }

    // Info("Set", "Setting option %s with no arg", fName.Data());
    // Allow flags to get =true, =1, =false, =0 values
    if (!val.IsNull() && 
	(val.EqualTo("false", TString::kIgnoreCase) || 
	 (val.IsDigit() && !val.Atoi()))) {
      fIsSet = false;
      fValue = "false";
    }
    else {
      fIsSet = true;
      fValue = "true";
    }
  }
  /** 
   * Set the value
   */
  void Set() 
  { 
    if (HasArg()) { 
      Error("Option::Set", "Option %s needs an argument", fName.Data());
      return;
    }
    Set("true");
  }
  /** 
   * Reset the set flag
   * 
   */
  void Reset() 
  { 
    fIsSet = false; 
    if (!HasArg()) fValue = "false";
  }
  /**
   * @return constant reference to value 
   */
  const TString& Get() const { return fValue; }
  /**
   * @return true if this option was set externally
   */
  Bool_t IsSet() const { return fIsSet; }
  /**
   * @return true if this option needs an argument
   */
  Bool_t HasArg() const { return !fArg.IsNull(); }
  /**
   * @return value as a boolean value
   */
  Bool_t AsBool() const { return fIsSet; }
  /**
   * @return value as an integer value
   */
  Int_t    AsInt() const { return fValue.Atoi(); }
  /**
   * @return value as a long integer value
   */
  Long64_t AsLong() const { return fValue.Atoll(); } 
  /**
   * @return value as a double precision value
   */
  Double_t AsDouble() const { return fValue.Atof(); } 
  /**
   * @return value as a C string
   */
  const char* AsString() const { return fValue.Data(); } 
  /** 
   * @return Width of the name 
   */
  Int_t NameWidth() const { return fName.IsNull() ? 0 : fName.Length(); }
  /** 
   * @return the width of the dummy argument
   */
  Int_t ArgWidth() const { return fArg.IsNull() ? 0 : fArg.Length(); }
  /** 
   * Show help 
   * 
   * @param o Output stream 
   * @param w With of option plus argument 
   */
  void Help(std::ostream& o, Int_t w=-1) const
  {
    TString tmp(fName);
    if (HasArg()) { 
      tmp.Append("=");
      tmp.Append(fArg);
    }
    if (w <= 0) w = NameWidth() + ArgWidth() + 1;
    std::ios::fmtflags oldf = o.setf(std::ios::left);
    o << std::setw(w) << tmp << "  " << fDescription << " [";
    if (!HasArg()) o << (IsSet() ? "true" : "false");
    else           o << fValue;
    o << "]" << std::endl;
    o.setf(oldf);
  }
  /** 
   * Show the option
   * 
   * @param o Output stream
   * @param w With of name 
   */
  void Show(std::ostream& o, Int_t w=-1) const 
  {
    if (w <= 0) w = NameWidth();
    std::ios::fmtflags oldf = o.setf(std::ios::left);
    o << std::setw(w) << fName << ": ";
    if (!HasArg()) o << (IsSet() ? "true" : "false");
    else           o << fValue;
    o << std::endl;
    o.setf(oldf);
  }
  /** 
   * Store option and possible value 
   * 
   * @param o Output stream
   * @param quote If true, quote output 
   */
  void Store(std::ostream& o, bool quote=true) const 
  {
    o << fName;
    if (!HasArg()) return;
    o << "=" << (quote ? "\"" : "") << fValue << (quote ? "\"" : "");
  }
  TString fName;        // Name 
  TString fDescription; // Description
  TString fValue;       // Value 
  TString fArg;         // Argument dummy 
  Bool_t  fIsSet;       // True if this option was set 
  
  // ClassDef(Option,1) // Option 
};

/** 
 * A List of options 
 */
struct OptionList 
{
  // Linked list element
  struct Link 
  {
    Link*   fPrev;
    Link*   fNext;
    Option* fThis;
    Link() : fPrev(0), fNext(0), fThis(0) {}
    Link(Link* next, Option* opt)
      : fPrev(next ? next->fPrev : 0), // Set previous 
	fNext(next), // Set next link
	fThis(opt) // Set data
    {
      if (fPrev) fPrev->fNext = this; // Set forward link
      if (fNext) fNext->fPrev = this; // Set previous link
    }
    ~Link() { 
      if (fPrev) fPrev->fNext = fNext;
      if (fNext) fNext->fPrev = fPrev;
      delete fThis;
    }
    Link(const Link& o)
      : fPrev(o.fPrev), 
	fNext(o.fNext), 
	fThis(o.fThis)
    {
    }
    Link& operator=(const Link& o)
    {
      if (&o == this) return *this;
      fPrev = o.fPrev;
      fNext = o.fNext;
      fThis = o.fThis;
      return *this;
    }	
  };
  /** 
   * Constructor 
   */
  OptionList() : fList(0) { }
  /** 
   * Copy constructor 
   *
   * @param other Object to copy from 
   */
  OptionList(const OptionList& other) 
    : fList(0)
  { 
    // fList.SetOwner(); 
    // TIter next(&other.fList);
    // Option* o = 0;
    // while ((o = static_cast<Option*>(next()))) 
    //   fList.Add(new Option(*o));
    Copy(other);
  }
  /** 
   * Destructor 
   */
  ~OptionList() { Delete(); }

  /** 
   * Remove all options 
   */
  void Delete()
  { 
    Link* cur = fList;
    while (cur) {
      Link* tmp = cur->fNext;
      delete cur;
      cur = tmp;
      // Remove(cur->fThis->fName);
      // cur = tmp;
    }
    fList = 0;
  }
  /** 
   * Assignment operator 
   *
   * @param other  Object to assign from 
   *
   * @return reference to this 
   */
  OptionList& operator=(const OptionList& other) 
  { 
    if (&other == this) return *this;
    Delete();
    Copy(other);
    
    return *this; 
  }
  /** 
   * Copy list from other object
   * 
   * @param other Object to copy from 
   */
  void Copy(const OptionList& other)
  {
    Delete();
    const Link* ocur = other.fList;
    Link*       cur  = fList;
    Link*       prev = fList;
    while (ocur) { 
      cur        = new Link;
      cur->fThis = new Option(*(ocur->fThis));
      cur->fNext = 0;
      cur->fPrev = prev;
      if (fList == 0) fList = cur;
      if (prev)       prev->fNext = cur;
      prev = cur;
      ocur = ocur->fNext;
    }
  }
  void DebugLink(const Link* link) const
  {
    std::cout << "Link=" << link;
    if (link) {
      std::cout << " prev=" << link->fPrev 
		<< " next=" << link->fNext
		<< " obj=" << link->fThis;
      if (link->fThis) 
        std::cout << " name=" << link->fThis->fName;
    }
    std::cout <<std::endl;
  }
  /** 
   * Find an optio by name 
   * 
   * @param name Name of option to find
   * 
   * @return Pointer to option or null
   */
  Option* Find(const TString& name) const
  {
    const Link* cur = fList;
    // DebugLink(cur);
    while (cur && cur->fThis) { 
      if (name.EqualTo(cur->fThis->fName)) return cur->fThis;
      cur = cur->fNext;
    }
    return 0;
  }
  /** 
   * Add an option with argument 
   * 
   * @param name Name of option
   * @param arg  Dummy argument
   * @param desc Description
   * @param val  Default value 
   * 
   * @return Newly added option 
   */
  Option* Add(const TString& name, 
	      const TString& arg, 
	      const TString& desc, 
	      const TString& val="")
  {
    Option* o = Find(name);
    if (o) { 
      Warning("OptionList::Add", "Option %s already registered", name.Data());
      return o;
    }
    // Info("Add", "New option %s with arg %s (%s) and value %s",    
    //	 name.Data(), arg.Data(), desc.Data(), val.Data());
    o = new Option(name, arg, desc, val);
    Link*  cur  = fList;
    if (!cur) { 
      cur = new Link;
      cur->fThis = o;
      cur->fNext = 0;
      cur->fPrev = 0;
      fList      = cur;
    }
    else {
      Link* n = 0;
      Link* l = 0;
      while (cur) { 
	if (cur->fThis->fName.CompareTo(name) < 0) { 
	  l   = cur;
	  cur = cur->fNext;
	  continue;
	}
	n = new Link(cur, o);
	if (cur == fList) fList = n;
	break;
      }
      if (!n) { 
	n = new Link;
	l->fNext = n;
	n->fPrev = l;
	n->fNext = 0;
	n->fThis = o;
      }
    }
    return o;
  }
  /** 
   * Add an option with no argument
   * 
   * @param name Name of option
   * @param desc Description 
   * 
   * @return Newly created option 
   */
  Option* Add(const TString& name, 
	      const TString& desc)
  {
    return Add(name, "", desc, "");
  }
  /** 
   * Add an option with no argument
   * 
   * @param name Name of option
   * @param desc Description 
   * @param def  Default value (true, or false)
   * 
   * @return Newly created option 
   */
  Option* Add(const TString& name, 
	      const TString& desc,
	      Bool_t         def)
  {
    Option* o = Add(name, "", desc, "");
    if (o) o->Set(def ? "true" : "false");
    return o;
  }
  /** 
   * Add an option with argument 
   * 
   * @param name Name of option
   * @param arg  Dummy argument
   * @param desc Description
   * @param val  Default value 
   * @param asHex If true, interpret as hex number 
   * 
   * @return Newly added option 
   */
  Option* Add(const TString& name, 
	      const TString& arg, 
	      const TString& desc, 
	      Int_t          val, 
	      Bool_t         asHex=false)
  {
    if (asHex) {
      UInt_t uval = val;
      return Add(name, arg, desc, Form("0x%x", uval));
    }
    return Add(name, arg, desc, Form("%d", val));
  }
  /** 
   * Add an option with argument 
   * 
   * @param name Name of option
   * @param arg  Dummy argument
   * @param desc Description
   * @param val  Default value 
   * @param asHex If true, interpret as hex 
   * 
   * @return Newly added option 
   */
  Option* Add(const TString& name, 
	      const TString& arg, 
	      const TString& desc, 
	      Long64_t       val, 
	      Bool_t         asHex=false)
  {
    if (asHex) {
      ULong64_t uval = val;
      return Add(name, arg, desc, Form("0x%llx", uval));
    }
    return Add(name, arg, desc, Form("%lld", val));
  }
  /** 
   * Add an option with argument 
   * 
   * @param name Name of option
   * @param arg  Dummy argument
   * @param desc Description
   * @param val  Default value 
   * 
   * @return Newly added option 
   */
  Option* Add(const TString& name, 
	      const TString& arg, 
	      const TString& desc, 
	      Double_t val)
  {
    return Add(name, arg, desc, Form("%lg", val));
  }

  /** 
   * Remove an option 
   * 
   * @param name Name of option to remove 
   */
  void Remove(const TString& name)
  {
    Link* cur = fList;
    while (cur) { 
      if (!cur->fThis->fName.EqualTo(name)) {
	cur = cur->fNext;
	continue;
      }
      if (fList == cur) fList = cur->fNext;
      delete cur;
      break;
    }
  }
  /** 
   * Check if a given option was set externally
   * 
   * @param name Name of option
   * 
   * @return true if option exists and was set externally 
   */
  Bool_t Has(const TString& name) const
  {
    Option* o = Find(name);
    return (o && o->IsSet());
  }
  /** 
   * Get the value of an option
   * 
   * @param name Name of option
   * 
   * @return Value of option, or empty string 
   */
  const TString& Get(const TString& name) const
  {
    static TString null("");
    Option* o = Find(name);
    if (!o) return null;
    return o->Get();
  }
  /** 
   * Get a value using a format statement. Remember argument(s) must
   * be passed by address (as pointers)
   * 
   * @param name Name of option @param format Format statement.
   * Remeber, double and long needs the "l" modifier
   * 
   * @return true on success
   */
  Bool_t GetF(const TString& name, const Char_t* format, ...) const
  {
    Option* o = Find(name);
    if (!o) return false;
    
    va_list ap;
    va_start(ap, format);
    int ret = vsscanf(o->fValue.Data(), format, ap);
    va_end(ap);
    
    return ret > 0;
  }
  /** 
   * Get value of an option as a boolean 
   * 
   * @param name Name of 
   * 
   * @return Value or false if not found
   */
  Bool_t AsBool(const TString& name) const 
  {
    Option* o = Find(name);
    if (!o) return false;
    return o->AsBool();
  }
  /** 
   * Return value of an option as an integer
   * 
   * @param name Name of option 
   * @param def  Default value if options isn't found 
   * 
   * @return Value or default value 
   */
  Int_t AsInt(const TString& name, Int_t def=0) const
  {
    Option* o = Find(name);
    if (!o) return def;
    return o->AsInt();
  }
  /** 
   * Return value of an option as an integer
   * 
   * @param name Name of option 
   * @param def  Default value if options isn't found 
   * 
   * @return Value or default value 
   */
  Long64_t AsLong(const TString& name, Long64_t def=0) const
  {
    Option* o = Find(name);
    if (!o) return def;
    return o->AsLong();
  }
  /** 
   * Return value of an option as a double precision real number
   * 
   * @param name Name of option 
   * @param def  Default value if options isn't found 
   * 
   * @return Value or default value 
   */
  Double_t AsDouble(const TString& name, Double_t def=0) const
  {
    Option* o = Find(name);
    if (!o) return def;
    return o->AsDouble();
  }
  /** 
   * return value of an option as a string 
   * 
   * @param name Name of option
   * @param def  Default valie if option isn't found 
   * 
   * @return Value or default value
   */
  const char* AsString(const TString& name, const TString& def="") const
  {
    Option* o = Find(name);
    if (!o) return def.Data();
    return o->AsString();
  }
  /** 
   * return value of an option as a string 
   * 
   * @param name Name of option
   * @param def  Default valie if option isn't found 
   * 
   * @return Value or default value
   */
  const TString& AsTString(const TString& name, const TString& def="") const
  {
    Option* o = Find(name);
    if (!o) return def;
    return o->Get();
  }
  /** 
   * Set value using a format statement 
   * 
   * @param name   Name of option.
   * @param format Format statement
   */
  void SetF(const TString& name, const Char_t* format, ...)
  {
    Option* o = Find(name);
    if (!o) return;
    
    static char buf[1024];
    va_list ap;
    
    va_start(ap, format);
    vsnprintf(buf, 1023, format, ap);
    buf[1023] = '\0';
    va_end(ap);
    
    o->Set(buf);
  }
  /** 
   * Set an option
   * 
   * @param name   Name of option
   * @param value  Value of option
   */
  void Set(const TString& name, const TString& value)
  {
    Option* o = Find(name);
    if (!o) return;
    o->Set(value);
  }
  /** 
   * Set a flag 
   * 
   * @param name Name of flag 
   */
  void Set(const TString& name)
  {
    Option* o = Find(name);
    if (!o) return;
    o->Set();
  }   
  /** 
   * Set long integer value 
   * 
   * @param name Name of option
   * @param val  Value 
   * @param asHex If true, interpret as hex 
   */
  void Set(const TString& name, Int_t val, Bool_t asHex=false)
  {
    if (asHex) Set(name, Form("0x%x", val));
    else       Set(name, Form("%d", val));
  }
  /** 
   * Set long integer value 
   * 
   * @param name Name of option
   * @param val  Value 
   * @param asHex If true, interpret as hex value 
   */
  void Set(const TString& name, Long64_t val, Bool_t asHex=false)
  {
    ULong64_t uval = val;
    if (asHex) Set(name, Form("0x%llx", uval));
    else       Set(name, Form("%lld", val));
  }
  /** 
   * Set double precision floating point value 
   * 
   * @param name Name of option
   * @param val  Value 
   */
  void Set(const TString& name, Double_t val) 
  {
    Set(name, Form("%lg", val));
  }
  /** 
   * Parse the options given in tmp 
   * 
   * @param tmp     String to pass
   * @param delims  Delimiters 
   * 
   * @return true on success 
   */
  Bool_t Parse(const TString& tmp, const TString& delims)
  {
    TObjArray* opts = tmp.Tokenize(delims);
    // Info("OptionList::Parse", "Parsing options %s", tmp.Data());
    Bool_t ret = Parse(opts);
    opts->Delete();
    return ret;
  }
  /** 
   * Parse options given in a collection 
   * 
   * @param opts List of arguments 
   * @param ignoreUnknown If true, ignore unknown options 
   * 
   * @return true on success
   */
  Bool_t Parse(const TCollection* opts, Bool_t ignoreUnknown=false)
  {
    // Info("OptionList::Parse", "List of options");
    // opts->ls();
    TIter       next(opts);
    TObjString* o = 0;
    while ((o = static_cast<TObjString*>(next()))) { 
      TString& s   = o->String();
      TString  key = s;
      TString  val = "";
      Int_t    eq  = s.Index("=");
      if (eq != kNPOS) {
	key = s(0, eq);
	val = s(eq+1, s.Length()-eq-1);
      }

      // Info("OptionList::Parse", "Looking for key=%s", key.Data());
      Option*  opt = Find(key);
      if (!opt) { 
	if (!ignoreUnknown)
	  Warning("OptionList::Parse", "Unknown option: \"%s\"", s.Data());
	continue;
      }
      if (opt->HasArg() && val.IsNull()) { 
	Warning("OptionList::Parse", 
		"Option %s needs an argument, using default %s", 
		key.Data(), opt->fValue.Data());
	val = opt->fValue;
	// return false;
      }
      opt->Set(val);
    }
    return true;
  }
  /** 
   * Find the widest name and dummy argument
   * 
   * @param nWidth On return, the largest width of option names 
   * @param aWidth On return, the largest width of option dummy args
   */
  void Widest(Int_t& nWidth, Int_t& aWidth) const 
  {
    nWidth = 0;
    aWidth = 0;
    const Link* cur = fList;
    while (cur) { 
      Option* opt = cur->fThis;
      nWidth = TMath::Max(nWidth, opt->NameWidth());
      aWidth = TMath::Max(aWidth, opt->ArgWidth());
      cur = cur->fNext;
    }

    // while ((opt = static_cast<Option*>(next()))) {
    // }
  }
  /** 
   * Display option help
   * 
   * @param o Output stream 
   * @param prefix Prefix for each option.
   */
  void Help(std::ostream& o, const char* prefix="  ") const 
  {
    Int_t nWidth, aWidth;
    Widest(nWidth, aWidth);
    if (aWidth > 0) nWidth += aWidth+1;

    const Link* cur = fList;
    while (cur) { 
      Option* opt = cur->fThis;
      o << prefix;
      opt->Help(o, nWidth);
      cur = cur->fNext;
    }
  }
  /** 
   * Show the values of options 
   * 
   * @param o Output stream
   * @param prefix Prefix for each option
   */
  void Show(std::ostream& o, const char* prefix="  ") const 
  {
    Int_t nWidth, aWidth;
    Widest(nWidth, aWidth);


    const Link* cur = fList;
    while (cur) { 
      Option* opt = cur->fThis;
      o << prefix;
      opt->Show(o, nWidth);
      cur = cur->fNext;
    }
  }
  /** 
   * Show the values of options 
   * 
   * @param o Output stream
   * @param prefix Prefix for each option
   * @param delim Delimters 
   * @param quote Quote output 
   * @param onlySet if true, only output set options 
   */
  void Store(std::ostream& o, const char* prefix="", 
	     const char* delim=",", bool quote=true, 
	     bool onlySet=false) const 
  {
    Int_t nWidth, aWidth;
    Widest(nWidth, aWidth);

    const Link* cur = fList;
    while (cur) { 
      Option* opt = cur->fThis;
      if ((!opt->HasArg() || onlySet) && !opt->IsSet()) {
	cur = cur->fNext;
	continue;
      }
      o << prefix;
      opt->Store(o, quote);
      o << delim;
      cur = cur->fNext;
    }
  }
  // Our linked list
  Link* fList;

  static void Test(const char* opts="")
  {
    OptionList l;
    l.Add("int", "NUMBER", "Integer", "42");
    l.Add("float", "NUMBER", "Floating point", "3.14");
    l.Add("bool", "Flag");
    l.Add("hex", "NUMBER", "Hexadecimal", "0xdead");
    l.Add("string", "STRING", "A string", "Hello, world");
    l.Show(std::cout, "\t");
    
    std::cout << "Find" << std::endl;
    Option* b = l.Find("bool");
    b->Set("true");
    b->Show(std::cout);

    std::cout << "SetF" << std::endl;
    l.SetF("float", "%f", 2.17);
    l.Show(std::cout, "\t");
    
    std::cout << "GetF" << std::endl;
    Float_t f;
    l.GetF("float", "%f", &f);
    std::cout << "\tf=" << f << std::endl;
    std::cout << "Remove" << std::endl;
    l.Remove("float");
    l.Show(std::cout, "\t");

    std::cout << "Set" << std::endl;
    l.Set("int", "10");
    l.Set("hex", 0xbeef, true);
    l.Set("bool", "false");
    l.Show(std::cout, "\t");

    std::cout << "Copy" << std::endl;
    OptionList c(l);
    c.Show(std::cout, "\t");

    std::cout << "Parse" << std::endl;
    c.Parse(opts,",");
    c.Show(std::cout, "\t");
    std::cout << "End of test" << std::endl;
  }
  // TList fList;
};

#endif

 Option.C:1
 Option.C:2
 Option.C:3
 Option.C:4
 Option.C:5
 Option.C:6
 Option.C:7
 Option.C:8
 Option.C:9
 Option.C:10
 Option.C:11
 Option.C:12
 Option.C:13
 Option.C:14
 Option.C:15
 Option.C:16
 Option.C:17
 Option.C:18
 Option.C:19
 Option.C:20
 Option.C:21
 Option.C:22
 Option.C:23
 Option.C:24
 Option.C:25
 Option.C:26
 Option.C:27
 Option.C:28
 Option.C:29
 Option.C:30
 Option.C:31
 Option.C:32
 Option.C:33
 Option.C:34
 Option.C:35
 Option.C:36
 Option.C:37
 Option.C:38
 Option.C:39
 Option.C:40
 Option.C:41
 Option.C:42
 Option.C:43
 Option.C:44
 Option.C:45
 Option.C:46
 Option.C:47
 Option.C:48
 Option.C:49
 Option.C:50
 Option.C:51
 Option.C:52
 Option.C:53
 Option.C:54
 Option.C:55
 Option.C:56
 Option.C:57
 Option.C:58
 Option.C:59
 Option.C:60
 Option.C:61
 Option.C:62
 Option.C:63
 Option.C:64
 Option.C:65
 Option.C:66
 Option.C:67
 Option.C:68
 Option.C:69
 Option.C:70
 Option.C:71
 Option.C:72
 Option.C:73
 Option.C:74
 Option.C:75
 Option.C:76
 Option.C:77
 Option.C:78
 Option.C:79
 Option.C:80
 Option.C:81
 Option.C:82
 Option.C:83
 Option.C:84
 Option.C:85
 Option.C:86
 Option.C:87
 Option.C:88
 Option.C:89
 Option.C:90
 Option.C:91
 Option.C:92
 Option.C:93
 Option.C:94
 Option.C:95
 Option.C:96
 Option.C:97
 Option.C:98
 Option.C:99
 Option.C:100
 Option.C:101
 Option.C:102
 Option.C:103
 Option.C:104
 Option.C:105
 Option.C:106
 Option.C:107
 Option.C:108
 Option.C:109
 Option.C:110
 Option.C:111
 Option.C:112
 Option.C:113
 Option.C:114
 Option.C:115
 Option.C:116
 Option.C:117
 Option.C:118
 Option.C:119
 Option.C:120
 Option.C:121
 Option.C:122
 Option.C:123
 Option.C:124
 Option.C:125
 Option.C:126
 Option.C:127
 Option.C:128
 Option.C:129
 Option.C:130
 Option.C:131
 Option.C:132
 Option.C:133
 Option.C:134
 Option.C:135
 Option.C:136
 Option.C:137
 Option.C:138
 Option.C:139
 Option.C:140
 Option.C:141
 Option.C:142
 Option.C:143
 Option.C:144
 Option.C:145
 Option.C:146
 Option.C:147
 Option.C:148
 Option.C:149
 Option.C:150
 Option.C:151
 Option.C:152
 Option.C:153
 Option.C:154
 Option.C:155
 Option.C:156
 Option.C:157
 Option.C:158
 Option.C:159
 Option.C:160
 Option.C:161
 Option.C:162
 Option.C:163
 Option.C:164
 Option.C:165
 Option.C:166
 Option.C:167
 Option.C:168
 Option.C:169
 Option.C:170
 Option.C:171
 Option.C:172
 Option.C:173
 Option.C:174
 Option.C:175
 Option.C:176
 Option.C:177
 Option.C:178
 Option.C:179
 Option.C:180
 Option.C:181
 Option.C:182
 Option.C:183
 Option.C:184
 Option.C:185
 Option.C:186
 Option.C:187
 Option.C:188
 Option.C:189
 Option.C:190
 Option.C:191
 Option.C:192
 Option.C:193
 Option.C:194
 Option.C:195
 Option.C:196
 Option.C:197
 Option.C:198
 Option.C:199
 Option.C:200
 Option.C:201
 Option.C:202
 Option.C:203
 Option.C:204
 Option.C:205
 Option.C:206
 Option.C:207
 Option.C:208
 Option.C:209
 Option.C:210
 Option.C:211
 Option.C:212
 Option.C:213
 Option.C:214
 Option.C:215
 Option.C:216
 Option.C:217
 Option.C:218
 Option.C:219
 Option.C:220
 Option.C:221
 Option.C:222
 Option.C:223
 Option.C:224
 Option.C:225
 Option.C:226
 Option.C:227
 Option.C:228
 Option.C:229
 Option.C:230
 Option.C:231
 Option.C:232
 Option.C:233
 Option.C:234
 Option.C:235
 Option.C:236
 Option.C:237
 Option.C:238
 Option.C:239
 Option.C:240
 Option.C:241
 Option.C:242
 Option.C:243
 Option.C:244
 Option.C:245
 Option.C:246
 Option.C:247
 Option.C:248
 Option.C:249
 Option.C:250
 Option.C:251
 Option.C:252
 Option.C:253
 Option.C:254
 Option.C:255
 Option.C:256
 Option.C:257
 Option.C:258
 Option.C:259
 Option.C:260
 Option.C:261
 Option.C:262
 Option.C:263
 Option.C:264
 Option.C:265
 Option.C:266
 Option.C:267
 Option.C:268
 Option.C:269
 Option.C:270
 Option.C:271
 Option.C:272
 Option.C:273
 Option.C:274
 Option.C:275
 Option.C:276
 Option.C:277
 Option.C:278
 Option.C:279
 Option.C:280
 Option.C:281
 Option.C:282
 Option.C:283
 Option.C:284
 Option.C:285
 Option.C:286
 Option.C:287
 Option.C:288
 Option.C:289
 Option.C:290
 Option.C:291
 Option.C:292
 Option.C:293
 Option.C:294
 Option.C:295
 Option.C:296
 Option.C:297
 Option.C:298
 Option.C:299
 Option.C:300
 Option.C:301
 Option.C:302
 Option.C:303
 Option.C:304
 Option.C:305
 Option.C:306
 Option.C:307
 Option.C:308
 Option.C:309
 Option.C:310
 Option.C:311
 Option.C:312
 Option.C:313
 Option.C:314
 Option.C:315
 Option.C:316
 Option.C:317
 Option.C:318
 Option.C:319
 Option.C:320
 Option.C:321
 Option.C:322
 Option.C:323
 Option.C:324
 Option.C:325
 Option.C:326
 Option.C:327
 Option.C:328
 Option.C:329
 Option.C:330
 Option.C:331
 Option.C:332
 Option.C:333
 Option.C:334
 Option.C:335
 Option.C:336
 Option.C:337
 Option.C:338
 Option.C:339
 Option.C:340
 Option.C:341
 Option.C:342
 Option.C:343
 Option.C:344
 Option.C:345
 Option.C:346
 Option.C:347
 Option.C:348
 Option.C:349
 Option.C:350
 Option.C:351
 Option.C:352
 Option.C:353
 Option.C:354
 Option.C:355
 Option.C:356
 Option.C:357
 Option.C:358
 Option.C:359
 Option.C:360
 Option.C:361
 Option.C:362
 Option.C:363
 Option.C:364
 Option.C:365
 Option.C:366
 Option.C:367
 Option.C:368
 Option.C:369
 Option.C:370
 Option.C:371
 Option.C:372
 Option.C:373
 Option.C:374
 Option.C:375
 Option.C:376
 Option.C:377
 Option.C:378
 Option.C:379
 Option.C:380
 Option.C:381
 Option.C:382
 Option.C:383
 Option.C:384
 Option.C:385
 Option.C:386
 Option.C:387
 Option.C:388
 Option.C:389
 Option.C:390
 Option.C:391
 Option.C:392
 Option.C:393
 Option.C:394
 Option.C:395
 Option.C:396
 Option.C:397
 Option.C:398
 Option.C:399
 Option.C:400
 Option.C:401
 Option.C:402
 Option.C:403
 Option.C:404
 Option.C:405
 Option.C:406
 Option.C:407
 Option.C:408
 Option.C:409
 Option.C:410
 Option.C:411
 Option.C:412
 Option.C:413
 Option.C:414
 Option.C:415
 Option.C:416
 Option.C:417
 Option.C:418
 Option.C:419
 Option.C:420
 Option.C:421
 Option.C:422
 Option.C:423
 Option.C:424
 Option.C:425
 Option.C:426
 Option.C:427
 Option.C:428
 Option.C:429
 Option.C:430
 Option.C:431
 Option.C:432
 Option.C:433
 Option.C:434
 Option.C:435
 Option.C:436
 Option.C:437
 Option.C:438
 Option.C:439
 Option.C:440
 Option.C:441
 Option.C:442
 Option.C:443
 Option.C:444
 Option.C:445
 Option.C:446
 Option.C:447
 Option.C:448
 Option.C:449
 Option.C:450
 Option.C:451
 Option.C:452
 Option.C:453
 Option.C:454
 Option.C:455
 Option.C:456
 Option.C:457
 Option.C:458
 Option.C:459
 Option.C:460
 Option.C:461
 Option.C:462
 Option.C:463
 Option.C:464
 Option.C:465
 Option.C:466
 Option.C:467
 Option.C:468
 Option.C:469
 Option.C:470
 Option.C:471
 Option.C:472
 Option.C:473
 Option.C:474
 Option.C:475
 Option.C:476
 Option.C:477
 Option.C:478
 Option.C:479
 Option.C:480
 Option.C:481
 Option.C:482
 Option.C:483
 Option.C:484
 Option.C:485
 Option.C:486
 Option.C:487
 Option.C:488
 Option.C:489
 Option.C:490
 Option.C:491
 Option.C:492
 Option.C:493
 Option.C:494
 Option.C:495
 Option.C:496
 Option.C:497
 Option.C:498
 Option.C:499
 Option.C:500
 Option.C:501
 Option.C:502
 Option.C:503
 Option.C:504
 Option.C:505
 Option.C:506
 Option.C:507
 Option.C:508
 Option.C:509
 Option.C:510
 Option.C:511
 Option.C:512
 Option.C:513
 Option.C:514
 Option.C:515
 Option.C:516
 Option.C:517
 Option.C:518
 Option.C:519
 Option.C:520
 Option.C:521
 Option.C:522
 Option.C:523
 Option.C:524
 Option.C:525
 Option.C:526
 Option.C:527
 Option.C:528
 Option.C:529
 Option.C:530
 Option.C:531
 Option.C:532
 Option.C:533
 Option.C:534
 Option.C:535
 Option.C:536
 Option.C:537
 Option.C:538
 Option.C:539
 Option.C:540
 Option.C:541
 Option.C:542
 Option.C:543
 Option.C:544
 Option.C:545
 Option.C:546
 Option.C:547
 Option.C:548
 Option.C:549
 Option.C:550
 Option.C:551
 Option.C:552
 Option.C:553
 Option.C:554
 Option.C:555
 Option.C:556
 Option.C:557
 Option.C:558
 Option.C:559
 Option.C:560
 Option.C:561
 Option.C:562
 Option.C:563
 Option.C:564
 Option.C:565
 Option.C:566
 Option.C:567
 Option.C:568
 Option.C:569
 Option.C:570
 Option.C:571
 Option.C:572
 Option.C:573
 Option.C:574
 Option.C:575
 Option.C:576
 Option.C:577
 Option.C:578
 Option.C:579
 Option.C:580
 Option.C:581
 Option.C:582
 Option.C:583
 Option.C:584
 Option.C:585
 Option.C:586
 Option.C:587
 Option.C:588
 Option.C:589
 Option.C:590
 Option.C:591
 Option.C:592
 Option.C:593
 Option.C:594
 Option.C:595
 Option.C:596
 Option.C:597
 Option.C:598
 Option.C:599
 Option.C:600
 Option.C:601
 Option.C:602
 Option.C:603
 Option.C:604
 Option.C:605
 Option.C:606
 Option.C:607
 Option.C:608
 Option.C:609
 Option.C:610
 Option.C:611
 Option.C:612
 Option.C:613
 Option.C:614
 Option.C:615
 Option.C:616
 Option.C:617
 Option.C:618
 Option.C:619
 Option.C:620
 Option.C:621
 Option.C:622
 Option.C:623
 Option.C:624
 Option.C:625
 Option.C:626
 Option.C:627
 Option.C:628
 Option.C:629
 Option.C:630
 Option.C:631
 Option.C:632
 Option.C:633
 Option.C:634
 Option.C:635
 Option.C:636
 Option.C:637
 Option.C:638
 Option.C:639
 Option.C:640
 Option.C:641
 Option.C:642
 Option.C:643
 Option.C:644
 Option.C:645
 Option.C:646
 Option.C:647
 Option.C:648
 Option.C:649
 Option.C:650
 Option.C:651
 Option.C:652
 Option.C:653
 Option.C:654
 Option.C:655
 Option.C:656
 Option.C:657
 Option.C:658
 Option.C:659
 Option.C:660
 Option.C:661
 Option.C:662
 Option.C:663
 Option.C:664
 Option.C:665
 Option.C:666
 Option.C:667
 Option.C:668
 Option.C:669
 Option.C:670
 Option.C:671
 Option.C:672
 Option.C:673
 Option.C:674
 Option.C:675
 Option.C:676
 Option.C:677
 Option.C:678
 Option.C:679
 Option.C:680
 Option.C:681
 Option.C:682
 Option.C:683
 Option.C:684
 Option.C:685
 Option.C:686
 Option.C:687
 Option.C:688
 Option.C:689
 Option.C:690
 Option.C:691
 Option.C:692
 Option.C:693
 Option.C:694
 Option.C:695
 Option.C:696
 Option.C:697
 Option.C:698
 Option.C:699
 Option.C:700
 Option.C:701
 Option.C:702
 Option.C:703
 Option.C:704
 Option.C:705
 Option.C:706
 Option.C:707
 Option.C:708
 Option.C:709
 Option.C:710
 Option.C:711
 Option.C:712
 Option.C:713
 Option.C:714
 Option.C:715
 Option.C:716
 Option.C:717
 Option.C:718
 Option.C:719
 Option.C:720
 Option.C:721
 Option.C:722
 Option.C:723
 Option.C:724
 Option.C:725
 Option.C:726
 Option.C:727
 Option.C:728
 Option.C:729
 Option.C:730
 Option.C:731
 Option.C:732
 Option.C:733
 Option.C:734
 Option.C:735
 Option.C:736
 Option.C:737
 Option.C:738
 Option.C:739
 Option.C:740
 Option.C:741
 Option.C:742
 Option.C:743
 Option.C:744
 Option.C:745
 Option.C:746
 Option.C:747
 Option.C:748
 Option.C:749
 Option.C:750
 Option.C:751
 Option.C:752
 Option.C:753
 Option.C:754
 Option.C:755
 Option.C:756
 Option.C:757
 Option.C:758
 Option.C:759
 Option.C:760
 Option.C:761
 Option.C:762
 Option.C:763
 Option.C:764
 Option.C:765
 Option.C:766
 Option.C:767
 Option.C:768
 Option.C:769
 Option.C:770
 Option.C:771
 Option.C:772
 Option.C:773
 Option.C:774
 Option.C:775
 Option.C:776
 Option.C:777
 Option.C:778
 Option.C:779
 Option.C:780
 Option.C:781
 Option.C:782
 Option.C:783
 Option.C:784
 Option.C:785
 Option.C:786
 Option.C:787
 Option.C:788
 Option.C:789
 Option.C:790
 Option.C:791
 Option.C:792
 Option.C:793
 Option.C:794
 Option.C:795
 Option.C:796
 Option.C:797
 Option.C:798
 Option.C:799
 Option.C:800
 Option.C:801
 Option.C:802
 Option.C:803
 Option.C:804
 Option.C:805
 Option.C:806
 Option.C:807
 Option.C:808
 Option.C:809
 Option.C:810
 Option.C:811
 Option.C:812
 Option.C:813
 Option.C:814
 Option.C:815
 Option.C:816
 Option.C:817
 Option.C:818
 Option.C:819
 Option.C:820
 Option.C:821
 Option.C:822
 Option.C:823
 Option.C:824
 Option.C:825
 Option.C:826
 Option.C:827
 Option.C:828
 Option.C:829
 Option.C:830
 Option.C:831
 Option.C:832
 Option.C:833
 Option.C:834
 Option.C:835
 Option.C:836
 Option.C:837
 Option.C:838
 Option.C:839
 Option.C:840
 Option.C:841
 Option.C:842
 Option.C:843
 Option.C:844
 Option.C:845
 Option.C:846
 Option.C:847
 Option.C:848
 Option.C:849
 Option.C:850
 Option.C:851
 Option.C:852
 Option.C:853
 Option.C:854
 Option.C:855
 Option.C:856
 Option.C:857
 Option.C:858
 Option.C:859
 Option.C:860
 Option.C:861
 Option.C:862
 Option.C:863
 Option.C:864
 Option.C:865
 Option.C:866
 Option.C:867
 Option.C:868
 Option.C:869
 Option.C:870
 Option.C:871
 Option.C:872
 Option.C:873
 Option.C:874
 Option.C:875
 Option.C:876
 Option.C:877
 Option.C:878
 Option.C:879
 Option.C:880
 Option.C:881
 Option.C:882
 Option.C:883
 Option.C:884
 Option.C:885
 Option.C:886
 Option.C:887
 Option.C:888
 Option.C:889
 Option.C:890
 Option.C:891
 Option.C:892
 Option.C:893
 Option.C:894
 Option.C:895
 Option.C:896
 Option.C:897
 Option.C:898
 Option.C:899
 Option.C:900
 Option.C:901
 Option.C:902
 Option.C:903
 Option.C:904
 Option.C:905
 Option.C:906
 Option.C:907
 Option.C:908
 Option.C:909
 Option.C:910
 Option.C:911
 Option.C:912
 Option.C:913
 Option.C:914
 Option.C:915
 Option.C:916
 Option.C:917
 Option.C:918
 Option.C:919
 Option.C:920
 Option.C:921
 Option.C:922
 Option.C:923
 Option.C:924
 Option.C:925
 Option.C:926
 Option.C:927
 Option.C:928
 Option.C:929
 Option.C:930
 Option.C:931
 Option.C:932
 Option.C:933
 Option.C:934
 Option.C:935
 Option.C:936
 Option.C:937
 Option.C:938
 Option.C:939
 Option.C:940
 Option.C:941
 Option.C:942
 Option.C:943
 Option.C:944
 Option.C:945
 Option.C:946
 Option.C:947
 Option.C:948