Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArsentiy Milchakov <a.milchakov@corp.mail.ru>2016-08-31 18:27:16 +0300
committerArsentiy Milchakov <a.milchakov@corp.mail.ru>2016-08-31 18:27:16 +0300
commit97f9878607fb15f406d3b52b2f06ca8ecbe4915a (patch)
tree9853b6922f09488092c8cbb0b396bb3b9bcfb0b2
parent39103b30cf1fcb94801d6725f60897c85df45304 (diff)
editor web config
-rw-r--r--data/editor.config19
-rw-r--r--editor/config_loader.cpp176
-rw-r--r--editor/config_loader.hpp73
-rw-r--r--editor/editor.pro2
-rw-r--r--editor/editor_config.cpp19
-rw-r--r--editor/editor_config.hpp33
-rw-r--r--editor/editor_tests/config_loader_test.cpp62
-rw-r--r--editor/editor_tests/editor_config_test.cpp11
-rw-r--r--editor/editor_tests/editor_tests.pro4
-rw-r--r--indexer/osm_editor.cpp7
-rw-r--r--indexer/osm_editor.hpp4
-rw-r--r--std/iterator.hpp1
-rw-r--r--xcode/editor/editor.xcodeproj/project.pbxproj8
13 files changed, 372 insertions, 47 deletions
diff --git a/data/editor.config b/data/editor.config
index c6c31da1ba..9b66ced5ae 100644
--- a/data/editor.config
+++ b/data/editor.config
@@ -1,9 +1,9 @@
+<?xml version="1.0"?>
<mapsme>
<editor>
<disable everywhere="no">
<!--bbox minlon="37.6120" minlat="55.7479" maxlon="37.6239" maxlat="55.7553" editable="no" /-->
</disable>
-
<fields>
<!-- Core fields of a feature. -->
<field name="name" multilanguage="yes">
@@ -123,7 +123,6 @@
<field_ref name="website" />
</field_group>
</fields>
-
<!-- Types should be sorted by their priority. -->
<!-- Buildings are hardcoded in editor_config.cpp and are mixed with any other type. -->
<types>
@@ -337,8 +336,7 @@
<type id="amenity-waste_disposal">
<include field="operator" />
</type>
- <type id="amenity-waste_basket">
- </type>
+ <type id="amenity-waste_basket" />
<type id="amenity-car_wash">
<include group="poi" />
<include field="internet" />
@@ -742,13 +740,11 @@
<include field="height" />
<include field="wikipedia" />
</type>
- <type id="amenity-bench">
- </type>
+ <type id="amenity-bench" />
<type id="amenity-shelter">
<include field="internet" />
</type>
- <type id="tourism-picnic_site">
- </type>
+ <type id="tourism-picnic_site" />
<type id="amenity-brothel" can_add="no">
<include group="poi" />
<include field="internet" />
@@ -781,10 +777,8 @@
<type id="leisure-sauna">
<include group="poi" />
</type>
- <type id="man_made-chimney">
- </type>
- <type id="man_made-water_well">
- </type>
+ <type id="man_made-chimney" />
+ <type id="man_made-water_well" />
<type id="shop-cosmetics" group="shop">
<include group="poi" />
</type>
@@ -871,7 +865,6 @@
<include group="address" />
</type>
</types>
-
<preferred_types>
<type id="amenity-restaurant" />
<type id="amenity-cafe" />
diff --git a/editor/config_loader.cpp b/editor/config_loader.cpp
new file mode 100644
index 0000000000..305910a4ed
--- /dev/null
+++ b/editor/config_loader.cpp
@@ -0,0 +1,176 @@
+#include "editor/config_loader.hpp"
+#include "editor/editor_config.hpp"
+
+#include "platform/platform.hpp"
+
+#include "coding/internal/file_data.hpp"
+#include "coding/reader.hpp"
+
+#include "std/atomic.hpp"
+#include "std/fstream.hpp"
+#include "std/iterator.hpp"
+
+#include "3party/Alohalytics/src/http_client.h"
+#include "3party/pugixml/src/pugixml.hpp"
+
+namespace
+{
+using alohalytics::HTTPClientPlatformWrapper;
+
+auto const kConfigFileName = "editor.config";
+auto const kHashFileName = "editor.config.hash";
+
+auto const kSynchroTimeout = hours(4);
+auto const kRemoteHashUrl = "http://osmz.ru/mwm/editor.config.date";
+auto const kRemoteConfigUrl = "http://osmz.ru/mwm/editor.config";
+
+string GetConfigFilePath() { return GetPlatform().WritablePathForFile(kConfigFileName); }
+string GetHashFilePath() { return GetPlatform().WritablePathForFile(kHashFileName); }
+
+string RunSimpleHttpRequest(string const & url)
+{
+ HTTPClientPlatformWrapper request(url);
+ auto const result = request.RunHTTPRequest();
+
+ if (result && !request.was_redirected() && request.error_code() == 200) // 200 - http status OK
+ {
+ return request.server_response();
+ }
+
+ return {};
+}
+} // namespace
+
+namespace editor
+{
+void Waiter::Interrupt()
+{
+ {
+ lock_guard<mutex> lock(m_mutex);
+ m_interrupted = true;
+ }
+
+ m_event.notify_all();
+}
+
+ConfigLoader::ConfigLoader(EditorConfigWrapper & config) : m_config(config)
+{
+ pugi::xml_document doc;
+ LoadFromLocal(doc);
+ ResetConfig(doc);
+ m_loaderThread = thread(&ConfigLoader::LoadFromServer, this);
+}
+
+ConfigLoader::~ConfigLoader()
+{
+ m_waiter.Interrupt();
+ m_loaderThread.join();
+}
+
+void ConfigLoader::LoadFromServer()
+{
+ auto const saveAndReload = [this](pugi::xml_document const & doc)
+ {
+ if (doc.empty())
+ return false;
+
+ auto const filePath = GetConfigFilePath();
+ auto const result =
+ my::WriteToTempAndRenameToFile(filePath, [&doc](string const & fileName)
+ {
+ return doc.save_file(fileName.c_str(), " ");
+ });
+
+ if (!result)
+ return false;
+
+ ResetConfig(doc);
+ return true;
+ };
+
+ auto const hash = LoadHash(GetHashFilePath());
+
+ try
+ {
+ do
+ {
+ auto const remoteHash = GetRemoteHash();
+ if (remoteHash.empty() || hash == remoteHash)
+ continue;
+
+ pugi::xml_document doc;
+ GetRemoteConfig(doc);
+
+ if (saveAndReload(doc))
+ SaveHash(remoteHash, GetHashFilePath());
+
+ } while (m_waiter.Wait(kSynchroTimeout));
+ }
+ catch (RootException const & ex)
+ {
+ LOG(LERROR, (ex.Msg()));
+ }
+}
+
+void ConfigLoader::ResetConfig(pugi::xml_document const & doc)
+{
+ auto config = make_shared<EditorConfig>();
+ config->SetConfig(doc);
+ m_config.Set(config);
+}
+
+//static
+void ConfigLoader::LoadFromLocal(pugi::xml_document & doc)
+{
+ string content;
+ auto const reader = GetPlatform().GetReader(kConfigFileName);
+ reader->ReadAsString(content);
+
+ if (!doc.load_buffer(content.data(), content.size()))
+ MYTHROW(ConfigLoadError, ("Can't parse config"));
+}
+
+// static
+string ConfigLoader::GetRemoteHash()
+{
+ return RunSimpleHttpRequest(kRemoteHashUrl);
+}
+
+// static
+void ConfigLoader::GetRemoteConfig(pugi::xml_document & doc)
+{
+ auto const result = RunSimpleHttpRequest(kRemoteConfigUrl);
+ if (result.empty())
+ return;
+
+ if (!doc.load_string(result.c_str(), pugi::parse_default | pugi::parse_comments))
+ doc.reset();
+}
+
+// static
+bool ConfigLoader::SaveHash(string const & hash, string const & filePath)
+{
+ auto const result =
+ my::WriteToTempAndRenameToFile(filePath, [&hash](string const & fileName)
+ {
+ ofstream ofs(fileName, ofstream::out);
+ if (!ofs.is_open())
+ return false;
+
+ ofs.write(hash.data(), hash.size());
+ return true;
+ });
+
+ return result;
+}
+
+// static
+string ConfigLoader::LoadHash(string const & filePath)
+{
+ ifstream ifs(filePath, ifstream::in);
+ if (!ifs.is_open())
+ return {};
+
+ return {istreambuf_iterator<char>(ifs), istreambuf_iterator<char>()};
+}
+} // namespace editor
diff --git a/editor/config_loader.hpp b/editor/config_loader.hpp
new file mode 100644
index 0000000000..8c252125db
--- /dev/null
+++ b/editor/config_loader.hpp
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "base/exception.hpp"
+#include "base/logging.hpp"
+
+#include "std/chrono.hpp"
+#include "std/condition_variable.hpp"
+#include "std/mutex.hpp"
+#include "std/shared_ptr.hpp"
+#include "std/string.hpp"
+#include "std/thread.hpp"
+
+namespace pugi
+{
+class xml_document;
+}
+
+namespace editor
+{
+class EditorConfigWrapper;
+
+// Class for multithreaded interruptable waiting.
+class Waiter
+{
+public:
+ template <typename Rep, typename Period>
+ bool Wait(duration<Rep, Period> const & waitDuration)
+ {
+ unique_lock<mutex> lock(m_mutex);
+
+ if (m_interrupted)
+ return false;
+
+ m_event.wait_for(lock, waitDuration, [this]() { return m_interrupted; });
+
+ return true;
+ }
+
+ void Interrupt();
+
+private:
+ bool m_interrupted = false;
+ mutex m_mutex;
+ condition_variable m_event;
+};
+
+DECLARE_EXCEPTION(ConfigLoadError, RootException);
+
+// Class which loads config from local drive, checks hash
+// for config on server and downloads new config if needed.
+class ConfigLoader
+{
+public:
+ explicit ConfigLoader(EditorConfigWrapper & config);
+ ~ConfigLoader();
+
+ // Static methods for production and testing.
+ static void LoadFromLocal(pugi::xml_document & doc);
+ static string GetRemoteHash();
+ static void GetRemoteConfig(pugi::xml_document & doc);
+ static bool SaveHash(string const & hash, string const & filePath);
+ static string LoadHash(string const & filePath);
+
+private:
+ void LoadFromServer();
+ void ResetConfig(pugi::xml_document const & doc);
+
+ EditorConfigWrapper & m_config;
+
+ Waiter m_waiter;
+ thread m_loaderThread;
+};
+} // namespace editor
diff --git a/editor/editor.pro b/editor/editor.pro
index 8f3d5d6fc0..4cf861450c 100644
--- a/editor/editor.pro
+++ b/editor/editor.pro
@@ -10,6 +10,7 @@ include($$ROOT_DIR/common.pri)
SOURCES += \
changeset_wrapper.cpp \
+ config_loader.cpp \
editor_config.cpp \
editor_notes.cpp \
editor_storage.cpp \
@@ -23,6 +24,7 @@ SOURCES += \
HEADERS += \
changeset_wrapper.hpp \
+ config_loader.hpp \
editor_config.hpp \
editor_notes.hpp \
editor_storage.hpp \
diff --git a/editor/editor_config.cpp b/editor/editor_config.cpp
index 9920464136..7dcef62f94 100644
--- a/editor/editor_config.cpp
+++ b/editor/editor_config.cpp
@@ -1,9 +1,5 @@
#include "editor/editor_config.hpp"
-#include "platform/platform.hpp"
-
-#include "coding/reader.hpp"
-
#include "base/stl_helpers.hpp"
#include "std/algorithm.hpp"
@@ -114,12 +110,6 @@ vector<pugi::xml_node> GetPrioritizedTypes(pugi::xml_node const & node)
namespace editor
{
-EditorConfig::EditorConfig(string const & fileName)
- : m_fileName(fileName)
-{
- Reload();
-}
-
bool EditorConfig::GetTypeDescription(vector<string> classificatorTypes,
TypeAggregatedDescription & outDesc) const
{
@@ -152,18 +142,15 @@ bool EditorConfig::GetTypeDescription(vector<string> classificatorTypes,
vector<string> EditorConfig::GetTypesThatCanBeAdded() const
{
auto const xpathResult = m_document.select_nodes("/mapsme/editor/types/type[not(@can_add='no' or @editable='no')]");
+
vector<string> result;
for (auto const xNode : xpathResult)
result.emplace_back(xNode.node().attribute("id").value());
return result;
}
-void EditorConfig::Reload()
+void EditorConfig::SetConfig(pugi::xml_document const & doc)
{
- string content;
- auto const reader = GetPlatform().GetReader(m_fileName);
- reader->ReadAsString(content);
- if (!m_document.load_buffer(content.data(), content.size()))
- MYTHROW(ConfigLoadError, ("Can't parse config"));
+ m_document.reset(doc);
}
} // namespace editor
diff --git a/editor/editor_config.hpp b/editor/editor_config.hpp
index 399f03c10a..f4217e1371 100644
--- a/editor/editor_config.hpp
+++ b/editor/editor_config.hpp
@@ -2,11 +2,8 @@
#include "indexer/feature_meta.hpp"
-#include "base/exception.hpp"
-
-#include "std/set.hpp"
+#include "std/shared_ptr.hpp"
#include "std/string.hpp"
-#include "std/unique_ptr.hpp"
#include "std/vector.hpp"
#include "3party/pugixml/src/pugixml.hpp"
@@ -36,27 +33,39 @@ struct TypeAggregatedDescription
bool m_address = false;
};
-DECLARE_EXCEPTION(ConfigLoadError, RootException);
-
class EditorConfig
{
public:
- EditorConfig(string const & fileName = "editor.config");
+ EditorConfig() = default;
// TODO(mgsergio): Reduce overhead by matching uint32_t types instead of strings.
- bool GetTypeDescription(vector<string> classificatorTypes, TypeAggregatedDescription & outDesc) const;
+ bool GetTypeDescription(vector<string> classificatorTypes,
+ TypeAggregatedDescription & outDesc) const;
vector<string> GetTypesThatCanBeAdded() const;
- bool EditingEnable() const;
-
- void Reload();
+ void SetConfig(pugi::xml_document const & doc);
// TODO(mgsergio): Implement this getter to avoid hard-code in XMLFeature::ApplyPatch.
// It should return [[phone, contact:phone], [website, contact:website, url], ...].
//vector<vector<string>> GetAlternativeFields() const;
private:
- string const m_fileName;
pugi::xml_document m_document;
};
+
+// Class which provides methods for EditorConfig concurrently using.
+class EditorConfigWrapper
+{
+public:
+ EditorConfigWrapper() = default;
+
+ void Set(shared_ptr<EditorConfig> config) { atomic_store(&m_config, config); }
+ shared_ptr<EditorConfig const> Get() const { return atomic_load(&m_config); }
+
+private:
+ shared_ptr<EditorConfig> m_config = make_shared<EditorConfig>();
+
+ // Just in case someone tryes to pass EditorConfigWrapper by value instead of referense.
+ DISALLOW_COPY_AND_MOVE(EditorConfigWrapper);
+};
} // namespace editor
diff --git a/editor/editor_tests/config_loader_test.cpp b/editor/editor_tests/config_loader_test.cpp
new file mode 100644
index 0000000000..9ad4a9faba
--- /dev/null
+++ b/editor/editor_tests/config_loader_test.cpp
@@ -0,0 +1,62 @@
+#include "testing/testing.hpp"
+
+#include "editor/config_loader.hpp"
+#include "editor/editor_config.hpp"
+
+#include "platform/platform_tests_support/scoped_file.hpp"
+
+#include "3party/pugixml/src/pugixml.hpp"
+
+namespace
+{
+using namespace editor;
+
+void CheckGeneralTags(pugi::xml_document const & doc)
+{
+ auto const types = doc.select_nodes("/mapsme/editor/types");
+ TEST(!types.empty(), ());
+ auto const fields = doc.select_nodes("/mapsme/editor/fields");
+ TEST(!fields.empty(), ());
+ auto const preferred_types = doc.select_nodes("/mapsme/editor/preferred_types");
+ TEST(!preferred_types.empty(), ());
+}
+
+UNIT_TEST(ConfigLoader_Base)
+{
+ EditorConfigWrapper config;
+ ConfigLoader loader(config);
+
+ TEST(!config.Get()->GetTypesThatCanBeAdded().empty(), ());
+}
+
+UNIT_TEST(ConfigLoader_GetRemoteHash)
+{
+ auto const hashStr = ConfigLoader::GetRemoteHash();
+ TEST_NOT_EQUAL(hashStr, "", ());
+ TEST_EQUAL(hashStr, ConfigLoader::GetRemoteHash(), ());
+}
+
+UNIT_TEST(ConfigLoader_GetRemoteConfig)
+{
+ pugi::xml_document doc;
+ ConfigLoader::GetRemoteConfig(doc);
+ CheckGeneralTags(doc);
+}
+
+UNIT_TEST(ConfigLoader_SaveLoadHash)
+{
+ platform::tests_support::ScopedFile sf("test.hash");
+ auto const testHash = "12345 678909 87654 321 \n 32";
+
+ ConfigLoader::SaveHash(testHash, sf.GetFullPath());
+ auto const loadedHash = ConfigLoader::LoadHash(sf.GetFullPath());
+ TEST_EQUAL(testHash, loadedHash, ());
+}
+
+UNIT_TEST(ConfigLoader_LoadFromLocal)
+{
+ pugi::xml_document doc;
+ ConfigLoader::LoadFromLocal(doc);
+ CheckGeneralTags(doc);
+}
+} // namespace
diff --git a/editor/editor_tests/editor_config_test.cpp b/editor/editor_tests/editor_config_test.cpp
index 329ea1488f..92faae7725 100644
--- a/editor/editor_tests/editor_config_test.cpp
+++ b/editor/editor_tests/editor_config_test.cpp
@@ -1,5 +1,6 @@
#include "testing/testing.hpp"
+#include "editor/config_loader.hpp"
#include "editor/editor_config.hpp"
#include "base/stl_helpers.hpp"
@@ -20,7 +21,11 @@ UNIT_TEST(EditorConfig_TypeDescription)
feature::Metadata::FMD_EMAIL
};
+ pugi::xml_document doc;
+ ConfigLoader::LoadFromLocal(doc);
+
EditorConfig config;
+ config.SetConfig(doc);
{
editor::TypeAggregatedDescription desc;
@@ -57,9 +62,13 @@ UNIT_TEST(EditorConfig_TypeDescription)
// TODO(mgsergio): Test case with priority="high" when there is one on editor.config.
}
-UNIT_TEST(EditorConfig_GetTypesThatGenBeAdded)
+UNIT_TEST(EditorConfig_GetTypesThatCanBeAdded)
{
+ pugi::xml_document doc;
+ ConfigLoader::LoadFromLocal(doc);
+
EditorConfig config;
+ config.SetConfig(doc);
auto const types = config.GetTypesThatCanBeAdded();
TEST(find(begin(types), end(types), "amenity-cafe") != end(types), ());
diff --git a/editor/editor_tests/editor_tests.pro b/editor/editor_tests/editor_tests.pro
index f4ead74e60..cfb2704eda 100644
--- a/editor/editor_tests/editor_tests.pro
+++ b/editor/editor_tests/editor_tests.pro
@@ -4,7 +4,8 @@ CONFIG -= app_bundle
TEMPLATE = app
ROOT_DIR = ../..
-DEPENDENCIES = editor platform_tests_support platform geometry coding base stats_client opening_hours pugixml oauthcpp
+DEPENDENCIES = editor platform_tests_support platform geometry coding base \
+ stats_client opening_hours pugixml oauthcpp tomcrypt
include($$ROOT_DIR/common.pri)
@@ -14,6 +15,7 @@ HEADERS += \
SOURCES += \
$$ROOT_DIR/testing/testingmain.cpp \
+ config_loader_test.cpp \
editor_config_test.cpp \
editor_notes_test.cpp \
opening_hours_ui_test.cpp \
diff --git a/indexer/osm_editor.cpp b/indexer/osm_editor.cpp
index 30a324770a..e09870dd3b 100644
--- a/indexer/osm_editor.cpp
+++ b/indexer/osm_editor.cpp
@@ -138,7 +138,8 @@ namespace osm
// (e.g. insert/remove spaces after ';' delimeter);
Editor::Editor()
- : m_notes(editor::Notes::MakeNotes())
+ : m_configLoader(m_config)
+ , m_notes(editor::Notes::MakeNotes())
, m_storage(make_unique<editor::LocalStorage>())
{}
@@ -701,7 +702,7 @@ EditableProperties Editor::GetEditableProperties(FeatureType const & feature) co
EditableProperties Editor::GetEditablePropertiesForTypes(feature::TypesHolder const & types) const
{
editor::TypeAggregatedDescription desc;
- if (m_config.GetTypeDescription(types.ToObjectNames(), desc))
+ if (m_config.Get()->GetTypeDescription(types.ToObjectNames(), desc))
return {desc.GetEditableFields(), desc.IsNameEditable(), desc.IsAddressEditable()};
return {};
}
@@ -1062,7 +1063,7 @@ Editor::Stats Editor::GetStats() const
NewFeatureCategories Editor::GetNewFeatureCategories() const
{
- return NewFeatureCategories(m_config);
+ return NewFeatureCategories(*(m_config.Get()));
}
FeatureID Editor::GenerateNewFeatureId(MwmSet::MwmId const & id)
diff --git a/indexer/osm_editor.hpp b/indexer/osm_editor.hpp
index 282f9b98ef..fd42fb965e 100644
--- a/indexer/osm_editor.hpp
+++ b/indexer/osm_editor.hpp
@@ -8,6 +8,7 @@
#include "indexer/mwm_set.hpp"
#include "indexer/new_feature_categories.hpp"
+#include "editor/config_loader.hpp"
#include "editor/editor_config.hpp"
#include "editor/editor_notes.hpp"
#include "editor/xml_feature.hpp"
@@ -238,7 +239,8 @@ private:
TForEachFeaturesNearByFn m_forEachFeatureAtPointFn;
/// Contains information about what and how can be edited.
- editor::EditorConfig m_config;
+ editor::EditorConfigWrapper m_config;
+ editor::ConfigLoader m_configLoader;
/// Notes to be sent to osm.
shared_ptr<editor::Notes> m_notes;
diff --git a/std/iterator.hpp b/std/iterator.hpp
index 998fc33f3e..a5447e3f9b 100644
--- a/std/iterator.hpp
+++ b/std/iterator.hpp
@@ -15,6 +15,7 @@ using std::end;
using std::insert_iterator;
using std::inserter;
using std::istream_iterator;
+using std::istreambuf_iterator;
using std::iterator_traits;
using std::next;
using std::reverse_iterator;
diff --git a/xcode/editor/editor.xcodeproj/project.pbxproj b/xcode/editor/editor.xcodeproj/project.pbxproj
index 74c669d0f8..d58e96f834 100644
--- a/xcode/editor/editor.xcodeproj/project.pbxproj
+++ b/xcode/editor/editor.xcodeproj/project.pbxproj
@@ -26,6 +26,8 @@
34EB09201C5F846900F47F1F /* osm_feature_matcher.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 34EB091E1C5F846900F47F1F /* osm_feature_matcher.hpp */; };
34FFB34C1C316A7600BFF6C3 /* server_api.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34FFB34A1C316A7600BFF6C3 /* server_api.cpp */; };
34FFB34D1C316A7600BFF6C3 /* server_api.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 34FFB34B1C316A7600BFF6C3 /* server_api.hpp */; };
+ 3D3058741D707DBE004AC712 /* config_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D3058721D707DBE004AC712 /* config_loader.cpp */; };
+ 3D3058751D707DBE004AC712 /* config_loader.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D3058731D707DBE004AC712 /* config_loader.hpp */; };
3D489BEF1D4F67E10052AA38 /* editor_storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D489BED1D4F67E10052AA38 /* editor_storage.cpp */; };
3D489BF01D4F67E10052AA38 /* editor_storage.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3D489BEE1D4F67E10052AA38 /* editor_storage.hpp */; };
F60F02EE1C92CBF1003A0AF6 /* editor_notes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F60F02EC1C92CBF1003A0AF6 /* editor_notes.cpp */; };
@@ -54,6 +56,8 @@
34EB091E1C5F846900F47F1F /* osm_feature_matcher.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = osm_feature_matcher.hpp; sourceTree = "<group>"; };
34FFB34A1C316A7600BFF6C3 /* server_api.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = server_api.cpp; sourceTree = "<group>"; };
34FFB34B1C316A7600BFF6C3 /* server_api.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = server_api.hpp; sourceTree = "<group>"; };
+ 3D3058721D707DBE004AC712 /* config_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_loader.cpp; sourceTree = "<group>"; };
+ 3D3058731D707DBE004AC712 /* config_loader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = config_loader.hpp; sourceTree = "<group>"; };
3D489BED1D4F67E10052AA38 /* editor_storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = editor_storage.cpp; sourceTree = "<group>"; };
3D489BEE1D4F67E10052AA38 /* editor_storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = editor_storage.hpp; sourceTree = "<group>"; };
F60F02EC1C92CBF1003A0AF6 /* editor_notes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = editor_notes.cpp; sourceTree = "<group>"; };
@@ -91,6 +95,8 @@
341138731C15AE02002E3B3E /* Editor */ = {
isa = PBXGroup;
children = (
+ 3D3058721D707DBE004AC712 /* config_loader.cpp */,
+ 3D3058731D707DBE004AC712 /* config_loader.hpp */,
3D489BED1D4F67E10052AA38 /* editor_storage.cpp */,
3D489BEE1D4F67E10052AA38 /* editor_storage.hpp */,
3441CE461CFC1D3C00CF30D4 /* user_stats.cpp */,
@@ -134,6 +140,7 @@
347C71291C295B1100BE9208 /* xml_feature.hpp in Headers */,
34583BC01C8854C100F94664 /* yes_no_unknown.hpp in Headers */,
340C20DF1C3E4DFD00111D22 /* osm_auth.hpp in Headers */,
+ 3D3058751D707DBE004AC712 /* config_loader.hpp in Headers */,
34527C521C89B1770015050E /* editor_config.hpp in Headers */,
3411387B1C15AE42002E3B3E /* ui2oh.hpp in Headers */,
3441CE491CFC1D3C00CF30D4 /* user_stats.hpp in Headers */,
@@ -203,6 +210,7 @@
3D489BEF1D4F67E10052AA38 /* editor_storage.cpp in Sources */,
3411387A1C15AE42002E3B3E /* ui2oh.cpp in Sources */,
340DC8291C4E71E500EAA2CC /* changeset_wrapper.cpp in Sources */,
+ 3D3058741D707DBE004AC712 /* config_loader.cpp in Sources */,
34EB091F1C5F846900F47F1F /* osm_feature_matcher.cpp in Sources */,
3441CE481CFC1D3C00CF30D4 /* user_stats.cpp in Sources */,
34527C511C89B1770015050E /* editor_config.cpp in Sources */,