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
path: root/stats
diff options
context:
space:
mode:
authorAlex Zolotarev <alex@mapswithme.com>2013-06-11 02:52:41 +0400
committerAlex Zolotarev <alex@maps.me>2015-09-23 02:09:06 +0300
commitdaa0c06cb887735b8007d6ea5bdd3788816b0a4e (patch)
treec003a5b6f72ad25d6874609bfffa800eed6de047 /stats
parent4530aeac40dbbdf8ea5414850e9ea54e255aac51 (diff)
[statistics] Add the stats client.
Diffstat (limited to 'stats')
-rw-r--r--stats/client/client.pro28
-rw-r--r--stats/client/client_tests/client_tests.pro20
-rw-r--r--stats/client/client_tests/stats_writer_test.cpp69
-rw-r--r--stats/client/leveldb_reader.hpp76
-rw-r--r--stats/client/stats_client.cpp34
-rw-r--r--stats/client/stats_client.hpp22
-rw-r--r--stats/client/stats_writer.cpp47
-rw-r--r--stats/client/stats_writer.hpp44
-rw-r--r--stats/common/wire.pb.cc642
-rw-r--r--stats/common/wire.pb.h515
-rw-r--r--stats/common/wire.proto27
-rw-r--r--stats/stats.pro10
12 files changed, 1534 insertions, 0 deletions
diff --git a/stats/client/client.pro b/stats/client/client.pro
new file mode 100644
index 0000000000..8cb689c0bc
--- /dev/null
+++ b/stats/client/client.pro
@@ -0,0 +1,28 @@
+# Statistics client library.
+
+TARGET = stats_client
+TEMPLATE = lib
+CONFIG += staticlib
+
+ROOT_DIR = ../..
+include($$ROOT_DIR/common.pri)
+INCLUDEPATH += $$ROOT_DIR/3party/leveldb/include \
+ $$ROOT_DIR/3party/protobuf/src \
+ $$ROOT_DIR/3party/cityhash/src \
+
+
+DEPENDENCIES = base protobuf leveldb cityhash
+
+
+SOURCES += \
+ stats_client.cpp \
+ stats_writer.cpp \
+ ../common/wire.pb.cc \
+
+HEADERS += \
+ stats_client.hpp \
+ stats_writer.hpp \
+ leveldb_reader.hpp \
+ ../common/wire.pb.h \
+
+OTHER_FILES += ../common/wire.proto
diff --git a/stats/client/client_tests/client_tests.pro b/stats/client/client_tests/client_tests.pro
new file mode 100644
index 0000000000..ad6d7531bb
--- /dev/null
+++ b/stats/client/client_tests/client_tests.pro
@@ -0,0 +1,20 @@
+TARGET = stats_client_tests
+CONFIG += console
+CONFIG -= app_bundle
+TEMPLATE = app
+
+ROOT_DIR = ../../..
+DEPENDENCIES = stats_client coding base protobuf leveldb cityhash
+include($$ROOT_DIR/common.pri)
+INCLUDEPATH += $$ROOT_DIR/3party/leveldb/include \
+ $$ROOT_DIR/3party/protobuf/src \
+ $$ROOT_DIR/3party/cityhash/src
+
+QT *= core
+
+HEADERS += \
+ ../leveldb_reader.hpp
+
+SOURCES += \
+ $$ROOT_DIR/testing/testingmain.cpp \
+ stats_writer_test.cpp \
diff --git a/stats/client/client_tests/stats_writer_test.cpp b/stats/client/client_tests/stats_writer_test.cpp
new file mode 100644
index 0000000000..d2e8e39a57
--- /dev/null
+++ b/stats/client/client_tests/stats_writer_test.cpp
@@ -0,0 +1,69 @@
+#include "../../testing/testing.hpp"
+
+#include "../stats_writer.hpp"
+#include "../leveldb_reader.hpp"
+
+#include "../../coding/file_writer.hpp"
+
+#include "../../std/cstdlib.hpp"
+#include "../../std/target_os.hpp"
+
+#include <city.h>
+
+#define USER_ID "123"
+#define DB_PATH "tmp_testdb"
+
+using namespace stats;
+
+namespace
+{
+
+template<class P>
+bool Compare(P const & a, P const & b)
+{
+ string as, bs;
+ a.SerializeToString(&as);
+ b.SerializeToString(&bs);
+ return as == bs;
+}
+
+template<class P>
+string Diff(P const & act, P const & exp)
+{
+// Doesn't work with lite protos.
+// return string("\nactual: ") + act.DebugString() +
+// + " expect: " + exp.DebugString();
+ return "";
+}
+
+UNIT_TEST(Simple)
+{
+ Search s;
+ s.set_query("pizza nyc");
+
+ {
+ StatsWriter w(USER_ID, DB_PATH);
+ TEST(w.Write(s), ());
+ }
+
+ vector<Event> v = ReadAllFromLevelDB<Event>(DB_PATH);
+ TEST_EQUAL(v.size(), 1, ());
+
+ Event exp;
+ exp.MutableExtension(Search::event)->CopyFrom(s);
+ exp.set_userid(CityHash64(USER_ID, strlen(USER_ID)));
+ exp.set_timestamp(0);
+
+ Event act = v[0];
+ act.set_timestamp(0);
+
+ TEST(Compare(act, exp), (Diff(act, exp)));
+
+#ifdef OMIM_OS_WINDOWS
+ system("rmdir /s /q " DB_PATH);
+#else
+ system("rm -rf " DB_PATH);
+#endif
+}
+
+} // namespace
diff --git a/stats/client/leveldb_reader.hpp b/stats/client/leveldb_reader.hpp
new file mode 100644
index 0000000000..131827303f
--- /dev/null
+++ b/stats/client/leveldb_reader.hpp
@@ -0,0 +1,76 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <leveldb/db.h>
+
+namespace stats
+{
+
+template <class P>
+class LevelDBReader
+{
+public:
+ LevelDBReader(string const & db_path) : m_db(NULL), m_it(NULL), m_path(db_path)
+ {
+ }
+
+ bool ReadNext(P * proto)
+ {
+ if ((m_it == NULL && !Open()) || !m_it->Valid())
+ return false;
+
+ string const s = m_it->value().ToString();
+ m_it->Next();
+
+ return proto->ParseFromString(s);
+ }
+
+ bool Open()
+ {
+ leveldb::Options options;
+ leveldb::Status status = leveldb::DB::Open(options, m_path, &m_db);
+
+ if (!status.ok())
+ return false;
+
+ m_it = m_db->NewIterator(leveldb::ReadOptions());
+ m_it->SeekToFirst();
+ if (!m_it->status().ok())
+ {
+ delete m_it;
+ m_it = NULL;
+ }
+
+ return m_it->status().ok();
+ }
+
+ ~LevelDBReader()
+ {
+ delete m_it;
+ delete m_db;
+ }
+
+ private:
+ leveldb::DB * m_db;
+ leveldb::Iterator * m_it;
+ string const m_path;
+};
+
+template <class P>
+vector<P> ReadAllFromLevelDB(string const & db_path)
+{
+ vector<P> res;
+
+ LevelDBReader<P> reader(db_path);
+
+ P proto;
+ while (reader.ReadNext(&proto))
+ {
+ res.push_back(proto);
+ }
+
+ return res;
+}
+
+} // namespace stats
diff --git a/stats/client/stats_client.cpp b/stats/client/stats_client.cpp
new file mode 100644
index 0000000000..1b1081b791
--- /dev/null
+++ b/stats/client/stats_client.cpp
@@ -0,0 +1,34 @@
+#include "stats_client.hpp"
+#include "stats_writer.hpp"
+
+#include "../common/wire.pb.h"
+
+namespace stats
+{
+
+Client::Client()
+ : m_writer(new StatsWriter(GetPlatform().UniqueClientId(), GetPlatform().WritableDir() + "stats"))
+{
+}
+
+Client::~Client()
+{
+ delete m_writer;
+}
+
+bool Client::Search(string const & query)
+{
+ class Search s;
+ s.set_query(query);
+ return m_writer->Write(s);
+}
+
+bool Client::DropPin(long long latlong, string const & label)
+{
+ PinDrop p;
+ p.set_latlong(latlong);
+ p.set_label(label);
+ return m_writer->Write(p);
+}
+
+} // namespace stats
diff --git a/stats/client/stats_client.hpp b/stats/client/stats_client.hpp
new file mode 100644
index 0000000000..0ffe0ffa6a
--- /dev/null
+++ b/stats/client/stats_client.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "../../platform/platform.hpp"
+
+namespace stats
+{
+
+class StatsWriter;
+
+class Client
+{
+public:
+ Client();
+ ~Client();
+ bool Search(string const & query);
+ bool DropPin(long long latlong, string const & label);
+
+private:
+ StatsWriter * m_writer;
+};
+
+} // namespace stats
diff --git a/stats/client/stats_writer.cpp b/stats/client/stats_writer.cpp
new file mode 100644
index 0000000000..2819139a06
--- /dev/null
+++ b/stats/client/stats_writer.cpp
@@ -0,0 +1,47 @@
+#include "stats_writer.hpp"
+
+#include "../../base/string_format.hpp"
+
+#include "../../std/ctime.hpp"
+
+#include <city.h>
+
+namespace stats
+{
+
+StatsWriter::StatsWriter(string const & uniqueClientId, string const & dbPath)
+ : m_cnt(0), m_db(0), m_path(dbPath),
+ m_uid(CityHash64(uniqueClientId.c_str(), uniqueClientId.size()))
+{
+}
+
+bool StatsWriter::Store(const Event & e)
+{
+ string buf;
+ e.SerializeToString(&buf);
+
+ if (!m_db)
+ {
+ if(!OpenDb(m_path))
+ {
+ return false;
+ }
+ }
+
+ // We can't just make timestamp a key - might have
+ // several writes per second.
+ string key(strings::ToString(e.timestamp()) + "-" + strings::ToString(m_cnt++));
+
+ leveldb::WriteOptions opt;
+ opt.sync = true; // Synchronous writes.
+ return m_db->Put(opt, key, buf).ok();
+}
+
+bool StatsWriter::OpenDb(string const & path)
+{
+ leveldb::Options options;
+ options.create_if_missing = true;
+ return leveldb::DB::Open(options, path, &m_db).ok();
+}
+
+} // namespace stats
diff --git a/stats/client/stats_writer.hpp b/stats/client/stats_writer.hpp
new file mode 100644
index 0000000000..4ad0e213a9
--- /dev/null
+++ b/stats/client/stats_writer.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "../../std/string.hpp"
+
+#include <google/protobuf/message.h>
+
+#include <leveldb/db.h>
+
+#include "../common/wire.pb.h"
+
+namespace stats
+{
+
+class StatsWriter
+{
+public:
+ StatsWriter(string const & uniqueClientId, string const & dbPath);
+
+ bool Store(Event const & e);
+
+ ~StatsWriter() { delete m_db; }
+
+ template<class T>
+ bool Write(T const & m)
+ {
+ Event e;
+ e.MutableExtension(T::event)->CopyFrom(m);
+ e.set_userid(m_uid);
+ e.set_timestamp(time(NULL));
+
+ return Store(e);
+ }
+
+private:
+ bool OpenDb(string const & path);
+
+private:
+ unsigned int m_cnt;
+ leveldb::DB * m_db;
+ string m_path;
+ unsigned long long m_uid;
+};
+
+} // namespace stats
diff --git a/stats/common/wire.pb.cc b/stats/common/wire.pb.cc
new file mode 100644
index 0000000000..a8873b1237
--- /dev/null
+++ b/stats/common/wire.pb.cc
@@ -0,0 +1,642 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: wire.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "wire.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+// @@protoc_insertion_point(includes)
+
+namespace stats {
+
+void protobuf_ShutdownFile_wire_2eproto() {
+ delete Event::default_instance_;
+ delete Search::default_instance_;
+ delete PinDrop::default_instance_;
+}
+
+void protobuf_AddDesc_wire_2eproto() {
+ static bool already_here = false;
+ if (already_here) return;
+ already_here = true;
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ Event::default_instance_ = new Event();
+ Search::default_instance_ = new Search();
+ PinDrop::default_instance_ = new PinDrop();
+ Event::default_instance_->InitAsDefaultInstance();
+ Search::default_instance_->InitAsDefaultInstance();
+ ::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(
+ &::stats::Event::default_instance(),
+ 100, 11, false, false,
+ &::stats::Search::default_instance());
+ PinDrop::default_instance_->InitAsDefaultInstance();
+ ::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(
+ &::stats::Event::default_instance(),
+ 101, 11, false, false,
+ &::stats::PinDrop::default_instance());
+ ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_wire_2eproto);
+}
+
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_wire_2eproto {
+ StaticDescriptorInitializer_wire_2eproto() {
+ protobuf_AddDesc_wire_2eproto();
+ }
+} static_descriptor_initializer_wire_2eproto_;
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int Event::kUserIdFieldNumber;
+const int Event::kTimestampFieldNumber;
+#endif // !_MSC_VER
+
+Event::Event()
+ : ::google::protobuf::MessageLite() {
+ SharedCtor();
+}
+
+void Event::InitAsDefaultInstance() {
+}
+
+Event::Event(const Event& from)
+ : ::google::protobuf::MessageLite() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Event::SharedCtor() {
+ _cached_size_ = 0;
+ userid_ = GOOGLE_LONGLONG(0);
+ timestamp_ = GOOGLE_LONGLONG(0);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Event::~Event() {
+ SharedDtor();
+}
+
+void Event::SharedDtor() {
+ if (this != default_instance_) {
+ }
+}
+
+void Event::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const Event& Event::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_wire_2eproto();
+ return *default_instance_;
+}
+
+Event* Event::default_instance_ = NULL;
+
+Event* Event::New() const {
+ return new Event;
+}
+
+void Event::Clear() {
+ _extensions_.Clear();
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ userid_ = GOOGLE_LONGLONG(0);
+ timestamp_ = GOOGLE_LONGLONG(0);
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+bool Event::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional int64 userId = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+ input, &userid_)));
+ set_has_userid();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(16)) goto parse_timestamp;
+ break;
+ }
+
+ // optional int64 timestamp = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_timestamp:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+ input, &timestamp_)));
+ set_has_timestamp();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ if ((800u <= tag && tag < 8000u)) {
+ DO_(_extensions_.ParseField(tag, input, default_instance_));
+ continue;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Event::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional int64 userId = 1;
+ if (has_userid()) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->userid(), output);
+ }
+
+ // optional int64 timestamp = 2;
+ if (has_timestamp()) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt64(2, this->timestamp(), output);
+ }
+
+ // Extension range [100, 1000)
+ _extensions_.SerializeWithCachedSizes(
+ 100, 1000, output);
+
+}
+
+int Event::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional int64 userId = 1;
+ if (has_userid()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int64Size(
+ this->userid());
+ }
+
+ // optional int64 timestamp = 2;
+ if (has_timestamp()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int64Size(
+ this->timestamp());
+ }
+
+ }
+ total_size += _extensions_.ByteSize();
+
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Event::CheckTypeAndMergeFrom(
+ const ::google::protobuf::MessageLite& from) {
+ MergeFrom(*::google::protobuf::down_cast<const Event*>(&from));
+}
+
+void Event::MergeFrom(const Event& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_userid()) {
+ set_userid(from.userid());
+ }
+ if (from.has_timestamp()) {
+ set_timestamp(from.timestamp());
+ }
+ }
+ _extensions_.MergeFrom(from._extensions_);
+}
+
+void Event::CopyFrom(const Event& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Event::IsInitialized() const {
+
+
+ if (!_extensions_.IsInitialized()) return false; return true;
+}
+
+void Event::Swap(Event* other) {
+ if (other != this) {
+ std::swap(userid_, other->userid_);
+ std::swap(timestamp_, other->timestamp_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ std::swap(_cached_size_, other->_cached_size_);
+ _extensions_.Swap(&other->_extensions_);
+ }
+}
+
+::std::string Event::GetTypeName() const {
+ return "stats.Event";
+}
+
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int Search::kQueryFieldNumber;
+#endif // !_MSC_VER
+
+#ifndef _MSC_VER
+const int Search::kEventFieldNumber;
+#endif
+::google::protobuf::internal::ExtensionIdentifier< ::stats::Event,
+ ::google::protobuf::internal::MessageTypeTraits< ::stats::Search >, 11, false >
+ Search::event(kEventFieldNumber, ::stats::Search::default_instance());
+Search::Search()
+ : ::google::protobuf::MessageLite() {
+ SharedCtor();
+}
+
+void Search::InitAsDefaultInstance() {
+}
+
+Search::Search(const Search& from)
+ : ::google::protobuf::MessageLite() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void Search::SharedCtor() {
+ _cached_size_ = 0;
+ query_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+Search::~Search() {
+ SharedDtor();
+}
+
+void Search::SharedDtor() {
+ if (query_ != &::google::protobuf::internal::kEmptyString) {
+ delete query_;
+ }
+ if (this != default_instance_) {
+ }
+}
+
+void Search::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const Search& Search::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_wire_2eproto();
+ return *default_instance_;
+}
+
+Search* Search::default_instance_ = NULL;
+
+Search* Search::New() const {
+ return new Search;
+}
+
+void Search::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (has_query()) {
+ if (query_ != &::google::protobuf::internal::kEmptyString) {
+ query_->clear();
+ }
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+bool Search::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional string query = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_query()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void Search::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional string query = 1;
+ if (has_query()) {
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 1, this->query(), output);
+ }
+
+}
+
+int Search::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional string query = 1;
+ if (has_query()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->query());
+ }
+
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void Search::CheckTypeAndMergeFrom(
+ const ::google::protobuf::MessageLite& from) {
+ MergeFrom(*::google::protobuf::down_cast<const Search*>(&from));
+}
+
+void Search::MergeFrom(const Search& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_query()) {
+ set_query(from.query());
+ }
+ }
+}
+
+void Search::CopyFrom(const Search& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool Search::IsInitialized() const {
+
+ return true;
+}
+
+void Search::Swap(Search* other) {
+ if (other != this) {
+ std::swap(query_, other->query_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::std::string Search::GetTypeName() const {
+ return "stats.Search";
+}
+
+
+// ===================================================================
+
+#ifndef _MSC_VER
+const int PinDrop::kLatlongFieldNumber;
+const int PinDrop::kLabelFieldNumber;
+#endif // !_MSC_VER
+
+#ifndef _MSC_VER
+const int PinDrop::kEventFieldNumber;
+#endif
+::google::protobuf::internal::ExtensionIdentifier< ::stats::Event,
+ ::google::protobuf::internal::MessageTypeTraits< ::stats::PinDrop >, 11, false >
+ PinDrop::event(kEventFieldNumber, ::stats::PinDrop::default_instance());
+PinDrop::PinDrop()
+ : ::google::protobuf::MessageLite() {
+ SharedCtor();
+}
+
+void PinDrop::InitAsDefaultInstance() {
+}
+
+PinDrop::PinDrop(const PinDrop& from)
+ : ::google::protobuf::MessageLite() {
+ SharedCtor();
+ MergeFrom(from);
+}
+
+void PinDrop::SharedCtor() {
+ _cached_size_ = 0;
+ latlong_ = GOOGLE_LONGLONG(0);
+ label_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+PinDrop::~PinDrop() {
+ SharedDtor();
+}
+
+void PinDrop::SharedDtor() {
+ if (label_ != &::google::protobuf::internal::kEmptyString) {
+ delete label_;
+ }
+ if (this != default_instance_) {
+ }
+}
+
+void PinDrop::SetCachedSize(int size) const {
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const PinDrop& PinDrop::default_instance() {
+ if (default_instance_ == NULL) protobuf_AddDesc_wire_2eproto();
+ return *default_instance_;
+}
+
+PinDrop* PinDrop::default_instance_ = NULL;
+
+PinDrop* PinDrop::New() const {
+ return new PinDrop;
+}
+
+void PinDrop::Clear() {
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ latlong_ = GOOGLE_LONGLONG(0);
+ if (has_label()) {
+ if (label_ != &::google::protobuf::internal::kEmptyString) {
+ label_->clear();
+ }
+ }
+ }
+ ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+bool PinDrop::MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
+ ::google::protobuf::uint32 tag;
+ while ((tag = input->ReadTag()) != 0) {
+ switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+ // optional int64 latlong = 1;
+ case 1: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+ input, &latlong_)));
+ set_has_latlong();
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(18)) goto parse_label;
+ break;
+ }
+
+ // optional string label = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
+ parse_label:
+ DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+ input, this->mutable_label()));
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectAtEnd()) return true;
+ break;
+ }
+
+ default: {
+ handle_uninterpreted:
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+ return true;
+ }
+ DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+ break;
+ }
+ }
+ }
+ return true;
+#undef DO_
+}
+
+void PinDrop::SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const {
+ // optional int64 latlong = 1;
+ if (has_latlong()) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->latlong(), output);
+ }
+
+ // optional string label = 2;
+ if (has_label()) {
+ ::google::protobuf::internal::WireFormatLite::WriteString(
+ 2, this->label(), output);
+ }
+
+}
+
+int PinDrop::ByteSize() const {
+ int total_size = 0;
+
+ if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ // optional int64 latlong = 1;
+ if (has_latlong()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::Int64Size(
+ this->latlong());
+ }
+
+ // optional string label = 2;
+ if (has_label()) {
+ total_size += 1 +
+ ::google::protobuf::internal::WireFormatLite::StringSize(
+ this->label());
+ }
+
+ }
+ GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+ _cached_size_ = total_size;
+ GOOGLE_SAFE_CONCURRENT_WRITES_END();
+ return total_size;
+}
+
+void PinDrop::CheckTypeAndMergeFrom(
+ const ::google::protobuf::MessageLite& from) {
+ MergeFrom(*::google::protobuf::down_cast<const PinDrop*>(&from));
+}
+
+void PinDrop::MergeFrom(const PinDrop& from) {
+ GOOGLE_CHECK_NE(&from, this);
+ if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+ if (from.has_latlong()) {
+ set_latlong(from.latlong());
+ }
+ if (from.has_label()) {
+ set_label(from.label());
+ }
+ }
+}
+
+void PinDrop::CopyFrom(const PinDrop& from) {
+ if (&from == this) return;
+ Clear();
+ MergeFrom(from);
+}
+
+bool PinDrop::IsInitialized() const {
+
+ return true;
+}
+
+void PinDrop::Swap(PinDrop* other) {
+ if (other != this) {
+ std::swap(latlong_, other->latlong_);
+ std::swap(label_, other->label_);
+ std::swap(_has_bits_[0], other->_has_bits_[0]);
+ std::swap(_cached_size_, other->_cached_size_);
+ }
+}
+
+::std::string PinDrop::GetTypeName() const {
+ return "stats.PinDrop";
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+} // namespace stats
+
+// @@protoc_insertion_point(global_scope)
diff --git a/stats/common/wire.pb.h b/stats/common/wire.pb.h
new file mode 100644
index 0000000000..ac276dcce9
--- /dev/null
+++ b/stats/common/wire.pb.h
@@ -0,0 +1,515 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// source: wire.proto
+
+#ifndef PROTOBUF_wire_2eproto__INCLUDED
+#define PROTOBUF_wire_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 2005000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please update
+#error your headers.
+#endif
+#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers. Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/message_lite.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace stats {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_wire_2eproto();
+void protobuf_AssignDesc_wire_2eproto();
+void protobuf_ShutdownFile_wire_2eproto();
+
+class Event;
+class Search;
+class PinDrop;
+
+// ===================================================================
+
+class Event : public ::google::protobuf::MessageLite {
+ public:
+ Event();
+ virtual ~Event();
+
+ Event(const Event& from);
+
+ inline Event& operator=(const Event& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ static const Event& default_instance();
+
+ void Swap(Event* other);
+
+ // implements Message ----------------------------------------------
+
+ Event* New() const;
+ void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+ void CopyFrom(const Event& from);
+ void MergeFrom(const Event& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::std::string GetTypeName() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional int64 userId = 1;
+ inline bool has_userid() const;
+ inline void clear_userid();
+ static const int kUserIdFieldNumber = 1;
+ inline ::google::protobuf::int64 userid() const;
+ inline void set_userid(::google::protobuf::int64 value);
+
+ // optional int64 timestamp = 2;
+ inline bool has_timestamp() const;
+ inline void clear_timestamp();
+ static const int kTimestampFieldNumber = 2;
+ inline ::google::protobuf::int64 timestamp() const;
+ inline void set_timestamp(::google::protobuf::int64 value);
+
+ GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(Event)
+ // @@protoc_insertion_point(class_scope:stats.Event)
+ private:
+ inline void set_has_userid();
+ inline void clear_has_userid();
+ inline void set_has_timestamp();
+ inline void clear_has_timestamp();
+
+ ::google::protobuf::internal::ExtensionSet _extensions_;
+
+ ::google::protobuf::int64 userid_;
+ ::google::protobuf::int64 timestamp_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
+ friend void protobuf_AddDesc_wire_2eproto();
+ friend void protobuf_AssignDesc_wire_2eproto();
+ friend void protobuf_ShutdownFile_wire_2eproto();
+
+ void InitAsDefaultInstance();
+ static Event* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class Search : public ::google::protobuf::MessageLite {
+ public:
+ Search();
+ virtual ~Search();
+
+ Search(const Search& from);
+
+ inline Search& operator=(const Search& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ static const Search& default_instance();
+
+ void Swap(Search* other);
+
+ // implements Message ----------------------------------------------
+
+ Search* New() const;
+ void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+ void CopyFrom(const Search& from);
+ void MergeFrom(const Search& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::std::string GetTypeName() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional string query = 1;
+ inline bool has_query() const;
+ inline void clear_query();
+ static const int kQueryFieldNumber = 1;
+ inline const ::std::string& query() const;
+ inline void set_query(const ::std::string& value);
+ inline void set_query(const char* value);
+ inline void set_query(const char* value, size_t size);
+ inline ::std::string* mutable_query();
+ inline ::std::string* release_query();
+ inline void set_allocated_query(::std::string* query);
+
+ static const int kEventFieldNumber = 100;
+ static ::google::protobuf::internal::ExtensionIdentifier< ::stats::Event,
+ ::google::protobuf::internal::MessageTypeTraits< ::stats::Search >, 11, false >
+ event;
+ // @@protoc_insertion_point(class_scope:stats.Search)
+ private:
+ inline void set_has_query();
+ inline void clear_has_query();
+
+ ::std::string* query_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
+
+ friend void protobuf_AddDesc_wire_2eproto();
+ friend void protobuf_AssignDesc_wire_2eproto();
+ friend void protobuf_ShutdownFile_wire_2eproto();
+
+ void InitAsDefaultInstance();
+ static Search* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class PinDrop : public ::google::protobuf::MessageLite {
+ public:
+ PinDrop();
+ virtual ~PinDrop();
+
+ PinDrop(const PinDrop& from);
+
+ inline PinDrop& operator=(const PinDrop& from) {
+ CopyFrom(from);
+ return *this;
+ }
+
+ static const PinDrop& default_instance();
+
+ void Swap(PinDrop* other);
+
+ // implements Message ----------------------------------------------
+
+ PinDrop* New() const;
+ void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
+ void CopyFrom(const PinDrop& from);
+ void MergeFrom(const PinDrop& from);
+ void Clear();
+ bool IsInitialized() const;
+
+ int ByteSize() const;
+ bool MergePartialFromCodedStream(
+ ::google::protobuf::io::CodedInputStream* input);
+ void SerializeWithCachedSizes(
+ ::google::protobuf::io::CodedOutputStream* output) const;
+ int GetCachedSize() const { return _cached_size_; }
+ private:
+ void SharedCtor();
+ void SharedDtor();
+ void SetCachedSize(int size) const;
+ public:
+
+ ::std::string GetTypeName() const;
+
+ // nested types ----------------------------------------------------
+
+ // accessors -------------------------------------------------------
+
+ // optional int64 latlong = 1;
+ inline bool has_latlong() const;
+ inline void clear_latlong();
+ static const int kLatlongFieldNumber = 1;
+ inline ::google::protobuf::int64 latlong() const;
+ inline void set_latlong(::google::protobuf::int64 value);
+
+ // optional string label = 2;
+ inline bool has_label() const;
+ inline void clear_label();
+ static const int kLabelFieldNumber = 2;
+ inline const ::std::string& label() const;
+ inline void set_label(const ::std::string& value);
+ inline void set_label(const char* value);
+ inline void set_label(const char* value, size_t size);
+ inline ::std::string* mutable_label();
+ inline ::std::string* release_label();
+ inline void set_allocated_label(::std::string* label);
+
+ static const int kEventFieldNumber = 101;
+ static ::google::protobuf::internal::ExtensionIdentifier< ::stats::Event,
+ ::google::protobuf::internal::MessageTypeTraits< ::stats::PinDrop >, 11, false >
+ event;
+ // @@protoc_insertion_point(class_scope:stats.PinDrop)
+ private:
+ inline void set_has_latlong();
+ inline void clear_has_latlong();
+ inline void set_has_label();
+ inline void clear_has_label();
+
+ ::google::protobuf::int64 latlong_;
+ ::std::string* label_;
+
+ mutable int _cached_size_;
+ ::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
+
+ friend void protobuf_AddDesc_wire_2eproto();
+ friend void protobuf_AssignDesc_wire_2eproto();
+ friend void protobuf_ShutdownFile_wire_2eproto();
+
+ void InitAsDefaultInstance();
+ static PinDrop* default_instance_;
+};
+// ===================================================================
+
+
+// ===================================================================
+
+// Event
+
+// optional int64 userId = 1;
+inline bool Event::has_userid() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Event::set_has_userid() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Event::clear_has_userid() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Event::clear_userid() {
+ userid_ = GOOGLE_LONGLONG(0);
+ clear_has_userid();
+}
+inline ::google::protobuf::int64 Event::userid() const {
+ return userid_;
+}
+inline void Event::set_userid(::google::protobuf::int64 value) {
+ set_has_userid();
+ userid_ = value;
+}
+
+// optional int64 timestamp = 2;
+inline bool Event::has_timestamp() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Event::set_has_timestamp() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void Event::clear_has_timestamp() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void Event::clear_timestamp() {
+ timestamp_ = GOOGLE_LONGLONG(0);
+ clear_has_timestamp();
+}
+inline ::google::protobuf::int64 Event::timestamp() const {
+ return timestamp_;
+}
+inline void Event::set_timestamp(::google::protobuf::int64 value) {
+ set_has_timestamp();
+ timestamp_ = value;
+}
+
+// -------------------------------------------------------------------
+
+// Search
+
+// optional string query = 1;
+inline bool Search::has_query() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Search::set_has_query() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void Search::clear_has_query() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void Search::clear_query() {
+ if (query_ != &::google::protobuf::internal::kEmptyString) {
+ query_->clear();
+ }
+ clear_has_query();
+}
+inline const ::std::string& Search::query() const {
+ return *query_;
+}
+inline void Search::set_query(const ::std::string& value) {
+ set_has_query();
+ if (query_ == &::google::protobuf::internal::kEmptyString) {
+ query_ = new ::std::string;
+ }
+ query_->assign(value);
+}
+inline void Search::set_query(const char* value) {
+ set_has_query();
+ if (query_ == &::google::protobuf::internal::kEmptyString) {
+ query_ = new ::std::string;
+ }
+ query_->assign(value);
+}
+inline void Search::set_query(const char* value, size_t size) {
+ set_has_query();
+ if (query_ == &::google::protobuf::internal::kEmptyString) {
+ query_ = new ::std::string;
+ }
+ query_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* Search::mutable_query() {
+ set_has_query();
+ if (query_ == &::google::protobuf::internal::kEmptyString) {
+ query_ = new ::std::string;
+ }
+ return query_;
+}
+inline ::std::string* Search::release_query() {
+ clear_has_query();
+ if (query_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = query_;
+ query_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+inline void Search::set_allocated_query(::std::string* query) {
+ if (query_ != &::google::protobuf::internal::kEmptyString) {
+ delete query_;
+ }
+ if (query) {
+ set_has_query();
+ query_ = query;
+ } else {
+ clear_has_query();
+ query_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
+
+// -------------------------------------------------------------------
+
+// PinDrop
+
+// optional int64 latlong = 1;
+inline bool PinDrop::has_latlong() const {
+ return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void PinDrop::set_has_latlong() {
+ _has_bits_[0] |= 0x00000001u;
+}
+inline void PinDrop::clear_has_latlong() {
+ _has_bits_[0] &= ~0x00000001u;
+}
+inline void PinDrop::clear_latlong() {
+ latlong_ = GOOGLE_LONGLONG(0);
+ clear_has_latlong();
+}
+inline ::google::protobuf::int64 PinDrop::latlong() const {
+ return latlong_;
+}
+inline void PinDrop::set_latlong(::google::protobuf::int64 value) {
+ set_has_latlong();
+ latlong_ = value;
+}
+
+// optional string label = 2;
+inline bool PinDrop::has_label() const {
+ return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void PinDrop::set_has_label() {
+ _has_bits_[0] |= 0x00000002u;
+}
+inline void PinDrop::clear_has_label() {
+ _has_bits_[0] &= ~0x00000002u;
+}
+inline void PinDrop::clear_label() {
+ if (label_ != &::google::protobuf::internal::kEmptyString) {
+ label_->clear();
+ }
+ clear_has_label();
+}
+inline const ::std::string& PinDrop::label() const {
+ return *label_;
+}
+inline void PinDrop::set_label(const ::std::string& value) {
+ set_has_label();
+ if (label_ == &::google::protobuf::internal::kEmptyString) {
+ label_ = new ::std::string;
+ }
+ label_->assign(value);
+}
+inline void PinDrop::set_label(const char* value) {
+ set_has_label();
+ if (label_ == &::google::protobuf::internal::kEmptyString) {
+ label_ = new ::std::string;
+ }
+ label_->assign(value);
+}
+inline void PinDrop::set_label(const char* value, size_t size) {
+ set_has_label();
+ if (label_ == &::google::protobuf::internal::kEmptyString) {
+ label_ = new ::std::string;
+ }
+ label_->assign(reinterpret_cast<const char*>(value), size);
+}
+inline ::std::string* PinDrop::mutable_label() {
+ set_has_label();
+ if (label_ == &::google::protobuf::internal::kEmptyString) {
+ label_ = new ::std::string;
+ }
+ return label_;
+}
+inline ::std::string* PinDrop::release_label() {
+ clear_has_label();
+ if (label_ == &::google::protobuf::internal::kEmptyString) {
+ return NULL;
+ } else {
+ ::std::string* temp = label_;
+ label_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ return temp;
+ }
+}
+inline void PinDrop::set_allocated_label(::std::string* label) {
+ if (label_ != &::google::protobuf::internal::kEmptyString) {
+ delete label_;
+ }
+ if (label) {
+ set_has_label();
+ label_ = label;
+ } else {
+ clear_has_label();
+ label_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
+ }
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+} // namespace stats
+
+// @@protoc_insertion_point(global_scope)
+
+#endif // PROTOBUF_wire_2eproto__INCLUDED
diff --git a/stats/common/wire.proto b/stats/common/wire.proto
new file mode 100644
index 0000000000..35def37a51
--- /dev/null
+++ b/stats/common/wire.proto
@@ -0,0 +1,27 @@
+package stats;
+
+option optimize_for = LITE_RUNTIME;
+
+message Event {
+ optional int64 userId = 1;
+ optional int64 timestamp = 2;
+
+ extensions 100 to 999;
+}
+
+message Search {
+ extend Event {
+ optional Search event = 100;
+ }
+
+ optional string query = 1;
+}
+
+message PinDrop {
+ extend Event {
+ optional PinDrop event = 101;
+ }
+
+ optional int64 latlong = 1;
+ optional string label = 2;
+}
diff --git a/stats/stats.pro b/stats/stats.pro
new file mode 100644
index 0000000000..5ccab609a5
--- /dev/null
+++ b/stats/stats.pro
@@ -0,0 +1,10 @@
+# Project that includes all stats projects.
+
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = client
+
+!iphone*:!bada*:!android* {
+ SUBDIRS += client/client_tests
+}