本文整理汇总了C++中BYTE_VECTOR类的典型用法代码示例。如果您正苦于以下问题:C++ BYTE_VECTOR类的具体用法?C++ BYTE_VECTOR怎么用?C++ BYTE_VECTOR使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了BYTE_VECTOR类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: SetDiff
void CFileDiffDlg::SetDiff(CTGitPath * path, CString &hash1, CString &hash2)
{
if(path!=NULL)
{
m_path1 = *path;
m_path2 = *path;
m_sFilter = path->GetGitPathString();
}
BYTE_VECTOR logout;
if(hash1 == GIT_REV_ZERO)
{
m_rev1.m_CommitHash.Empty();
m_rev1.GetSubject()=_T("Working Copy");
}
else
{
m_rev1.GetCommit(hash1);
}
logout.clear();
if(hash2 == GIT_REV_ZERO)
{
m_rev2.m_CommitHash.Empty();
m_rev2.GetSubject()=_T("Working Copy");
}
else
{
m_rev2.GetCommit(hash2);
}
}
示例2: SetDiff
void CFileDiffDlg::SetDiff(const CTGitPath * path, const CString &hash1, const CString &hash2)
{
if(path!=NULL)
{
m_path1 = *path;
m_path2 = *path;
m_sFilter = path->GetGitPathString();
}
BYTE_VECTOR logout;
if(hash1 == GIT_REV_ZERO)
{
m_rev1.m_CommitHash.Empty();
m_rev1.GetSubject().LoadString(IDS_git_DEPTH_WORKING);
}
else
{
if (m_rev1.GetCommit(hash1))
MessageBox(m_rev1.GetLastErr(), _T("TortoiseGit"), MB_ICONERROR);
}
logout.clear();
if(hash2 == GIT_REV_ZERO)
{
m_rev2.m_CommitHash.Empty();
m_rev2.GetSubject().LoadString(IDS_git_DEPTH_WORKING);
}
else
{
if (m_rev2.GetCommit(hash2))
MessageBox(m_rev2.GetLastErr(), _T("TortoiseGit"), MB_ICONERROR);
}
}
示例3: SetDiff
void CFileDiffDlg::SetDiff(CTGitPath * path, CString hash1, CString hash2)
{
if(path!=NULL)
{
m_path1 = *path;
m_path2 = *path;
m_sFilter = path->GetGitPathString();
}
BYTE_VECTOR logout;
if(hash1 == GIT_REV_ZERO)
{
m_rev1.m_CommitHash.Empty();
m_rev1.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
}
else
{
m_rev1.GetCommit(hash1);
}
logout.clear();
if(hash2 == GIT_REV_ZERO)
{
m_rev2.m_CommitHash.Empty();
m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
}
else
{
m_rev2.GetCommit(hash2);
}
}
示例4: GetEncode
int CTortoiseGitBlameData::GetEncode(int *bomoffset)
{
int encoding = 0;
BYTE_VECTOR rawAll;
for (const auto& rawBytes : m_RawLines)
rawAll.append(rawBytes.data(), rawBytes.size());
encoding = GetEncode(rawAll.data(), static_cast<int>(rawAll.size()), bomoffset);
return encoding;
}
示例5: GetEncode
int CTortoiseGitBlameData::GetEncode(int *bomoffset)
{
int encoding = 0;
BYTE_VECTOR rawAll;
for (auto it = m_RawLines.begin(), it_end = m_RawLines.end(); it != it_end; ++it)
{
rawAll.append(&(*it)[0], it->size());
}
encoding = GetEncode(&rawAll[0], (int)rawAll.size(), bomoffset);
return encoding;
}
示例6: GetEncode
int CTortoiseGitBlameData::GetEncode(int *bomoffset)
{
int encoding = 0;
BYTE_VECTOR rawAll;
for (const auto& rawBytes : m_RawLines)
{
rawAll.append(&rawBytes[0], rawBytes.size());
}
encoding = GetEncode(&rawAll[0], (int)rawAll.size(), bomoffset);
return encoding;
}
示例7: Run
int CGit::Run(CString cmd, CString* output,int code)
{
BYTE_VECTOR vector;
int ret;
ret=Run(cmd,&vector);
vector.push_back(0);
StringAppend(output,&(vector[0]),code);
return ret;
}
示例8: ParserFromLsFile
int CTGitPathList::ParserFromLsFile(BYTE_VECTOR &out,bool /*staged*/)
{
int pos=0;
CString one;
CTGitPath path;
CString part;
this->Clear();
while (pos >= 0 && pos < (int)out.size())
{
one.Empty();
path.Reset();
CGit::StringAppend(&one, &out[pos], CP_UTF8);
int tabstart=0;
// m_Action is never used and propably never worked (needs to be set after path.SetFromGit)
// also dropped LOGACTIONS_CACHE for 'H'
// path.m_Action=path.ParserAction(out[pos]);
one.Tokenize(_T("\t"),tabstart);
if(tabstart>=0)
path.SetFromGit(one.Right(one.GetLength()-tabstart));
else
return -1;
tabstart=0;
part=one.Tokenize(_T(" "),tabstart); //Tag
if (tabstart < 0)
return -1;
part=one.Tokenize(_T(" "),tabstart); //Mode
if (tabstart < 0)
return -1;
part=one.Tokenize(_T(" "),tabstart); //Hash
if (tabstart < 0)
return -1;
part=one.Tokenize(_T("\t"),tabstart); //Stage
if (tabstart < 0)
return -1;
path.m_Stage=_ttol(part);
this->AddPath(path);
pos=out.findNextString(pos);
}
return 0;
}
示例9: SetDiff
void CFileDiffDlg::SetDiff(const CTGitPath * path, const CString &hash1, const CString &hash2)
{
if(path!=NULL)
{
m_path1 = *path;
m_path2 = *path;
m_sFilter = path->GetGitPathString();
}
BYTE_VECTOR logout;
if(hash1 == GIT_REV_ZERO)
{
m_rev1.m_CommitHash.Empty();
m_rev1.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
}
else
{
try
{
m_rev1.GetCommit(hash1);
}
catch (const char *msg)
{
MessageBox(_T("Could not get commit ") + hash1 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
}
}
logout.clear();
if(hash2 == GIT_REV_ZERO)
{
m_rev2.m_CommitHash.Empty();
m_rev2.GetSubject() = CString(MAKEINTRESOURCE(IDS_git_DEPTH_WORKING));
}
else
{
try
{
m_rev2.GetCommit(hash2);
}
catch (const char *msg)
{
MessageBox(_T("Could not get commit ") + hash2 + _T("\nlibgit reports:\n") + CString(msg), _T("TortoiseGit"), MB_ICONERROR);
}
}
}
示例10: _T
BOOL CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName,CString Rev)
{
if(Rev.IsEmpty())
Rev = _T("HEAD");
// enable blame for files which do not exist in current working tree
if (!PathFileExists(lpszPathName) && Rev != _T("HEAD"))
{
if (!CDocument::OnOpenDocument(GetTempFile()))
return FALSE;
}
else
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
}
m_CurrentFileName = lpszPathName;
m_Rev=Rev;
// (SDI documents will reuse this document)
if(!g_Git.CheckMsysGitDir())
{
CCommonAppUtils::RunTortoiseGitProc(_T(" /command:settings"));
return FALSE;
}
CString topdir;
if (!GitAdminDir::HasAdminDir(m_CurrentFileName, &topdir))
{
CString temp;
temp.Format(IDS_CANNOTBLAMENOGIT, (LPCTSTR)m_CurrentFileName);
MessageBox(nullptr, temp, _T("TortoiseGitBlame"), MB_OK | MB_ICONERROR);
return FALSE;
}
else
{
m_IsGitFile=TRUE;
sOrigCWD = g_Git.m_CurrentDir = topdir;
CString PathName = m_CurrentFileName;
if(topdir[topdir.GetLength()-1] == _T('\\') ||
topdir[topdir.GetLength()-1] == _T('/'))
PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength());
else
PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()-1);
CTGitPath path;
path.SetFromWin(PathName);
if(!g_Git.m_CurrentDir.IsEmpty())
SetCurrentDirectory(g_Git.m_CurrentDir);
try
{
// make sure all config files are read in order to check that none contains an error
g_Git.GetConfigValue(_T("doesnot.exist"));
}
catch (char * libgiterr)
{
MessageBox(nullptr, CString(libgiterr), _T("TortoiseGitBlame"), MB_ICONERROR);
return FALSE;
}
CString cmd, option;
int dwDetectMovedOrCopiedLines = theApp.GetInt(_T("DetectMovedOrCopiedLines"), BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED);
int dwDetectMovedOrCopiedLinesNumCharactersWithinFile = theApp.GetInt(_T("DetectMovedOrCopiedLinesNumCharactersWithinFile"), BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_WITHIN_FILE_DEFAULT);
int dwDetectMovedOrCopiedLinesNumCharactersFromFiles = theApp.GetInt(_T("DetectMovedOrCopiedLinesNumCharactersFromFiles"), BLAME_DETECT_MOVED_OR_COPIED_LINES_NUM_CHARACTERS_FROM_FILES_DEFAULT);
switch(dwDetectMovedOrCopiedLines)
{
default:
case BLAME_DETECT_MOVED_OR_COPIED_LINES_DISABLED:
option.Empty();
break;
case BLAME_DETECT_MOVED_OR_COPIED_LINES_WITHIN_FILE:
option.Format(_T("-M%d"), dwDetectMovedOrCopiedLinesNumCharactersWithinFile);
break;
case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_MODIFIED_FILES:
option.Format(_T("-C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles);
break;
case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES_AT_FILE_CREATION:
option.Format(_T("-C -C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles);
break;
case BLAME_DETECT_MOVED_OR_COPIED_LINES_FROM_EXISTING_FILES:
option.Format(_T("-C -C -C%d"), dwDetectMovedOrCopiedLinesNumCharactersFromFiles);
break;
}
if (theApp.GetInt(_T("IgnoreWhitespace"), 0) == 1)
option += _T(" -w");
cmd.Format(_T("git.exe blame -p %s %s -- \"%s\""), (LPCTSTR)option, (LPCTSTR)Rev, (LPCTSTR)path.GetGitPathString());
m_BlameData.clear();
BYTE_VECTOR err;
if(g_Git.Run(cmd, &m_BlameData, &err))
{
CString str;
if (!m_BlameData.empty())
CGit::StringAppend(&str, &m_BlameData[0], CP_UTF8);
if (!err.empty())
//.........这里部分代码省略.........
示例11: ParserFromLog
int CTGitPathList::ParserFromLog(BYTE_VECTOR &log, bool parseDeletes /*false*/)
{
this->Clear();
std::map<CString, size_t> duplicateMap;
int pos=0;
CTGitPath path;
m_Action=0;
int logend = (int)log.size();
while (pos >= 0 && pos < logend)
{
path.Reset();
if(log[pos]=='\n')
++pos;
if (pos >= logend)
return -1;
if(log[pos]==':')
{
bool merged=false;
if (pos + 1 >= logend)
return -1;
if(log[pos+1] ==':')
{
merged=true;
}
int end=log.find(0,pos);
int actionstart=-1;
int file1=-1,file2=-1;
if( end>0 )
{
actionstart=log.find(' ',end-6);
pos=actionstart;
}
if( actionstart>0 )
{
++actionstart;
if (actionstart >= logend)
return -1;
file1 = log.find(0,actionstart);
if( file1>=0 )
{
++file1;
pos=file1;
}
if( log[actionstart] == 'C' || log[actionstart] == 'R' )
{
file2=file1;
file1 = log.find(0,file1);
if(file1>=0 )
{
++file1;
pos=file1;
}
}
}
CString pathname1;
CString pathname2;
if( file1>=0 )
CGit::StringAppend(&pathname1, &log[file1], CP_UTF8);
if( file2>=0 )
CGit::StringAppend(&pathname2, &log[file2], CP_UTF8);
if (actionstart < 0)
return -1;
auto existing = duplicateMap.find(pathname1);
if (existing != duplicateMap.end())
{
CTGitPath& p = m_paths[existing->second];
p.ParserAction(log[actionstart]);
if(merged)
p.m_Action |= CTGitPath::LOGACTIONS_MERGED;
m_Action |= p.m_Action;
}
else
{
int ac=path.ParserAction(log[actionstart] );
ac |= merged?CTGitPath::LOGACTIONS_MERGED:0;
path.SetFromGit(pathname1,&pathname2);
path.m_Action=ac;
//action must be set after setfromgit. SetFromGit will clear all status.
this->m_Action|=ac;
AddPath(path);
duplicateMap.insert(std::pair<CString, size_t>(path.GetGitPathString(), m_paths.size() - 1));
}
}
else
{
int tabstart=0;
path.Reset();
//.........这里部分代码省略.........
示例12: while
void CTortoiseGitBlameData::ParseBlameOutput(BYTE_VECTOR &data, CGitHashMap & HashToRev, DWORD dateFormat, bool bRelativeTimes)
{
std::map<CGitHash, CString> hashToFilename;
std::vector<CGitHash> hashes;
std::vector<int> originalLineNumbers;
std::vector<CString> filenames;
std::vector<BYTE_VECTOR> rawLines;
std::vector<CString> authors;
std::vector<CString> dates;
CGitHash hash;
int originalLineNumber = 0;
int finalLineNumber = 0;
int numberOfSubsequentLines = 0;
CString filename;
int pos = 0;
bool expectHash = true;
while (pos >= 0 && (size_t)pos < data.size())
{
if (data[pos] == 0)
{
++pos;
continue;
}
int lineBegin = pos;
int lineEnd = data.find('\n', lineBegin);
if (lineEnd < 0)
lineEnd = (int)data.size();
if (lineEnd > lineBegin)
{
if (data[lineBegin] != '\t')
{
if (expectHash)
{
expectHash = false;
if (lineEnd - lineBegin > 40)
{
hash.ConvertFromStrA((char*)&data[lineBegin]);
int hashEnd = lineBegin + 40;
int originalLineNumberBegin = hashEnd + 1;
int originalLineNumberEnd = data.find(' ', originalLineNumberBegin);
if (originalLineNumberEnd >= 0)
{
originalLineNumber = atoi(CStringA((LPCSTR)&data[originalLineNumberBegin], originalLineNumberEnd - originalLineNumberBegin));
int finalLineNumberBegin = originalLineNumberEnd + 1;
int finalLineNumberEnd = (numberOfSubsequentLines == 0) ? data.find(' ', finalLineNumberBegin) : lineEnd;
if (finalLineNumberEnd >= 0)
{
finalLineNumber = atoi(CStringA((LPCSTR)&data[finalLineNumberBegin], finalLineNumberEnd - finalLineNumberBegin));
if (numberOfSubsequentLines == 0)
{
int numberOfSubsequentLinesBegin = finalLineNumberEnd + 1;
int numberOfSubsequentLinesEnd = lineEnd;
numberOfSubsequentLines = atoi(CStringA((LPCSTR)&data[numberOfSubsequentLinesBegin], numberOfSubsequentLinesEnd - numberOfSubsequentLinesBegin));
}
}
else
{
// parse error
finalLineNumber = 0;
numberOfSubsequentLines = 0;
}
}
else
{
// parse error
finalLineNumber = 0;
numberOfSubsequentLines = 0;
}
auto it = hashToFilename.find(hash);
if (it != hashToFilename.end())
filename = it->second;
else
filename.Empty();
}
else
{
// parse error
finalLineNumber = 0;
numberOfSubsequentLines = 0;
}
}
else
{
int tokenBegin = lineBegin;
int tokenEnd = data.find(' ', tokenBegin);
if (tokenEnd >= 0)
{
if (!strncmp("filename", (const char*)&data[tokenBegin], tokenEnd - tokenBegin))
{
int filenameBegin = tokenEnd + 1;
int filenameEnd = lineEnd;
CStringA filenameA = CStringA((LPCSTR)&data[filenameBegin], filenameEnd - filenameBegin);
filename = UnquoteFilename(filenameA);
//.........这里部分代码省略.........
示例13: _T
BOOL CTortoiseGitBlameDoc::OnOpenDocument(LPCTSTR lpszPathName,CString Rev)
{
if(Rev.IsEmpty())
Rev = _T("HEAD");
// enable blame for files which do not exist in current working tree
if (!PathFileExists(lpszPathName) && Rev != _T("HEAD"))
{
if (!CDocument::OnOpenDocument(GetTempFile()))
return FALSE;
}
else
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
}
m_CurrentFileName = lpszPathName;
m_Rev=Rev;
// (SDI documents will reuse this document)
if(!g_Git.CheckMsysGitDir())
{
CCommonAppUtils::RunTortoiseGitProc(_T(" /command:settings"));
return FALSE;
}
GitAdminDir admindir;
CString topdir;
if(!admindir.HasAdminDir(m_CurrentFileName, &topdir))
{
CString temp;
temp.Format(IDS_CANNOTBLAMENOGIT, CString(m_CurrentFileName));
CMessageBox::Show(NULL, temp, _T("TortoiseGitBlame"), MB_OK);
return FALSE;
}
else
{
GitAdminDir lastAdminDir;
CString oldTopDir;
if (topdir != g_Git.m_CurrentDir && CTGitPath(g_Git.m_CurrentDir).HasAdminDir(&oldTopDir) && oldTopDir != topdir)
{
CString sMsg;
sMsg.Format(IDS_ERR_DIFFENERTPREPO, oldTopDir, topdir);
MessageBox(NULL, sMsg, _T("TortoiseGitBlame"), MB_OK | MB_ICONERROR);
return FALSE;
}
m_IsGitFile=TRUE;
sOrigCWD = g_Git.m_CurrentDir = topdir;
CString PathName = m_CurrentFileName;
if(topdir[topdir.GetLength()-1] == _T('\\') ||
topdir[topdir.GetLength()-1] == _T('/'))
PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength());
else
PathName=PathName.Right(PathName.GetLength()-g_Git.m_CurrentDir.GetLength()-1);
CTGitPath path;
path.SetFromWin(PathName);
if(!g_Git.m_CurrentDir.IsEmpty())
SetCurrentDirectory(g_Git.m_CurrentDir);
try
{
// make sure all config files are read in order to check that none contains an error
g_Git.GetConfigValue(_T("doesnot.exist"));
}
catch (char * libgiterr)
{
MessageBox(NULL, CString(libgiterr), _T("TortoiseGitBlame"), MB_ICONERROR);
return FALSE;
}
CString cmd;
cmd.Format(_T("git.exe blame -s -l %s -- \"%s\""),Rev,path.GetGitPathString());
m_BlameData.clear();
BYTE_VECTOR err;
if(g_Git.Run(cmd, &m_BlameData, &err))
{
CString str;
if (!m_BlameData.empty())
g_Git.StringAppend(&str, &m_BlameData[0], CP_UTF8);
if (!err.empty())
g_Git.StringAppend(&str, &err[0], CP_UTF8);
MessageBox(NULL, CString(MAKEINTRESOURCE(IDS_BLAMEERROR)) + _T("\n\n") + str, _T("TortoiseGitBlame"), MB_OK);
return FALSE;
}
if(!m_TempFileName.IsEmpty())
{
::DeleteFile(m_TempFileName);
m_TempFileName.Empty();
}
m_TempFileName=GetTempFile();
cmd.Format(_T("git.exe cat-file blob %s:\"%s\""),Rev,path.GetGitPathString());
//.........这里部分代码省略.........
示例14: while
void CTortoiseGitBlameData::ParseBlameOutput(BYTE_VECTOR &data, CGitHashMap & HashToRev, DWORD dateFormat, bool bRelativeTimes)
{
std::unordered_map<CGitHash, CString> hashToFilename;
std::vector<CGitHash> hashes;
std::vector<int> originalLineNumbers;
std::vector<CString> filenames;
std::vector<BYTE_VECTOR> rawLines;
std::vector<CString> authors;
std::vector<CString> dates;
CGitHash hash;
int originalLineNumber = 0;
int numberOfSubsequentLines = 0;
CString filename;
size_t pos = 0;
bool expectHash = true;
while (pos < data.size())
{
if (data[pos] == 0)
{
++pos;
continue;
}
size_t lineBegin = pos;
size_t lineEnd = data.find('\n', lineBegin);
if (lineEnd == BYTE_VECTOR::npos)
lineEnd = data.size();
if (lineEnd > lineBegin)
{
if (data[lineBegin] != '\t')
{
if (expectHash)
{
expectHash = false;
if (lineEnd - lineBegin > 2 * GIT_HASH_SIZE)
{
hash = CGitHash::FromHexStr(reinterpret_cast<char*>(&data[lineBegin]));
size_t hashEnd = lineBegin + 2 * GIT_HASH_SIZE;
size_t originalLineNumberBegin = hashEnd + 1;
size_t originalLineNumberEnd = data.find(' ', originalLineNumberBegin);
if (originalLineNumberEnd != BYTE_VECTOR::npos)
{
originalLineNumber = atoi(CStringA(reinterpret_cast<LPCSTR>(&data[originalLineNumberBegin]), static_cast<int>(originalLineNumberEnd - originalLineNumberBegin)));
size_t finalLineNumberBegin = originalLineNumberEnd + 1;
size_t finalLineNumberEnd = (numberOfSubsequentLines == 0) ? data.find(' ', finalLineNumberBegin) : lineEnd;
if (finalLineNumberEnd != BYTE_VECTOR::npos)
{
if (numberOfSubsequentLines == 0)
{
size_t numberOfSubsequentLinesBegin = finalLineNumberEnd + 1;
size_t numberOfSubsequentLinesEnd = lineEnd;
numberOfSubsequentLines = atoi(CStringA(reinterpret_cast<LPCSTR>(&data[numberOfSubsequentLinesBegin]), static_cast<int>(numberOfSubsequentLinesEnd - numberOfSubsequentLinesBegin)));
}
}
else
{
// parse error
numberOfSubsequentLines = 0;
}
}
else
{
// parse error
numberOfSubsequentLines = 0;
}
auto it = hashToFilename.find(hash);
if (it != hashToFilename.end())
filename = it->second;
else
filename.Empty();
}
else
{
// parse error
numberOfSubsequentLines = 0;
}
}
else
{
size_t tokenBegin = lineBegin;
size_t tokenEnd = data.find(' ', tokenBegin);
if (tokenEnd != BYTE_VECTOR::npos)
{
if (!strncmp("filename", reinterpret_cast<const char*>(&data[tokenBegin]), tokenEnd - tokenBegin))
{
size_t filenameBegin = tokenEnd + 1;
size_t filenameEnd = lineEnd;
CStringA filenameA = CStringA(reinterpret_cast<LPCSTR>(&data[filenameBegin]), static_cast<int>(filenameEnd - filenameBegin));
filename = UnquoteFilename(filenameA);
auto r = hashToFilename.emplace(hash, filename);
if (!r.second)
{
r.first->second = filename;
}
//.........这里部分代码省略.........
示例15:
virtual bool OnOutputData(const BYTE* data, size_t size)
{
m_DataCollector.append(data,size);
while(true)
{
// lines from igit.exe are 0 terminated
int found=m_DataCollector.findData((const BYTE*)"",1);
if(found<0)
return false;
OnSingleLine( (LPCSTR)&*m_DataCollector.begin() );
m_DataCollector.erase(m_DataCollector.begin(), m_DataCollector.begin()+found+1);
}
return false;//Should never reach this
}