Пример #1
0
CString
CKeyMap::formatKey(KeyID key, KeyModifierMask mask)
{
	// initialize tables
	initKeyNameMaps();

	CString x;
	for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) {
		KeyModifierMask mod = (1u << i);
		if ((mask & mod) != 0 && s_modifierToNameMap->count(mod) > 0) {
			x += s_modifierToNameMap->find(mod)->second;
			x += "+";
		}
	}
	if (key != kKeyNone) {
		if (s_keyToNameMap->count(key) > 0) {
			x += s_keyToNameMap->find(key)->second;
		}
		// XXX -- we're assuming ASCII here
		else if (key >= 33 && key < 127) {
			x += (char)key;
		}
		else {
			x += CStringUtil::print("\\u%04x", key);
		}
	}
	else if (!x.empty()) {
		// remove trailing '+'
		x.erase(x.size() - 1);
	}
	return x;
}
void RageFileManager::GetDirListing( CString sPath, CStringArray &AddTo, bool bOnlyDirs, bool bReturnPathToo )
{
	LockMut( *g_Mutex );

	NormalizePath( sPath );
	
	for( unsigned i = 0; i < g_Drivers.size(); ++i )
	{
		LoadedDriver &ld = g_Drivers[i];
		const CString p = ld.GetPath( sPath );
		if( p.size() == 0 )
			continue;

		const unsigned OldStart = AddTo.size();
		
		g_Drivers[i].driver->GetDirListing( p, AddTo, bOnlyDirs, bReturnPathToo );

		/* If returning the path, prepend the mountpoint name to the files this driver returned. */
		if( bReturnPathToo )
			for( unsigned j = OldStart; j < AddTo.size(); ++j )
				AddTo[j] = ld.MountPoint + AddTo[j];
	}

	/* More than one driver might return the same file.  Remove duplicates (case-
	 * insensitively). */
	sort( AddTo.begin(), AddTo.end(), ilt );
	CStringArray::iterator it = unique( AddTo.begin(), AddTo.end(), ieq );
	AddTo.erase(it, AddTo.end());
}
Пример #3
0
bool CNamedItem::isEquals(const CString &name, bool startsWith) const {
	if (startsWith) {
		return getName().left(name.size()).compareToIgnoreCase(name) == 0;
	} else {
		return getName().compareToIgnoreCase(name) == 0;
	}
}
Пример #4
0
CString ScreenPackages::StripOutContainers( const CString & In )
{
	if( In.size() == 0 )
		return "";

	unsigned i = 0;
	char t = In.at(i);
	while( t == ' ' && i < In.length() )
	{
		t = In.at(++i);
	}

	if( t == '\"' || t == '\'' )
	{
		unsigned j = i+1; 
		char u = In.at(j);
		while( u != t && j < In.length() )
		{
			u = In.at(++j);
		}
		if( j == i )
			return StripOutContainers( In.substr(i+1) );
		else
			return StripOutContainers( In.substr(i+1, j-i-1) );
	}
	return In.substr( i );
}
Пример #5
0
void ScreenTestSound::UpdateText(int n)
{
	CString fn = Basename( s[n].s.GetLoadedFilePath() );

	vector<RageSound *> snds;
	SOUNDMAN->GetCopies(s[n].s, snds);

	CString pos;
	for(unsigned p = 0; p < snds.size(); ++p)
	{
		if(p) pos += ", ";
		pos += ssprintf("%.3f", snds[p]->GetPositionSeconds());
	}

	s[n].txt.SetText(ssprintf(
		"%i: %s\n"
		"%s\n"
		"%s\n"
		"(%s)\n"
		"%s",
		n+1, fn.c_str(),
		s[n].s.IsPlaying()? "Playing":"Stopped",
		s[n].s.GetParams().StopMode == RageSoundParams::M_STOP?
			"Stop when finished":
		s[n].s.GetParams().StopMode == RageSoundParams::M_CONTINUE?
			"Continue until stopped":
			"Loop",
		pos.size()? pos.c_str(): "none playing",
		selected == n? "^^^^^^":""
		));
}
Пример #6
0
void CGlassStatePacket::Send(CPlayer *pPlayer) const
{
    CString RoomsBitmap;
    
    const set<CElement*> Rooms = pPlayer->GetServer()->GetLevel()->GetElementsMgr()->GetByType(OFET_LEVEL);
    set<CElement*>::iterator it;
    for(it = Rooms.begin(); it != Rooms.end(); ++it)
    {
        CRoom *pRoom = (CRoom*)*it;
        
        if(pRoom->IsGlass())
        {
            unsigned i = pRoom->GetGlassIndex();
            
            if(i / 8 >= RoomsBitmap.size())
                RoomsBitmap.resize(i / 8 + 1);
            
            if(pRoom->GetLife() > 0.0f)
                RoomsBitmap[i / 8] |= 1 << (i % 8);
        }
    }
    
    if(!RoomsBitmap.empty())
        pPlayer->GetConnection()->AddPacket(RF_GLASS_STATE, RoomsBitmap, true);
}
void RageFileManager::Unmount( CString Type, CString Root, CString MountPoint )
{
	LockMut( *g_Mutex );

	FixSlashesInPlace( Root );
	FixSlashesInPlace( MountPoint );

	if( MountPoint.size() && MountPoint.Right(1) != "/" )
		MountPoint += '/';

	for( unsigned i = 0; i < g_Drivers.size(); ++i )
	{
		if( g_Drivers[i].Type.CompareNoCase( Type ) )
			continue;
		if( g_Drivers[i].Root.CompareNoCase( Root ) )
			continue;
		if( g_Drivers[i].MountPoint.CompareNoCase( MountPoint ) )
			continue;

		delete g_Drivers[i].driver;
		g_Drivers.erase( g_Drivers.begin()+i );
	}

	g_Mountpoints->LoadFromDrivers( g_Drivers );
}
Пример #8
0
void TextBanner::LoadFromString( 
	CString sDisplayTitle, CString sTranslitTitle, 
	CString sDisplaySubTitle, CString sTranslitSubTitle, 
	CString sDisplayArtist, CString sTranslitArtist )
{
	Init();

	bool bTwoLines = sDisplaySubTitle.size() == 0;

	if( bTwoLines )
	{
		m_textTitle.Command( TWO_LINES_TITLE_COMMAND );
		m_textSubTitle.Command( TWO_LINES_SUBTITLE_COMMAND );
		m_textArtist.Command( TWO_LINES_ARTIST_COMMAND );
	}
	else
	{
		m_textTitle.Command( THREE_LINES_TITLE_COMMAND );
		m_textSubTitle.Command( THREE_LINES_SUBTITLE_COMMAND );
		m_textArtist.Command( THREE_LINES_ARTIST_COMMAND );
	}

	m_textTitle.SetText( sDisplayTitle, sTranslitTitle );
	m_textSubTitle.SetText( sDisplaySubTitle, sTranslitSubTitle );
	m_textArtist.SetText( sDisplayArtist, sTranslitArtist );
}
Пример #9
0
// Variant value must be released with NPReleaseVariantValue()
void coerceValueToNPVariantStringType (KJS::ExecState *exec, const KJS::Value &value, NPVariant *result)
{
    UString ustring = value.toString(exec);
    CString cstring = ustring.UTF8String();
    NPString string = { (const NPUTF8 *)cstring.c_str(), cstring.size() };
    NPN_InitializeVariantWithStringCopy (result, &string);
}
Пример #10
0
void split( const CString &Source, const CString &Delimitor, CStringArray &AddIt, const bool bIgnoreEmpty )
{
	if( Delimitor.size() == 1 )
		do_split( Source, Delimitor[0], AddIt, bIgnoreEmpty );
	else
		do_split( Source, Delimitor, AddIt, bIgnoreEmpty );
}
Пример #11
0
void
CServerProxy::onClipboardChanged(ClipboardID id, const IClipboard* clipboard)
{
	CString data = IClipboard::marshall(clipboard);
	LOG((CLOG_DEBUG1 "sending clipboard %d seqnum=%d, size=%d", id, m_seqNum, data.size()));
	CProtocolUtil::writef(m_stream, kMsgDClipboard, id, m_seqNum, &data);
}
Пример #12
0
void RSAKey::Sign( const CString &data, CString &out ) const
{
	Bignum in;
	{
		unsigned char hash[20];
		SHA_Simple(data.data(), data.size(), hash);

		int nbytes = (bignum_bitcount(this->modulus) - 1) / 8;
		unsigned char *bytes = new unsigned char[nbytes];

		memset( bytes, 0xFF, nbytes );
		bytes[0] = 1;
		memcpy( bytes + nbytes - 20, hash, 20 );

		in = bignum_from_bytes(bytes, nbytes);
		delete [] bytes;
	}

	Bignum outnum = rsa_privkey_op(in, this);
	delete [] in;

	int siglen;
	unsigned char *bytes = bignum_to_bytes( outnum, &siglen );
	delete [] outnum;

	out = CString( (const char *) bytes, siglen );
	delete [] bytes;
}
Пример #13
0
IKeyState::CKeyInfo*
IKeyState::CKeyInfo::alloc(KeyID id,
				KeyModifierMask mask, KeyButton button, SInt32 count,
				const std::set<CString>& destinations)
{
	// collect destinations into a string.  names are surrounded by ':'
	// which makes searching easy later.  the string is empty if there
	// are no destinations and "*" means all destinations.
	CString screens;
	for (std::set<CString>::const_iterator i = destinations.begin();
								i != destinations.end(); ++i) {
		if (*i == "*") {
			screens = "*";
			break;
		}
		else {
			if (screens.empty()) {
				screens = ":";
			}
			screens += *i;
			screens += ":";
		}
	}

	// build structure
	CKeyInfo* info = (CKeyInfo*)malloc(sizeof(CKeyInfo) + screens.size());
	info->m_key    = id;
	info->m_mask   = mask;
	info->m_button = button;
	info->m_count  = count;
	strcpy(info->m_screens, screens.c_str());
	return info;
}
Пример #14
0
void TextBanner::LoadFromString( 
	const CString &sDisplayTitle, const CString &sTranslitTitle, 
	const CString &sDisplaySubTitle, const CString &sTranslitSubTitle, 
	const CString &sDisplayArtist, const CString &sTranslitArtist )
{
	ASSERT( m_bInitted );

	m_textTitle.SetText( sDisplayTitle, sTranslitTitle );
	m_textSubTitle.SetText( sDisplaySubTitle, sTranslitSubTitle );
	m_textArtist.SetText( sDisplayArtist, sTranslitArtist );

	bool bTwoLines = sDisplaySubTitle.size() == 0;

	if( bTwoLines )
	{
		m_textTitle.RunCommands( TWO_LINES_TITLE_COMMAND, this );
		m_textSubTitle.RunCommands( TWO_LINES_SUBTITLE_COMMAND, this );
		m_textArtist.RunCommands( TWO_LINES_ARTIST_COMMAND, this );
	}
	else
	{
		m_textTitle.RunCommands( THREE_LINES_TITLE_COMMAND, this );
		m_textSubTitle.RunCommands( THREE_LINES_SUBTITLE_COMMAND, this );
		m_textArtist.RunCommands( THREE_LINES_ARTIST_COMMAND, this );
	}
}
Пример #15
0
void CChan::ModeChange(const CString& sModes, const CString& sOpNick) {
	CString sModeArg = sModes.Token(0);
	CString sArgs = sModes.Token(1, true);
	bool bAdd = true;

#ifdef _MODULES
	CNick* pOpNick = FindNick(sOpNick);

	if (pOpNick) {
		MODULECALL(OnRawMode(*pOpNick, *this, sModeArg, sArgs), m_pUser, NULL, );
	}
#endif

	for (unsigned int a = 0; a < sModeArg.size(); a++) {
		const unsigned char& uMode = sModeArg[a];

		if (uMode == '+') {
			bAdd = true;
		} else if (uMode == '-') {
			bAdd = false;
		} else if (m_pUser->GetIRCSock()->IsPermMode(uMode)) {
			CString sArg = GetModeArg(sArgs);
			CNick* pNick = FindNick(sArg);
			if (pNick) {
				unsigned char uPerm = m_pUser->GetIRCSock()->GetPermFromMode(uMode);

				if (uPerm) {
					if (bAdd) {
						pNick->AddPerm(uPerm);

						if (pNick->GetNick().Equals(m_pUser->GetCurNick())) {
							AddPerm(uPerm);
						}
					} else {
						pNick->RemPerm(uPerm);

						if (pNick->GetNick().Equals(m_pUser->GetCurNick())) {
							RemPerm(uPerm);
						}
					}
#ifdef _MODULES
					bool bNoChange = (pNick->HasPerm(uPerm) == bAdd);

					if (uMode && pOpNick) {
						MODULECALL(OnChanPermission(*pOpNick, *pNick, *this, uMode, bAdd, bNoChange), m_pUser, NULL, );

						if (uMode == CChan::M_Op) {
							if (bAdd) {
								MODULECALL(OnOp(*pOpNick, *pNick, *this, bNoChange), m_pUser, NULL, );
							} else {
								MODULECALL(OnDeop(*pOpNick, *pNick, *this, bNoChange), m_pUser, NULL, );
							}
						} else if (uMode == CChan::M_Voice) {
							if (bAdd) {
								MODULECALL(OnVoice(*pOpNick, *pNick, *this, bNoChange), m_pUser, NULL, );
							} else {
								MODULECALL(OnDevoice(*pOpNick, *pNick, *this, bNoChange), m_pUser, NULL, );
							}
						}
					}
/* path must be normalized (FixSlashesInPlace, CollapsePath). */
CString LoadedDriver::GetPath( const CString &path )
{
	/* Default mountpoints: */
	if( MountPoint.size() == 0 )
	{
		/* If the path begins with @, default mount points don't count. */
		if( path.size() && path[0] == '@' )
			return "";
		return path;
	}
	
	if( path.Left( MountPoint.size() ).CompareNoCase( MountPoint ) )
		return ""; /* no match */

	return path.Right( path.size() - MountPoint.size() );
}
Пример #17
0
RageFileBasic *RageFileDriverDirect::Open( const CString &sPath_, int iMode, int &iError )
{
	CString sPath = sPath_;
	ASSERT( sPath.size() && sPath[0] == '/' );

	/* This partially resolves.  For example, if "abc/def" exists, and we're opening
	 * "ABC/DEF/GHI/jkl/mno", this will resolve it to "abc/def/GHI/jkl/mno"; we'll
	 * create the missing parts below. */
	FDB->ResolvePath( sPath );

	if( iMode & RageFile::WRITE )
	{
		const CString dir = Dirname(sPath);
		if( this->GetFileType(dir) != RageFileManager::TYPE_DIR )
			CreateDirectories( m_sRoot + dir );
	}

	RageFileObjDirect *ret = this->CreateInternal( m_sRoot + sPath );

	if( ret->OpenInternal( m_sRoot + sPath, iMode, iError) )
		return ret;

	SAFE_DELETE( ret );
	return NULL;
}
bool
CXWindowsClipboard::motifOwnsClipboard() const
{
	// get the current selection owner
	// FIXME -- this can't be right.  even if the window is destroyed
	// Motif will still have a valid clipboard.  how can we tell if
	// some other client owns CLIPBOARD?
	Window owner = XGetSelectionOwner(m_display, m_selection);
	if (owner == None) {
		return false;
	}

	// get the Motif clipboard header property from the root window
	Atom target;
	SInt32 format;
	CString data;
	Window root = RootWindow(m_display, DefaultScreen(m_display));
	if (!CXWindowsUtil::getWindowProperty(m_display, root,
								m_atomMotifClipHeader,
								&data, &target, &format, False)) {
		return false;
	}

	// check the owner window against the current clipboard owner
	const CMotifClipHeader* header =
						reinterpret_cast<const CMotifClipHeader*>(data.data());
	if (data.size() >= sizeof(CMotifClipHeader) &&
		header->m_id == kMotifClipHeader) {
		if (static_cast<Window>(header->m_selectionOwner) == owner) {
			return true;
		}
	}

	return false;
}
Пример #19
0
bool getline(CString &_str, CString &line){
  if(_str.size()==0)  return false;
  CString::size_type pLeft=0, pRight = _str.find('\n');
  line = _str.substr( pLeft, pRight );
  _str = _str.erase(0,pRight+1);
  return true;
};
Пример #20
0
void FileReading::SkipBytes( RageFileBasic &f, int iBytes, CString &sError )
{
	if( sError.size() != 0 )
		return;

	iBytes += f.Tell();
	FileReading::Seek( f, iBytes, sError );
}
Пример #21
0
bool
CConfig::isValidScreenName(const CString& name) const
{
	// name is valid if matches validname
	//  name      ::= [_A-Za-z0-9] | [_A-Za-z0-9][-_A-Za-z0-9]*[_A-Za-z0-9]
	//  domain    ::= . name
	//  validname ::= name domain*

	// check each dot separated part
	CString::size_type b = 0;
	for (;;) {
		// find end of part
		CString::size_type e = name.find('.', b);
		if (e == CString::npos) {
			e = name.size();
		}

		// part may not be empty
		if (e - b < 1) {
			return false;
		}

		// check first and last characters
		if (!(isalnum(name[b]) || name[b] == '_') ||
			!(isalnum(name[e - 1]) || name[e - 1] == '_')) {
			return false;
		}

		// check interior characters
		for (CString::size_type i = b; i < e; ++i) {
			if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') {
				return false;
			}
		}

		// next part
		if (e == name.size()) {
			// no more parts
			break;
		}
		b = e + 1;
	}

	return true;
}
Пример #22
0
// 从注册表取ECC 服务端安装目录
CString GetRootPath()
{
	CString resultStr =  _T("");
	string rootPath = _T("");

	try
	{
		HKEY hKey = NULL;
		LONG lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,KEY_PATH,0,KEY_READ,&hKey);
		if(lRet != ERROR_SUCCESS)
			return resultStr;
		
		LPTSTR  lpName = NULL,
 				lpValue = NULL;
		TCHAR	strSubKey[1024]={0};
		TCHAR	strValKey[1024]={0};
		DWORD   dwIndex = 0,
				dwS1 = 1024,
				dwS2 = 1024,
				dwType = REG_SZ;
		BOOL    bFindFlag = FALSE;
		TCHAR szAppRoot[1024] = {0};
		while(lRet == ERROR_SUCCESS)
		{
			lpName = (LPTSTR)strSubKey;
			lpValue = (LPTSTR)strValKey;
			lRet = RegEnumValue(hKey, dwIndex++, lpName , &dwS1,NULL, &dwType ,(LPBYTE)lpValue, &dwS2);
			dwS1 = 1024;
			dwS2 = 1024;
			if(lRet == ERROR_NO_MORE_ITEMS)
				break;

			if(::_stricmp(strSubKey,KEY_NAME)==0)
			{
				bFindFlag = TRUE;
				rootPath = strValKey;//

				//strcpy(rootPath,strValKey);
				break;
			}
		}

		RegCloseKey(hKey);		
	}
	catch(...)
	{
		return resultStr;
	}
	
	int pos = rootPath.rfind("\\");
	if(pos == rootPath.size()-1)
		rootPath.erase(pos,1);

	resultStr = rootPath.c_str();

	return resultStr;
}
Пример #23
0
	CString(const CString& theOther)
	{
		if (this != &theOther)
		{
			this->m_pszData = (char*)theOther.c_str();
			this->m_stLength = theOther.size();
			this->m_pszData[m_stLength + sizeof(char)]++;
		}
	}
Пример #24
0
// Variant value must be released with NPReleaseVariantValue()
void convertValueToNPVariant (KJS::ExecState *exec, const KJS::Value &value, NPVariant *result)
{
    Type type = value.type();

    if (type == StringType) {
        UString ustring = value.toString(exec);
        CString cstring = ustring.UTF8String();
        NPString string = { (const NPUTF8 *)cstring.c_str(), cstring.size() };
        NPN_InitializeVariantWithStringCopy (result, &string );
    }
    else if (type == NumberType) {
        NPN_InitializeVariantWithDouble (result, value.toNumber(exec));
    }
    else if (type == BooleanType) {
        NPN_InitializeVariantWithBool (result, value.toBoolean(exec));
    }
    else if (type == UnspecifiedType) {
        NPN_InitializeVariantAsUndefined(result);
    }
    else if (type == NullType) {
        NPN_InitializeVariantAsNull(result);
    }
    else if (type == ObjectType) {
        KJS::ObjectImp *objectImp = static_cast<KJS::ObjectImp*>(value.imp());
        if (objectImp->classInfo() == &KJS::RuntimeObjectImp::info) {
            KJS::RuntimeObjectImp *imp = static_cast<KJS::RuntimeObjectImp *>(value.imp());
            CInstance *instance = static_cast<CInstance*>(imp->getInternalInstance());
            NPN_InitializeVariantWithObject (result, instance->getObject());
        }
        else {

            KJS::Interpreter *originInterpreter = exec->interpreter();
            const Bindings::RootObject *originExecutionContext = rootForInterpreter(originInterpreter);

            KJS::Interpreter *interpreter = 0;
            if (originInterpreter->isGlobalObject(value)) {
                interpreter = originInterpreter->interpreterForGlobalObject (value.imp());
            }

            if (!interpreter)
                interpreter = originInterpreter;

            const Bindings::RootObject *executionContext = rootForInterpreter(interpreter);
            if (!executionContext) {
                Bindings::RootObject *newExecutionContext = new KJS::Bindings::RootObject(0);
                newExecutionContext->setInterpreter (interpreter);
                executionContext = newExecutionContext;
            }

            NPObject *obj = (NPObject *)exec->interpreter()->createLanguageInstanceForValue (exec, Instance::CLanguage, value.toObject(exec), originExecutionContext, executionContext);
            NPN_InitializeVariantWithObject (result, obj);
            _NPN_ReleaseObject (obj);
        }
    }
    else
        NPN_InitializeVariantAsUndefined(result);
}
Пример #25
0
void DifficultyMeter::LoadFromNode( const CString& sDir, const XNode* pNode )
{
	ActorFrame::LoadFromNode( sDir, pNode );

	CString s;
	pNode->GetAttrValue( "Type", s );
	ASSERT( s.size() );
	Load( s );
}
Пример #26
0
bool
CKeyMap::parseModifiers(CString& x, KeyModifierMask& mask)
{
	// initialize tables
	initKeyNameMaps();

	mask = 0;
	CString::size_type tb = x.find_first_not_of(" \t", 0);
	while (tb != CString::npos) {
		// get next component
		CString::size_type te = x.find_first_of(" \t+)", tb);
		if (te == CString::npos) {
			te = x.size();
		}
		CString c = x.substr(tb, te - tb);
		if (c.empty()) {
			// missing component
			return false;
		}

		if (s_nameToModifierMap->count(c) > 0) {
			KeyModifierMask mod = s_nameToModifierMap->find(c)->second;
			if ((mask & mod) != 0) {
				// modifier appears twice
				return false;
			}
			mask |= mod;
		}
		else {
			// unknown string
			x.erase(0, tb);
			CString::size_type tb = x.find_first_not_of(" \t");
			CString::size_type te = x.find_last_not_of(" \t");
			if (tb == CString::npos) {
				x = "";
			}
			else {
				x = x.substr(tb, te - tb + 1);
			}
			return true;
		}

		// check for '+' or end of string
		tb = x.find_first_not_of(" \t", te);
		if (tb != CString::npos) {
			if (x[tb] != '+') {
				// expected '+'
				return false;
			}
			tb = x.find_first_not_of(" \t", tb + 1);
		}
	}

	// parsed the whole thing
	x = "";
	return true;
}
Пример #27
0
uint8_t FileReading::read_8( RageFileBasic &f, CString &sError )
{
	uint8_t val;
	ReadBytes( f, &val, sizeof(uint8_t), sError );
	if( sError.size() == 0 )
		return val;
	else
		return 0;
}
Пример #28
0
uint16_t FileReading::read_u16_le( RageFileBasic &f, CString &sError )
{
	uint16_t val;
	ReadBytes( f, &val, sizeof(uint16_t), sError );
	if( sError.size() == 0 )
		return Swap16LE( val );
	else
		return 0;
}
Пример #29
0
int32_t FileReading::read_32_le( RageFileBasic &f, CString &sError )
{
	int32_t val;
	ReadBytes( f, &val, sizeof(int32_t), sError );
	if( sError.size() == 0 )
		return Swap32LE( val );
	else
		return 0;
}
Пример #30
0
size_t JSStringGetUTF8CString(JSStringRef string, char* buffer, size_t bufferSize)
{
    JSLock lock;
    UString::Rep* rep = toJS(string);
    CString cString = UString(rep).UTF8String();

    size_t length = std::min(bufferSize, cString.size() + 1); // + 1 for terminating '\0'
    memcpy(buffer, cString.c_str(), length);
    return length;
}