text:
#include <ostream>
#include "fit_mesg.hpp"
#include "fit_mesg_definition.hpp"
#include "fit_factory.hpp"

namespace fit
{

Mesg::Mesg()
: profile(FIT_NULL), localNum(0), fields()
{
}

Mesg::Mesg(const Mesg &mesg)
: profile(mesg.profile), localNum(mesg.localNum), fields(mesg.fields)
{
}

Mesg::Mesg(const Profile::MESG_INDEX index)
: profile(&Profile::mesgs[index]), localNum(0), fields()
{
}

Mesg::Mesg(const std::string& name)
: profile(Profile::GetMesg(name)), localNum(0), fields()
{
}

Mesg::Mesg(const FIT_UINT16 num)
: profile(Profile::GetMesg(num)), localNum(0), fields()
{
}

FIT_BOOL Mesg::IsValid(void) const
{
   return (profile != FIT_NULL);
}

int Mesg::Write(std::ostream& file, const MesgDefinition* mesgDef) const
{
   MesgDefinition mesgDefOnNull;
   FIT_UINT8 mesgSize = 1;

   file.put((localNum & FIT_HDR_TYPE_MASK)); // Message record header with local message number.

   if (mesgDef == FIT_NULL)
   {
      mesgDefOnNull = MesgDefinition(*this);
      mesgDef = &mesgDefOnNull;
   }

   for (FIT_UINT16 fieldDefIndex = 0; fieldDefIndex < (mesgDef->GetFields().size()); fieldDefIndex++)
   {
      const Field* field = GetField(mesgDef->GetFieldByIndex(fieldDefIndex)->GetNum());
      FIT_UINT8 fieldSize = 0;

      if (field != FIT_NULL)
      {
         fieldSize = field->Write(file);

         if (fieldSize == 0)
            return 0;
      }

      if (fieldSize < (mesgDef->GetFieldByIndex(fieldDefIndex)->GetSize()))
      {
         FIT_UINT8 baseTypeNum = ((mesgDef->GetFieldByIndex(fieldDefIndex)->GetType()) & FIT_BASE_TYPE_NUM_MASK);

         if (baseTypeNum < FIT_BASE_TYPES)
         {
            FIT_UINT8 baseTypeByteIndex = (fieldSize % (baseTypeSizes[baseTypeNum]));
            FIT_UINT8 numBytesRemaining = (mesgDef->GetFieldByIndex(fieldDefIndex)->GetSize()) - fieldSize;

            while (numBytesRemaining--)
            {
               file.put(*(baseTypeInvalids[baseTypeNum] + baseTypeByteIndex));

               if ((++baseTypeByteIndex) >= baseTypeSizes[baseTypeNum])
                  baseTypeByteIndex = 0;

               fieldSize++;
            }
         }
         else
         {
            return 0;   // Do not continue if base type not supported.
         }
      }

      mesgSize += fieldSize;
   }

   return mesgSize;
}

std::string Mesg::GetName() const
{
   if (profile == FIT_NULL)
      return "unknown";

   return profile->name;
}

FIT_UINT16 Mesg::GetNum() const
{
   if (profile == FIT_NULL)
      return FIT_MESG_NUM_INVALID;

   return profile->num;
}

FIT_UINT8 Mesg::GetLocalNum() const
{
   return localNum;
}

void Mesg::SetLocalNum(const FIT_UINT8 newLocalNum)
{
   if (newLocalNum < FIT_MAX_LOCAL_MESGS)
      localNum = newLocalNum;
}

FIT_BOOL Mesg::HasField(const int fieldNum) const
{
   for (int i = 0; i < (int)fields.size(); i++)
   {
      if (fields[i].GetNum() == fieldNum)
         return FIT_TRUE;
   }

   return FIT_FALSE;
}

void Mesg::AddField(const Field& field)
{
   Field *existingField = GetField(field.GetNum());

   if (existingField == FIT_NULL)
      fields.push_back(field);
}

Field* Mesg::AddField(const FIT_UINT8 fieldNum)
{
   Field *field = GetField(fieldNum);

   if (field == FIT_NULL)
   {
      fields.push_back(Field(profile->num, fieldNum));
      field = &fields[fields.size() - 1];
   }

   return field;
}

void Mesg::SetField(const Field& field)
{
   for (int i = 0; i < (int)fields.size(); i++)
   {
      if (fields[i].GetNum() == field.GetNum())
      {
         fields[i] = field;
         return;
      }
   }

   fields.push_back(field);
}

void Mesg::SetFields(const Mesg& mesg)
{
   if (mesg.GetNum() != GetNum())
      return;

   for (int i=0; i < (int)mesg.fields.size(); i++)
      SetField(mesg.fields[i]);
}

int Mesg::GetNumFields() const
{
   return (int)fields.size();
}

Field* Mesg::GetFieldByIndex(const FIT_UINT16 index)
{
   if (index < fields.size())
      return &fields[index];

   return FIT_NULL;
}

Field* Mesg::GetField(const FIT_UINT8 fieldNum)
{
   for (int i = 0; i < (int)fields.size(); i++)
   {
      if (fields[i].GetNum() == fieldNum)
         return &fields[i];
   }

   return FIT_NULL;
}

Field* Mesg::GetField(const std::string& name)
{
   for (int i = 0; i < (int)fields.size(); i++)
   {
      if (fields[i].GetName().compare(name) == 0)
         return &fields[i];

      for (int j = 0; j < (int)fields[i].GetNumSubFields(); j++)
      {
         if ((fields[i].GetName(j).compare(name) == 0) && CanSupportSubField(&(fields[i]),j))
            return &fields[i];
      }
   }

   return FIT_NULL;
}

const Field* Mesg::GetFieldByIndex(const FIT_UINT16 index) const
{
   if (index < fields.size())
      return &fields[index];

   return FIT_NULL;
}

const Field* Mesg::GetField(const FIT_UINT8 fieldNum) const
{
   for (int i = 0; i < (int)fields.size(); i++)
   {
      if (fields[i].GetNum() == fieldNum)
         return &fields[i];
   }

   return FIT_NULL;
}

const Field* Mesg::GetField(const std::string& name) const
{
   for (int i = 0; i < (int)fields.size(); i++)
   {
      if (fields[i].GetName().compare(name) == 0)
         return &fields[i];

      for (int j = 0; j < (int)fields[i].GetNumSubFields(); j++)
      {
         if ((fields[i].GetName(j).compare(name) == 0) && CanSupportSubField(&(fields[i]),j))
            return &fields[i];
      }
   }

   return FIT_NULL;
}

FIT_BOOL Mesg::CanSupportSubField(const FIT_UINT8 fieldNum, const FIT_UINT16 subFieldIndex) const
{
   if ((subFieldIndex == FIT_SUBFIELD_INDEX_MAIN_FIELD) || (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD))
      return FIT_TRUE;

   const Profile::SUBFIELD* subField = Profile::GetSubField(GetNum(), fieldNum, subFieldIndex);

   if (subField == FIT_NULL)
      return FIT_FALSE;

   for (int i = 0; i < (int) subField->numMaps; i++)
   {
      const Field* refField = GetField(subField->maps[i].refFieldNum);

      if (refField != FIT_NULL)
      {
         FIT_FLOAT64 refValue = refField->GetFLOAT64Value(0, FIT_SUBFIELD_INDEX_MAIN_FIELD);
         refValue += ((refValue >= 0.0) ? (0.5) : (-0.5));
         if ((FIT_SINT32)refValue == subField->maps[i].refFieldValue)
            return FIT_TRUE;
      }
   }

   return FIT_FALSE;
}

FIT_BOOL Mesg::CanSupportSubField(const Field* field, const FIT_UINT16 subFieldIndex) const
{
   if ((subFieldIndex == FIT_SUBFIELD_INDEX_MAIN_FIELD) || (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD))
      return FIT_TRUE;

   if (field == FIT_NULL)
      return FIT_FALSE;

   const Profile::SUBFIELD* subField = field->GetSubField(subFieldIndex);

   if (subField == FIT_NULL)
      return FIT_FALSE;

   for (int i = 0; i < (int) subField->numMaps; i++)
   {
      const Field* refField = GetField(subField->maps[i].refFieldNum);

      if (refField != FIT_NULL)
      {
         FIT_FLOAT64 refValue = refField->GetFLOAT64Value(0, FIT_SUBFIELD_INDEX_MAIN_FIELD);
         refValue += ((refValue >= 0.0) ? (0.5) : (-0.5));
         if ((FIT_SINT32)refValue == subField->maps[i].refFieldValue)
            return FIT_TRUE;
      }
   }

   return FIT_FALSE;
}

FIT_UINT16 Mesg::GetActiveSubFieldIndexByFieldIndex(const FIT_UINT16 fieldIndex) const
{
   if ((int) fieldIndex >= GetNumFields())
      return FIT_SUBFIELD_INDEX_MAIN_FIELD;

   for (int i = 0; i < (int) fields[fieldIndex].GetNumSubFields(); i++)
   {
      const Profile::SUBFIELD* subField = fields[fieldIndex].GetSubField(i);

      if (subField != FIT_NULL)
      {
         for (int j = 0; j < (int) subField->numMaps; j++)
         {
            const Field* refField = GetField(subField->maps[j].refFieldNum);

            if (refField != FIT_NULL)
            {
               FIT_FLOAT64 refValue = refField->GetFLOAT64Value(0, FIT_SUBFIELD_INDEX_MAIN_FIELD);
               refValue += ((refValue >= 0.0) ? (0.5) : (-0.5));
               if ((FIT_SINT32)refValue == subField->maps[j].refFieldValue)
                  return ((FIT_UINT16) i);
            }
         }
      }
   }

   return FIT_SUBFIELD_INDEX_MAIN_FIELD;
}

FIT_UINT16 Mesg::GetActiveSubFieldIndex(const FIT_UINT8 fieldNum) const
{
   const Profile::FIELD* field = Profile::GetField(GetNum(), fieldNum);

   if (field == FIT_NULL)
      return FIT_SUBFIELD_INDEX_MAIN_FIELD;

   for (int i = 0; i < (int) field->numSubFields; i++)
   {
      const Profile::SUBFIELD& subField = field->subFields[i];

      for (int j = 0; j < (int) subField.numMaps; j++)
      {
         const Field* refField = GetField(subField.maps[j].refFieldNum);

         if (refField != FIT_NULL)
         {
            FIT_FLOAT64 refValue = refField->GetFLOAT64Value(0, FIT_SUBFIELD_INDEX_MAIN_FIELD);
            refValue += ((refValue >= 0.0) ? (0.5) : (-0.5));
            if ((FIT_SINT32)refValue == subField.maps[j].refFieldValue)
               return ((FIT_UINT16) i);
         }
      }
   }

   return FIT_SUBFIELD_INDEX_MAIN_FIELD;
}

FIT_UINT8 Mesg::GetFieldNumValues(const FIT_UINT8 fieldNum, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return 0;

   return field->GetNumValues();
}

FIT_ENUM Mesg::GetFieldENUMValue(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_ENUM_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetENUMValue(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetENUMValue(fieldArrayIndex, subFieldIndex);
}

FIT_BYTE Mesg::GetFieldBYTEValue(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_BYTE_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetBYTEValue(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetBYTEValue(fieldArrayIndex, subFieldIndex);
}

FIT_SINT8 Mesg::GetFieldSINT8Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_SINT8_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetSINT8Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetSINT8Value(fieldArrayIndex, subFieldIndex);
}

FIT_UINT8 Mesg::GetFieldUINT8Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_UINT8_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetUINT8Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetUINT8Value(fieldArrayIndex, subFieldIndex);
}

FIT_UINT8Z Mesg::GetFieldUINT8ZValue(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_UINT8Z_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetUINT8ZValue(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetUINT8ZValue(fieldArrayIndex, subFieldIndex);
}

FIT_SINT16 Mesg::GetFieldSINT16Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_SINT16_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetSINT16Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetSINT16Value(fieldArrayIndex, subFieldIndex);
}

FIT_UINT16 Mesg::GetFieldUINT16Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_UINT16_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetUINT16Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetUINT16Value(fieldArrayIndex, subFieldIndex);
}

FIT_UINT16Z Mesg::GetFieldUINT16ZValue(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_UINT16Z_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetUINT16ZValue(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetUINT16ZValue(fieldArrayIndex, subFieldIndex);
}

FIT_SINT32 Mesg::GetFieldSINT32Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_SINT32_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetSINT32Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetSINT32Value(fieldArrayIndex, subFieldIndex);
}

FIT_UINT32 Mesg::GetFieldUINT32Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_UINT32_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetUINT32Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetUINT32Value(fieldArrayIndex, subFieldIndex);
}

FIT_UINT32Z Mesg::GetFieldUINT32ZValue(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_UINT32Z_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetUINT32ZValue(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetUINT32ZValue(fieldArrayIndex, subFieldIndex);
}

FIT_FLOAT32 Mesg::GetFieldFLOAT32Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_FLOAT32_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetFLOAT32Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetFLOAT32Value(fieldArrayIndex, subFieldIndex);
}

FIT_FLOAT64 Mesg::GetFieldFLOAT64Value(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_FLOAT64_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetFLOAT64Value(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetFLOAT64Value(fieldArrayIndex, subFieldIndex);
}

FIT_WSTRING Mesg::GetFieldSTRINGValue(const FIT_UINT8 fieldNum, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex) const
{
   const Field *field = GetField(fieldNum);

   if ((field == FIT_NULL) || (!CanSupportSubField(fieldNum, subFieldIndex)))
      return FIT_WSTRING_INVALID;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->GetSTRINGValue(fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->GetSTRINGValue(fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldENUMValue(const FIT_UINT8 fieldNum, const FIT_ENUM value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetENUMValue(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetENUMValue(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldBYTEValue(const FIT_UINT8 fieldNum, const FIT_BYTE value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetBYTEValue(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetBYTEValue(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldSINT8Value(const FIT_UINT8 fieldNum, const FIT_SINT8 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetSINT8Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetSINT8Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldUINT8Value(const FIT_UINT8 fieldNum, const FIT_UINT8 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetUINT8Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetUINT8Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldUINT8ZValue(const FIT_UINT8 fieldNum, const FIT_UINT8 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetUINT8ZValue(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetUINT8ZValue(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldSINT16Value(const FIT_UINT8 fieldNum, const FIT_SINT16 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetSINT16Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetSINT16Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldUINT16Value(const FIT_UINT8 fieldNum, const FIT_UINT16 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetUINT16Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetUINT16Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldUINT16ZValue(const FIT_UINT8 fieldNum, const FIT_UINT16Z value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetUINT16ZValue(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetUINT16ZValue(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldSINT32Value(const FIT_UINT8 fieldNum, const FIT_SINT32 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetSINT32Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetSINT32Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldUINT32Value(const FIT_UINT8 fieldNum, const FIT_UINT32 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetUINT32Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetUINT32Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldUINT32ZValue(const FIT_UINT8 fieldNum, const FIT_UINT32Z value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetUINT32ZValue(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetUINT32ZValue(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldFLOAT32Value(const FIT_UINT8 fieldNum, const FIT_FLOAT32 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetFLOAT32Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetFLOAT32Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldFLOAT64Value(const FIT_UINT8 fieldNum, const FIT_FLOAT64 value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetFLOAT64Value(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetFLOAT64Value(value, fieldArrayIndex, subFieldIndex);
}

void Mesg::SetFieldSTRINGValue(const FIT_UINT8 fieldNum, const FIT_WSTRING& value, const FIT_UINT8 fieldArrayIndex, const FIT_UINT16 subFieldIndex)
{
   if (!CanSupportSubField(fieldNum, subFieldIndex))
      return;

   Field *field = AddField(fieldNum);

   if (field == FIT_NULL)
      return;

   if (subFieldIndex == FIT_SUBFIELD_INDEX_ACTIVE_SUBFIELD)
      return field->SetSTRINGValue(value, fieldArrayIndex, GetActiveSubFieldIndex(fieldNum));
   else
      return field->SetSTRINGValue(value, fieldArrayIndex, subFieldIndex);
}

} // namespace fit


text:
require 'active_support/hash_with_indifferent_access'
require 'active_support/core_ext/object/duplicable'

module ActiveModel
  # == Active \Model \Dirty
  #
  # Provides a way to track changes in your object in the same way as
  # Active Record does.
  #
  # The requirements for implementing ActiveModel::Dirty are:
  #
  # * <tt>include ActiveModel::Dirty</tt> in your object.
  # * Call <tt>define_attribute_methods</tt> passing each method you want to
  #   track.
  # * Call <tt>attr_name_will_change!</tt> before each change to the tracked
  #   attribute.
  # * Call <tt>changes_applied</tt> after the changes are persisted.
  # * Call <tt>reset_changes</tt> when you want to reset the changes
  #   information.
  #
  # A minimal implementation could be:
  #
  #   class Person
  #     include ActiveModel::Dirty
  #
  #     define_attribute_methods :name
  #
  #     def name
  #       @name
  #     end
  #
  #     def name=(val)
  #       name_will_change! unless val == @name
  #       @name = val
  #     end
  #
  #     def save
  #       # do persistence work
  #       changes_applied
  #     end
  #
  #     def reload!
  #       reset_changes
  #     end
  #   end
  #
  # A newly instantiated object is unchanged:
  #
  #   person = Person.find_by(name: 'Uncle Bob')
  #   person.changed?       # => false
  #
  # Change the name:
  #
  #   person.name = 'Bob'
  #   person.changed?       # => true
  #   person.name_changed?  # => true
  #   person.name_changed?(from: "Uncle Bob", to: "Bob") # => true
  #   person.name_was       # => "Uncle Bob"
  #   person.name_change    # => ["Uncle Bob", "Bob"]
  #   person.name = 'Bill'
  #   person.name_change    # => ["Uncle Bob", "Bill"]
  #
  # Save the changes:
  #
  #   person.save
  #   person.changed?       # => false
  #   person.name_changed?  # => false
  #
  # Reset the changes:
  #
  #   person.previous_changes # => {"name" => ["Uncle Bob", "Bill"]}
  #   person.reload!
  #   person.previous_changes # => {}
  #
  # Assigning the same value leaves the attribute unchanged:
  #
  #   person.name = 'Bill'
  #   person.name_changed?  # => false
  #   person.name_change    # => nil
  #
  # Which attributes have changed?
  #
  #   person.name = 'Bob'
  #   person.changed        # => ["name"]
  #   person.changes        # => {"name" => ["Bill", "Bob"]}
  #
  # If an attribute is modified in-place then make use of <tt>[attribute_name]_will_change!</tt>
  # to mark that the attribute is changing. Otherwise ActiveModel can't track
  # changes to in-place attributes.
  #
  #   person.name_will_change!
  #   person.name_change    # => ["Bill", "Bill"]
  #   person.name << 'y'
  #   person.name_change    # => ["Bill", "Billy"]
  module Dirty
    extend ActiveSupport::Concern
    include ActiveModel::AttributeMethods

    included do
      attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
      attribute_method_affix prefix: 'reset_', suffix: '!'
    end

    # Returns +true+ if any attribute have unsaved changes, +false+ otherwise.
    #
    #   person.changed? # => false
    #   person.name = 'bob'
    #   person.changed? # => true
    def changed?
      changed_attributes.present?
    end

    # Returns an array with the name of the attributes with unsaved changes.
    #
    #   person.changed # => []
    #   person.name = 'bob'
    #   person.changed # => ["name"]
    def changed
      changed_attributes.keys
    end

    # Returns a hash of changed attributes indicating their original
    # and new values like <tt>attr => [original value, new value]</tt>.
    #
    #   person.changes # => {}
    #   person.name = 'bob'
    #   person.changes # => { "name" => ["bill", "bob"] }
    def changes
      ActiveSupport::HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
    end

    # Returns a hash of attributes that were changed before the model was saved.
    #
    #   person.name # => "bob"
    #   person.name = 'robert'
    #   person.save
    #   person.previous_changes # => {"name" => ["bob", "robert"]}
    def previous_changes
      @previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new
    end

    # Returns a hash of the attributes with unsaved changes indicating their original
    # values like <tt>attr => original value</tt>.
    #
    #   person.name # => "bob"
    #   person.name = 'robert'
    #   person.changed_attributes # => {"name" => "bob"}
    def changed_attributes
      @changed_attributes ||= ActiveSupport::HashWithIndifferentAccess.new
    end

    # Handle <tt>*_changed?</tt> for +method_missing+.
    def attribute_changed?(attr, options = {}) #:nodoc:
      result = changed_attributes.include?(attr)
      result &&= options[:to] == __send__(attr) if options.key?(:to)
      result &&= options[:from] == changed_attributes[attr] if options.key?(:from)
      result
    end

    # Handle <tt>*_was</tt> for +method_missing+.
    def attribute_was(attr) # :nodoc:
      attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
    end

    private

      # Removes current changes and makes them accessible through +previous_changes+.
      def changes_applied
        @previously_changed = changes
        @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
      end

      # Removes all dirty data: current changes and previous changes
      def reset_changes
        @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
        @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
      end

      # Handle <tt>*_change</tt> for +method_missing+.
      def attribute_change(attr)
        [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
      end

      # Handle <tt>*_will_change!</tt> for +method_missing+.
      def attribute_will_change!(attr)
        return if attribute_changed?(attr)

        begin
          value = __send__(attr)
          value = value.duplicable? ? value.clone : value
        rescue TypeError, NoMethodError
        end

        changed_attributes[attr] = value
      end

      # Handle <tt>reset_*!</tt> for +method_missing+.
      def reset_attribute!(attr)
        if attribute_changed?(attr)
          __send__("#{attr}=", changed_attributes[attr])
          changed_attributes.delete(attr)
        end
      end
  end
end

redpajama_set_name: RedPajamaGithub


text:
// Copyright (c) MarinAtanasov. All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the project root for license information.
//
using AppBrix.Backgammon.Board;
using AppBrix.Backgammon.Game;
using System.Collections.Generic;

namespace AppBrix.Backgammon.Rules;

public interface IRules
{
    IEnumerable<IMove> GetAvailableMoves(IBoard board, ITurn turn);
}


text:
using System.Collections.Generic;
using System.Text.Json;
using Azure.Core;

namespace Azure.ResourceManager.Avs.Models
{
    public partial class WorkloadNetworkDhcpRelay : IUtf8JsonSerializable
    {
        void IUtf8JsonSerializable.Write(Utf8JsonWriter writer)
        {
            writer.WriteStartObject();
            if (Optional.IsCollectionDefined(ServerAddresses))
            {
                writer.WritePropertyName("serverAddresses");
                writer.WriteStartArray();
                foreach (var item in ServerAddresses)
                {
                    writer.WriteStringValue(item);
                }
                writer.WriteEndArray();
            }
            writer.WritePropertyName("dhcpType");
            writer.WriteStringValue(DhcpType.ToString());
            if (Optional.IsDefined(DisplayName))
            {
                writer.WritePropertyName("displayName");
                writer.WriteStringValue(DisplayName);
            }
            if (Optional.IsDefined(Revision))
            {
                writer.WritePropertyName("revision");
                writer.WriteNumberValue(Revision.Value);
            }
            writer.WriteEndObject();
        }

        internal static WorkloadNetworkDhcpRelay DeserializeWorkloadNetworkDhcpRelay(JsonElement element)
        {
            Optional<IList<string>> serverAddresses = default;
            DhcpTypeEnum dhcpType = default;
            Optional<string> displayName = default;
            Optional<IReadOnlyList<string>> segments = default;
            Optional<WorkloadNetworkDhcpProvisioningState> provisioningState = default;
            Optional<long> revision = default;
            foreach (var property in element.EnumerateObject())
            {
                if (property.NameEquals("serverAddresses"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    List<string> array = new List<string>();
                    foreach (var item in property.Value.EnumerateArray())
                    {
                        array.Add(item.GetString());
                    }
                    serverAddresses = array;
                    continue;
                }
                if (property.NameEquals("dhcpType"))
                {
                    dhcpType = new DhcpTypeEnum(property.Value.GetString());
                    continue;
                }
                if (property.NameEquals("displayName"))
                {
                    displayName = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("segments"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    List<string> array = new List<string>();
                    foreach (var item in property.Value.EnumerateArray())
                    {
                        array.Add(item.GetString());
                    }
                    segments = array;
                    continue;
                }
                if (property.NameEquals("provisioningState"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    provisioningState = new WorkloadNetworkDhcpProvisioningState(property.Value.GetString());
                    continue;
                }
                if (property.NameEquals("revision"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        property.ThrowNonNullablePropertyIsNull();
                        continue;
                    }
                    revision = property.Value.GetInt64();
                    continue;
                }
            }
            return new WorkloadNetworkDhcpRelay(dhcpType, displayName.Value, Optional.ToList(segments), Optional.ToNullable(provisioningState), Optional.ToNullable(revision), Optional.ToList(serverAddresses));
        }
    }
}


text:
from distutils.core import setup, Extension

from Cython.Distutils import build_ext
import pkg_resources

data_dir = pkg_resources.resource_filename("autowrap", "data_files")

ext = Extension("py_int_holder",
                sources = ['py_int_holder.cpp'],
                language="c++",
                include_dirs = [data_dir],
               )

setup(cmdclass={'build_ext':build_ext},
      name="py_int_holder",
      version="0.0.1",
      ext_modules = [ext]
     )


text:
[![Build Status](https://travis-ci.org/atom/apm.svg?branch=master)](https://travis-ci.org/atom/apm)
[![Dependency Status](https://david-dm.org/atom/apm.svg)](https://david-dm.org/atom/apm)

Discover and install Atom packages powered by [atom.io](https://atom.io)

You can configure apm via a `~/.atom/.apmrc` file similarly to
[npm config](https://www.npmjs.org/doc/misc/npm-config.html).

## Relation to npm

apm comes with [npm](https://github.com/npm/npm) and spawns `npm` processes to
install Atom packages. The major difference is that `apm` sets multiple command
line arguments to `npm` to ensure that native modules are built against
Chromium's v8 headers instead of node's v8 headers.

The other major difference is that Atom packages are installed to
`~/.atom/packages` instead of a local `node_modules` folder and Atom packages
are published to and installed from GitHub repositories instead of
[npmjs.org](https://www.npmjs.org)

Therefore you can think of `apm` as a simple `npm` wrapper that builds on top
of the many strengths of `npm` but is customized and optimized to be used for
Atom packages.

## Installing

apm is bundled and installed automatically with Atom. You can run the
_Atom > Install Shell Commands_ menu option to install it again if you aren't
able to run it from a terminal.

## Building
  * Clone the repository
  * :penguin: Install `libgnome-keyring-dev` if you are on Linux
  * Run `npm install`
  * Run `grunt` to compile the CoffeeScript code
  * Run `npm test` to run the specs

## Using

Run `apm help` to see all the supported commands and `apm help <command>` to
learn more about a specific command.

The common commands are `apm install <package_name>` to install a new package,
`apm featured` to see all the featured packages, and `apm publish` to publish
a package to [atom.io](https://atom.io).

## Behind a firewall?

If you are behind a firewall and seeing SSL errors when installing packages
you can disable strict SSL by putting the following in your `~/.atom/.apmrc`
file:

```
strict-ssl = false
```

If you are using a proxy you can configure `apm` to use it by setting the
`https-proxy` config in your `~/.atom/.apmrc` file like so:

```
https-proxy = https://9.0.2.1:0
```

You can run `apm config get https-proxy` to verify it has been set correctly.

You can also run `apm config list` to see all the custom config settings.


text:
'''
Created on 22 Jan 2013
@date:$Date: 2013-12-12 12:35:19 +0000 (Thu, 12 Dec 2013) $
@author: gfagiolo
'''
from PhilipsMultiFrameDcm import PhilipsMultiFrameDcm, FrameIndexList
from helpers import is_multiframe, dicomobj_to_str, METADATA_DESCRIPTION

#from helpers import TAG_SOP_CLASS_UID
__version__ = "1.0 ($Revision: 37 $)"


text:
package com.taobao.tddl.group.config;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.taobao.tddl.atom.TAtomDbStatusEnum;
import com.taobao.tddl.atom.TAtomDsStandard;
import com.taobao.tddl.common.exception.TddlException;
import com.taobao.tddl.common.exception.TddlNestableRuntimeException;
import com.taobao.tddl.common.exception.code.ErrorCode;
import com.taobao.tddl.common.model.DBType;
import com.taobao.tddl.common.model.DataSourceType;
import com.taobao.tddl.common.model.lifecycle.AbstractLifecycle;
import com.taobao.tddl.common.model.lifecycle.Lifecycle;
import com.taobao.tddl.common.utils.TStringUtil;
import com.taobao.tddl.common.utils.extension.ExtensionLoader;
import com.taobao.tddl.config.ConfigDataHandler;
import com.taobao.tddl.config.ConfigDataHandlerFactory;
import com.taobao.tddl.config.ConfigDataListener;
import com.taobao.tddl.config.impl.ConfigDataHandlerCity;
import com.taobao.tddl.group.dbselector.AbstractDBSelector;
import com.taobao.tddl.group.dbselector.DBSelector;
import com.taobao.tddl.group.dbselector.EquityDbManager;
import com.taobao.tddl.group.dbselector.OneDBSelector;
import com.taobao.tddl.group.dbselector.PriorityDbGroupSelector;
import com.taobao.tddl.group.dbselector.RuntimeWritableAtomDBSelector;
import com.taobao.tddl.group.jdbc.DataSourceFetcher;
import com.taobao.tddl.group.jdbc.DataSourceWrapper;
import com.taobao.tddl.group.jdbc.TGroupDataSource;
import com.taobao.tddl.group.listener.DataSourceChangeListener;
import com.taobao.tddl.monitor.logger.LoggerInit;

import com.taobao.tddl.common.utils.logger.Logger;
import com.taobao.tddl.common.utils.logger.LoggerFactory;

/**
 * 一个ConfigManager对应一个TGroupDataSource,
 * 主要用于将根据Group的dataID取得的对应配置字符串信(比如db0:rwp1q1i0, db1:rwp0q0i1),
 * 转化为真正的Group层的配置体系结构:一个Group层挂着两个Atom db0 与 db1 , 则我们使用一个 Map<String,
 * DataSourceWrapper> 来表示 其中的String 为每个Atom DS 的dbKey ,DataSourceWrapper
 * 为经过封装的TAtomDataSource
 * ---这里需要解释一下,为什么不直接使用AtomDataSource?因为每个AtomDataSource还有相应的权重和优先级信息 因此,需要***方法
 * 其中,配置的每一个Atom DataSource也只是用Atom
 * 的dbKey表示,因此,我们还需要根据此dbKey取得Atom的配置信息,并且将它封装成一个AtomDataSource对象。 因此需要***方法
 * 有了这个map能根据dbKey迅速的找到对应的Datasource也是不够的,我们的Group层应该是对应用透明的,
 * 因此,当我们的读写请求进来时,Group层应该能够根据配置的权重和优先级,自动的选择一个合适的DB上进行读写,
 * 所以,我们还需要将配置信息生成一个DBSelector来自动的完成根据权重、优先级选择合适的目标库 因此,需要***方法
 *
 * @author yangzhu
 * @author linxuan refactor
 */
public class GroupConfigManager extends AbstractLifecycle implements Lifecycle {

    private static final Logger                                                    logger                = LoggerFactory.getLogger(GroupConfigManager.class);

    private final ConfigDataListener                                               configReceiver;                                                           // //动态接收Diamond推送过来的信息
    private ConfigDataHandlerFactory                                               configFactory;
    private ConfigDataHandler                                                      globalHandler;

    // add by junyu
    private final ConfigDataListener                                               extraGroupConfigReceiver;
    private ConfigDataHandler                                                      extraHandler;
    private ConfigDataHandlerFactory                                               extraFactory;

    private final TGroupDataSource                                                 tGroupDataSource;

    private boolean                                                                createTAtomDataSource = true;

    private Map<String/* Atom dbIndex */, DataSourceWrapper/* Wrapper过的Atom DS */> dataSourceWrapperMap  = new HashMap<String, DataSourceWrapper>();

    private volatile GroupExtraConfig                                              groupExtraConfig      = new GroupExtraConfig();

    public GroupConfigManager(TGroupDataSource tGroupDataSource){
        this.tGroupDataSource = tGroupDataSource;
        this.configReceiver = new ConfigReceiver();
        this.extraGroupConfigReceiver = new ExtraGroupConfigReceiver();

        ((ConfigReceiver) this.configReceiver).setConfigManager(this);
    }

    /**
     * 从Diamond配置中心提取信息,构造TAtomDataSource、构造有优先级信息的读写DBSelector ---add by
     * mazhidan.pt
     */
    public void doInit() throws TddlException {
        // 警告: 不要在构造DefaultDiamondManager时就注册ManagerListener(比如:configReceiver)
        // 也就是说,不要这样用: new DefaultDiamondManager(dbGroupKey, configReceiver),
        // 而是要设成null,等第一次取得信息并解析完成后再注册,这样可以不用同步,避免任何与并发相关的问题,
        // 因为有可能在第一次刚取回信息后,Diamond配置中心那边马上修改了记录,导致ManagerListener这个线程立刻收到信息,
        // 造成初始化线程和ManagerListener线程同时解析信息。

        // 目前针对parse方法会做同步处理,避免并发操作. 同时针对diamond相同配置的进行cache,避免重复相同内容的通知

        configFactory = ConfigDataHandlerCity.getFactory(tGroupDataSource.getAppName(), tGroupDataSource.getUnitName());
        globalHandler = configFactory.getConfigDataHandler(tGroupDataSource.getFullDbGroupKey(), configReceiver);

        String dsWeightCommaStr = globalHandler.getData();

        // extra config
        extraFactory = ConfigDataHandlerCity.getFactory(tGroupDataSource.getAppName(), tGroupDataSource.getUnitName());

        extraHandler = extraFactory.getConfigDataHandler(tGroupDataSource.getDbGroupExtraConfigKey(),
            extraGroupConfigReceiver);
        String extraConfig = extraHandler.getNullableData(tGroupDataSource.getConfigReceiveTimeout(),
            ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY);

        if (extraConfig != null) {
            parseExtraConfig(extraConfig);
        }

        parse(dsWeightCommaStr);
        // 已经使用过的配置移除
        // destoryConfigHoderFactory();
    }

    /**
     * 根据普通的DataSource构造读写DBSelector
     */
    public void init(List<DataSourceWrapper> dataSourceWrappers) throws TddlException {
        if ((dataSourceWrappers == null) || dataSourceWrappers.size() < 1) {
            throw new TddlException(ErrorCode.ERR_CONFIG, "dataSourceWrappers is empty");
        }
        createTAtomDataSource = false;
        // update(createDBSelectors2(dataSourceWrappers));
        resetByDataSourceWrapper(dataSourceWrappers);
        isInited = true;
    }

    private TAtomDsStandard initAtomDataSource(String appName, String dsKey, String unitName) {
        try {
            if (tGroupDataSource.getDataSourceType().equals(DataSourceType.DruidDataSource)) {
                TAtomDsStandard atomDataSource = ExtensionLoader.load(TAtomDsStandard.class);
                // TAtomDsStandard atomDataSource = new TAtomDataSource();
                atomDataSource.init(appName, dsKey, unitName);
                atomDataSource.setLogWriter(tGroupDataSource.getLogWriter());
                atomDataSource.setLoginTimeout(tGroupDataSource.getLoginTimeout());
                return atomDataSource;
            } else {
                throw new IllegalArgumentException("do not have this datasource type : "
                                                   + tGroupDataSource.getDataSourceType());
            }
        } catch (Exception e) {
            throw new TddlNestableRuntimeException("TAtomDataSource init failed: dsKey=" + dsKey, e);
        }
    }

    private class MyDataSourceFetcher implements DataSourceFetcher {

        private DBType dbType = DBType.MYSQL;

        @Override
        public DataSource getDataSource(String dsKey) {
            DataSourceWrapper dsw = dataSourceWrapperMap.get(dsKey);
            if (dsw != null) {
                dbType = dsw.getDBType();
                return dsw.getWrappedDataSource();
            } else {
                if (createTAtomDataSource) {
                    TAtomDsStandard atomDs = initAtomDataSource(tGroupDataSource.getAppName(),
                        dsKey,
                        tGroupDataSource.getUnitName());
                    dbType = DBType.valueOf(atomDs.getDbType().name());
                    return atomDs;
                } else {
                    throw new IllegalArgumentException(dsKey + " not exist!");
                }
            }
        }

        @Override
        public DBType getDataSourceDBType(String key) {
            return dbType;
        }
    };

    // configInfo样例: db1:rw, db2:r, db3:r
    private synchronized void parse(String dsWeightCommaStr) throws TddlException {
        List<DataSourceWrapper> dswList = parse2DataSourceWrapperList(dsWeightCommaStr);
        resetByDataSourceWrapper(dswList);
    }

    /**
     * extraConfig is a json format string,include table dataSourceIndex
     * relation or sql dataSourceIndex relation or default go main db config.
     * example: {sqlDsIndex: { 0:[sql1,sql2,sql3], 1:[sql0], 2:[sql4] },
     * tabDsIndex: { 0:[table1,table2] 1:[table3,table4] }, defaultMain:true}
     *
     * @throws TddlException
     **/
    @SuppressWarnings("rawtypes")
    private synchronized void parseExtraConfig(String extraConfig) throws TddlException {
        if (extraConfig == null) {
            this.groupExtraConfig.getSqlForbidSet().clear();
            this.groupExtraConfig.getSqlDsIndexMap().clear();
            this.groupExtraConfig.getTableDsIndexMap().clear();
            this.groupExtraConfig.setDefaultMain(false);
        }
        try {
            JSONObject obj = JSONObject.parseObject(extraConfig);
            if (obj.containsKey("sqlForbid")) {
                Set<String> tempSqlForbidSet = new HashSet<String>();
                JSONArray array = obj.getJSONArray("sqlForbid");
                for (int i = 0; i < array.size(); i++) {
                    String sql = array.getString(i);
                    String nomalSql = TStringUtil.fillTabWithSpace(sql.trim().toLowerCase());
                    if (nomalSql != null && !nomalSql.trim().isEmpty()) {
                        tempSqlForbidSet.add(nomalSql);
                    }
                }
                this.groupExtraConfig.setSqlForbidSet(tempSqlForbidSet);
            } else {
                this.groupExtraConfig.getSqlForbidSet().clear();
            }

            if (obj.containsKey("sqlDsIndex")) {
                Map<String, Integer> tempSqlDsIndexMap = new HashMap<String, Integer>();
                JSONObject sqlDsIndex = obj.getJSONObject("sqlDsIndex");
                Iterator it = sqlDsIndex.keySet().iterator();
                while (it.hasNext()) {
                    String key = String.valueOf(it.next()).trim();
                    Integer index = Integer.valueOf(key);
                    JSONArray array = sqlDsIndex.getJSONArray(key);
                    for (int i = 0; i < array.size(); i++) {
                        String sql = array.getString(i);
                        String nomalSql = TStringUtil.fillTabWithSpace(sql.trim().toLowerCase());
                        if (tempSqlDsIndexMap.get(nomalSql) == null) {
                            tempSqlDsIndexMap.put(nomalSql, index);
                        } else {
                            // have a nice log
                            throw new TddlException(ErrorCode.ERR_CONFIG,
                                "sql can not be route to different dataSourceIndex:" + sql);
                        }
                    }
                }
                this.groupExtraConfig.setSqlDsIndexMap(tempSqlDsIndexMap);
            } else {
                this.groupExtraConfig.getSqlDsIndexMap().clear();
            }

            if (obj.containsKey("tabDsIndex")) {
                Map<String, Integer> tempTabDsIndexMap = new HashMap<String, Integer>();
                JSONObject sqlDsIndex = obj.getJSONObject("tabDsIndex");
                Iterator it = sqlDsIndex.keySet().iterator();
                while (it.hasNext()) {
                    String key = String.valueOf(it.next()).trim();
                    Integer index = Integer.valueOf(key);
                    JSONArray array = sqlDsIndex.getJSONArray(key);
                    for (int i = 0; i < array.size(); i++) {
                        String table = array.getString(i);
                        String nomalTable = table.trim().toLowerCase();
                        if (tempTabDsIndexMap.get(nomalTable) == null) {
                            tempTabDsIndexMap.put(nomalTable, index);
                        } else {
                            // have a nice log
                            throw new TddlException(ErrorCode.ERR_CONFIG,
                                "table can not be route to different dataSourceIndex:" + table);
                        }
                    }
                }
                this.groupExtraConfig.setTableDsIndexMap(tempTabDsIndexMap);
            } else {
                this.groupExtraConfig.getTableDsIndexMap().clear();
            }

            if (obj.containsKey("defaultMain")) {
                this.groupExtraConfig.setDefaultMain(obj.getBoolean("defaultMain"));
            } else {
                this.groupExtraConfig.setDefaultMain(false);
            }

        } catch (JSONException e) {
            throw new TddlNestableRuntimeException("group extraConfig is not json valid string:" + extraConfig, e);
        }
    }

    /**
     * 警告: 逗号的位置很重要,要是有连续的两个逗号也不要人为的省略掉, 数据库的个数 =
     * 逗号的个数+1,用0、1、2...编号,比如"db1,,db3",实际上有3个数据库,
     * 业务层通过传一个ThreadLocal进来,ThreadLocal中就是这种索引编号。
     */
    private List<DataSourceWrapper> parse2DataSourceWrapperList(String dsWeightCommaStr) throws TddlException {
        logger.info("[parse2DataSourceWrapperList]dsWeightCommaStr=" + dsWeightCommaStr);
        this.tGroupDataSource.setDsKeyAndWeightCommaArray(dsWeightCommaStr);
        if ((dsWeightCommaStr == null) || (dsWeightCommaStr = dsWeightCommaStr.trim()).length() == 0) {
            throw new TddlException(ErrorCode.ERR_CONFIG_MISS_GROUPKEY, tGroupDataSource.getFullDbGroupKey());
        }
        return buildDataSourceWrapperSequential(dsWeightCommaStr, new MyDataSourceFetcher());
    }

    /**
     * 将封装好的AtomDataSource的列表,进一步封装为可以根据权重优先级随机选择模板库的DBSelector ---add by
     * mazhidan.pt
     *
     * @param dswList
     */
    private void resetByDataSourceWrapper(List<DataSourceWrapper> dswList) {
        // 删掉已经不存在的DataSourceWrapper
        Map<String, DataSourceWrapper> newDataSourceWrapperMap = new HashMap<String, DataSourceWrapper>(dswList.size());
        for (DataSourceWrapper dsw : dswList) {
            newDataSourceWrapperMap.put(dsw.getDataSourceKey(), dsw);
        }
        Map<String, DataSourceWrapper> old = this.dataSourceWrapperMap;
        this.dataSourceWrapperMap = newDataSourceWrapperMap;
        // TODO 需要考虑关闭老的DataSource对象
        old.clear();
        old = null;

        DBSelector r_DBSelector = null;
        DBSelector w_DBSelector = null;

        // 如果只有一个db,则用OneDBSelector
        if (dswList.size() == 1) {
            DataSourceWrapper dsw2 = dswList.get(0);
            r_DBSelector = new OneDBSelector(dsw2);
            r_DBSelector.setDbType(dsw2.getDBType());
            w_DBSelector = r_DBSelector;
        } else {
            // 读写优先级Map
            Map<Integer/* 优先级 */, List<DataSourceWrapper>/* 优先级为key的DS 列表 */> rPriority2DswList = new HashMap<Integer, List<DataSourceWrapper>>();
            Map<Integer, List<DataSourceWrapper>> wPriority2DswList = new HashMap<Integer, List<DataSourceWrapper>>();
            for (DataSourceWrapper dsw1 : dswList) {
                add2LinkedListMap(rPriority2DswList, dsw1.getWeight().p, dsw1);
                add2LinkedListMap(wPriority2DswList, dsw1.getWeight().q, dsw1);
            }
            r_DBSelector = createDBSelector(rPriority2DswList, true);
            w_DBSelector = createDBSelector(wPriority2DswList, false);
        }

        r_DBSelector.setReadable(true);
        w_DBSelector.setReadable(false);

        this.readDBSelectorWrapper = r_DBSelector;
        this.writeDBSelectorWrapper = w_DBSelector;

        if (tGroupDataSource.getAutoSelectWriteDataSource()) {
            runtimeWritableAtomDBSelectorWrapper = new RuntimeWritableAtomDBSelector(dataSourceWrapperMap,
                groupExtraConfig);
        }

        // System.out.println("dataSourceWrapperMap=" + dataSourceWrapperMap);
        if (this.dataSourceChangeListener != null) {
            dataSourceChangeListener.onDataSourceChanged(null);// 业务通过getDataSource()获取更新后的结果
        }
    }

    private DataSourceChangeListener dataSourceChangeListener;

    public void setDataSourceChangeListener(DataSourceChangeListener dataSourceChangeListener) {
        this.dataSourceChangeListener = dataSourceChangeListener;
    }

    /**
     * 将给定的k 优先级 加入这个优先级对应的V list 里面。 ----因为可能有多个DS具有相同的优先级 ---add by
     * mazhidan.pt
     */
    private static <K, V> void add2LinkedListMap(Map<K, List<V>> m, K key, V value) {
        // 从Map中先取出这个优先级的List
        List<V> c = m.get(key);
        // 如果为空,则new一个
        if (c == null) {
            c = new LinkedList<V>();
            m.put(key, c);
        }
        // 不为空,在后面add()
        c.add(value);
    }

    /**
     * @param dsWeightCommaStr : 例如 db0:rwp1q1i0, db1:rwp0q0i1
     */
    public static List<DataSourceWrapper> buildDataSourceWrapper(String dsWeightCommaStr, DataSourceFetcher fetcher) {
        String[] dsWeightArray = dsWeightCommaStr.split(","); // 逗号分隔:db0:rwp1q1i0,
                                                              // db1:rwp0q0i1
        List<DataSourceWrapper> dss = new ArrayList<DataSourceWrapper>(dsWeightArray.length);
        for (int i = 0; i < dsWeightArray.length; i++) {
            String[] dsAndWeight = dsWeightArray[i].split(":"); // 冒号分隔:db0:rwp1q1i0
            String dsKey = dsAndWeight[0].trim();
            String weightStr = dsAndWeight.length == 2 ? dsAndWeight[1] : null;

            DataSourceWrapper dsw = getDataSourceWrapper(dsKey, weightStr, i, fetcher);
            dss.add(dsw);
        }
        return dss;
    }

    public static DataSourceWrapper getDataSourceWrapper(String dsKey, String weightStr, int index,
                                                         DataSourceFetcher fetcher) {
        // 如果多个group复用一个真实dataSource,会造成所有group引用
        // 这个dataSource的配置 会以最后一个dataSource的配置为准
        DataSource dataSource = fetcher.getDataSource(dsKey);
        DBType fetcherDbType = fetcher.getDataSourceDBType(dsKey);
        // dbType = fetcherDbType == null ? dbType :
        // fetcherDbType;
        DataSourceWrapper dsw = new DataSourceWrapper(dsKey, weightStr, dataSource, fetcherDbType, index);
        return dsw;
    }

    public static List<DataSourceWrapper> buildDataSourceWrapperSequential(String dsWeightCommaStr,
                                                                           final DataSourceFetcher fetcher) {
        final String[] dsWeightArray = dsWeightCommaStr.split(","); // 逗号分隔:db0:rwp1q1i0,
        // db1:rwp0q0i1
        List<DataSourceWrapper> dss = new ArrayList<DataSourceWrapper>(dsWeightArray.length);

        for (int i = 0; i < dsWeightArray.length; i++) {
            final int j = i;
            final String[] dsAndWeight = dsWeightArray[j].split(":"); // 冒号分隔:db0:rwp1q1i0
            final String dsKey = dsAndWeight[0].trim();
            String weightStr = dsAndWeight.length == 2 ? dsAndWeight[1] : null;
            try {
                dss.add(getDataSourceWrapper(dsKey, weightStr, j, fetcher));
            } catch (Exception e) {
                throw new RuntimeException("init ds error! atom key is " + dsKey, e);
            }
        }

        return dss;
    }

    /**
     * 根据给定的具有读写优先级及每个优先级对应的DataSource链表的Map,构造DBSelector---add by mazhidan.pt
     *
     * @param priority2DswList
     * @param isRead
     * @return
     */
    private DBSelector createDBSelector(Map<Integer/* 优先级 */, List<DataSourceWrapper>> priority2DswList, boolean isRead) {
        if (priority2DswList.size() == 1) { // 只有一个优先级直接使用EquityDbManager
            return createDBSelector2(priority2DswList.entrySet().iterator().next().getValue(), isRead);
        } else {
            List<Integer> priorityKeys = new LinkedList<Integer>();
            priorityKeys.addAll(priority2DswList.keySet());
            Collections.sort(priorityKeys); // 优先级从小到大排序
            EquityDbManager[] priorityGroups = new EquityDbManager[priorityKeys.size()];
            for (int i = 0; i < priorityGroups.length; i++) { // 最大的优先级放到最前面
                int priority = priorityKeys.get(priorityGroups.length - 1 - i);// 倒序
                List<DataSourceWrapper> dswList = priority2DswList.get(priority);
                // PriorityDbGroupSelector依赖EquityDbManager抛出的NoMoreDataSourceException来实现,
                // 所以这里即使只有一个ds也只能仍然用EquityDbManager
                priorityGroups[i] = createEquityDbManager(dswList, isRead, groupExtraConfig);

            }
            return new PriorityDbGroupSelector(priorityGroups);
        }
    }

    private AbstractDBSelector createDBSelector2(List<DataSourceWrapper> dswList, boolean isRead) {
        AbstractDBSelector dbSelector;
        if (dswList.size() == 1) {
            DataSourceWrapper dsw = dswList.get(0);
            dbSelector = new OneDBSelector(dsw);
            dbSelector.setDbType(dsw.getDBType());
        } else {
            dbSelector = createEquityDbManager(dswList, isRead, groupExtraConfig);
        }
        return dbSelector;
    }

    /*
     * private DBSelector createDBSelector(List<List<DataSourceWrapper>> list,
     * boolean isRead) { int size = list.size(); //优先级别个数 if (size == 1) {
     * //只有一个优先级直接使用EquityDbManager return createEquityDbManager(list.get(0),
     * isRead); } else { EquityDbManager[] priorityGroups = new
     * EquityDbManager[size]; for (int i = 0; i < size; i++) { priorityGroups[i]
     * = createEquityDbManager(list.get(i), isRead); } return new
     * PriorityDbGroupSelector(priorityGroups); } }
     */

    private static EquityDbManager createEquityDbManager(List<DataSourceWrapper> list, boolean isRead,
                                                         GroupExtraConfig groupExtraConfig) {
        Map<String, DataSourceWrapper> dataSourceMap = new HashMap<String, DataSourceWrapper>(list.size());
        Map<String, Integer> weightMap = new HashMap<String, Integer>(list.size());

        DBType dbType = null;
        for (DataSourceWrapper dsw : list) {
            String dsKey = dsw.getDataSourceKey();
            dataSourceMap.put(dsKey, dsw);
            weightMap.put(dsKey, isRead ? dsw.getWeight().r : dsw.getWeight().w);

            if (dbType == null) {
                dbType = dsw.getDBType();
            }
        }
        EquityDbManager equityDbManager = new EquityDbManager(dataSourceMap, weightMap, groupExtraConfig);
        equityDbManager.setDbType(dbType);
        return equityDbManager;
    }

    /**
     * 因为数据源个数通常在3个左右,所以这里使用了简单的插入排序算法,
     * 两级List(如:List<List<DataSourceWrapper>>)类似下面这种结构,
     * 第一级List(纵列)代表优先级,优先级最高的排在List的0号位置处,其次是1号位置,依此类推,
     * 第二级List(横列)表示相同优先级的多个数据源。 ---- |p9|-->|db0|-->|db2| ---- |p8|-->|db1|
     * ---- |p7|-->|db3| ----
     *
     * @param priorityList 上一次已排好序的数据源列表,由调用者确保不为null。
     * @param dsw 当前需要插入到列表的数据源
     * @param isRead 因为优先级分读写优先级,读用p表示,写用q表示,如果isRead为true就使用P,否则用q。
     */
    /*
     * public static void insertSort(List<List<DataSourceWrapper>> priorityList,
     * DataSourceWrapper dsw, boolean isRead) {
     * //如果读或写的权重为0,那么就表示此数据源对应的数据库不可读或不可写,此时什么都不做,忽略此数据源。 // if ((isRead &&
     * dsw.getWeight().r == 0) || (!isRead && dsw.getWeight().w == 0)) //
     * return; List<DataSourceWrapper> samePriorityDataSourceWrappers; int
     * newPriority = isRead ? dsw.getWeight().p : dsw.getWeight().q; int index =
     * 0; int size = priorityList.size(); while (index < size) {
     * samePriorityDataSourceWrappers = priorityList.get(index);
     * //去除priorityList中的无效元素,防止空指针异常和下标越界异常。 if (samePriorityDataSourceWrappers
     * == null || samePriorityDataSourceWrappers.size() == 0) {
     * priorityList.remove(index); size--; continue; } Weight oldWeight =
     * samePriorityDataSourceWrappers.get(0).getWeight(); int oldPriority =
     * isRead ? oldWeight.p : oldWeight.q; if (newPriority == oldPriority) {
     * //这里不用按权重排序了 samePriorityDataSourceWrappers.add(dsw); return; } else if
     * (newPriority > oldPriority) { break; } else { index++; } }
     * //没有找到相同优先级时新插入一个优先级 (当size=0时也会走到这里) samePriorityDataSourceWrappers =
     * new ArrayList<DataSourceWrapper>();
     * samePriorityDataSourceWrappers.add(dsw); priorityList.add(index,
     * samePriorityDataSourceWrappers); }
     */
    /*
     * private DataSourceWrapper createDataSourceWrapper(String dsKey, String
     * weightStr, int dataSourceIndex) { aliveDataSourceKeys.add(dsKey);
     * DataSourceWrapper dsw = dataSourceWrapperMap.get(dsKey); if (dsw != null)
     * { //dsw.setWeightStr(weightStr);
     * //dsw.setDataSourceIndex(dataSourceIndex); } else { if
     * (createTAtomDataSource) { TAtomDataSource ads =
     * createTAtomDataSource(dsKey); dsw = new DataSourceWrapper(dsKey,
     * weightStr, ads, getDBTypeFrom(ads), dataSourceIndex);
     * dataSourceWrapperMap.put(dsKey, dsw); } else { throw new
     * IllegalArgumentException(dsKey + " not exist!"); } } return dsw; }
     */

    /**
     * 根据当前的读写状态,检查数据源是否可用,数据源分两种:TAtomDataSource和普通的数据源(如DBCP数据源) 新添加一个数据源
     * druid
     *
     * @param ds 要检查的数据源
     * @param isRead 是对数据源进行读操作(isRead=true),还是写操作(isRead=false)
     * @return 普通的数据源不管当前的读写状态是什么,总是可用的,返回true。
     * TAtomDataSource如果当前的状态是NA返回false, 否则根据WR状态以及isRead的值决定
     */
    public static boolean isDataSourceAvailable(DataSource ds, boolean isRead) {
        if (ds instanceof DataSourceWrapper) {
            ds = ((DataSourceWrapper) ds).getWrappedDataSource();
        }

        if (!(ds instanceof TAtomDsStandard)) {
            return true;
        }

        if (ds instanceof TAtomDsStandard) {
            TAtomDbStatusEnum status = ((TAtomDsStandard) ds).getDbStatus();
            if (status.isNaStatus()) {
                return false;
            }

            if (status.isRstatus() && isRead) {
                return true;
            }
            if (status.isWstatus() && !isRead) {
                return true;
            }
        }
        return false;
    }

    /**
     * 不能在TGroupDataSource或TGroupConnection或其他地方把DBSelector做为一个字段保存下来,
     * 否则db权重配置变了之后无法使用最新的权重配置
     */
    private volatile DBSelector readDBSelectorWrapper;
    private volatile DBSelector writeDBSelectorWrapper;
    private volatile DBSelector runtimeWritableAtomDBSelectorWrapper;

    /**
     * 根据是读还是写来选择对应的DBSelector---add by mazhidan.pt
     */
    public DBSelector getDBSelector(boolean isRead, boolean autoSelectWriteDataSource) {
        DBSelector dbSelector = isRead ? readDBSelectorWrapper : writeDBSelectorWrapper;
        if (!isRead && autoSelectWriteDataSource) {
            // 因为所有dbSelector内部的TAtomDataSource都是指向同一个实例,如果某一个TAtomDataSource的状态改了,
            // 那么所有包含这个TAtomDataSource的dbSelector都会知道状态改变了,
            // 所以只要有一个TAtomDataSource的状态变成W,
            // 那么不管这个dbSelector是专门用于读的,还是专门用于写的,也不管是不是runtimeWritableAtomDBSelector,
            // 只要调用了hasWritableDataSource()都会返回true

            // if(!dbSelector.hasWritableDataSource())
            dbSelector = runtimeWritableAtomDBSelectorWrapper;
        }
        return dbSelector;
    }

    private class ConfigReceiver implements ConfigDataListener {

        private GroupConfigManager configManager;

        public void setConfigManager(GroupConfigManager configManager) {
            this.configManager = configManager;
        }

        @Override
        public void onDataRecieved(String dataId, String data) {
            try {
                String oldData = this.configManager.tGroupDataSource.getDsKeyAndWeightCommaArray();
                LoggerInit.TDDL_DYNAMIC_CONFIG.info("group ds data received !dataId:" + dataId + ", new data:" + data
                                                    + ", old data:" + oldData);
                parse(data);
            } catch (Throwable t) {
                logger.error("动态解析配置信息时出现错误:" + data, t);
            }
        }
    }

    private class ExtraGroupConfigReceiver implements ConfigDataListener {

        @Override
        public void onDataRecieved(String dataId, String data) {
            LoggerInit.TDDL_DYNAMIC_CONFIG.info("receive group extra data:" + data);
            try {
                parseExtraConfig(data);
            } catch (TddlException e) {
                throw new TddlNestableRuntimeException(e);
            }
        }
    }

    // 仅用于测试
    public void receiveConfigInfo(String configInfo) {
        configReceiver.onDataRecieved(null, configInfo);
    }

    // 仅用于测试
    public void resetDbGroup(String configInfo) {
        try {
            parse(configInfo);
        } catch (Throwable t) {
            logger.error("resetDbGroup failed:" + configInfo, t);
        }

    }

    @Override
    protected void doDestroy() throws TddlException {
        // 关闭下层DataSource
        if (dataSourceWrapperMap != null) {
            for (DataSourceWrapper dsw : dataSourceWrapperMap.values()) {
                try {
                    DataSource ds = dsw.getWrappedDataSource();
                    if (ds instanceof TAtomDsStandard) {
                        TAtomDsStandard tads = (TAtomDsStandard) ds;
                        tads.destroyDataSource();
                    } else {
                        logger.error("target datasource is not a TAtom Data Source");
                    }
                } catch (Exception e) {
                    logger.error("we got exception when close datasource : " + dsw.getDataSourceKey(), e);
                }
            }
        }
        // 关闭global datasource handler
        try {
            if (globalHandler != null) {
                globalHandler.destroy();
            }
        } catch (Exception e) {
            logger.error("we got exception when close datasource .", e);
        }
        // 关闭extraDataSource handler.
        try {
            if (extraHandler != null) {
                extraHandler.destroy();
            }
        } catch (Exception e) {
            logger.error("we got exception when close datasource .", e);
        }
    }

    public void destroyDataSource() throws TddlException {
        destroy();
    }
}


text:
/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
/*
 * Copyright (c) 1982, 1986, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)resource.h	8.2 (Berkeley) 1/4/94
 */

#ifndef _SYS_RESOURCE_H_
#define	_SYS_RESOURCE_H_

#include <sys/appleapiopts.h>
#include <sys/cdefs.h>
#include <sys/_types.h>

#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#include <stdint.h>
#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */

#ifndef KERNEL
#include <Availability.h>
#endif

/* [XSI] The timeval structure shall be defined as described in
 * <sys/time.h>
 */
#include <sys/_types/_timeval.h>
#ifdef KERNEL
#include <sys/_types/_user32_timeval.h>
#include <sys/_types/_user64_timeval.h>
#endif

/* The id_t type shall be defined as described in <sys/types.h> */
#include <sys/_types/_id_t.h>

/*
 * Resource limit type (low 63 bits, excluding the sign bit)
 */
typedef __uint64_t	rlim_t;

/*****
 * PRIORITY
 */

/*
 * Possible values of the first parameter to getpriority()/setpriority(),
 * used to indicate the type of the second parameter.
 */
#define	PRIO_PROCESS	0		/* Second argument is a PID */
#define	PRIO_PGRP	1		/* Second argument is a GID */
#define	PRIO_USER	2		/* Second argument is a UID */

#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#define	PRIO_DARWIN_THREAD	3		/* Second argument is always 0 (current thread) */
#define	PRIO_DARWIN_PROCESS	4		/* Second argument is a PID */

/*
 * Range limitations for the value of the third parameter to setpriority().
 */
#define	PRIO_MIN	-20
#define	PRIO_MAX	20

/*
 * use PRIO_DARWIN_BG to set the current thread into "background" state
 * which lowers CPU, disk IO, and networking priorites until thread terminates
 * or "background" state is revoked
 */
#define PRIO_DARWIN_BG 0x1000

/*
 * use PRIO_DARWIN_NONUI to restrict a process's ability to make calls to
 * the GPU.
 */
#define PRIO_DARWIN_NONUI 0x1001

#endif	/* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */

/*****
 * RESOURCE USAGE
 */

/*
 * Possible values of the first parameter to getrusage(), used to indicate
 * the scope of the information to be returned.
 */
#define	RUSAGE_SELF	0		/* Current process information */
#define	RUSAGE_CHILDREN	-1		/* Current process' children */

/*
 * A structure representing an accounting of resource utilization.  The
 * address of an instance of this structure is the second parameter to
 * getrusage().
 *
 * Note: All values other than ru_utime and ru_stime are implementaiton
 *       defined and subject to change in a future release.  Their use
 *       is discouraged for standards compliant programs.
 */
struct	rusage {
	struct timeval ru_utime;	/* user time used (PL) */
	struct timeval ru_stime;	/* system time used (PL) */
#if __DARWIN_C_LEVEL < __DARWIN_C_FULL
	long	ru_opaque[14];		/* implementation defined */
#else
	/*
	 * Informational aliases for source compatibility with programs
	 * that need more information than that provided by standards,
	 * and which do not mind being OS-dependent.
	 */
	long	ru_maxrss;		/* max resident set size (PL) */
#define	ru_first	ru_ixrss	/* internal: ruadd() range start */
	long	ru_ixrss;		/* integral shared memory size (NU) */
	long	ru_idrss;		/* integral unshared data (NU)  */
	long	ru_isrss;		/* integral unshared stack (NU) */
	long	ru_minflt;		/* page reclaims (NU) */
	long	ru_majflt;		/* page faults (NU) */
	long	ru_nswap;		/* swaps (NU) */
	long	ru_inblock;		/* block input operations (atomic) */
	long	ru_oublock;		/* block output operations (atomic) */
	long	ru_msgsnd;		/* messages sent (atomic) */
	long	ru_msgrcv;		/* messages received (atomic) */
	long	ru_nsignals;		/* signals received (atomic) */
	long	ru_nvcsw;		/* voluntary context switches (atomic) */
	long	ru_nivcsw;		/* involuntary " */
#define	ru_last		ru_nivcsw	/* internal: ruadd() range end */
#endif	/* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
};

#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
/*
 * Flavors for proc_pid_rusage().
 */
#define RUSAGE_INFO_V0	0
#define RUSAGE_INFO_V1	1
#define RUSAGE_INFO_V2	2
#define	RUSAGE_INFO_CURRENT RUSAGE_INFO_V2

typedef void *rusage_info_t;

struct rusage_info_v0 {
	uint8_t  ri_uuid[16];
	uint64_t ri_user_time;
	uint64_t ri_system_time;
	uint64_t ri_pkg_idle_wkups;
	uint64_t ri_interrupt_wkups;
	uint64_t ri_pageins;
	uint64_t ri_wired_size;
	uint64_t ri_resident_size;
	uint64_t ri_phys_footprint;
	uint64_t ri_proc_start_abstime;
	uint64_t ri_proc_exit_abstime;
};

struct rusage_info_v1 {
	uint8_t  ri_uuid[16];
	uint64_t ri_user_time;
	uint64_t ri_system_time;
	uint64_t ri_pkg_idle_wkups;
	uint64_t ri_interrupt_wkups;
	uint64_t ri_pageins;
	uint64_t ri_wired_size;
	uint64_t ri_resident_size;
	uint64_t ri_phys_footprint;
	uint64_t ri_proc_start_abstime;
	uint64_t ri_proc_exit_abstime;
	uint64_t ri_child_user_time;
	uint64_t ri_child_system_time;
	uint64_t ri_child_pkg_idle_wkups;
	uint64_t ri_child_interrupt_wkups;
	uint64_t ri_child_pageins;
	uint64_t ri_child_elapsed_abstime;
};

struct rusage_info_v2 {
	uint8_t  ri_uuid[16];
	uint64_t ri_user_time;
	uint64_t ri_system_time;
	uint64_t ri_pkg_idle_wkups;
	uint64_t ri_interrupt_wkups;
	uint64_t ri_pageins;
	uint64_t ri_wired_size;
	uint64_t ri_resident_size;
	uint64_t ri_phys_footprint;
	uint64_t ri_proc_start_abstime;
	uint64_t ri_proc_exit_abstime;
	uint64_t ri_child_user_time;
	uint64_t ri_child_system_time;
	uint64_t ri_child_pkg_idle_wkups;
	uint64_t ri_child_interrupt_wkups;
	uint64_t ri_child_pageins;
	uint64_t ri_child_elapsed_abstime;
	uint64_t ri_diskio_bytesread;
	uint64_t ri_diskio_byteswritten;
};

#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */

#ifdef KERNEL

struct rusage_superset {
	struct rusage 			ru;
	struct rusage_info_v2 	ri;
};

struct rusage_info_child {
	uint64_t ri_child_user_time;
	uint64_t ri_child_system_time;
	uint64_t ri_child_pkg_idle_wkups;
	uint64_t ri_child_interrupt_wkups;
	uint64_t ri_child_pageins;
	uint64_t ri_child_elapsed_abstime;
};

struct rusage_info_diskiobytes {
	volatile uint64_t ri_bytesread __attribute__((aligned(8)));
	volatile uint64_t ri_byteswritten __attribute__((aligned(8)));
};

struct	user64_rusage {
	struct user64_timeval ru_utime;	/* user time used */
	struct user64_timeval ru_stime;	/* system time used */
	user64_long_t	ru_maxrss;		/* max resident set size */
	user64_long_t	ru_ixrss;		/* integral shared memory size */
	user64_long_t	ru_idrss;		/* integral unshared data " */
	user64_long_t	ru_isrss;		/* integral unshared stack " */
	user64_long_t	ru_minflt;		/* page reclaims */
	user64_long_t	ru_majflt;		/* page faults */
	user64_long_t	ru_nswap;		/* swaps */
	user64_long_t	ru_inblock;		/* block input operations */
	user64_long_t	ru_oublock;		/* block output operations */
	user64_long_t	ru_msgsnd;		/* messages sent */
	user64_long_t	ru_msgrcv;		/* messages received */
	user64_long_t	ru_nsignals;	/* signals received */
	user64_long_t	ru_nvcsw;		/* voluntary context switches */
	user64_long_t	ru_nivcsw;		/* involuntary " */
};

struct	user32_rusage {
	struct user32_timeval ru_utime;	/* user time used */
	struct user32_timeval ru_stime;	/* system time used */
	user32_long_t	ru_maxrss;		/* max resident set size */
	user32_long_t	ru_ixrss;		/* integral shared memory size */
	user32_long_t	ru_idrss;		/* integral unshared data " */
	user32_long_t	ru_isrss;		/* integral unshared stack " */
	user32_long_t	ru_minflt;		/* page reclaims */
	user32_long_t	ru_majflt;		/* page faults */
	user32_long_t	ru_nswap;		/* swaps */
	user32_long_t	ru_inblock;		/* block input operations */
	user32_long_t	ru_oublock;		/* block output operations */
	user32_long_t	ru_msgsnd;		/* messages sent */
	user32_long_t	ru_msgrcv;		/* messages received */
	user32_long_t	ru_nsignals;	/* signals received */
	user32_long_t	ru_nvcsw;		/* voluntary context switches */
	user32_long_t	ru_nivcsw;		/* involuntary " */
};

#endif /* KERNEL */

/*****
 * RESOURCE LIMITS
 */

/*
 * Symbolic constants for resource limits; since all limits are representable
 * as a type rlim_t, we are permitted to define RLIM_SAVED_* in terms of
 * RLIM_INFINITY.
 */
#define	RLIM_INFINITY	(((__uint64_t)1 << 63) - 1)	/* no limit */
#define	RLIM_SAVED_MAX	RLIM_INFINITY	/* Unrepresentable hard limit */
#define	RLIM_SAVED_CUR	RLIM_INFINITY	/* Unrepresentable soft limit */

/*
 * Possible values of the first parameter to getrlimit()/setrlimit(), to
 * indicate for which resource the operation is being performed.
 */
#define	RLIMIT_CPU	0		/* cpu time per process */
#define	RLIMIT_FSIZE	1		/* file size */
#define	RLIMIT_DATA	2		/* data segment size */
#define	RLIMIT_STACK	3		/* stack size */
#define	RLIMIT_CORE	4		/* core file size */
#define	RLIMIT_AS	5		/* address space (resident set size) */
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#define	RLIMIT_RSS	RLIMIT_AS	/* source compatibility alias */
#define	RLIMIT_MEMLOCK	6		/* locked-in-memory address space */
#define	RLIMIT_NPROC	7		/* number of processes */
#endif	/* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
#define	RLIMIT_NOFILE	8		/* number of open files */
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
#define	RLIM_NLIMITS	9		/* total number of resource limits */
#endif	/* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
#define _RLIMIT_POSIX_FLAG	0x1000	/* Set bit for strict POSIX */

/*
 * A structure representing a resource limit.  The address of an instance
 * of this structure is the second parameter to getrlimit()/setrlimit().
 */
struct rlimit {
	rlim_t	rlim_cur;		/* current (soft) limit */
	rlim_t	rlim_max;		/* maximum value for rlim_cur */
};

#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
/*
 * proc_rlimit_control()
 *
 * Resource limit flavors
 */
#define RLIMIT_WAKEUPS_MONITOR		0x1 /* Configure the wakeups monitor. */
#define	RLIMIT_CPU_USAGE_MONITOR	0x2 /* Configure the CPU usage monitor. */

/*
 * Flags for wakeups monitor control.
 */
#define WAKEMON_ENABLE			0x01
#define WAKEMON_DISABLE			0x02
#define WAKEMON_GET_PARAMS		0x04
#define WAKEMON_SET_DEFAULTS		0x08
#define	WAKEMON_MAKE_FATAL		0x10 /* Configure the task so that violations are fatal. */
/*
 * Flags for CPU usage monitor control.
 */
#define	CPUMON_MAKE_FATAL		0x1000

struct proc_rlimit_control_wakeupmon {
	uint32_t wm_flags;
	int32_t wm_rate;
};

/* I/O type */
#define IOPOL_TYPE_DISK	0
#if PRIVATE
#define IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY 1
#endif

/* scope */
#define IOPOL_SCOPE_PROCESS   0
#define IOPOL_SCOPE_THREAD    1
#define IOPOL_SCOPE_DARWIN_BG 2

/* I/O Priority */
#define IOPOL_DEFAULT		0
#define IOPOL_IMPORTANT		1
#define IOPOL_PASSIVE		2
#define IOPOL_THROTTLE		3
#define IOPOL_UTILITY		4
#define IOPOL_STANDARD		5

/* compatibility with older names */
#define IOPOL_APPLICATION       IOPOL_STANDARD
#define IOPOL_NORMAL            IOPOL_IMPORTANT

#if PRIVATE
#define IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT	0
#define IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE	1
#endif

#ifdef PRIVATE
/*
 * Structures for use in communicating via iopolicysys() between Libc and the
 * kernel.  Not to be used by user programs directly.
 */

/*
 * the command to iopolicysys()
 */
#define	IOPOL_CMD_GET		0x00000001	/* Get I/O policy */
#define	IOPOL_CMD_SET		0x00000002	/* Set I/O policy */

/*
 * Second parameter to iopolicysys()
 */
struct _iopol_param_t {
	int iop_scope;	/* current process or a thread */
	int iop_iotype;
	int iop_policy;
};

#endif	/* PRIVATE */
#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */

#ifndef KERNEL

__BEGIN_DECLS
int	getpriority(int, id_t);
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
int	getiopolicy_np(int, int) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
int	getrlimit(int, struct rlimit *) __DARWIN_ALIAS(getrlimit);
int	getrusage(int, struct rusage *);
int	setpriority(int, id_t, int);
#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
int	setiopolicy_np(int, int, int) __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
#endif /* __DARWIN_C_LEVEL >= __DARWIN_C_FULL */
int	setrlimit(int, const struct rlimit *) __DARWIN_ALIAS(setrlimit);
__END_DECLS

#endif	/* !KERNEL */
#endif	/* !_SYS_RESOURCE_H_ */


text:
<refentry xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:xi="http://www.w3.org/2001/XInclude"
          xmlns:src="http://nwalsh.com/xmlns/litprog/fragment"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          version="5.0" xml:id="toc.bg.color">
<refmeta>
<refentrytitle>toc.bg.color</refentrytitle>
<refmiscinfo class="other" otherclass="datatype">color</refmiscinfo>
</refmeta>
<refnamediv>
<refname>toc.bg.color</refname>
<refpurpose>Background color for ToC frame</refpurpose>
</refnamediv>

<refsynopsisdiv>
<src:fragment xml:id="toc.bg.color.frag">
<xsl:param name="toc.bg.color">#FFFFFF</xsl:param>
</src:fragment>
</refsynopsisdiv>

<refsection><info><title>Description</title></info>

<para>Specifies the background color used in the ToC frame.</para>

</refsection>
</refentry>


text:
<resources>
    <string name="app_name">Adventures of Pokemons</string>
</resources>