Browse Source

Change --imports-per-dev to return imports through time

Signed-off-by: Vadim Markovtsev <vadim@athenian.co>
Vadim Markovtsev 5 years ago
parent
commit
8c012d1ee2

+ 175 - 124
internal/pb/pb.pb.go

@@ -1443,18 +1443,56 @@ func (m *TyposDataset) GetTypos() []*Typo {
 	return nil
 }
 
+type ImportsPerTick struct {
+	Counts               map[int32]int64 `protobuf:"bytes,1,rep,name=counts,proto3" json:"counts,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
+	XXX_NoUnkeyedLiteral struct{}        `json:"-"`
+	XXX_unrecognized     []byte          `json:"-"`
+	XXX_sizecache        int32           `json:"-"`
+}
+
+func (m *ImportsPerTick) Reset()         { *m = ImportsPerTick{} }
+func (m *ImportsPerTick) String() string { return proto.CompactTextString(m) }
+func (*ImportsPerTick) ProtoMessage()    {}
+func (*ImportsPerTick) Descriptor() ([]byte, []int) {
+	return fileDescriptor_f80abaa17e25ccc8, []int{26}
+}
+func (m *ImportsPerTick) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_ImportsPerTick.Unmarshal(m, b)
+}
+func (m *ImportsPerTick) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_ImportsPerTick.Marshal(b, m, deterministic)
+}
+func (m *ImportsPerTick) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_ImportsPerTick.Merge(m, src)
+}
+func (m *ImportsPerTick) XXX_Size() int {
+	return xxx_messageInfo_ImportsPerTick.Size(m)
+}
+func (m *ImportsPerTick) XXX_DiscardUnknown() {
+	xxx_messageInfo_ImportsPerTick.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_ImportsPerTick proto.InternalMessageInfo
+
+func (m *ImportsPerTick) GetCounts() map[int32]int64 {
+	if m != nil {
+		return m.Counts
+	}
+	return nil
+}
+
 type ImportsPerLanguage struct {
-	Counts               map[string]int64 `protobuf:"bytes,1,rep,name=counts,proto3" json:"counts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
-	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
-	XXX_unrecognized     []byte           `json:"-"`
-	XXX_sizecache        int32            `json:"-"`
+	Ticks                map[string]*ImportsPerTick `protobuf:"bytes,1,rep,name=ticks,proto3" json:"ticks,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	XXX_NoUnkeyedLiteral struct{}                   `json:"-"`
+	XXX_unrecognized     []byte                     `json:"-"`
+	XXX_sizecache        int32                      `json:"-"`
 }
 
 func (m *ImportsPerLanguage) Reset()         { *m = ImportsPerLanguage{} }
 func (m *ImportsPerLanguage) String() string { return proto.CompactTextString(m) }
 func (*ImportsPerLanguage) ProtoMessage()    {}
 func (*ImportsPerLanguage) Descriptor() ([]byte, []int) {
-	return fileDescriptor_f80abaa17e25ccc8, []int{26}
+	return fileDescriptor_f80abaa17e25ccc8, []int{27}
 }
 func (m *ImportsPerLanguage) XXX_Unmarshal(b []byte) error {
 	return xxx_messageInfo_ImportsPerLanguage.Unmarshal(m, b)
@@ -1474,9 +1512,9 @@ func (m *ImportsPerLanguage) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_ImportsPerLanguage proto.InternalMessageInfo
 
-func (m *ImportsPerLanguage) GetCounts() map[string]int64 {
+func (m *ImportsPerLanguage) GetTicks() map[string]*ImportsPerTick {
 	if m != nil {
-		return m.Counts
+		return m.Ticks
 	}
 	return nil
 }
@@ -1492,7 +1530,7 @@ func (m *ImportsPerDeveloper) Reset()         { *m = ImportsPerDeveloper{} }
 func (m *ImportsPerDeveloper) String() string { return proto.CompactTextString(m) }
 func (*ImportsPerDeveloper) ProtoMessage()    {}
 func (*ImportsPerDeveloper) Descriptor() ([]byte, []int) {
-	return fileDescriptor_f80abaa17e25ccc8, []int{27}
+	return fileDescriptor_f80abaa17e25ccc8, []int{28}
 }
 func (m *ImportsPerDeveloper) XXX_Unmarshal(b []byte) error {
 	return xxx_messageInfo_ImportsPerDeveloper.Unmarshal(m, b)
@@ -1520,18 +1558,20 @@ func (m *ImportsPerDeveloper) GetLanguages() map[string]*ImportsPerLanguage {
 }
 
 type ImportsPerDeveloperResults struct {
-	Imports              []*ImportsPerDeveloper `protobuf:"bytes,1,rep,name=imports,proto3" json:"imports,omitempty"`
-	AuthorIndex          []string               `protobuf:"bytes,2,rep,name=author_index,json=authorIndex,proto3" json:"author_index,omitempty"`
-	XXX_NoUnkeyedLiteral struct{}               `json:"-"`
-	XXX_unrecognized     []byte                 `json:"-"`
-	XXX_sizecache        int32                  `json:"-"`
+	Imports     []*ImportsPerDeveloper `protobuf:"bytes,1,rep,name=imports,proto3" json:"imports,omitempty"`
+	AuthorIndex []string               `protobuf:"bytes,2,rep,name=author_index,json=authorIndex,proto3" json:"author_index,omitempty"`
+	// how long each tick is, as an int64 nanosecond count (Go's time.Duration)
+	TickSize             int64    `protobuf:"varint,3,opt,name=tick_size,json=tickSize,proto3" json:"tick_size,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
 }
 
 func (m *ImportsPerDeveloperResults) Reset()         { *m = ImportsPerDeveloperResults{} }
 func (m *ImportsPerDeveloperResults) String() string { return proto.CompactTextString(m) }
 func (*ImportsPerDeveloperResults) ProtoMessage()    {}
 func (*ImportsPerDeveloperResults) Descriptor() ([]byte, []int) {
-	return fileDescriptor_f80abaa17e25ccc8, []int{28}
+	return fileDescriptor_f80abaa17e25ccc8, []int{29}
 }
 func (m *ImportsPerDeveloperResults) XXX_Unmarshal(b []byte) error {
 	return xxx_messageInfo_ImportsPerDeveloperResults.Unmarshal(m, b)
@@ -1565,6 +1605,13 @@ func (m *ImportsPerDeveloperResults) GetAuthorIndex() []string {
 	return nil
 }
 
+func (m *ImportsPerDeveloperResults) GetTickSize() int64 {
+	if m != nil {
+		return m.TickSize
+	}
+	return 0
+}
+
 type AnalysisResults struct {
 	Header *Metadata `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
 	// the mapped values are dynamic messages which require the second parsing pass.
@@ -1578,7 +1625,7 @@ func (m *AnalysisResults) Reset()         { *m = AnalysisResults{} }
 func (m *AnalysisResults) String() string { return proto.CompactTextString(m) }
 func (*AnalysisResults) ProtoMessage()    {}
 func (*AnalysisResults) Descriptor() ([]byte, []int) {
-	return fileDescriptor_f80abaa17e25ccc8, []int{29}
+	return fileDescriptor_f80abaa17e25ccc8, []int{30}
 }
 func (m *AnalysisResults) XXX_Unmarshal(b []byte) error {
 	return xxx_messageInfo_AnalysisResults.Unmarshal(m, b)
@@ -1648,8 +1695,10 @@ func init() {
 	proto.RegisterType((*CommitsAnalysisResults)(nil), "CommitsAnalysisResults")
 	proto.RegisterType((*Typo)(nil), "Typo")
 	proto.RegisterType((*TyposDataset)(nil), "TyposDataset")
+	proto.RegisterType((*ImportsPerTick)(nil), "ImportsPerTick")
+	proto.RegisterMapType((map[int32]int64)(nil), "ImportsPerTick.CountsEntry")
 	proto.RegisterType((*ImportsPerLanguage)(nil), "ImportsPerLanguage")
-	proto.RegisterMapType((map[string]int64)(nil), "ImportsPerLanguage.CountsEntry")
+	proto.RegisterMapType((map[string]*ImportsPerTick)(nil), "ImportsPerLanguage.TicksEntry")
 	proto.RegisterType((*ImportsPerDeveloper)(nil), "ImportsPerDeveloper")
 	proto.RegisterMapType((map[string]*ImportsPerLanguage)(nil), "ImportsPerDeveloper.LanguagesEntry")
 	proto.RegisterType((*ImportsPerDeveloperResults)(nil), "ImportsPerDeveloperResults")
@@ -1660,112 +1709,114 @@ func init() {
 func init() { proto.RegisterFile("pb.proto", fileDescriptor_f80abaa17e25ccc8) }
 
 var fileDescriptor_f80abaa17e25ccc8 = []byte{
-	// 1699 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0xcd, 0x6e, 0x1b, 0x47,
-	0x12, 0xc6, 0xf0, 0x9f, 0x45, 0x8a, 0x5a, 0xb5, 0xb4, 0xd6, 0x98, 0x86, 0x6c, 0x7a, 0x56, 0xbb,
-	0x2b, 0xaf, 0xd7, 0x63, 0x43, 0x86, 0xb1, 0xb6, 0xf7, 0xb2, 0x12, 0xb5, 0x86, 0x05, 0xf8, 0x77,
-	0x28, 0x7b, 0xb1, 0x17, 0x13, 0x23, 0x4e, 0x4b, 0x9c, 0x98, 0xec, 0x19, 0x74, 0xcf, 0x90, 0xa2,
-	0x91, 0x5c, 0x83, 0x3c, 0x45, 0x6e, 0xb9, 0x24, 0xc8, 0x29, 0xaf, 0x10, 0x04, 0x08, 0x72, 0xcb,
-	0x43, 0xe4, 0x39, 0x82, 0xfe, 0x9b, 0x1f, 0x7a, 0x24, 0x2b, 0xb7, 0xa9, 0xaa, 0xaf, 0xbb, 0xab,
-	0xbe, 0xaa, 0xae, 0x6a, 0x12, 0x1a, 0xe1, 0xb1, 0x1d, 0xd2, 0x20, 0x0a, 0xac, 0xdf, 0x4a, 0xd0,
-	0x78, 0x8e, 0x23, 0xd7, 0x73, 0x23, 0x17, 0x99, 0x50, 0x9f, 0x61, 0xca, 0xfc, 0x80, 0x98, 0x46,
-	0xcf, 0xd8, 0xa9, 0x3a, 0x5a, 0x44, 0x08, 0x2a, 0x63, 0x97, 0x8d, 0xcd, 0x52, 0xcf, 0xd8, 0x69,
-	0x3a, 0xe2, 0x1b, 0x5d, 0x07, 0xa0, 0x38, 0x0c, 0x98, 0x1f, 0x05, 0x74, 0x61, 0x96, 0x85, 0x25,
-	0xa3, 0x41, 0x7f, 0x83, 0xd5, 0x63, 0x7c, 0xea, 0x93, 0x61, 0x4c, 0xfc, 0xb3, 0x61, 0xe4, 0x4f,
-	0xb1, 0x59, 0xe9, 0x19, 0x3b, 0x65, 0x67, 0x45, 0xa8, 0xdf, 0x10, 0xff, 0xec, 0xc8, 0x9f, 0x62,
-	0x64, 0xc1, 0x0a, 0x26, 0x5e, 0x06, 0x55, 0x15, 0xa8, 0x16, 0x26, 0x5e, 0x82, 0x31, 0xa1, 0x3e,
-	0x0a, 0xa6, 0x53, 0x3f, 0x62, 0x66, 0x4d, 0x7a, 0xa6, 0x44, 0x74, 0x15, 0x1a, 0x34, 0x26, 0x72,
-	0x61, 0x5d, 0x2c, 0xac, 0xd3, 0x98, 0x88, 0x45, 0x4f, 0x61, 0x4d, 0x9b, 0x86, 0x21, 0xa6, 0x43,
-	0x3f, 0xc2, 0x53, 0xb3, 0xd1, 0x2b, 0xef, 0xb4, 0x76, 0xb7, 0x6c, 0x1d, 0xb4, 0xed, 0x48, 0xf4,
-	0x2b, 0x4c, 0x0f, 0x23, 0x3c, 0xfd, 0x2f, 0x89, 0xe8, 0xc2, 0xe9, 0xd0, 0x9c, 0xb2, 0xbb, 0x07,
-	0xeb, 0x05, 0x30, 0xf4, 0x27, 0x28, 0xbf, 0xc7, 0x0b, 0xc1, 0x55, 0xd3, 0xe1, 0x9f, 0x68, 0x03,
-	0xaa, 0x33, 0x77, 0x12, 0x63, 0x41, 0x94, 0xe1, 0x48, 0xe1, 0x71, 0xe9, 0xa1, 0x61, 0xdd, 0x87,
-	0xcd, 0xfd, 0x98, 0x12, 0x2f, 0x98, 0x93, 0x41, 0xe8, 0x52, 0x86, 0x9f, 0xbb, 0x11, 0xf5, 0xcf,
-	0x9c, 0x60, 0x2e, 0x83, 0x9b, 0xc4, 0x53, 0xc2, 0x4c, 0xa3, 0x57, 0xde, 0x59, 0x71, 0xb4, 0x68,
-	0x7d, 0x6b, 0xc0, 0x46, 0xd1, 0x2a, 0x9e, 0x0f, 0xe2, 0x4e, 0xb1, 0x3a, 0x5a, 0x7c, 0xa3, 0x6d,
-	0xe8, 0x90, 0x78, 0x7a, 0x8c, 0xe9, 0x30, 0x38, 0x19, 0xd2, 0x60, 0xce, 0x84, 0x13, 0x55, 0xa7,
-	0x2d, 0xb5, 0x2f, 0x4f, 0x9c, 0x60, 0xce, 0xd0, 0x3f, 0x60, 0x2d, 0x45, 0xe9, 0x63, 0xcb, 0x02,
-	0xb8, 0xaa, 0x81, 0x7d, 0xa9, 0x46, 0xff, 0x84, 0x8a, 0xd8, 0xa7, 0x22, 0x38, 0x33, 0xed, 0x73,
-	0x02, 0x70, 0x04, 0xca, 0xfa, 0x1c, 0x3a, 0x4f, 0xfc, 0x09, 0x66, 0x2f, 0xe7, 0x04, 0x53, 0x36,
-	0xf6, 0x43, 0x74, 0x4f, 0xb3, 0x61, 0x88, 0x0d, 0xba, 0x76, 0xde, 0x6e, 0xbf, 0xe5, 0x46, 0xc9,
-	0xb8, 0x04, 0x76, 0x1f, 0x02, 0xa4, 0xca, 0x2c, 0xbf, 0xd5, 0x02, 0x7e, 0xab, 0x59, 0x7e, 0xbf,
-	0x2c, 0xa7, 0x04, 0xef, 0x11, 0x77, 0xb2, 0x60, 0x3e, 0x73, 0x30, 0x8b, 0x27, 0x11, 0x43, 0x3d,
-	0x68, 0x9d, 0x52, 0x97, 0xc4, 0x13, 0x97, 0xfa, 0x91, 0xde, 0x2f, 0xab, 0x42, 0x5d, 0x68, 0x30,
-	0x77, 0x1a, 0x4e, 0x7c, 0x72, 0xaa, 0xb6, 0x4e, 0x64, 0x74, 0x17, 0xea, 0x21, 0x0d, 0x3e, 0xc3,
-	0xa3, 0x48, 0xf0, 0xd4, 0xda, 0xfd, 0x73, 0x31, 0x11, 0x1a, 0x85, 0x6e, 0x43, 0xf5, 0x84, 0x07,
-	0xaa, 0x78, 0x3b, 0x07, 0x2e, 0x31, 0xe8, 0x0e, 0xd4, 0x42, 0x1c, 0x84, 0x13, 0x5e, 0xf6, 0x17,
-	0xa0, 0x15, 0x08, 0x1d, 0x02, 0x92, 0x5f, 0x43, 0x9f, 0x44, 0x98, 0xba, 0xa3, 0x88, 0xdf, 0xd6,
-	0x9a, 0xf0, 0xab, 0x6b, 0xf7, 0x83, 0x69, 0x48, 0x31, 0x63, 0xd8, 0x93, 0x8b, 0x9d, 0x60, 0xae,
-	0xd6, 0xaf, 0xc9, 0x55, 0x87, 0xe9, 0x22, 0xf4, 0x10, 0x56, 0x85, 0x0b, 0xc3, 0x40, 0x27, 0xc4,
-	0xac, 0x0b, 0x17, 0x56, 0x97, 0xf2, 0xe4, 0x74, 0x4e, 0xf2, 0x79, 0xbd, 0x06, 0xcd, 0xc8, 0x1f,
-	0xbd, 0x1f, 0x32, 0xff, 0x03, 0x36, 0x1b, 0xe2, 0xd2, 0x35, 0xb8, 0x62, 0xe0, 0x7f, 0xc0, 0xd6,
-	0x0f, 0x06, 0x5c, 0x3d, 0xd7, 0x8f, 0x82, 0x22, 0x35, 0x2e, 0x5b, 0xa4, 0xa5, 0xe2, 0x22, 0x45,
-	0x50, 0xe1, 0xf7, 0xd8, 0x2c, 0xf7, 0xca, 0x3b, 0x65, 0xa7, 0xa2, 0x1b, 0x99, 0x4f, 0x3c, 0x7f,
-	0xa4, 0x72, 0x50, 0x75, 0xb4, 0x88, 0xae, 0x40, 0xcd, 0x27, 0x5e, 0x18, 0x51, 0x41, 0x77, 0xd9,
-	0x51, 0x92, 0x35, 0x80, 0x7a, 0x3f, 0x88, 0x43, 0x9e, 0x91, 0x0d, 0xa8, 0xfa, 0xc4, 0xc3, 0x67,
-	0xa2, 0x6a, 0x9b, 0x8e, 0x14, 0xd0, 0x2e, 0xd4, 0xa6, 0x22, 0x04, 0xe1, 0xc7, 0xc5, 0x64, 0x2b,
-	0xa4, 0xb5, 0x0d, 0xed, 0xa3, 0x20, 0x1e, 0x8d, 0xb1, 0x27, 0x08, 0xe5, 0x3b, 0xcb, 0xc2, 0x30,
-	0x84, 0x53, 0x52, 0xb0, 0x7e, 0x36, 0xe0, 0x8a, 0x3a, 0x7b, 0xb9, 0x70, 0x6f, 0x43, 0x9b, 0x63,
-	0x86, 0x23, 0x69, 0x56, 0x79, 0x6e, 0xd8, 0x0a, 0xee, 0xb4, 0xb8, 0x55, 0xfb, 0x7d, 0x17, 0x3a,
-	0xaa, 0x34, 0x34, 0xbc, 0xbe, 0x04, 0x5f, 0x91, 0x76, 0xbd, 0xe0, 0x1e, 0xb4, 0xd5, 0x02, 0xe9,
-	0x95, 0x6c, 0x8d, 0x2b, 0x76, 0xd6, 0x67, 0xa7, 0x25, 0x21, 0x32, 0x80, 0x1b, 0xd0, 0x92, 0x25,
-	0x33, 0xf1, 0x09, 0x66, 0x66, 0x53, 0x84, 0x01, 0x42, 0xf5, 0x8c, 0x6b, 0xac, 0x6f, 0x0c, 0x80,
-	0x37, 0x7b, 0x83, 0xa3, 0xfe, 0xd8, 0x25, 0xa7, 0x98, 0x17, 0x8a, 0xf0, 0x3f, 0xd3, 0xab, 0x1a,
-	0x5c, 0xf1, 0x82, 0xf7, 0xab, 0x2d, 0x00, 0x46, 0x47, 0xc3, 0x63, 0x7c, 0x12, 0x50, 0xac, 0x26,
-	0x4b, 0x93, 0xd1, 0xd1, 0xbe, 0x50, 0xf0, 0xb5, 0xdc, 0xec, 0x9e, 0x44, 0x98, 0xaa, 0xe9, 0xd2,
-	0x60, 0x74, 0xb4, 0xc7, 0x65, 0xee, 0x48, 0xec, 0xb2, 0x48, 0x2f, 0xae, 0xc8, 0xe1, 0xc3, 0x55,
-	0x6a, 0xf5, 0x16, 0x08, 0x49, 0x2d, 0xaf, 0xca, 0xcd, 0xb9, 0x46, 0xac, 0xb7, 0xfe, 0x03, 0x9b,
-	0xa9, 0x9b, 0x6c, 0xe0, 0xce, 0x30, 0xd5, 0x9c, 0xff, 0x15, 0xea, 0x23, 0xa9, 0x56, 0x6d, 0xab,
-	0x65, 0xa7, 0x50, 0x47, 0xdb, 0xac, 0x1f, 0x0d, 0xe8, 0x0c, 0xc6, 0x41, 0x44, 0x30, 0x63, 0x0e,
-	0x1e, 0x05, 0xd4, 0xe3, 0x95, 0x18, 0x2d, 0xc2, 0xa4, 0x29, 0xf3, 0xef, 0xa4, 0x51, 0x97, 0x32,
-	0x8d, 0x1a, 0x41, 0x85, 0x93, 0xa0, 0x82, 0x12, 0xdf, 0xe8, 0x11, 0x34, 0x46, 0x41, 0xcc, 0x6f,
-	0xa7, 0x6e, 0x1b, 0x5b, 0x76, 0x7e, 0x7b, 0x9e, 0x45, 0x61, 0x97, 0x0d, 0x33, 0x81, 0x77, 0xff,
-	0x0d, 0x2b, 0x39, 0xd3, 0x1f, 0x6a, 0x9b, 0x07, 0xb0, 0xa9, 0x8f, 0x59, 0x2e, 0xbe, 0x5b, 0x50,
-	0xa7, 0xe2, 0x64, 0x4d, 0xc4, 0xea, 0x92, 0x47, 0x8e, 0xb6, 0x5b, 0xbf, 0x1a, 0xd0, 0xe2, 0x15,
-	0xf2, 0xd4, 0x67, 0x62, 0xf4, 0x67, 0xc6, 0xb5, 0xbc, 0x44, 0xc9, 0xb8, 0x7e, 0x0b, 0x1b, 0x8a,
-	0xc1, 0xe1, 0xf1, 0x62, 0xe8, 0xe1, 0x19, 0x9e, 0x04, 0x21, 0xa6, 0x66, 0x49, 0x9c, 0xb0, 0x6d,
-	0x67, 0x76, 0xb1, 0x55, 0x76, 0xf6, 0x17, 0x07, 0x1a, 0x26, 0x43, 0x47, 0xa3, 0x8f, 0x0c, 0xdd,
-	0xd7, 0xb0, 0x79, 0x0e, 0xbc, 0x80, 0x8e, 0x5e, 0x96, 0x8e, 0xd6, 0x2e, 0xd8, 0xbc, 0x78, 0x07,
-	0x91, 0x1b, 0xb1, 0x2c, 0x35, 0x5f, 0x1b, 0x60, 0x66, 0xdc, 0x91, 0xb4, 0x3c, 0xc7, 0x8c, 0xb9,
-	0xa7, 0x18, 0x3d, 0xce, 0x5e, 0xe5, 0x25, 0xc7, 0x73, 0x48, 0xd9, 0x4b, 0xd5, 0x90, 0x13, 0x4b,
-	0xba, 0x4f, 0x00, 0x52, 0x65, 0xc1, 0x23, 0xc2, 0xca, 0xbb, 0xd7, 0xce, 0xed, 0x9d, 0x71, 0xf0,
-	0x0d, 0x34, 0x13, 0xc7, 0x79, 0x8a, 0x5d, 0xcf, 0xc3, 0x9e, 0x8a, 0x53, 0x0a, 0x3c, 0x11, 0x14,
-	0x4f, 0x83, 0x19, 0xf6, 0x54, 0xea, 0xb5, 0x28, 0x52, 0x24, 0x08, 0xf3, 0xd4, 0xf4, 0xd7, 0xa2,
-	0xf5, 0x93, 0x01, 0xf5, 0x03, 0x3c, 0x3b, 0xf2, 0x47, 0xef, 0xf3, 0x89, 0xcc, 0xbd, 0xbb, 0x7a,
-	0x50, 0x65, 0xfc, 0xe0, 0x22, 0x0e, 0x85, 0x01, 0x3d, 0x80, 0xe6, 0xc4, 0x25, 0xa7, 0xb1, 0xcb,
-	0xaf, 0x52, 0x59, 0xd0, 0xb4, 0x69, 0xab, 0x8d, 0xed, 0x67, 0xda, 0x22, 0x99, 0x49, 0x91, 0xdd,
-	0xa7, 0xd0, 0xc9, 0x1b, 0x0b, 0x18, 0xba, 0x5c, 0x02, 0x67, 0xd0, 0xe0, 0x67, 0x1d, 0xe0, 0x19,
-	0x43, 0x7f, 0x87, 0x8a, 0x87, 0x67, 0x3a, 0x5d, 0xeb, 0xb6, 0x36, 0x70, 0x87, 0x94, 0x0f, 0x02,
-	0xd0, 0xdd, 0x83, 0x66, 0xa2, 0x2a, 0x28, 0x9d, 0xeb, 0xf9, 0x93, 0x1b, 0x3a, 0xa0, 0xec, 0xb9,
-	0xbf, 0x18, 0xb0, 0xce, 0xf7, 0x58, 0xbe, 0x50, 0x0f, 0xa0, 0xca, 0xa7, 0xa4, 0x76, 0xe2, 0x86,
-	0x5d, 0x00, 0x12, 0x8e, 0xe9, 0x72, 0x11, 0x68, 0xde, 0x08, 0x3d, 0x3c, 0x1b, 0xca, 0x99, 0x54,
-	0x12, 0xd7, 0xa9, 0xe1, 0xe1, 0xd9, 0xa1, 0x18, 0x4b, 0x17, 0x8d, 0xe2, 0x6e, 0x1f, 0x20, 0xdd,
-	0xae, 0x20, 0x98, 0x1b, 0xf9, 0x60, 0x9a, 0x09, 0x2b, 0xd9, 0x68, 0xfe, 0x07, 0xcd, 0x01, 0x26,
-	0xfc, 0x11, 0x4d, 0xa2, 0xb4, 0x91, 0xf0, 0x5d, 0x4a, 0x0a, 0xc6, 0x5f, 0x4f, 0xbc, 0x2c, 0x30,
-	0x11, 0xe5, 0x20, 0x1c, 0xd4, 0x72, 0xb6, 0x82, 0xca, 0xb9, 0x56, 0xc0, 0x3b, 0xe8, 0x66, 0x5f,
-	0xc2, 0x92, 0x03, 0x34, 0x55, 0xff, 0x87, 0x35, 0xa6, 0x75, 0xbc, 0x51, 0xf0, 0x90, 0x14, 0x6d,
-	0x77, 0xec, 0x73, 0x16, 0xd9, 0x89, 0x62, 0x7f, 0xc1, 0x03, 0x91, 0x24, 0xae, 0xb2, 0xbc, 0xb6,
-	0xfb, 0x02, 0x36, 0x8a, 0x80, 0x97, 0x69, 0x13, 0xe9, 0x89, 0x19, 0x7e, 0xde, 0x01, 0xf4, 0x45,
-	0x44, 0xfc, 0x96, 0x16, 0x3e, 0xcc, 0xbb, 0xd0, 0xd0, 0xe5, 0xad, 0x07, 0x99, 0x96, 0xd3, 0x6b,
-	0x54, 0x39, 0xe7, 0x1a, 0x59, 0x5f, 0x40, 0x4d, 0xee, 0x9f, 0xfc, 0x08, 0x33, 0x32, 0x3f, 0xc2,
-	0xb6, 0xa1, 0x33, 0x1f, 0xe3, 0xec, 0x6f, 0xac, 0x92, 0x28, 0x82, 0x36, 0xd7, 0x26, 0x3f, 0x9f,
-	0xae, 0x40, 0xcd, 0x8d, 0xa3, 0x71, 0x40, 0xd5, 0x5d, 0x57, 0x12, 0xba, 0x99, 0x7f, 0xa9, 0xb6,
-	0xec, 0x34, 0x12, 0xfd, 0x3a, 0x79, 0xc7, 0x1f, 0x27, 0x22, 0x61, 0xcb, 0xe5, 0x7c, 0x33, 0xdf,
-	0xe4, 0x5b, 0xbb, 0x75, 0xb5, 0x3c, 0x6d, 0x12, 0x37, 0xa1, 0x2d, 0x4f, 0xca, 0x55, 0x6f, 0x4b,
-	0xea, 0x44, 0x01, 0x5b, 0x33, 0xa8, 0x1c, 0x2d, 0xc2, 0x80, 0x57, 0xd6, 0x9c, 0x06, 0xe4, 0x54,
-	0x45, 0x27, 0x05, 0x59, 0x3d, 0x94, 0xf2, 0xb7, 0xb7, 0x9c, 0xa0, 0x5a, 0xe4, 0x21, 0xc9, 0x53,
-	0x14, 0xa5, 0x4a, 0x4a, 0x86, 0x6b, 0x25, 0x33, 0x5c, 0x11, 0x54, 0xf8, 0x83, 0x45, 0x3c, 0x03,
-	0xaa, 0x8e, 0xf8, 0xb6, 0x6e, 0x43, 0x9b, 0x9f, 0xcb, 0x0e, 0xdc, 0xc8, 0x65, 0x38, 0x42, 0xd7,
-	0xa0, 0x1a, 0x71, 0x59, 0xc5, 0x52, 0xb5, 0xb9, 0xd5, 0x91, 0x3a, 0xeb, 0x2b, 0x03, 0xd0, 0xe1,
-	0x34, 0x0c, 0x68, 0xc4, 0x5e, 0x61, 0xaa, 0xdb, 0x13, 0xfa, 0x17, 0xf7, 0x21, 0x26, 0x51, 0x7a,
-	0xa3, 0x3f, 0x06, 0xc9, 0xb1, 0xad, 0x6e, 0xb4, 0x82, 0x77, 0x1f, 0x41, 0x2b, 0xa3, 0xfe, 0xd4,
-	0xef, 0xc8, 0x72, 0xb6, 0xdc, 0xbe, 0x33, 0x60, 0x3d, 0x3d, 0x25, 0x19, 0x75, 0x68, 0x2f, 0xdb,
-	0x6d, 0xa5, 0x3b, 0x7f, 0xb1, 0x0b, 0x80, 0x17, 0x74, 0xde, 0xd7, 0x97, 0xe8, 0xbc, 0xb7, 0xf2,
-	0x77, 0x62, 0xbd, 0x20, 0xe2, 0xac, 0xb7, 0x01, 0x74, 0x0b, 0x7c, 0xd0, 0x15, 0x64, 0x43, 0xdd,
-	0x97, 0x56, 0xe5, 0xf1, 0x46, 0x91, 0xc7, 0x8e, 0x06, 0x5d, 0xa6, 0x9c, 0xbe, 0x37, 0x60, 0xf5,
-	0xe3, 0x42, 0xad, 0x8d, 0xb1, 0xeb, 0x61, 0x2a, 0x02, 0xe1, 0x7d, 0x4e, 0xff, 0xf8, 0x77, 0x94,
-	0x01, 0x3d, 0xe6, 0x1d, 0x8c, 0x44, 0x49, 0x07, 0x6b, 0xed, 0x5e, 0xb7, 0x97, 0x3b, 0x73, 0x5f,
-	0x01, 0x92, 0xf7, 0x97, 0x14, 0xe5, 0xfb, 0x2b, 0x63, 0xfa, 0x54, 0x3a, 0xdb, 0x19, 0x82, 0x8e,
-	0x6b, 0xe2, 0x6f, 0x98, 0xfb, 0xbf, 0x07, 0x00, 0x00, 0xff, 0xff, 0x8e, 0x4f, 0xe3, 0x8d, 0x92,
-	0x11, 0x00, 0x00,
+	// 1741 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0xcd, 0x6f, 0xdb, 0xca,
+	0x11, 0x07, 0xf5, 0xad, 0x91, 0x2c, 0xd5, 0x6b, 0x37, 0xe6, 0x63, 0xe0, 0x44, 0x61, 0xfd, 0x5a,
+	0xbf, 0xa6, 0x8f, 0xef, 0xc1, 0xe9, 0x03, 0x92, 0xf4, 0x52, 0x5b, 0x6e, 0x10, 0x03, 0xf9, 0xa4,
+	0x9c, 0x14, 0xbd, 0x44, 0xa0, 0xc5, 0xb5, 0xc5, 0x46, 0x5a, 0x12, 0xbb, 0xa4, 0x64, 0x05, 0x2d,
+	0xd0, 0x53, 0x4f, 0xbd, 0xf6, 0xda, 0x5b, 0x2f, 0x2d, 0x7a, 0xea, 0xbf, 0x50, 0x14, 0x28, 0x7a,
+	0xeb, 0x1f, 0xd1, 0xbf, 0xa3, 0xd8, 0x2f, 0x7e, 0xc8, 0xb4, 0xe3, 0xde, 0x38, 0x33, 0xbf, 0xdd,
+	0x9d, 0xf9, 0xcd, 0xec, 0xcc, 0x4a, 0xd0, 0x8a, 0xce, 0x9c, 0x88, 0x86, 0x71, 0x68, 0xff, 0xb7,
+	0x02, 0xad, 0x97, 0x38, 0xf6, 0x7c, 0x2f, 0xf6, 0x90, 0x09, 0xcd, 0x05, 0xa6, 0x2c, 0x08, 0x89,
+	0x69, 0x0c, 0x8c, 0xfd, 0xba, 0xab, 0x45, 0x84, 0xa0, 0x36, 0xf5, 0xd8, 0xd4, 0xac, 0x0c, 0x8c,
+	0xfd, 0xb6, 0x2b, 0xbe, 0xd1, 0x3d, 0x00, 0x8a, 0xa3, 0x90, 0x05, 0x71, 0x48, 0x57, 0x66, 0x55,
+	0x58, 0x72, 0x1a, 0xf4, 0x43, 0xe8, 0x9f, 0xe1, 0x8b, 0x80, 0x8c, 0x13, 0x12, 0x5c, 0x8e, 0xe3,
+	0x60, 0x8e, 0xcd, 0xda, 0xc0, 0xd8, 0xaf, 0xba, 0x1b, 0x42, 0xfd, 0x8e, 0x04, 0x97, 0xa7, 0xc1,
+	0x1c, 0x23, 0x1b, 0x36, 0x30, 0xf1, 0x73, 0xa8, 0xba, 0x40, 0x75, 0x30, 0xf1, 0x53, 0x8c, 0x09,
+	0xcd, 0x49, 0x38, 0x9f, 0x07, 0x31, 0x33, 0x1b, 0xd2, 0x33, 0x25, 0xa2, 0x2f, 0xa0, 0x45, 0x13,
+	0x22, 0x17, 0x36, 0xc5, 0xc2, 0x26, 0x4d, 0x88, 0x58, 0xf4, 0x1c, 0x36, 0xb5, 0x69, 0x1c, 0x61,
+	0x3a, 0x0e, 0x62, 0x3c, 0x37, 0x5b, 0x83, 0xea, 0x7e, 0xe7, 0x60, 0xd7, 0xd1, 0x41, 0x3b, 0xae,
+	0x44, 0xbf, 0xc1, 0xf4, 0x24, 0xc6, 0xf3, 0x5f, 0x90, 0x98, 0xae, 0xdc, 0x1e, 0x2d, 0x28, 0xad,
+	0x43, 0xd8, 0x2a, 0x81, 0xa1, 0xef, 0x41, 0xf5, 0x23, 0x5e, 0x09, 0xae, 0xda, 0x2e, 0xff, 0x44,
+	0xdb, 0x50, 0x5f, 0x78, 0xb3, 0x04, 0x0b, 0xa2, 0x0c, 0x57, 0x0a, 0x4f, 0x2b, 0x8f, 0x0d, 0xfb,
+	0x11, 0xec, 0x1c, 0x25, 0x94, 0xf8, 0xe1, 0x92, 0x8c, 0x22, 0x8f, 0x32, 0xfc, 0xd2, 0x8b, 0x69,
+	0x70, 0xe9, 0x86, 0x4b, 0x19, 0xdc, 0x2c, 0x99, 0x13, 0x66, 0x1a, 0x83, 0xea, 0xfe, 0x86, 0xab,
+	0x45, 0xfb, 0x2f, 0x06, 0x6c, 0x97, 0xad, 0xe2, 0xf9, 0x20, 0xde, 0x1c, 0xab, 0xa3, 0xc5, 0x37,
+	0xda, 0x83, 0x1e, 0x49, 0xe6, 0x67, 0x98, 0x8e, 0xc3, 0xf3, 0x31, 0x0d, 0x97, 0x4c, 0x38, 0x51,
+	0x77, 0xbb, 0x52, 0xfb, 0xfa, 0xdc, 0x0d, 0x97, 0x0c, 0xfd, 0x18, 0x36, 0x33, 0x94, 0x3e, 0xb6,
+	0x2a, 0x80, 0x7d, 0x0d, 0x1c, 0x4a, 0x35, 0xfa, 0x09, 0xd4, 0xc4, 0x3e, 0x35, 0xc1, 0x99, 0xe9,
+	0x5c, 0x13, 0x80, 0x2b, 0x50, 0xf6, 0x6f, 0xa0, 0xf7, 0x2c, 0x98, 0x61, 0xf6, 0x7a, 0x49, 0x30,
+	0x65, 0xd3, 0x20, 0x42, 0xdf, 0x6a, 0x36, 0x0c, 0xb1, 0x81, 0xe5, 0x14, 0xed, 0xce, 0x7b, 0x6e,
+	0x94, 0x8c, 0x4b, 0xa0, 0xf5, 0x18, 0x20, 0x53, 0xe6, 0xf9, 0xad, 0x97, 0xf0, 0x5b, 0xcf, 0xf3,
+	0xfb, 0xfb, 0x6a, 0x46, 0xf0, 0x21, 0xf1, 0x66, 0x2b, 0x16, 0x30, 0x17, 0xb3, 0x64, 0x16, 0x33,
+	0x34, 0x80, 0xce, 0x05, 0xf5, 0x48, 0x32, 0xf3, 0x68, 0x10, 0xeb, 0xfd, 0xf2, 0x2a, 0x64, 0x41,
+	0x8b, 0x79, 0xf3, 0x68, 0x16, 0x90, 0x0b, 0xb5, 0x75, 0x2a, 0xa3, 0x6f, 0xa0, 0x19, 0xd1, 0xf0,
+	0xd7, 0x78, 0x12, 0x0b, 0x9e, 0x3a, 0x07, 0xdf, 0x2f, 0x27, 0x42, 0xa3, 0xd0, 0x43, 0xa8, 0x9f,
+	0xf3, 0x40, 0x15, 0x6f, 0xd7, 0xc0, 0x25, 0x06, 0x7d, 0x0d, 0x8d, 0x08, 0x87, 0xd1, 0x8c, 0x97,
+	0xfd, 0x0d, 0x68, 0x05, 0x42, 0x27, 0x80, 0xe4, 0xd7, 0x38, 0x20, 0x31, 0xa6, 0xde, 0x24, 0xe6,
+	0xb7, 0xb5, 0x21, 0xfc, 0xb2, 0x9c, 0x61, 0x38, 0x8f, 0x28, 0x66, 0x0c, 0xfb, 0x72, 0xb1, 0x1b,
+	0x2e, 0xd5, 0xfa, 0x4d, 0xb9, 0xea, 0x24, 0x5b, 0x84, 0x1e, 0x43, 0x5f, 0xb8, 0x30, 0x0e, 0x75,
+	0x42, 0xcc, 0xa6, 0x70, 0xa1, 0xbf, 0x96, 0x27, 0xb7, 0x77, 0x5e, 0xcc, 0xeb, 0x5d, 0x68, 0xc7,
+	0xc1, 0xe4, 0xe3, 0x98, 0x05, 0x9f, 0xb0, 0xd9, 0x12, 0x97, 0xae, 0xc5, 0x15, 0xa3, 0xe0, 0x13,
+	0xb6, 0xff, 0x6e, 0xc0, 0x17, 0xd7, 0xfa, 0x51, 0x52, 0xa4, 0xc6, 0x6d, 0x8b, 0xb4, 0x52, 0x5e,
+	0xa4, 0x08, 0x6a, 0xfc, 0x1e, 0x9b, 0xd5, 0x41, 0x75, 0xbf, 0xea, 0xd6, 0x74, 0x23, 0x0b, 0x88,
+	0x1f, 0x4c, 0x54, 0x0e, 0xea, 0xae, 0x16, 0xd1, 0x1d, 0x68, 0x04, 0xc4, 0x8f, 0x62, 0x2a, 0xe8,
+	0xae, 0xba, 0x4a, 0xb2, 0x47, 0xd0, 0x1c, 0x86, 0x49, 0xc4, 0x33, 0xb2, 0x0d, 0xf5, 0x80, 0xf8,
+	0xf8, 0x52, 0x54, 0x6d, 0xdb, 0x95, 0x02, 0x3a, 0x80, 0xc6, 0x5c, 0x84, 0x20, 0xfc, 0xb8, 0x99,
+	0x6c, 0x85, 0xb4, 0xf7, 0xa0, 0x7b, 0x1a, 0x26, 0x93, 0x29, 0xf6, 0x05, 0xa1, 0x7c, 0x67, 0x59,
+	0x18, 0x86, 0x70, 0x4a, 0x0a, 0xf6, 0xbf, 0x0c, 0xb8, 0xa3, 0xce, 0x5e, 0x2f, 0xdc, 0x87, 0xd0,
+	0xe5, 0x98, 0xf1, 0x44, 0x9a, 0x55, 0x9e, 0x5b, 0x8e, 0x82, 0xbb, 0x1d, 0x6e, 0xd5, 0x7e, 0x7f,
+	0x03, 0x3d, 0x55, 0x1a, 0x1a, 0xde, 0x5c, 0x83, 0x6f, 0x48, 0xbb, 0x5e, 0xf0, 0x2d, 0x74, 0xd5,
+	0x02, 0xe9, 0x95, 0x6c, 0x8d, 0x1b, 0x4e, 0xde, 0x67, 0xb7, 0x23, 0x21, 0x32, 0x80, 0xfb, 0xd0,
+	0x91, 0x25, 0x33, 0x0b, 0x08, 0x66, 0x66, 0x5b, 0x84, 0x01, 0x42, 0xf5, 0x82, 0x6b, 0xec, 0x3f,
+	0x1b, 0x00, 0xef, 0x0e, 0x47, 0xa7, 0xc3, 0xa9, 0x47, 0x2e, 0x30, 0x2f, 0x14, 0xe1, 0x7f, 0xae,
+	0x57, 0xb5, 0xb8, 0xe2, 0x15, 0xef, 0x57, 0xbb, 0x00, 0x8c, 0x4e, 0xc6, 0x67, 0xf8, 0x3c, 0xa4,
+	0x58, 0x4d, 0x96, 0x36, 0xa3, 0x93, 0x23, 0xa1, 0xe0, 0x6b, 0xb9, 0xd9, 0x3b, 0x8f, 0x31, 0x55,
+	0xd3, 0xa5, 0xc5, 0xe8, 0xe4, 0x90, 0xcb, 0xdc, 0x91, 0xc4, 0x63, 0xb1, 0x5e, 0x5c, 0x93, 0xc3,
+	0x87, 0xab, 0xd4, 0xea, 0x5d, 0x10, 0x92, 0x5a, 0x5e, 0x97, 0x9b, 0x73, 0x8d, 0x58, 0x6f, 0xff,
+	0x1c, 0x76, 0x32, 0x37, 0xd9, 0xc8, 0x5b, 0x60, 0xaa, 0x39, 0xff, 0x12, 0x9a, 0x13, 0xa9, 0x56,
+	0x6d, 0xab, 0xe3, 0x64, 0x50, 0x57, 0xdb, 0xec, 0x7f, 0x18, 0xd0, 0x1b, 0x4d, 0xc3, 0x98, 0x60,
+	0xc6, 0x5c, 0x3c, 0x09, 0xa9, 0xcf, 0x2b, 0x31, 0x5e, 0x45, 0x69, 0x53, 0xe6, 0xdf, 0x69, 0xa3,
+	0xae, 0xe4, 0x1a, 0x35, 0x82, 0x1a, 0x27, 0x41, 0x05, 0x25, 0xbe, 0xd1, 0x13, 0x68, 0x4d, 0xc2,
+	0x84, 0xdf, 0x4e, 0xdd, 0x36, 0x76, 0x9d, 0xe2, 0xf6, 0x3c, 0x8b, 0xc2, 0x2e, 0x1b, 0x66, 0x0a,
+	0xb7, 0x7e, 0x06, 0x1b, 0x05, 0xd3, 0xff, 0xd5, 0x36, 0x8f, 0x61, 0x47, 0x1f, 0xb3, 0x5e, 0x7c,
+	0x5f, 0x41, 0x93, 0x8a, 0x93, 0x35, 0x11, 0xfd, 0x35, 0x8f, 0x5c, 0x6d, 0xb7, 0xff, 0x63, 0x40,
+	0x87, 0x57, 0xc8, 0xf3, 0x80, 0x89, 0xd1, 0x9f, 0x1b, 0xd7, 0xf2, 0x12, 0xa5, 0xe3, 0xfa, 0x3d,
+	0x6c, 0x2b, 0x06, 0xc7, 0x67, 0xab, 0xb1, 0x8f, 0x17, 0x78, 0x16, 0x46, 0x98, 0x9a, 0x15, 0x71,
+	0xc2, 0x9e, 0x93, 0xdb, 0xc5, 0x51, 0xd9, 0x39, 0x5a, 0x1d, 0x6b, 0x98, 0x0c, 0x1d, 0x4d, 0xae,
+	0x18, 0xac, 0xb7, 0xb0, 0x73, 0x0d, 0xbc, 0x84, 0x8e, 0x41, 0x9e, 0x8e, 0xce, 0x01, 0x38, 0xbc,
+	0x78, 0x47, 0xb1, 0x17, 0xb3, 0x3c, 0x35, 0x7f, 0x32, 0xc0, 0xcc, 0xb9, 0x23, 0x69, 0x79, 0x89,
+	0x19, 0xf3, 0x2e, 0x30, 0x7a, 0x9a, 0xbf, 0xca, 0x6b, 0x8e, 0x17, 0x90, 0xb2, 0x97, 0xaa, 0x21,
+	0x27, 0x96, 0x58, 0xcf, 0x00, 0x32, 0x65, 0xc9, 0x23, 0xc2, 0x2e, 0xba, 0xd7, 0x2d, 0xec, 0x9d,
+	0x73, 0xf0, 0x1d, 0xb4, 0x53, 0xc7, 0x79, 0x8a, 0x3d, 0xdf, 0xc7, 0xbe, 0x8a, 0x53, 0x0a, 0x3c,
+	0x11, 0x14, 0xcf, 0xc3, 0x05, 0xf6, 0x55, 0xea, 0xb5, 0x28, 0x52, 0x24, 0x08, 0xf3, 0xd5, 0xf4,
+	0xd7, 0xa2, 0xfd, 0x4f, 0x03, 0x9a, 0xc7, 0x78, 0x71, 0x1a, 0x4c, 0x3e, 0x16, 0x13, 0x59, 0x78,
+	0x77, 0x0d, 0xa0, 0xce, 0xf8, 0xc1, 0x65, 0x1c, 0x0a, 0x03, 0xfa, 0x0e, 0xda, 0x33, 0x8f, 0x5c,
+	0x24, 0x1e, 0xbf, 0x4a, 0x55, 0x41, 0xd3, 0x8e, 0xa3, 0x36, 0x76, 0x5e, 0x68, 0x8b, 0x64, 0x26,
+	0x43, 0x5a, 0xcf, 0xa1, 0x57, 0x34, 0x96, 0x30, 0x74, 0xbb, 0x04, 0x2e, 0xa0, 0xc5, 0xcf, 0x3a,
+	0xc6, 0x0b, 0x86, 0x7e, 0x04, 0x35, 0x1f, 0x2f, 0x74, 0xba, 0xb6, 0x1c, 0x6d, 0xe0, 0x0e, 0x29,
+	0x1f, 0x04, 0xc0, 0x3a, 0x84, 0x76, 0xaa, 0x2a, 0x29, 0x9d, 0x7b, 0xc5, 0x93, 0x5b, 0x3a, 0xa0,
+	0xfc, 0xb9, 0xff, 0x36, 0x60, 0x8b, 0xef, 0xb1, 0x7e, 0xa1, 0xbe, 0x83, 0x3a, 0x9f, 0x92, 0xda,
+	0x89, 0xfb, 0x4e, 0x09, 0x48, 0x38, 0xa6, 0xcb, 0x45, 0xa0, 0x79, 0x23, 0xf4, 0xf1, 0x62, 0x2c,
+	0x67, 0x52, 0x45, 0x5c, 0xa7, 0x96, 0x8f, 0x17, 0x27, 0x62, 0x2c, 0xdd, 0x34, 0x8a, 0xad, 0x21,
+	0x40, 0xb6, 0x5d, 0x49, 0x30, 0xf7, 0x8b, 0xc1, 0xb4, 0x53, 0x56, 0xf2, 0xd1, 0xfc, 0x12, 0xda,
+	0x23, 0x4c, 0xf8, 0x23, 0x9a, 0xc4, 0x59, 0x23, 0xe1, 0xbb, 0x54, 0x14, 0x8c, 0xbf, 0x9e, 0x78,
+	0x59, 0x60, 0x22, 0xca, 0x41, 0x38, 0xa8, 0xe5, 0x7c, 0x05, 0x55, 0x0b, 0xad, 0x80, 0x77, 0xd0,
+	0x9d, 0xa1, 0x84, 0xa5, 0x07, 0x68, 0xaa, 0x7e, 0x05, 0x9b, 0x4c, 0xeb, 0x78, 0xa3, 0xe0, 0x21,
+	0x29, 0xda, 0xbe, 0x76, 0xae, 0x59, 0xe4, 0xa4, 0x8a, 0xa3, 0x15, 0x0f, 0x44, 0x92, 0xd8, 0x67,
+	0x45, 0xad, 0xf5, 0x0a, 0xb6, 0xcb, 0x80, 0xb7, 0x69, 0x13, 0xd9, 0x89, 0x39, 0x7e, 0x3e, 0x00,
+	0x0c, 0x45, 0x44, 0xfc, 0x96, 0x96, 0x3e, 0xcc, 0x2d, 0x68, 0xe9, 0xf2, 0xd6, 0x83, 0x4c, 0xcb,
+	0xd9, 0x35, 0xaa, 0x5d, 0x73, 0x8d, 0xec, 0xdf, 0x42, 0x43, 0xee, 0x9f, 0xfe, 0x08, 0x33, 0x72,
+	0x3f, 0xc2, 0xf6, 0xa0, 0xb7, 0x9c, 0xe2, 0xfc, 0x6f, 0xac, 0x8a, 0x28, 0x82, 0x2e, 0xd7, 0xa6,
+	0x3f, 0x9f, 0xee, 0x40, 0xc3, 0x4b, 0xe2, 0x69, 0x48, 0xd5, 0x5d, 0x57, 0x12, 0x7a, 0x50, 0x7c,
+	0xa9, 0x76, 0x9c, 0x2c, 0x12, 0xfd, 0x3a, 0xf9, 0xc0, 0x1f, 0x27, 0x22, 0x61, 0xeb, 0xe5, 0xfc,
+	0xa0, 0xd8, 0xe4, 0x3b, 0x07, 0x4d, 0xb5, 0x3c, 0x6b, 0x12, 0x0f, 0xa0, 0x2b, 0x4f, 0x2a, 0x54,
+	0x6f, 0x47, 0xea, 0x44, 0x01, 0xdb, 0x0b, 0xa8, 0x9d, 0xae, 0xa2, 0x90, 0x57, 0xd6, 0x92, 0x86,
+	0xe4, 0x42, 0x45, 0x27, 0x05, 0x59, 0x3d, 0x94, 0xf2, 0xb7, 0xb7, 0x9c, 0xa0, 0x5a, 0xe4, 0x21,
+	0xc9, 0x53, 0x14, 0xa5, 0x4a, 0x4a, 0x87, 0x6b, 0x2d, 0x37, 0x5c, 0x11, 0xd4, 0xf8, 0x83, 0x45,
+	0x3c, 0x03, 0xea, 0xae, 0xf8, 0xb6, 0x1f, 0x42, 0x97, 0x9f, 0xcb, 0x8e, 0xbd, 0xd8, 0x63, 0x38,
+	0x46, 0x77, 0xa1, 0x1e, 0x73, 0x59, 0xc5, 0x52, 0x77, 0xb8, 0xd5, 0x95, 0x3a, 0xfb, 0x77, 0x06,
+	0xf4, 0x4e, 0xe6, 0x51, 0x48, 0x63, 0xf6, 0x06, 0x53, 0xd1, 0x19, 0x1f, 0xf1, 0xf3, 0x13, 0x92,
+	0x06, 0x7f, 0xd7, 0x29, 0x02, 0xe4, 0xb8, 0x56, 0x37, 0x59, 0x41, 0xad, 0x27, 0xd0, 0xc9, 0xa9,
+	0x3f, 0x37, 0xa8, 0xab, 0xf9, 0x32, 0xfb, 0xa3, 0x01, 0x28, 0x3b, 0x41, 0x77, 0x48, 0xf4, 0xd3,
+	0x62, 0x4f, 0xb9, 0xe7, 0x5c, 0xc5, 0x5c, 0x6d, 0x29, 0xd6, 0xc9, 0x75, 0x8d, 0x41, 0xf5, 0xd7,
+	0x2f, 0x8b, 0x95, 0xdf, 0x5f, 0x8b, 0x2d, 0xef, 0xd7, 0x5f, 0x0d, 0xd8, 0xca, 0xac, 0xe9, 0xe8,
+	0x45, 0x87, 0xf9, 0xee, 0x2f, 0x9d, 0xfb, 0x81, 0x53, 0x02, 0xbc, 0x61, 0x12, 0xbc, 0xbd, 0xc5,
+	0x24, 0xf8, 0xaa, 0xe8, 0xe9, 0x56, 0x49, 0xfc, 0x79, 0x6f, 0xff, 0x60, 0x80, 0x55, 0xe2, 0x84,
+	0x2e, 0x69, 0x07, 0x9a, 0x81, 0xb4, 0x2a, 0x97, 0xb7, 0xcb, 0x5c, 0x76, 0x35, 0xe8, 0x16, 0xf5,
+	0x5d, 0x6c, 0xd0, 0xd5, 0xb5, 0xdf, 0x4a, 0x7f, 0x33, 0xa0, 0x7f, 0xf5, 0x5a, 0x35, 0xa6, 0xd8,
+	0xf3, 0x31, 0x15, 0x61, 0xf2, 0xae, 0xac, 0xff, 0xaa, 0x70, 0x95, 0x01, 0x3d, 0xe5, 0xfd, 0x96,
+	0xc4, 0x69, 0xbf, 0xe5, 0x79, 0x5f, 0x9f, 0x23, 0x43, 0x05, 0x48, 0x5f, 0x8b, 0x52, 0x94, 0xaf,
+	0xc5, 0x9c, 0xe9, 0x73, 0x7f, 0x62, 0x74, 0x73, 0xf4, 0x9d, 0x35, 0xc4, 0x9f, 0x46, 0x8f, 0xfe,
+	0x17, 0x00, 0x00, 0xff, 0xff, 0x01, 0xe4, 0xea, 0x45, 0x40, 0x12, 0x00, 0x00,
 }

+ 7 - 1
internal/pb/pb.proto

@@ -182,8 +182,12 @@ message TyposDataset {
     repeated Typo typos = 1;
 }
 
+message ImportsPerTick {
+    map<int32, int64> counts = 1;
+}
+
 message ImportsPerLanguage {
-    map<string, int64> counts = 1;
+    map<string, ImportsPerTick> ticks = 1;
 }
 
 message ImportsPerDeveloper {
@@ -193,6 +197,8 @@ message ImportsPerDeveloper {
 message ImportsPerDeveloperResults {
     repeated ImportsPerDeveloper imports = 1;
     repeated string author_index = 2;
+    // how long each tick is, as an int64 nanosecond count (Go's time.Duration)
+    int64 tick_size = 3;
 }
 
 message AnalysisResults {

+ 12 - 11
leaves/burndown.go

@@ -47,6 +47,9 @@ type BurndownAnalysis struct {
 	// PeopleNumber is the number of developers for which to collect the burndown stats. 0 disables it.
 	PeopleNumber int
 
+	// TickSize indicates the size of each time granule: day, hour, week, etc.
+	TickSize time.Duration
+
 	// HibernationThreshold sets the hibernation threshold for the underlying
 	// RBTree allocator. It is useful to trade CPU time for reduced peak memory consumption
 	// if there are many branches.
@@ -103,8 +106,6 @@ type BurndownAnalysis struct {
 	// previousTick is the tick from the previous sample period -
 	// different from TicksSinceStart.previousTick.
 	previousTick int
-	// tickSize indicates the size of each tick.
-	tickSize time.Duration
 	// references IdentityDetector.ReversedPeopleDict
 	reversedPeopleDict []string
 
@@ -140,7 +141,7 @@ type BurndownResult struct {
 	// Pipeline.Initialize(facts map[string]interface{}). Thus it can be obtained via
 	// facts[FactIdentityDetectorReversedPeopleDict].
 	reversedPeopleDict []string
-	// tickSize references TicksSinceStart.tickSize
+	// TickSize references TicksSinceStart.TickSize
 	tickSize time.Duration
 	// sampling and granularity are copied from BurndownAnalysis and stored for service purposes
 	// such as merging several results together.
@@ -294,7 +295,7 @@ func (analyser *BurndownAnalysis) Configure(facts map[string]interface{}) error
 		analyser.Debug = val
 	}
 	if val, exists := facts[items.FactTickSize].(time.Duration); exists {
-		analyser.tickSize = val
+		analyser.TickSize = val
 	}
 	return nil
 }
@@ -329,10 +330,10 @@ func (analyser *BurndownAnalysis) Initialize(repository *git.Repository) error {
 			analyser.Granularity)
 		analyser.Sampling = analyser.Granularity
 	}
-	if analyser.tickSize == 0 {
+	if analyser.TickSize == 0 {
 		def := items.DefaultTicksSinceStartTickSize * time.Hour
 		analyser.l.Warnf("tick size was not set, adjusted to %v\n", def)
-		analyser.tickSize = items.DefaultTicksSinceStartTickSize * time.Hour
+		analyser.TickSize = items.DefaultTicksSinceStartTickSize * time.Hour
 	}
 	analyser.repository = repository
 	analyser.globalHistory = sparseHistory{}
@@ -570,7 +571,7 @@ func (analyser *BurndownAnalysis) Finalize() interface{} {
 		FileOwnership:      fileOwnership,
 		PeopleHistories:    peopleHistories,
 		PeopleMatrix:       peopleMatrix,
-		tickSize:           analyser.tickSize,
+		tickSize:           analyser.TickSize,
 		reversedPeopleDict: analyser.reversedPeopleDict,
 		sampling:           analyser.Sampling,
 		granularity:        analyser.Granularity,
@@ -653,12 +654,12 @@ func (analyser *BurndownAnalysis) MergeResults(
 			bar1.tickSize, bar2.tickSize)
 	}
 	// for backwards-compatibility, if no tick size is present set to default
-	analyser.tickSize = bar1.tickSize
-	if analyser.tickSize == 0 {
-		analyser.tickSize = items.DefaultTicksSinceStartTickSize * time.Hour
+	analyser.TickSize = bar1.tickSize
+	if analyser.TickSize == 0 {
+		analyser.TickSize = items.DefaultTicksSinceStartTickSize * time.Hour
 	}
 	merged := BurndownResult{
-		tickSize: analyser.tickSize,
+		tickSize: analyser.TickSize,
 	}
 	if bar1.sampling < bar2.sampling {
 		merged.sampling = bar1.sampling

+ 9 - 9
leaves/burndown_test.go

@@ -87,7 +87,7 @@ func TestBurndownConfigure(t *testing.T) {
 	assert.True(t, bd.HibernationToDisk)
 	assert.Equal(t, bd.HibernationDirectory, "xxx")
 	assert.Equal(t, bd.Debug, true)
-	assert.Equal(t, bd.tickSize, 24*time.Hour)
+	assert.Equal(t, bd.TickSize, 24*time.Hour)
 	assert.Equal(t, bd.reversedPeopleDict, bd.Requires())
 	facts[ConfigBurndownTrackPeople] = false
 	facts[identity.FactIdentityDetectorPeopleCount] = 50
@@ -480,7 +480,7 @@ func bakeBurndownForSerialization(t *testing.T, firstAuthor, secondAuthor int) (
 		Sampling:     30,
 		PeopleNumber: 2,
 		TrackFiles:   true,
-		tickSize:     24 * time.Hour,
+		TickSize:     24 * time.Hour,
 	}
 	assert.Nil(t, bd.Initialize(test.Repository))
 	deps := map[string]interface{}{}
@@ -1153,7 +1153,7 @@ func TestBurndownMergeGlobalHistory(t *testing.T) {
 	res2.PeopleMatrix[1][2] = 700
 	res2.PeopleMatrix[1][3] = 800
 	bd := BurndownAnalysis{
-		tickSize: 24 * time.Hour,
+		TickSize: 24 * time.Hour,
 	}
 	merged := bd.MergeResults(res1, res2, &c1, &c2).(BurndownResult)
 	assert.Equal(t, merged.granularity, 19)
@@ -1212,7 +1212,7 @@ func TestBurndownMergeGlobalHistory_withDifferentTickSizes(t *testing.T) {
 		RunTime:       100000,
 	}
 	bd := BurndownAnalysis{
-		tickSize: 24 * time.Hour,
+		TickSize: 24 * time.Hour,
 	}
 	merged := bd.MergeResults(res1, res2, &c1, &c2)
 	assert.IsType(t, errors.New(""), merged)
@@ -1253,7 +1253,7 @@ func TestBurndownMergeNils(t *testing.T) {
 		RunTime:       100000,
 	}
 	bd := BurndownAnalysis{
-		tickSize: 24 * time.Hour,
+		TickSize: 24 * time.Hour,
 	}
 	merged := bd.MergeResults(res1, res2, &c1, &c2).(BurndownResult)
 	assert.Equal(t, merged.granularity, 19)
@@ -1499,14 +1499,14 @@ func TestBurndownMergeMatrices(t *testing.T) {
 		CommitsNumber: 6982,
 		RunTime:       1567214,
 	}
-	bd := BurndownAnalysis{tickSize: 24 * time.Hour}
-	nh := bd.mergeMatrices(h, nil, 30, 30, 30, 30, bd.tickSize, cr, cr)
+	bd := BurndownAnalysis{TickSize: 24 * time.Hour}
+	nh := bd.mergeMatrices(h, nil, 30, 30, 30, 30, bd.TickSize, cr, cr)
 	for y, row := range nh {
 		for x, v := range row {
 			assert.InDelta(t, v, h[y][x], 1, fmt.Sprintf("y=%d x=%d", y, x))
 		}
 	}
-	nh = bd.mergeMatrices(h, h, 30, 30, 30, 30, bd.tickSize, cr, cr)
+	nh = bd.mergeMatrices(h, h, 30, 30, 30, 30, bd.TickSize, cr, cr)
 	for y, row := range nh {
 		for x, v := range row {
 			assert.InDelta(t, v, h[y][x]*2, 1, fmt.Sprintf("y=%d x=%d", y, x))
@@ -1559,7 +1559,7 @@ func TestBurndownMergePeopleHistories(t *testing.T) {
 		RunTime:       100000,
 	}
 	bd := BurndownAnalysis{
-		tickSize: 24 * time.Hour,
+		TickSize: 24 * time.Hour,
 	}
 	merged := bd.MergeResults(res1, res2, &c1, &c2).(BurndownResult)
 	mh := [][]int64{

+ 2 - 2
leaves/devs.go

@@ -33,7 +33,7 @@ type DevsAnalysis struct {
 	ticks map[int]map[int]*DevTick
 	// reversedPeopleDict references IdentityDetector.ReversedPeopleDict
 	reversedPeopleDict []string
-	// tickSize references TicksSinceStart.tickSize
+	// TickSize references TicksSinceStart.TickSize
 	tickSize time.Duration
 
 	l core.Logger
@@ -47,7 +47,7 @@ type DevsResult struct {
 
 	// reversedPeopleDict references IdentityDetector.ReversedPeopleDict
 	reversedPeopleDict []string
-	// tickSize references TicksSinceStart.tickSize
+	// TickSize references TicksSinceStart.TickSize
 	tickSize time.Duration
 }
 

+ 87 - 23
leaves/imports_printer.go

@@ -6,36 +6,46 @@ import (
 	"io"
 	"log"
 	"sort"
+	"time"
 
 	"github.com/gogo/protobuf/proto"
 	imports2 "github.com/src-d/imports"
 	"gopkg.in/src-d/go-git.v4"
-	"gopkg.in/src-d/go-git.v4/plumbing"
+	gitplumbing "gopkg.in/src-d/go-git.v4/plumbing"
 	"gopkg.in/src-d/hercules.v10/internal/core"
 	"gopkg.in/src-d/hercules.v10/internal/pb"
+	"gopkg.in/src-d/hercules.v10/internal/plumbing"
 	"gopkg.in/src-d/hercules.v10/internal/plumbing/identity"
 	"gopkg.in/src-d/hercules.v10/internal/plumbing/imports"
 	"gopkg.in/src-d/hercules.v10/internal/yaml"
 )
 
+// ImportsMap is the type of the mapping from dev indexes to languages to import names to ticks to
+// usage counts. Ticks start counting from 0 and correspond to the earliest commit timestamp
+// (included in the YAML/protobuf header).
+type ImportsMap = map[int]map[string]map[string]map[int]int64
+
 // ImportsPerDeveloper collects imports per developer.
 type ImportsPerDeveloper struct {
 	core.NoopMerger
 	core.OneShotMergeProcessor
-	// imports is the mapping from dev indexes to languages to import names to usage counts.
-	imports map[int]map[string]map[string]int
+	// TickSize defines the time mapping granularity (the last ImportsMap's key).
+	TickSize time.Duration
+	// imports mapping, see the referenced type for details.
+	imports ImportsMap
 	// reversedPeopleDict references IdentityDetector.ReversedPeopleDict
 	reversedPeopleDict []string
-
-	l core.Logger
+	l                  core.Logger
 }
 
 // ImportsPerDeveloperResult is returned by Finalize() and represents the analysis result.
 type ImportsPerDeveloperResult struct {
-	// Imports is the mapping from dev indexes to languages to import names to usage counts.
-	Imports map[int]map[string]map[string]int
+	// Imports is the imports mapping, see the referenced type for details.
+	Imports ImportsMap
 	// reversedPeopleDict references IdentityDetector.ReversedPeopleDict
 	reversedPeopleDict []string
+	// tickSize references TicksSinceStart.TickSize
+	tickSize time.Duration
 }
 
 // Name of this PipelineItem. Uniquely identifies the type, used for mapping keys, etc.
@@ -54,7 +64,7 @@ func (ipd *ImportsPerDeveloper) Provides() []string {
 // Each requested entity will be inserted into `deps` of Consume(). In turn, those
 // entities are Provides() upstream.
 func (ipd *ImportsPerDeveloper) Requires() []string {
-	return []string{imports.DependencyImports, identity.DependencyAuthor}
+	return []string{imports.DependencyImports, identity.DependencyAuthor, plumbing.DependencyTick}
 }
 
 // ListConfigurationOptions returns the list of changeable public properties of this PipelineItem.
@@ -79,6 +89,9 @@ func (ipd *ImportsPerDeveloper) Configure(facts map[string]interface{}) error {
 		ipd.l = l
 	}
 	ipd.reversedPeopleDict = facts[identity.FactIdentityDetectorReversedPeopleDict].([]string)
+	if val, exists := facts[plumbing.FactTickSize].(time.Duration); exists {
+		ipd.TickSize = val
+	}
 	return nil
 }
 
@@ -86,8 +99,12 @@ func (ipd *ImportsPerDeveloper) Configure(facts map[string]interface{}) error {
 // calls. The repository which is going to be analysed is supplied as an argument.
 func (ipd *ImportsPerDeveloper) Initialize(repository *git.Repository) error {
 	ipd.l = core.NewLogger()
-	ipd.imports = map[int]map[string]map[string]int{}
+	ipd.imports = ImportsMap{}
 	ipd.OneShotMergeProcessor.Initialize()
+	if ipd.TickSize == 0 {
+		ipd.TickSize = time.Hour * 24
+		ipd.l.Warnf("tick size was not set, adjusted to %v\n", ipd.TickSize)
+	}
 	return nil
 }
 
@@ -103,20 +120,26 @@ func (ipd *ImportsPerDeveloper) Consume(deps map[string]interface{}) (map[string
 		return nil, nil
 	}
 	author := deps[identity.DependencyAuthor].(int)
-	imps := deps[imports.DependencyImports].(map[plumbing.Hash]imports2.File)
+	imps := deps[imports.DependencyImports].(map[gitplumbing.Hash]imports2.File)
 	aimps := ipd.imports[author]
+	tick := deps[plumbing.DependencyTick].(int)
 	if aimps == nil {
-		aimps = map[string]map[string]int{}
+		aimps = map[string]map[string]map[int]int64{}
 		ipd.imports[author] = aimps
 	}
 	for _, file := range imps {
 		limps := aimps[file.Lang]
 		if limps == nil {
-			limps = map[string]int{}
+			limps = map[string]map[int]int64{}
 			aimps[file.Lang] = limps
 		}
 		for _, imp := range file.Imports {
-			limps[imp]++
+			timps, exists := limps[imp]
+			if !exists {
+				timps = map[int]int64{}
+				limps[imp] = timps
+			}
+			timps[tick]++
 		}
 	}
 	return nil, nil
@@ -124,7 +147,11 @@ func (ipd *ImportsPerDeveloper) Consume(deps map[string]interface{}) (map[string
 
 // Finalize returns the result of the analysis. Further Consume() calls are not expected.
 func (ipd *ImportsPerDeveloper) Finalize() interface{} {
-	return ImportsPerDeveloperResult{Imports: ipd.imports, reversedPeopleDict: ipd.reversedPeopleDict}
+	return ImportsPerDeveloperResult{
+		Imports:            ipd.imports,
+		reversedPeopleDict: ipd.reversedPeopleDict,
+		tickSize:           ipd.TickSize,
+	}
 }
 
 // Fork clones this PipelineItem.
@@ -149,13 +176,15 @@ func (ipd *ImportsPerDeveloper) serializeText(result *ImportsPerDeveloperResult,
 		devs = append(devs, dev)
 	}
 	sort.Ints(devs)
+	fmt.Fprintln(writer, "  tick_size:", int(result.tickSize.Seconds()))
+	fmt.Fprintln(writer, "  imports:")
 	for _, dev := range devs {
 		imps := result.Imports[dev]
 		obj, err := json.Marshal(imps)
 		if err != nil {
 			log.Panicf("Could not serialize %v: %v", imps, err)
 		}
-		fmt.Fprintf(writer, "  - %s: %s\n", yaml.SafeString(result.reversedPeopleDict[dev]), string(obj))
+		fmt.Fprintf(writer, "    %s: %s\n", yaml.SafeString(result.reversedPeopleDict[dev]), string(obj))
 	}
 }
 
@@ -163,15 +192,20 @@ func (ipd *ImportsPerDeveloper) serializeBinary(result *ImportsPerDeveloperResul
 	message := pb.ImportsPerDeveloperResults{
 		Imports:     make([]*pb.ImportsPerDeveloper, len(result.Imports)),
 		AuthorIndex: result.reversedPeopleDict,
+		TickSize:    int64(result.tickSize),
 	}
-	for key, vals := range result.Imports {
-		dev := &pb.ImportsPerDeveloper{Languages: map[string]*pb.ImportsPerLanguage{}}
-		message.Imports[key] = dev
-		for lang, counts := range vals {
-			counts64 := map[string]int64{}
-			dev.Languages[lang] = &pb.ImportsPerLanguage{Counts: counts64}
-			for imp, n := range counts {
-				counts64[imp] = int64(n)
+	for key, dev := range result.Imports {
+		pbdev := &pb.ImportsPerDeveloper{Languages: map[string]*pb.ImportsPerLanguage{}}
+		message.Imports[key] = pbdev
+		for lang, ticks := range dev {
+			pbticks := map[string]*pb.ImportsPerTick{}
+			pbdev.Languages[lang] = &pb.ImportsPerLanguage{Ticks: pbticks}
+			for imp, tick := range ticks {
+				counts := map[int32]int64{}
+				pbticks[imp] = &pb.ImportsPerTick{Counts: counts}
+				for ti, val := range tick {
+					counts[int32(ti)] = val
+				}
 			}
 		}
 	}
@@ -183,6 +217,36 @@ func (ipd *ImportsPerDeveloper) serializeBinary(result *ImportsPerDeveloperResul
 	return err
 }
 
+// Deserialize converts the specified protobuf bytes to ImportsPerDeveloperResult.
+func (ipd *ImportsPerDeveloper) Deserialize(pbmessage []byte) (interface{}, error) {
+	msg := pb.ImportsPerDeveloperResults{}
+	err := proto.Unmarshal(pbmessage, &msg)
+	if err != nil {
+		return nil, err
+	}
+	r := ImportsPerDeveloperResult{
+		Imports:            ImportsMap{},
+		reversedPeopleDict: msg.AuthorIndex,
+		tickSize:           time.Duration(msg.TickSize),
+	}
+	for devi, dev := range msg.Imports {
+		rdev := map[string]map[string]map[int]int64{}
+		r.Imports[devi] = rdev
+		for lang, names := range dev.Languages {
+			rlang := map[string]map[int]int64{}
+			rdev[lang] = rlang
+			for name, ticks := range names.Ticks {
+				rticks := map[int]int64{}
+				rlang[name] = rticks
+				for tick, val := range ticks.Counts {
+					rticks[int(tick)] = val
+				}
+			}
+		}
+	}
+	return r, nil
+}
+
 func init() {
 	core.Registry.Register(&ImportsPerDeveloper{})
 }

+ 41 - 33
leaves/imports_printer_test.go

@@ -2,15 +2,14 @@ package leaves
 
 import (
 	"bytes"
-	"fmt"
 	"testing"
+	"time"
 
-	"github.com/gogo/protobuf/proto"
 	imports2 "github.com/src-d/imports"
 	"github.com/stretchr/testify/assert"
 	gitplumbing "gopkg.in/src-d/go-git.v4/plumbing"
 	"gopkg.in/src-d/hercules.v10/internal/core"
-	"gopkg.in/src-d/hercules.v10/internal/pb"
+	"gopkg.in/src-d/hercules.v10/internal/plumbing"
 	"gopkg.in/src-d/hercules.v10/internal/plumbing/identity"
 	"gopkg.in/src-d/hercules.v10/internal/plumbing/imports"
 	"gopkg.in/src-d/hercules.v10/internal/test"
@@ -26,21 +25,25 @@ func fixtureImportsPerDev() *ImportsPerDeveloper {
 
 func TestImportsPerDeveloperMeta(t *testing.T) {
 	ipd := fixtureImportsPerDev()
-	assert.Equal(t, ipd.Name(), "ImportsPerDeveloper")
-	assert.Equal(t, len(ipd.Provides()), 0)
-	assert.Equal(t, len(ipd.Requires()), 2)
-	assert.Equal(t, ipd.Requires()[0], imports.DependencyImports)
-	assert.Equal(t, ipd.Requires()[1], identity.DependencyAuthor)
-	assert.Equal(t, ipd.Flag(), "imports-per-dev")
+	ass := assert.New(t)
+	ass.Equal(ipd.Name(), "ImportsPerDeveloper")
+	ass.Equal(len(ipd.Provides()), 0)
+	ass.Equal(len(ipd.Requires()), 3)
+	ass.Equal(ipd.Requires()[0], imports.DependencyImports)
+	ass.Equal(ipd.Requires()[1], identity.DependencyAuthor)
+	ass.Equal(ipd.Requires()[2], plumbing.DependencyTick)
+	ass.Equal(ipd.Flag(), "imports-per-dev")
 	assert.Len(t, ipd.ListConfigurationOptions(), 0)
 	assert.True(t, len(ipd.Description()) > 0)
 	logger := core.NewLogger()
 	assert.NoError(t, ipd.Configure(map[string]interface{}{
 		core.ConfigLogger: logger,
 		identity.FactIdentityDetectorReversedPeopleDict: []string{"1", "2"},
+		plumbing.FactTickSize:                           time.Hour,
 	}))
-	assert.Equal(t, logger, ipd.l)
-	assert.Equal(t, []string{"1", "2"}, ipd.reversedPeopleDict)
+	ass.Equal(logger, ipd.l)
+	ass.Equal([]string{"1", "2"}, ipd.reversedPeopleDict)
+	ass.Equal(time.Hour, ipd.TickSize)
 }
 
 func TestImportsPerDeveloperRegistration(t *testing.T) {
@@ -61,12 +64,14 @@ func TestImportsPerDeveloperRegistration(t *testing.T) {
 func TestImportsPerDeveloperInitialize(t *testing.T) {
 	ipd := fixtureImportsPerDev()
 	assert.NotNil(t, ipd.imports)
+	assert.Equal(t, time.Hour*24, ipd.TickSize)
 }
 
 func TestImportsPerDeveloperConsumeFinalize(t *testing.T) {
 	deps := map[string]interface{}{}
 	deps[core.DependencyIsMerge] = false
 	deps[identity.DependencyAuthor] = 0
+	deps[plumbing.DependencyTick] = 1
 	imps := map[gitplumbing.Hash]imports2.File{}
 	imps[gitplumbing.NewHash("291286b4ac41952cbd1389fda66420ec03c1a9fe")] =
 		imports2.File{Lang: "Go", Path: "test.go", Imports: []string{"sys"}}
@@ -77,27 +82,27 @@ func TestImportsPerDeveloperConsumeFinalize(t *testing.T) {
 	ipd.reversedPeopleDict = []string{"1", "2"}
 	_, err := ipd.Consume(deps)
 	assert.NoError(t, err)
-	assert.Equal(t, map[int]map[string]map[string]int{
-		0: {"Go": {"sys": 1}, "Python": {"sys": 1}},
+	assert.Equal(t, ImportsMap{
+		0: {"Go": {"sys": {1: 1}}, "Python": {"sys": {1: 1}}},
 	}, ipd.imports)
 	_, err = ipd.Consume(deps)
 	assert.NoError(t, err)
-	assert.Equal(t, map[int]map[string]map[string]int{
-		0: {"Go": {"sys": 2}, "Python": {"sys": 2}},
+	assert.Equal(t, ImportsMap{
+		0: {"Go": {"sys": {1: 2}}, "Python": {"sys": {1: 2}}},
 	}, ipd.imports)
 	deps[identity.DependencyAuthor] = 1
 	_, err = ipd.Consume(deps)
 	assert.NoError(t, err)
-	assert.Equal(t, map[int]map[string]map[string]int{
-		0: {"Go": {"sys": 2}, "Python": {"sys": 2}},
-		1: {"Go": {"sys": 1}, "Python": {"sys": 1}},
+	assert.Equal(t, ImportsMap{
+		0: {"Go": {"sys": {1: 2}}, "Python": {"sys": {1: 2}}},
+		1: {"Go": {"sys": {1: 1}}, "Python": {"sys": {1: 1}}},
 	}, ipd.imports)
 	deps[core.DependencyIsMerge] = true
 	_, err = ipd.Consume(deps)
 	assert.NoError(t, err)
-	assert.Equal(t, map[int]map[string]map[string]int{
-		0: {"Go": {"sys": 2}, "Python": {"sys": 2}},
-		1: {"Go": {"sys": 1}, "Python": {"sys": 1}},
+	assert.Equal(t, ImportsMap{
+		0: {"Go": {"sys": {1: 2}}, "Python": {"sys": {1: 2}}},
+		1: {"Go": {"sys": {1: 1}}, "Python": {"sys": {1: 1}}},
 	}, ipd.imports)
 	result := ipd.Finalize().(ImportsPerDeveloperResult)
 	assert.Equal(t, ipd.reversedPeopleDict, result.reversedPeopleDict)
@@ -106,26 +111,29 @@ func TestImportsPerDeveloperConsumeFinalize(t *testing.T) {
 
 func TestImportsPerDeveloperSerializeText(t *testing.T) {
 	ipd := fixtureImportsPerDev()
-	res := ImportsPerDeveloperResult{Imports: map[int]map[string]map[string]int{
-		0: {"Go": {"sys": 2}, "Python": {"sys": 2}},
-		1: {"Go": {"sys": 1}, "Python": {"sys": 1}},
+	res := ImportsPerDeveloperResult{Imports: ImportsMap{
+		0: {"Go": {"sys": {1: 2}}, "Python": {"sys": {1: 2}}},
+		1: {"Go": {"sys": {1: 1}}, "Python": {"sys": {1: 1}}},
 	}, reversedPeopleDict: []string{"one", "two"}}
 	buffer := &bytes.Buffer{}
 	assert.NoError(t, ipd.Serialize(res, false, buffer))
-	assert.Equal(t, `  - "one": {"Go":{"sys":2},"Python":{"sys":2}}
-  - "two": {"Go":{"sys":1},"Python":{"sys":1}}
+	assert.Equal(t, `  tick_size: 0
+  imports:
+    "one": {"Go":{"sys":{"1":2}},"Python":{"sys":{"1":2}}}
+    "two": {"Go":{"sys":{"1":1}},"Python":{"sys":{"1":1}}}
 `, buffer.String())
 }
 
 func TestImportsPerDeveloperSerializeBinary(t *testing.T) {
 	ipd := fixtureImportsPerDev()
-	res := ImportsPerDeveloperResult{Imports: map[int]map[string]map[string]int{
-		0: {"Go": {"sys": 2}, "Python": {"sys": 2}},
-		1: {"Go": {"sys": 1}, "Python": {"sys": 1}},
+	ass := assert.New(t)
+	res := ImportsPerDeveloperResult{Imports: ImportsMap{
+		0: {"Go": {"sys": {1: 2}}, "Python": {"sys": {1: 2}}},
+		1: {"Go": {"sys": {1: 1}}, "Python": {"sys": {1: 1}}},
 	}, reversedPeopleDict: []string{"one", "two"}}
 	buffer := &bytes.Buffer{}
-	assert.NoError(t, ipd.Serialize(res, true, buffer))
-	msg := pb.ImportsPerDeveloperResults{}
-	assert.Nil(t, proto.Unmarshal(buffer.Bytes(), &msg))
-	assert.Equal(t, `{[languages:<key:"Go" value:<counts:<key:"sys" value:2 > > > languages:<key:"Python" value:<counts:<key:"sys" value:2 > > >  languages:<key:"Go" value:<counts:<key:"sys" value:1 > > > languages:<key:"Python" value:<counts:<key:"sys" value:1 > > > ] [one two] {} [] 0}`, fmt.Sprint(msg))
+	ass.NoError(ipd.Serialize(res, true, buffer))
+	back, err := ipd.Deserialize(buffer.Bytes())
+	ass.NoError(err)
+	ass.Equal(res, back)
 }

File diff suppressed because it is too large
+ 125 - 30
python/labours/pb_pb2.py


+ 1 - 1
python/setup.py

@@ -22,7 +22,7 @@ setup(
     description="Python companion for github.com/src-d/hercules to visualize the results.",
     long_description=long_description,
     long_description_content_type="text/markdown",
-    version="10.6.2",
+    version="10.7.0",
     license="Apache-2.0",
     author="source{d}",
     author_email="machine-learning@sourced.tech",