This commit is contained in:
Martin Marmsoler 2022-09-07 09:43:06 +02:00
parent 71da9986ad
commit 048980a97b
28 changed files with 173 additions and 114 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@ build
.vscode/
CMakeLists.txt.user
cmake-build-debug/
build*
cmake-build-release/
build
.idea/

2
.gitmodules vendored
View File

@ -1,6 +1,6 @@
[submodule "dep/libgit2/libgit2"]
path = dep/libgit2/libgit2
url = https://github.com/stinb/libgit2.git
url = https://github.com/Murmele/libgit2.git
[submodule "dep/libssh2/libssh2"]
path = dep/libssh2/libssh2
url = https://github.com/libssh2/libssh2.git

View File

@ -3,6 +3,10 @@ find_package(PkgConfig)
add_subdirectory(openssl)
add_subdirectory(libssh2)
add_subdirectory(libgit2)
# otherwise the zlib is not available in the src/git
set(LIBGIT2_DEPENDENCY_OBJECTS ${LIBGIT2_DEPENDENCY_OBJECTS} PARENT_SCOPE)
set(LIBGIT2_SYSTEM_LIBS ${LIBGIT2_SYSTEM_LIBS} PARENT_SCOPE)
set(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE)
add_subdirectory(cmark)
add_subdirectory(lua)

@ -1 +1 @@
Subproject commit 4c53a8c20f8984adb226293a3ffd7b88c3f4ac1a
Subproject commit 61a22ddaf0626111193a17ac12f366bd6d167dff

View File

@ -36,4 +36,8 @@ if(NOT USE_SYSTEM_LIBGIT2)
add_subdirectory(libgit2)
target_include_directories(
git2 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/libgit2/include)
# otherwise the zlib is not available in the src/git
set(LIBGIT2_DEPENDENCY_OBJECTS ${LIBGIT2_DEPENDENCY_OBJECTS} PARENT_SCOPE)
set(LIBGIT2_SYSTEM_LIBS ${LIBGIT2_SYSTEM_LIBS} PARENT_SCOPE)
set(LIBGIT2_INCLUDES ${LIBGIT2_INCLUDES} PARENT_SCOPE)
endif()

@ -1 +1 @@
Subproject commit 7861f401ea25e1ceaf7323c1585de4d633e0ec39
Subproject commit 59e41acbcc7993ae9013f2729d60437ec56f9ed8

View File

@ -0,0 +1,27 @@
declare -a branches=("fetch_annotated_tags" "blame_abort" "disableRenameDetection" "checkout_deletion_notification" "diff_checkout" "fix_push_callback_issues" "disable_mmap" "context_line_accessor´" "disableRenameDetection" "submodule" "hash" "callback_connect_disconnect" "blame_buffer" "libgit2_includes_public")
cd libgit2
git remote remove origin
git remote remove upstream
git remote add origin https://github.com/Murmele/libgit2.git
git remote add upstream https://github.com/libgit2/libgit2.git
git fetch --all
for branch in ${branches[@]}; do
echo $branch
git checkout -B $branch "origin/$branch"
git rebase upstream/main
done
git checkout Gittyup
git reset --hard upstream/main
for branch in ${branches[@]}; do
git merge --no-edit $branch
done
git push --force origin
echo "Script finished. Check if all branches are rebased correctly and push them to origin!"

@ -1 +1 @@
Subproject commit 3f499b24f3bcd66db022074f7e8b4f6ee266a3ae
Subproject commit 29708a562a1887a91de0fa6ca668c71871accde9

View File

@ -126,7 +126,7 @@ bool SubmoduleTableModel::setData(const QModelIndex &index,
QMessageBox::Warning, tr("Deinitialize Submodule?"), text,
QMessageBox::Cancel, qobject_cast<QWidget *>(parent()));
if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(submodule.status()))
if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(mRepo.submoduleStatus(submodule.name())))
mb->setInformativeText(
tr("The submodule working directory contains uncommitted "
"changes that will be lost if you continue."));

View File

@ -83,7 +83,7 @@ Remote Branch::remote() const {
return up.isValid() ? up.remote() : Remote();
}
git_buf buf = GIT_BUF_INIT_CONST(nullptr, 0);
git_buf buf = GIT_BUF_INIT;
git_repository *repo = git_reference_owner(d.data());
if (git_branch_remote_name(&buf, repo, qualifiedName().toUtf8()))
return Remote();

View File

@ -8,12 +8,17 @@
//
#include "Buffer.h"
#include "git2/blob.h"
namespace git {
Buffer::Buffer(const char *data, int size)
: d(GIT_BUF_INIT_CONST(data, size)) {}
: data(data), size(size)
{}
bool Buffer::isBinary() const { return git_buf_is_binary(&d); }
bool Buffer::isBinary() const
{
return git_blob_data_is_binary(data, size);
}
} // namespace git

View File

@ -10,8 +10,6 @@
#ifndef BUFFER_H
#define BUFFER_H
#include "git2/buffer.h"
namespace git {
class Buffer {
@ -21,7 +19,8 @@ public:
bool isBinary() const;
private:
git_buf d;
const char* data;
const int size;
};
} // namespace git

View File

@ -27,6 +27,19 @@ add_library(
TagRef.cpp
Tree.cpp)
target_link_libraries(git git2 Qt5::Core Qt5::Network util)
target_link_libraries(git
git2
${LIBGIT2_DEPENDENCY_OBJECTS}
${LIBGIT2_SYSTEM_LIBS}
$<TARGET_OBJECTS:libgit2>
$<TARGET_OBJECTS:util>
Qt5::Core
Qt5::Network
)
# needed also by the plugin target so it must be public
target_include_directories(git PUBLIC
${LIBGIT2_INCLUDES}
)
set_target_properties(git PROPERTIES AUTOMOC ON)

View File

@ -102,7 +102,7 @@ QString Config::value<QString>(const QString &key,
return defaultValue;
}
git_buf buf = GIT_BUF_INIT_CONST(nullptr, 0);
git_buf buf = GIT_BUF_INIT;
git_config_get_string_buf(&buf, d.data(), key.toUtf8());
QString value = QString::fromUtf8(buf.ptr, buf.size);
git_buf_dispose(&buf);
@ -182,7 +182,7 @@ QString Config::globalPath() {
config.remove("global.force");
}
git_buf buf = GIT_BUF_INIT_CONST(nullptr, 0);
git_buf buf = GIT_BUF_INIT;
git_config_find_global(&buf);
QString path = QString::fromUtf8(buf.ptr, buf.size);
git_buf_dispose(&buf);

View File

@ -38,38 +38,44 @@ struct FilterInfo {
QString quote(const QString &path) { return QString("\"%1\"").arg(path); }
int apply(git_filter *self, void **payload, git_buf *to, const git_buf *from,
const git_filter_source *src) {
FilterInfo *info = reinterpret_cast<FilterInfo *>(self);
git_filter_mode_t mode = git_filter_source_mode(src);
QString command = (mode == GIT_FILTER_SMUDGE) ? info->smudge : info->clean;
int stream(
git_writestream **out,
git_filter *self,
void **payload,
const git_filter_source *src,
git_writestream *next)
{
return -1;
// FilterInfo *info = reinterpret_cast<FilterInfo *>(self);
// git_filter_mode_t mode = git_filter_source_mode(src);
// QString command = (mode == GIT_FILTER_SMUDGE) ? info->smudge : info->clean;
// Substitute path.
command.replace("%f", quote(git_filter_source_path(src)));
// // Substitute path.
// command.replace("%f", quote(git_filter_source_path(src)));
QString bash = Command::bashPath();
if (bash.isEmpty())
return info->required ? GIT_EUSER : GIT_PASSTHROUGH;
// QString bash = Command::bashPath();
// if (bash.isEmpty())
// return info->required ? GIT_EUSER : GIT_PASSTHROUGH;
QProcess process;
git_repository *repo = git_filter_source_repo(src);
process.setWorkingDirectory(git_repository_workdir(repo));
// QProcess process;
// git_repository *repo = git_filter_source_repo(src);
// process.setWorkingDirectory(git_repository_workdir(repo));
process.start(bash, {"-c", command});
if (!process.waitForStarted())
return info->required ? GIT_EUSER : GIT_PASSTHROUGH;
// process.start(bash, {"-c", command});
// if (!process.waitForStarted())
// return info->required ? GIT_EUSER : GIT_PASSTHROUGH;
process.write(from->ptr, from->size);
process.closeWriteChannel();
// process.write(from->ptr, from->size);
// process.closeWriteChannel();
if (!process.waitForFinished() || process.exitCode()) {
git_error_set_str(GIT_ERROR_FILTER, process.readAllStandardError());
return info->required ? GIT_EUSER : GIT_PASSTHROUGH;
}
// if (!process.waitForFinished() || process.exitCode()) {
// git_error_set_str(GIT_ERROR_FILTER, process.readAllStandardError());
// return info->required ? GIT_EUSER : GIT_PASSTHROUGH;
// }
QByteArray data = process.readAll();
git_buf_set(to, data.constData(), data.length());
return 0;
// QByteArray data = process.readAll();
// git_buf_set(to, data.constData(), data.length());
// return 0;
}
} // namespace
@ -101,7 +107,7 @@ void Filter::init() {
info.name = key.toUtf8();
info.attributes = kFilterFmt.arg(key).toUtf8();
info.filter.apply = &apply;
info.filter.stream = &stream;
info.filter.attributes = info.attributes.constData();
git_filter_register(info.name.constData(), &info.filter,
GIT_FILTER_DRIVER_PRIORITY);

View File

@ -15,11 +15,11 @@ namespace git {
namespace {
const Id kInvalidId = QByteArray(GIT_OID_RAWSZ, -1);
const Id kInvalidId = QByteArray(GIT_OID_SHA1_SIZE, -1);
} // namespace
Id::Id() { memset(d.id, 0, GIT_OID_RAWSZ); }
Id::Id() { memset(d.id, 0, GIT_OID_SHA1_SIZE); }
Id::Id(const QByteArray &id) {
git_oid_fromraw(&d, reinterpret_cast<const unsigned char *>(id.constData()));
@ -31,7 +31,7 @@ Id::Id(const git_oid *id) {
if (id) {
git_oid_cpy(&d, id);
} else {
memset(d.id, 0, GIT_OID_RAWSZ);
memset(d.id, 0, GIT_OID_SHA1_SIZE);
}
}
@ -45,7 +45,7 @@ QString Id::toString() const { return toByteArray().toHex(); }
QByteArray Id::toByteArray() const {
const char *data = reinterpret_cast<const char *>(d.id);
return QByteArray::fromRawData(data, GIT_OID_RAWSZ);
return QByteArray::fromRawData(data, GIT_OID_SHA1_SIZE);
}
bool Id::operator<(const Id &rhs) const { return (git_oid_cmp(&d, rhs) < 0); }

View File

@ -25,8 +25,9 @@ git_object_t Object::type() const { return git_object_type(d.data()); }
Id Object::id() const { return git_object_id(d.data()); }
QString Object::shortId() const {
git_buf buf = GIT_BUF_INIT_CONST(0, 0);
QString Object::shortId() const
{
git_buf buf = GIT_BUF_INIT;
git_object_short_id(&buf, d.data());
QByteArray result(buf.ptr, buf.size);
git_buf_dispose(&buf);

View File

@ -326,10 +326,8 @@ QByteArray Patch::generateResult(QList<QList<QByteArray>> &image,
return result;
// Apply filters.
git_buf out = GIT_BUF_INIT_CONST(nullptr, 0);
git_buf raw = GIT_BUF_INIT_CONST(result.constData(), result.length());
(&out, filters, &raw);
git_buf_dispose(&raw);
git_buf out = GIT_BUF_INIT;
git_filter_list_apply_to_buffer(&out, filters, result.data(), result.length());
QByteArray filtered(out.ptr, out.size);
git_buf_dispose(&out);

View File

@ -243,18 +243,16 @@ private:
} // namespace
int Remote::Callbacks::connect(git_remote *remote, void *payload) {
void Remote::Callbacks::connected(git_remote *remote, void *payload) {
Remote::Callbacks *cbs = reinterpret_cast<Remote::Callbacks *>(payload);
cbs->mRemote = remote;
return 0;
}
int Remote::Callbacks::disconnect(git_remote *remote, void *payload) {
void Remote::Callbacks::about_to_disconnect(git_remote *remote, void *payload) {
Q_UNUSED(remote)
Remote::Callbacks *cbs = reinterpret_cast<Remote::Callbacks *>(payload);
cbs->mRemote = nullptr;
return 0;
}
int Remote::Callbacks::sideband(const char *str, int len, void *payload) {
@ -457,12 +455,15 @@ int Remote::Callbacks::update(const char *name, const git_oid *a,
return 0;
}
int Remote::Callbacks::url(git_buf *out, const char *url, int direction,
void *payload) {
int Remote::Callbacks::remoteReady(
git_remote* remote,
int direction,
void *payload)
{
Q_UNUSED(direction)
Remote::Callbacks *cbs = reinterpret_cast<Remote::Callbacks *>(payload);
QString resolved(url);
QString resolved(git_remote_url(remote));
if (!cbs->url(resolved))
return -1;
@ -494,7 +495,7 @@ int Remote::Callbacks::url(git_buf *out, const char *url, int direction,
}
resolved = resolvedUrl.toString();
git_buf_set(out, resolved.toUtf8(), resolved.length());
git_remote_set_instance_url(remote, resolved.toUtf8());
return 0;
}
@ -532,14 +533,14 @@ void Remote::setUrl(const QString &url) {
Result Remote::fetch(Callbacks *callbacks, bool tags, bool prune) {
git_fetch_options opts = GIT_FETCH_OPTIONS_INIT;
opts.callbacks.connect = &Remote::Callbacks::connect;
opts.callbacks.disconnect = &Remote::Callbacks::disconnect;
opts.callbacks.connected = &Remote::Callbacks::connected;
opts.callbacks.about_to_disconnect = &Remote::Callbacks::about_to_disconnect;
opts.callbacks.sideband_progress = &Remote::Callbacks::sideband;
opts.callbacks.credentials = &Remote::Callbacks::credentials;
opts.callbacks.certificate_check = &Remote::Callbacks::certificate;
opts.callbacks.transfer_progress = &Remote::Callbacks::transfer;
opts.callbacks.update_tips = &Remote::Callbacks::update;
opts.callbacks.resolve_url = &Remote::Callbacks::url;
opts.callbacks.remote_ready = &Remote::Callbacks::remoteReady;
opts.callbacks.payload = callbacks;
QByteArray proxy = proxyUrl(url(), opts.proxy_opts.type);
@ -559,14 +560,14 @@ Result Remote::fetch(Callbacks *callbacks, bool tags, bool prune) {
Result Remote::push(Callbacks *callbacks, const QStringList &refspecs) {
git_push_options opts = GIT_PUSH_OPTIONS_INIT;
opts.callbacks.connect = &Remote::Callbacks::connect;
opts.callbacks.disconnect = &Remote::Callbacks::disconnect;
opts.callbacks.connected = &Remote::Callbacks::connected;
opts.callbacks.about_to_disconnect = &Remote::Callbacks::about_to_disconnect;
opts.callbacks.sideband_progress = &Remote::Callbacks::sideband;
opts.callbacks.credentials = &Remote::Callbacks::credentials;
opts.callbacks.certificate_check = &Remote::Callbacks::certificate;
opts.callbacks.transfer_progress = &Remote::Callbacks::transfer;
opts.callbacks.update_tips = &Remote::Callbacks::update;
opts.callbacks.resolve_url = &Remote::Callbacks::url;
opts.callbacks.remote_ready = &Remote::Callbacks::remoteReady;
opts.callbacks.pack_progress = &pack_progress;
opts.callbacks.push_transfer_progress = &push_transfer_progress;
opts.callbacks.push_update_reference = &push_update_reference;
@ -617,14 +618,14 @@ Result Remote::clone(Callbacks *callbacks, const QString &url,
const QString &path, bool bare) {
git_repository *repo = nullptr;
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
opts.fetch_opts.callbacks.connect = &Remote::Callbacks::connect;
opts.fetch_opts.callbacks.disconnect = &Remote::Callbacks::disconnect;
opts.fetch_opts.callbacks.connected = &Remote::Callbacks::connected;
opts.fetch_opts.callbacks.about_to_disconnect = &Remote::Callbacks::about_to_disconnect;
opts.fetch_opts.callbacks.sideband_progress = &Remote::Callbacks::sideband;
opts.fetch_opts.callbacks.credentials = &Remote::Callbacks::credentials;
opts.fetch_opts.callbacks.certificate_check = &Remote::Callbacks::certificate;
opts.fetch_opts.callbacks.transfer_progress = &Remote::Callbacks::transfer;
opts.fetch_opts.callbacks.update_tips = &Remote::Callbacks::update;
opts.fetch_opts.callbacks.resolve_url = &Remote::Callbacks::url;
opts.fetch_opts.callbacks.remote_ready = &Remote::Callbacks::remoteReady;
opts.fetch_opts.callbacks.payload = callbacks;
opts.bare = bare;

View File

@ -93,9 +93,9 @@ public:
virtual bool connectToAgent() const { return false; }
// static callback wrappers
static int connect(git_remote *remote, void *payload);
static void connected(git_remote *remote, void *payload);
static int disconnect(git_remote *remote, void *payload);
static void about_to_disconnect(git_remote *remote, void *payload);
static int sideband(const char *str, int len, void *payload);
@ -110,7 +110,9 @@ public:
static int update(const char *name, const git_oid *a, const git_oid *b,
void *payload);
static int url(git_buf *out, const char *url, int direction, void *payload);
static int remoteReady(git_remote *remote,
int direction,
void *payload);
protected:
// Try to stop the current remote.

View File

@ -175,8 +175,9 @@ Id Repository::workdirId(const QString &path) const {
return id;
}
QString Repository::message() const {
git_buf buf = GIT_BUF_INIT_CONST(nullptr, 0);
QString Repository::message() const
{
git_buf buf = GIT_BUF_INIT;
git_repository_message(&buf, d->repo);
return QString::fromUtf8(buf.ptr, buf.size);
}
@ -334,7 +335,7 @@ Diff Repository::diffIndexToWorkdir(const Index &index,
Diff::Callbacks *callbacks,
bool ignoreWhitespace) const {
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
opts.flags |= (GIT_DIFF_DISABLE_MMAP | GIT_DIFF_INCLUDE_TYPECHANGE);
opts.flags |= GIT_DIFF_INCLUDE_TYPECHANGE; // GIT_DIFF_DISABLE_MMAP flag really needed?
if (!appConfig().value<bool>("untracked.hide", false))
opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_RECURSE_UNTRACKED_DIRS;
@ -706,7 +707,18 @@ Submodule Repository::lookupSubmodule(const QString &name) const {
return Submodule(submodule);
}
Remote Repository::addRemote(const QString &name, const QString &url) {
int Repository::submoduleStatus(const QString& name) const {
unsigned int status;
// TODO: testing!!!!
int returnValue = git_submodule_status(&status, d->repo, name.toLocal8Bit().data(), GIT_SUBMODULE_IGNORE_UNSPECIFIED);
if (returnValue < 0)
return returnValue;
return status;
}
Remote Repository::addRemote(const QString &name, const QString &url)
{
// FIXME: Validate name?
emit d->notifier->remoteAboutToBeAdded(name);

View File

@ -166,6 +166,7 @@ public:
void invalidateSubmoduleCache();
QList<Submodule> submodules() const;
Submodule lookupSubmodule(const QString &path) const;
int submoduleStatus(const QString& name) const;
// remote
Remote addRemote(const QString &name, const QString &url);

View File

@ -80,25 +80,17 @@ Id Submodule::indexId() const { return git_submodule_index_id(d.data()); }
Id Submodule::workdirId() const { return git_submodule_wd_id(d.data()); }
int Submodule::status() const {
unsigned int status = 0;
if (git_submodule_status(&status, d.data(), GIT_SUBMODULE_IGNORE_UNSPECIFIED))
return -1;
return status;
}
Result Submodule::update(Remote::Callbacks *callbacks, bool init,
bool checkout_force) {
Result Submodule::update(Remote::Callbacks *callbacks, bool init, bool checkout_force)
{
git_submodule_update_options opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
opts.fetch_opts.callbacks.connect = &Remote::Callbacks::connect;
opts.fetch_opts.callbacks.disconnect = &Remote::Callbacks::disconnect;
opts.fetch_opts.callbacks.connected = &Remote::Callbacks::connected;
opts.fetch_opts.callbacks.about_to_disconnect = &Remote::Callbacks::about_to_disconnect;
opts.fetch_opts.callbacks.sideband_progress = &Remote::Callbacks::sideband;
opts.fetch_opts.callbacks.credentials = &Remote::Callbacks::credentials;
opts.fetch_opts.callbacks.certificate_check = &Remote::Callbacks::certificate;
opts.fetch_opts.callbacks.transfer_progress = &Remote::Callbacks::transfer;
opts.fetch_opts.callbacks.update_tips = &Remote::Callbacks::update;
opts.fetch_opts.callbacks.resolve_url = &Remote::Callbacks::url;
opts.fetch_opts.callbacks.remote_ready = &Remote::Callbacks::remoteReady;
opts.fetch_opts.callbacks.payload = callbacks;
if (checkout_force)

View File

@ -44,16 +44,7 @@ public:
Id indexId() const;
Id workdirId() const;
/*!
* \brief status
* Return the status of the submodule as a combination of flags described in
* https://libgit2.org/libgit2/index.html#HEAD/type/git_submodule_status_t
* \return current status
*/
int status() const;
Result update(Remote::Callbacks *callbacks, bool init = false,
bool checkout_force = false);
Result update(Remote::Callbacks *callbacks, bool init = false, bool checkout_force = false);
Repository open() const;

View File

@ -12,11 +12,13 @@ target_link_libraries(
set_target_properties(index PROPERTIES AUTOMOC ON)
add_executable(lexer_test lexer_test.cpp)
target_link_libraries(lexer_test index)
if (BUILD_GITTYUP_TEST)
add_executable(lexer_test lexer_test.cpp)
target_link_libraries(lexer_test index)
add_executable(index_test index_test.cpp)
target_link_libraries(index_test index Qt5::Widgets)
add_executable(index_test index_test.cpp)
target_link_libraries(index_test index Qt5::Widgets)
endif()
add_executable(indexer indexer.cpp)
target_link_libraries(indexer index)

View File

@ -67,7 +67,7 @@ void Index::reset() {
QFile idFile(dir.filePath(kIdFile));
if (idFile.open(QIODevice::ReadOnly)) {
while (idFile.bytesAvailable() > 0)
mIds.append(idFile.read(GIT_OID_RAWSZ));
mIds.append(idFile.read(GIT_OID_SHA1));
}
// Read dictionary.
@ -140,7 +140,7 @@ bool Index::write(PostingMap map) {
// Write id file.
foreach (const git::Id &id, mIds)
idFile.write(id.toByteArray(), GIT_OID_RAWSZ);
idFile.write(id.toByteArray(), GIT_OID_SHA1);
// Merge new entries into existing postings file.
// Write dictionary and postings files in lockstep.

View File

@ -1050,7 +1050,7 @@ QFuture<git::Result> RepoView::fetch(const git::Remote &rmt, bool tags,
if (result && submodules) {
// Scan for unmodified submodules on the fetch thread.
foreach (const git::Submodule &submodule, mRepo.submodules()) {
if (GIT_SUBMODULE_STATUS_IS_UNMODIFIED(submodule.status()))
if (GIT_SUBMODULE_STATUS_IS_UNMODIFIED(mRepo.submoduleStatus(submodule.name())))
submodules->append(submodule.name());
}
}
@ -2385,7 +2385,7 @@ RepoView::submoduleResetInfoList(const git::Repository &repo,
// Only reset modified submodules
QList<git::Submodule> modules;
foreach (const git::Submodule &submodule, submodules) {
int status = submodule.status();
int status = repo.submoduleStatus(submodule.name());
if (status & (GIT_SUBMODULE_STATUS_WD_MODIFIED |
GIT_SUBMODULE_STATUS_WD_WD_MODIFIED |

@ -1 +1 @@
Subproject commit 96825016edb6e63698ec2314349daeae345ad2fe
Subproject commit fefb8d6acc78b5f63d5a78b86a4900e694bd2862