m_TagState(eTagOutside), m_LeadingWs(0), m_Attlist(
false),
63m_SkipNextTag(
false)
70m_TagState(eTagOutside), m_LeadingWs(0), m_Attlist(
false),
74m_SkipNextTag(
false)
150 template<
typenameType>
inline 160(c >=
'A'&& c <=
'Z') ||
161(c >=
'a'&& c <=
'z') ||
162(c >=
'\xC0'&& c <=
'\xD6') ||
163(c >=
'\xD8'&& c <=
'\xF6') ||
164(c >=
'\xF8'&& c <=
'\xFF');
170 returnc >=
'0'&& c <=
'9';
188 return IsLetter(c) || c ==
'_'|| c ==
':';
207 IsDigit(c) || c ==
'.'|| c ==
'-'||
214 returnc ==
' '|| c ==
'\t'|| c ==
'\n'|| c ==
'\r';
220 returnc ==
'>'|| c ==
'/';
276 "double-hyphen '--' is not allowed in XML comments");
290 "double-hyphen '--' is not allowed in XML comments");
437 "Name begins with an invalid character: #" 441 size_t i= 1, iColon = 0;
454ns_prefix =
string(ptr, iColon-1);
459 if(c ==
'\n'|| c ==
'\r') {
464 if(ns_prefix ==
"xmlns") {
472 if(
type->GetName().empty() &&
477 if(
type&&
type->HasNamespaceName()) {
485}
else if(ns_prefix ==
"xml") {
499 if(
type->HasNamespaceName()) {
509 #if defined(NCBI_SERIAL_IO_TRACE) 531 #if defined(NCBI_SERIAL_IO_TRACE) 561 if(tagName ==
"encoding") {
588 if((
unsigned char)c == 0xEF) {
613 if( tagName ==
"DOCTYPE") {
624 else if( c ==
'"'|| c ==
'\'') {
635 "unknown tag in file header: "+
string(tagName));
648 if( !typeName.empty() && !tname.empty() && typeName != tname ) {
707 if(
type->HasNamespaceName()) {
708 stringnsName =
type->GetNamespaceName();
733 const size_tlimit = 32;
742 const char* end = p +
offset;
754 if( c >=
'0'&& c <=
'9')
755v = v * 16 + (c -
'0');
756 else if( c >=
'A'&& c <=
'F')
757v = v * 16 + (c -
'A'+ 0xA);
758 else if( c >=
'a'&& c <=
'f')
759v = v * 16 + (c -
'a'+ 0xA);
762 "invalid symbol in char reference");
771 if( c >=
'0'&& c <=
'9')
772v = v * 10 + (c -
'0');
775 "invalid symbol in char reference");
795 else if( c == endingChar ) {
812 return(x < 0x20 && x > 0x0 && x != 0x9 && x != 0xA && x != 0xD);
852 if(enc_in != enc_out) {
859 if((c & 0x80) == 0) {
875 while(chU && more--) {
896 charstartChar =
SkipWS();
897 if( startChar !=
'\''&& startChar !=
'\"')
900 boolencoded =
false;
925 if(!tagName.
empty()) {
939 boolhaveattr=
false;
943 if( attr ==
"value") {
948 if( attr ==
"nil") {
955 returnx_UseMemberDefault<bool>();
965 if( sValue ==
"true"|| sValue ==
"1")
968 if( sValue !=
"false"&& sValue !=
"0") {
970 "'true' or 'false' value expected: "+sValue);
982 returnx_UseMemberDefault<char>();
994 returnx_UseMemberDefault<Int4>();
1003 returnx_UseMemberDefault<Uint4>();
1012 returnx_UseMemberDefault<Int8>();
1021 returnx_UseMemberDefault<Uint8>();
1030 returnx_UseMemberDefault<double>();
1064 if(attribName.empty()) {
1069 value+= attribName;
1073 value+= attribValue;
1085 if(value2.empty()) {
1117 if(attribName.empty()) {
1122 if(attribName ==
"xmlns") {
1179 #if BITSTRING_AS_VECTOR 1185 const size_tstep=128;
1186obj.reserve( reserve=step );
1190obj.push_back( (
byte&
mask) != 0 );
1191 if(--reserve == 0) {
1192obj.reserve(obj.
size() + (reserve=step));
1196obj.reserve(obj.
size());
1213}
else if(c !=
'0') {
1280 const char* open =
"[CDATA[";
1281 for( ; *open; ++open) {
1317 boolencoded =
false;
1335}
else if(c ==
'\r') {
1338}
else if(c ==
'\r') {
1347 if(
str.size() > 128 && (double)
str.capacity()/((double)
str.size()+1.0) < 1.1 ) {
1348 str.reserve(
str.size()*2);
1353 str.reserve(
str.size());
1359 boolencoded =
false;
1373 str.reserve(
str.size());
1390 const string& enumName = values.
GetName();
1417 if( attr ==
"value") {
1423 if( attr !=
"value") {
1436 "incompatible name and value of named integer");
1509 const char*
str,
size_tlength)
1511 if(
tag.size() < length ||
1512memcmp(
tag.data(),
str, length) != 0 )
1528 if( !name.empty() )
1555 size_tlevel,
charc)
1558 if(
tag.empty() ||
tag[0] != c )
1595 if( !rest.
empty() )
1597 "unexpected tag: "+
string(tagName)+
string(rest));
1616 if( !rest.
empty() )
1618 "unexpected tag: "+
string(tagName)+
string(rest));
1627 if( !
type->GetName().empty() ) {
1634 if( !
type->GetName().empty() )
1640 while( elementType->
GetName().empty() ) {
1644elementType)->GetPointedType();
1689 if(clType && clType->
Implicit()) {
1767 boolno_more=
false;
1806 if(classType || aliasType) {
1817 if(classType && classType->
GetName().empty()) {
1821 return(classType && tagName == classType->
GetName()) || (aliasType && tagName == aliasType->
GetName());
1859 #ifdef VIRTUAL_MID_LEVEL_IO 1930 boolold_element = cType->
InitIterator(iter, containerPtr);
1934 if( old_element ) {
1946 if( old_element ) {
1954 boolold_element = cType->
InitIterator(iter, containerPtr);
1956 if( old_element ) {
1965 if( old_element ) {
2039 #ifdef VIRTUAL_MID_LEVEL_IO 2109 "\""+
string(
id)+
"\": unexpected member, should be one of: ";
2151 boolneedUndo =
false;
2179 string tag(tagName);
2206 if(!tagName.
empty()) {
2219 if(pos ==
first) {
2271 if(pos <= classType->GetItems().LastIndex()) {
2315 boolneedUndo =
false;
2342pos <= classType->GetMembers().LastIndex()) {
2357 string tag(tagName);
2385 #if defined(NCBI_SERIAL_IO_TRACE) 2473 boolneedUndo =
false;
2527 if( c >=
'0'&& c <=
'9') {
2530 else if( c >=
'A'&& c <=
'Z') {
2531 returnc -
'A'+ 10;
2533 else if( c >=
'a'&& c <=
'z') {
2534 returnc -
'a'+ 10;
2548( c >=
'A'&& c <=
'Z') ||
2549( c >=
'a'&& c <=
'z') ||
2550( c ==
'+'|| c ==
'/'|| c ==
'=')) {
2561 char* dst,
size_tlength)
2565 boolend_of_data =
false;
2566 const size_tchunk_in = 80;
2567 charsrc_buf[chunk_in];
2568 size_tbytes_left = length;
2569 size_tsrc_size, src_read, dst_written;
2570 while(!end_of_data && bytes_left > chunk_in && bytes_left <= length) {
2571 for( src_size = 0; src_size < chunk_in; ) {
2574end_of_data =
true;
2578src_buf[ src_size++ ] = (char)c;
2583dst, bytes_left, &dst_written);
2584 if(src_size != src_read) {
2587 count+= dst_written;
2588bytes_left -= dst_written;
2596 while( length-- > 0 ) {
2604*dst++ = char(c1 << 4);
2610*dst++ = char((c1 << 4) | c2);
2623 char* dst,
size_tlength)
2626 while( length-- > 0 ) {
2668 if( c < '0' || c >
'9') {
2696 if( c < '0' || c >
'9') {
2739 else if( c >=
'A'&& c <=
'Z') {
2742 else if( c >=
'a'&& c <=
'z') {
2745 else if( c ==
'\r'|| c ==
'\n') {
2749 else if( c ==
'+'|| c ==
'/'|| c ==
'=') {
2753 else if( c ==
'<') {
ncbi::TMaskedQueryRegions mask
Serializable object that stores any combination of parsable data.
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
CTypeInfo class contains all information about C++ types (both basic and classes): members and layout...
void resize(size_type new_size)
Change size of the bvector.
size_type size() const noexcept
Returns bvector's capacity (number of bits it can store)
bool set_bit(size_type n, bool val=true)
Sets bit n.
bvector_size_type size_type
void clear(const size_type *ids, size_type ids_size, bm::sort_order so=bm::BM_UNKNOWN)
clear list of bits in this bitset
const_iterator end() const
const_iterator find(const key_type &key) const
Include a standard set of the NCBI C++ Toolkit most basic headers.
static unsigned char depth[2 *(256+1+29)+1]
static const unsigned long CR
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
static const char * str(char *buf, int n)
const CMemberId & GetId(void) const
bool HasAnyContent(void) const
bool IsAttlist(void) const
const string & GetName(void) const
TMemberIndex Find(const CTempString &name) const
TMemberIndex FindEmpty(void) const
TMemberIndex FindDeep(const CTempString &name, bool search_attlist=false, const CClassTypeInfoBase **classInfo=nullptr) const
const CItemInfo * GetItemInfo(TMemberIndex index) const
static TMemberIndex FirstIndex(void)
bool HasNotag(void) const
TEnumValueType FindValue(const CTempString &name) const
Find numeric value by the name of the enum.
const string & GetName(void) const
bool HaveNoPrefix(void) const
TTypeInfo GetTypeInfo(void) const
TMemberIndex LastIndex(void) const
bool IsInteger(void) const
Check whether the type is defined as INTEGER in ASN.1 spec.
string ToString(void) const
static TObjectType & Get(TObjectPtr object)
size_t TMemberIndex
Type used for indexing class members and choice variants.
const TMemberIndex kInvalidMember
Special value returned from FindMember.
void SetName(const string &name)
Set local name.
void AddAttribute(const string &name, const string &ns_name, const CStringUTF8 &value)
Add attribute.
void SetNamespacePrefix(const string &ns_prefix)
Set namespace prefix.
void SetNamespaceName(const string &ns_name)
Set namespace name.
static const TObjectType * SafeCast(TTypeInfo type)
void SetValue(const CStringUTF8 &value)
Set normalized value.
@ eStringTypeUTF8
UTF8-encoded string.
virtual void SkipBitString(void) override
char BeginClosingTag(void)
void ReadWord(string &s, EStringType type=eStringTypeVisible)
static ETypeFamily GetRealTypeFamily(TTypeInfo typeInfo)
TFlags SetFlags(TFlags flags)
char ReplaceVisibleChar(char c, EFixNonPrint fix_method, const CObjectStack *io, const CTempString &str, char subst)
virtual void SkipByteBlock(void) override
CTempString SkipStackTagName(CTempString tag, size_t level)
void OpenTag(const string &e)
virtual void StartDelayBuffer(void) override
virtual TMemberIndex BeginClassMember(const CClassTypeInfo *classType) override
bool SelfClosedTag(void) const
TMemberIndex HasAnyContent(const CClassTypeInfoBase *classType, TMemberIndex pos=kInvalidMember)
virtual void ReadBitString(CBitString &obj) override
virtual void SkipUNumber(void) override
virtual char * ReadCString(void) override
virtual Uint4 ReadUint4(void) override
static CObjectIStream * CreateObjectIStreamXml(void)
virtual CRef< CByteSource > EndDelayBuffer(void) override
void CheckStdXml(TTypeInfo classType)
TUnicodeSymbol ReadUtf8Char(char ch)
CObjectTypeInfo GetPointedType(void) const
Get type information of data to which this type refers.
bool InsideOpeningTag(void) const
virtual void EndChoiceVariant(void) override
virtual void SkipChar(void) override
virtual string PeekNextTypeName(void) override
Peek next data type name in XML stream.
void OpenTagIfNamed(TTypeInfo type)
static TTypeInfo GetRealTypeInfo(TTypeInfo typeInfo)
bool ReadAnyContent(const string &ns_prefix, string &value)
bool GetEnforcedStdXml(void)
Get scope prefixes handling parameter.
#define BEGIN_OBJECT_FRAME(Type)
#define ThrowError(flag, mess)
virtual void ReadAnyContentObject(CAnyContentObject &obj) override
bool HasTypeInfo(void) const
virtual void SkipFNumber(void) override
EEncoding GetEncoding(void) const
Get XML character encoding.
virtual TMemberIndex BeginChoiceVariant(const CChoiceTypeInfo *choiceType) override
virtual char ReadChar(void) override
void EndArrayElement(void)
virtual string ReadFileHeader(void) override
Read file header.
virtual bool EndOfData(void)
Check if there is still some meaningful data that can be read; in text streams this function will ski...
virtual size_t ReadBytes(ByteBlock &block, char *dst, size_t length) override
bool IsCompressed(void) const
void SetSpecialCaseUsed(ESpecialCaseRead used)
#define BEGIN_OBJECT_FRAME2(Type, Arg)
MLIOVIR void ReadContainer(const CContainerTypeInfo *containerType, TObjectPtr containerPtr)
char SkipWSAndComments(void)
EEncoding m_StringEncoding
void SkipContainerContents(const CContainerTypeInfo *containerType)
void SkipObject(const CObjectTypeInfo &objectType)
Skip child object.
virtual double ReadDouble(void) override
void OpenStackTag(size_t level)
virtual void ResetState(void) override
map< string, string > m_NsNameToPrefix
void BeginArrayElement(TTypeInfo elementType)
virtual void EndNamedType(void) override
char BeginOpeningTag(void)
void Found_slash_gt(void)
virtual void BeginContainer(const CContainerTypeInfo *containerType) override
void UnexpectedMember(const CTempString &id, const CItemsInfo &items)
virtual Int8 ReadInt8(void) override
CObjectInfo ReadObject(void)
virtual void ResetState(void) override
CTempString ReadName(char c)
void CloseTagIfNamed(TTypeInfo type)
void SetNotag(bool set=true)
bool CanSkipUnknownMembers(void)
Simple check if it's allowed to skip unknown members.
bool InsideTag(void) const
void EndSelfClosedTag(void)
void Found_lt_slash(void)
void CloseStackTag(size_t level)
void SkipAttributeValue(char c)
virtual void BeginBytes(ByteBlock &) override
TFrame & FetchFrameFromTop(size_t index)
virtual size_t ReadChars(CharBlock &block, char *dst, size_t length) override
virtual void BeginChoice(const CChoiceTypeInfo *choiceType) override
void ReadAttributeValue(string &value, bool skipClosing=false)
bool UseSpecialCaseRead(void)
int ReadEncodedChar(char endingChar, EStringType type, bool &encoded)
bool ReadCDSection(string &s)
virtual void BeginClass(const CClassTypeInfo *classInfo) override
bool NextTagIsClosing(void)
CTempString SkipTagName(CTempString tag, const char *s, size_t length)
virtual bool EndOfData(void) override
Check if there is still some meaningful data that can be read; this function will skip white spaces a...
char ReadUndefinedAttributes(void)
virtual void ReadString(string &s, EStringType type=eStringTypeVisible) override
TObjectIndex ReadObjectPointer(void) override
virtual void SkipSNumber(void) override
virtual void BeginNamedType(TTypeInfo namedTypeInfo) override
static TTypeInfo GetContainerElementTypeInfo(TTypeInfo typeInfo)
void SetDefaultStringEncoding(EEncoding enc)
Set default encoding of 'string' objects If XML data encoding is different, string will be converted ...
virtual void BeginChars(CharBlock &) override
#define END_OBJECT_FRAME()
size_t GetStackDepth(void) const
virtual void SkipAnyContentObject(void) override
static CObjectIStream * Open(ESerialDataFormat format, CNcbiIstream &inStream, bool deleteInStream)
Create serial object reader and attach it to an input stream.
virtual void ReadNull(void) override
TEnumValueType ReadEnum(const CEnumeratedTypeValues &values) override
bool IsKnownElement(const CTempString &name) const
const TFrame & TopFrame(void) const
TTypeInfo GetTypeInfo(void) const
bool SkipAnyContent(void)
EFixNonPrint x_FixCharsMethod(void) const
TFailFlags SetFailFlags(TFailFlags flags, const char *message=0)
Set fail flags.
TFlags ClearFlags(TFlags flags)
virtual void SkipBool(void) override
bool StackIsEmpty(void) const
TMemberIndex FindDeep(TTypeInfo type, const CTempString &name) const
virtual bool BeginContainerElement(TTypeInfo elementType) override
bool OutsideTag(void) const
virtual void EndContainer(void) override
const CMemberId & GetMemberId(void) const
virtual bool ReadBool(void) override
EPointerType ReadPointerType(void) override
ETypeFamily GetTypeFamily(void) const
Get data type family.
virtual Int4 ReadInt4(void) override
MLIOVIR void ReadNamedType(TTypeInfo namedTypeInfo, TTypeInfo typeInfo, TObjectPtr object)
bool HasMoreElements(TTypeInfo elementType)
TConstObjectPtr GetMemberDefault(void) const
CStringUTF8::const_iterator m_Utf8Pos
bool WillHaveName(TTypeInfo elementType)
MLIOVIR void SkipContainer(const CContainerTypeInfo *containerType)
int ExpectSpecialCase(void) const
void FindFileHeader(bool find_XMLDecl=true)
void SetEnforcedStdXml(bool set=true)
Set up scope prefixes handling.
virtual void EndClassMember(void) override
string ReadOtherPointer(void) override
virtual void UndoClassMember(void) override
virtual void SkipString(EStringType type=eStringTypeVisible) override
virtual void EndClass(void) override
bool ThisTagIsSelfClosed(void)
EFrameType GetFrameType(void) const
bool CanSkipUnknownVariants(void)
Simple check if it's allowed to skip unknown variants.
virtual void Location(string &, size_t &) const override
Get current stream location as tuple (positiontype:string, size_t).
EEncoding GetDefaultStringEncoding(void) const
Get default encoding of 'string' objects.
int x_ReadEncodedChar(char endingChar, EStringType type, bool &encoded)
map< string, string > m_NsPrefixToName
CTempString RejectedName(void)
virtual void StartDelayBuffer(void)
Type x_UseMemberDefault(void)
char x_FixCharsSubst(void) const
int ReadEscapedChar(char endingChar, bool *encoded=0)
virtual void EndChoice(void) override
CTempString ReadAttributeName(void)
EPrimitiveValueType GetPrimitiveValueType(void) const
Get type of primitive value.
void x_EndTypeNamespace(void)
void ReadTagData(string &s, EStringType type=eStringTypeVisible)
virtual void EndContainerElement(void) override
bool EndOpeningTagSelfClosed(void)
void CloseTag(const string &e)
CObjectTypeInfo GetElementType(void) const
Get type information of an element of container.
virtual CRef< CByteSource > EndDelayBuffer(void)
void ReadCompressedBitString(CBitString &data)
virtual void SkipNull(void) override
virtual Uint8 ReadUint8(void) override
void ReadContainerContents(const CContainerTypeInfo *containerType, TObjectPtr containerPtr)
@ fIllegalCall
Illegal in a given context function call.
@ fNotImplemented
Method is not implemented.
@ fMissingValue
Mandatory value was missing in the input.
@ fInvalidData
Input data is incorrect (e.g. invalid enum)
@ fFail
Internal error, the real reason is unclear.
@ fUnknownValue
Unknown value was present in the input.
@ fFormatError
Input file formatting does not conform with specification.
uint8_t Uint1
1-byte (8-bit) unsigned integer
int32_t Int4
4-byte (32-bit) signed integer
uint32_t Uint4
4-byte (32-bit) unsigned integer
int64_t Int8
8-byte (64-bit) signed integer
uint64_t Uint8
8-byte (64-bit) unsigned integer
#define END_NCBI_SCOPE
End previously defined NCBI scope.
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
char PeekChar(size_t offset=0)
Int8 GetStreamPosAsInt8(void) const
size_t PeekFindChar(char c, size_t limit)
virtual void AddChunk(const char *buffer, size_t bufferLength)
Add data to the sub-source.
void SkipEndOfLine(char lastChar)
size_t GetLine(void) const
void SkipChars(size_t count)
const char * GetCurrentPos(void) const
char PeekCharNoEOF(size_t offset=0)
CRef< CSubSourceCollector > & GetSubSourceCollector(void)
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
static EEncoding StringToEncoding(const CTempString &encoding_name)
Convert encoding name into EEncoding enum, taking into account synonyms as per http://www....
static bool StringToBool(const CTempString str)
Convert string to bool.
static string AsSingleByteString(const CTempString &src, EEncoding encoding, const char *substitute_on_error=0, EValidate validate=eNoValidate)
Convert UTF8 string into a single-byte character representation.
static int strcmp(const char *s1, const char *s2)
String compare.
static void TruncateSpacesInPlace(string &str, ETrunc where=eTrunc_Both)
Truncate whitespace in a string (in-place)
static double StringToDoublePosix(const char *str, char **endptr=0, TStringToNumFlags flags=0)
Convert string to double-precision value (analog of strtod function)
char32_t TUnicodeSymbol
Unicode character.
static TUnicodeSymbol DecodeFirst(char ch, SIZE_TYPE &more)
Begin converting first character of UTF8 sequence into Unicode.
bool empty(void) const
Return true if the represented string is empty (i.e., the length is zero)
static char SymbolToChar(TUnicodeSymbol sym, EEncoding encoding)
Convert Unicode code point into encoded character.
static CStringUTF8 AsUTF8(const CTempString &src, EEncoding encoding, EValidate validate=eNoValidate)
Convert into UTF8 from a C/C++ string.
static string UIntToString(unsigned int value, TNumToStringFlags flags=0, int base=10)
Convert UInt to string.
static TUnicodeSymbol DecodeNext(TUnicodeSymbol chU, char ch)
Convert next character of UTF8 sequence into Unicode.
static TUnicodeSymbol CharToSymbol(char ch, EEncoding encoding)
Convert encoded character into Unicode.
@ eEncoding_ISO8859_1
Note: From the point of view of the C++.
@ fDecimalPosixFinite
StringToDouble*(): Keep result finite and normalized: if DBL_MAX < result < INF, result becomes DBL_M...
const string & GetName(void) const
Get name of this type.
const CItemsInfo & GetItems(void) const
EDataSpec GetDataSpec(void) const
ETypeFamily GetTypeFamily(void) const
TObjectPtr AddElement(TObjectPtr containerPtr, TConstObjectPtr elementPtr, ESerialRecursionMode how=eRecursive) const
TTypeInfo GetPointedType(void) const
const CItemsInfo & GetVariants(void) const
bool MayBeEmpty(void) const
const CMemberInfo * GetMemberInfo(TMemberIndex index) const
const CVariantInfo * GetVariantInfo(TMemberIndex index) const
bool Implicit(void) const
void ReadData(CObjectIStream &in, TObjectPtr object) const
size_t GetCodeVersion(void) const
TConstObjectPtr GetElementPtr(const CConstIterator &it) const
bool InitIterator(CConstIterator &it, TConstObjectPtr containerPtr) const
bool NextElement(CConstIterator &it) const
void EraseAllElements(CIterator &it) const
const CItemsInfo & GetMembers(void) const
bool IsFullAlias(void) const
TTypeInfo GetElementType(void) const
bool IsImplicitNonEmpty(void) const
enum ENcbiOwnership EOwnership
Ownership relations between objects.
constexpr bool empty(list< Ts... >) noexcept
const GenericPointer< typename T::ValueType > T2 value
std::istream & in(std::istream &in_, double &x_)
static bool IsWhiteSpace(char c)
static bool IsNameChar(char c)
static bool IsIdeographic(char)
static bool IsCombiningChar(char)
static const char * s_SchemaInstanceNamespace
static bool IsFirstNameChar(char c)
static bool IsExtender(char c)
static bool IsBaseChar(char c)
static bool IsLetter(char c)
static bool IsEndOfTagChar(char c)
static bool IsDigit(char c)
#define NcbiSysChar_strdup
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4