Skip to content

Commit de499c5

Browse files
Baseline for Customer Segmentation (Clustering Sample)
1 parent ba3009f commit de499c5

28 files changed

Lines changed: 4347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.1</TargetFramework>
6+
<LangVersion>7.2</LangVersion>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<Compile Include="..\CustomerSegmentation.Train\ModelBuilder\ConsoleHelpers.cs" Link="ModelScorer\ConsoleHelpers.cs" />
11+
<Compile Include="..\CustomerSegmentation.Train\ModelBuilder\ModelHelpers.cs" Link="ModelScorer\ModelHelpers.cs" />
12+
<Compile Include="..\CustomerSegmentation.Train\RetailData\ClusteringPrediction.cs" Link="RetailData\ClusteringPrediction.cs" />
13+
<Compile Include="..\CustomerSegmentation.Train\RetailData\DataHelpers.cs" Link="RetailData\DataHelpers.cs" />
14+
<Compile Include="..\CustomerSegmentation.Train\RetailData\Offer.cs" Link="RetailData\Offer.cs" />
15+
<Compile Include="..\CustomerSegmentation.Train\RetailData\PivotData.cs" Link="RetailData\PivotData.cs" />
16+
<Compile Include="..\CustomerSegmentation.Train\RetailData\Transaction.cs" Link="RetailData\Transaction.cs" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<PackageReference Include="Microsoft.ML" Version="$(MicrosoftMLVersion)" />
21+
<PackageReference Include="OxyPlot.Core" Version="1.0.0" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<Folder Include="RetailData\" />
26+
</ItemGroup>
27+
28+
</Project>
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using CustomerSegmentation.RetailData;
2+
using Microsoft.ML.Core.Data;
3+
using Microsoft.ML.Runtime.Api;
4+
using Microsoft.ML.Runtime.Data;
5+
using OxyPlot;
6+
using OxyPlot.Series;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Diagnostics;
10+
using System.IO;
11+
using System.Linq;
12+
using static CustomerSegmentation.Model.ConsoleHelpers;
13+
14+
namespace CustomerSegmentation.Model
15+
{
16+
public class ModelEvaluator
17+
{
18+
private readonly string pivotDataLocation;
19+
private readonly string modelLocation;
20+
private readonly string plotLocation;
21+
private readonly LocalEnvironment env;
22+
23+
public ModelEvaluator(string pivotDataLocation, string modelLocation, string plotLocation)
24+
{
25+
this.pivotDataLocation = pivotDataLocation;
26+
this.modelLocation = modelLocation;
27+
this.plotLocation = plotLocation;
28+
env = new LocalEnvironment(seed: 1); //Seed set to any number so you have a deterministic environment
29+
}
30+
31+
public void Evaluate()
32+
{
33+
ITransformer model;
34+
using (var file = File.OpenRead(modelLocation))
35+
{
36+
model = TransformerChain
37+
.LoadFrom(env, file);
38+
}
39+
40+
var reader = new TextLoader(env,
41+
new TextLoader.Arguments
42+
{
43+
Column = new[] {
44+
new TextLoader.Column("Features", DataKind.R4, new[] {new TextLoader.Range(0, 31) }),
45+
new TextLoader.Column("LastName", DataKind.Text, 32)
46+
},
47+
HasHeader = true,
48+
Separator = ","
49+
});
50+
51+
ConsoleWriteHeader("Read model");
52+
Console.WriteLine($"Model location: {modelLocation}");
53+
var data = reader.Read(new MultiFileSource(pivotDataLocation));
54+
55+
var predictions = model.Transform(data)
56+
.AsEnumerable<ClusteringPrediction>(env, false)
57+
.ToArray();
58+
59+
SaveCustomerSegmentationPlot(predictions, plotLocation);
60+
61+
OpenChartInDefaultWindow(plotLocation);
62+
63+
64+
}
65+
66+
private static void SaveCustomerSegmentationPlot(IEnumerable<ClusteringPrediction> predictions, string plotLocation)
67+
{
68+
ConsoleWriteHeader("Plot Customer Segmentation");
69+
70+
var plot = new PlotModel { Title = "Customer Segmentation", IsLegendVisible = true };
71+
72+
var clusters = predictions.Select(p => p.SelectedClusterId).Distinct().OrderBy(x => x);
73+
74+
foreach (var cluster in clusters)
75+
{
76+
var scatter = new ScatterSeries { MarkerType = MarkerType.Circle, MarkerStrokeThickness = 2, Title = $"Cluster: {cluster}", RenderInLegend=true };
77+
var series = predictions
78+
.Where(p => p.SelectedClusterId == cluster)
79+
.Select(p => new ScatterPoint(p.Location[0], p.Location[1])).ToArray();
80+
scatter.Points.AddRange(series);
81+
plot.Series.Add(scatter);
82+
}
83+
84+
plot.DefaultColors = OxyPalettes.HueDistinct(plot.Series.Count).Colors;
85+
86+
var exporter = new SvgExporter { Width = 600, Height = 400 };
87+
using (var fs = new System.IO.FileStream(plotLocation, System.IO.FileMode.Create))
88+
{
89+
exporter.Export(plot, fs);
90+
}
91+
92+
Console.WriteLine($"Plot location: {plotLocation}");
93+
}
94+
95+
private static void OpenChartInDefaultWindow(string plotLocation)
96+
{
97+
Console.WriteLine("Showing chart...");
98+
var p = new Process();
99+
p.StartInfo = new ProcessStartInfo(plotLocation)
100+
{
101+
UseShellExecute = true
102+
};
103+
p.Start();
104+
}
105+
}
106+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using CustomerSegmentation.Model;
3+
using System.IO;
4+
using System.Threading.Tasks;
5+
using static CustomerSegmentation.Model.ConsoleHelpers;
6+
7+
namespace CustomerSegmentation
8+
{
9+
public class Program
10+
{
11+
static async Task Main(string[] args)
12+
{
13+
var assetsPath = ModelHelpers.GetAssetsPath(@"..\..\..\assets");
14+
15+
var pivotCsv = Path.Combine(assetsPath, "inputs", "pivot.csv");
16+
var modelZip = Path.Combine(assetsPath, "inputs", "retailClustering.zip");
17+
var plotSvg = Path.Combine(assetsPath, "outputs", "customerSegmentation.svg");
18+
19+
try
20+
{
21+
var modelEvaluator = new ModelEvaluator(pivotCsv, modelZip, plotSvg);
22+
modelEvaluator.Evaluate();
23+
} catch (Exception ex)
24+
{
25+
ConsoleWriteException(ex.Message);
26+
}
27+
28+
ConsolePressAnyKey();
29+
}
30+
}
31+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15,C16,C17,C18,C19,C20,C21,C22,C23,C24,C25,C26,C27,C28,C29,C30,C31,C32,LastName
2+
1,0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,Thomas
3+
1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,Jackson
4+
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Mitchell
5+
1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,Peterson
6+
1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,Wood
7+
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,Price
8+
1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,Foster
9+
1,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,Sanders
10+
1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,Butler
11+
1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,1,1,0,Fisher
12+
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,Smith
13+
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,Rodriguez
14+
0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,Martin
15+
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Campbell
16+
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Bell
17+
0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Cox
18+
0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,Lee
19+
0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,Nelson
20+
0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,Rogers
21+
0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,Richardson
22+
0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,Brooks
23+
0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Long
24+
0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,Harris
25+
0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,Clark
26+
0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,Sanchez
27+
0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,Wright
28+
0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,Turner
29+
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,Cooper
30+
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Ward
31+
0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Reed
32+
0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Powell
33+
0,0,0,0,0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,Miller
34+
0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,Young
35+
0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,Scott
36+
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,Kelly
37+
0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,Morales
38+
0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Gutierrez
39+
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Brown
40+
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Taylor
41+
0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,Lewis
42+
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,Robinson
43+
0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,King
44+
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Green
45+
0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,Baker
46+
0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Carter
47+
0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Murphy
48+
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Rivera
49+
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,Bailey
50+
0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Diaz
51+
0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,Watson
52+
0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,James
53+
0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Hughes
54+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Jones
55+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,Wilson
56+
0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,Hill
57+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Torres
58+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,Edwards
59+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Stewart
60+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,Morgan
61+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,Bennett
62+
0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Sullivan
63+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Ortiz
64+
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Perry
65+
0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,Thompson
66+
0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,Lopez
67+
0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,Gonzalez
68+
0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,Allen
69+
0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Ramirez
70+
0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,Reyes
71+
0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,Barnes
72+
0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,Hall
73+
0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,Parker
74+
0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,Collins
75+
0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,Gomez
76+
0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,Howard
77+
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,Davis
78+
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,Martinez
79+
0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,Gray
80+
0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,Garcia
81+
0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,White
82+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Johnson
83+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,Moore
84+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,Phillips
85+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,Flores
86+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Morris
87+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,Williams
88+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,Walker
89+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,Perez
90+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Adams
91+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,Myers
92+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,Ross
93+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,Nguyen
94+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,Evans
95+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Anderson
96+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Cook
97+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,Jenkins
98+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,Russell
99+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,Hernandez
100+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,Cruz
101+
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,Roberts

0 commit comments

Comments
 (0)