From d77d471ae773dde6b2bc705f932beabdac303478 Mon Sep 17 00:00:00 2001 From: wangruimin <1575248743@qq.com> Date: Mon, 11 Jul 2022 11:08:21 +0800 Subject: [PATCH] add TelcoGeneratorCore project --- DataGenerators/DataGeneratorsCore.sln | 31 ++ DataGenerators/TelcoGeneratorCore/App.config | 8 + .../TelcoGeneratorCore/CDRrecord.cs | 265 ++++++++++++++ .../TelcoGeneratorCore/CallStore.cs | 39 +++ .../TelcoGeneratorCore/GenConfig.cs | 50 +++ DataGenerators/TelcoGeneratorCore/Program.cs | 322 ++++++++++++++++++ .../TelcoGeneratorCore.csproj | 15 + 7 files changed, 730 insertions(+) create mode 100644 DataGenerators/DataGeneratorsCore.sln create mode 100644 DataGenerators/TelcoGeneratorCore/App.config create mode 100644 DataGenerators/TelcoGeneratorCore/CDRrecord.cs create mode 100644 DataGenerators/TelcoGeneratorCore/CallStore.cs create mode 100644 DataGenerators/TelcoGeneratorCore/GenConfig.cs create mode 100644 DataGenerators/TelcoGeneratorCore/Program.cs create mode 100644 DataGenerators/TelcoGeneratorCore/TelcoGeneratorCore.csproj diff --git a/DataGenerators/DataGeneratorsCore.sln b/DataGenerators/DataGeneratorsCore.sln new file mode 100644 index 0000000..8e3f127 --- /dev/null +++ b/DataGenerators/DataGeneratorsCore.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32602.290 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelcoGeneratorCore", "TelcoGeneratorCore\TelcoGeneratorCore.csproj", "{57B6140A-E68A-4BEB-93CD-E4184EA46F9D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwitterClientCore", "TwitterClientCore\TwitterClientCore.csproj", "{4B42D4AE-A957-4BC5-B8D0-381F772CFBAB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {57B6140A-E68A-4BEB-93CD-E4184EA46F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {57B6140A-E68A-4BEB-93CD-E4184EA46F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {57B6140A-E68A-4BEB-93CD-E4184EA46F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {57B6140A-E68A-4BEB-93CD-E4184EA46F9D}.Release|Any CPU.Build.0 = Release|Any CPU + {4B42D4AE-A957-4BC5-B8D0-381F772CFBAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B42D4AE-A957-4BC5-B8D0-381F772CFBAB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B42D4AE-A957-4BC5-B8D0-381F772CFBAB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B42D4AE-A957-4BC5-B8D0-381F772CFBAB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5CFD7572-EC31-45E4-91E1-316F3472DB63} + EndGlobalSection +EndGlobal diff --git a/DataGenerators/TelcoGeneratorCore/App.config b/DataGenerators/TelcoGeneratorCore/App.config new file mode 100644 index 0000000..8c97874 --- /dev/null +++ b/DataGenerators/TelcoGeneratorCore/App.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/DataGenerators/TelcoGeneratorCore/CDRrecord.cs b/DataGenerators/TelcoGeneratorCore/CDRrecord.cs new file mode 100644 index 0000000..4756995 --- /dev/null +++ b/DataGenerators/TelcoGeneratorCore/CDRrecord.cs @@ -0,0 +1,265 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the Microsoft Public License. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +using System; +using System.Collections; +using System.Runtime.Serialization; +using System.Text; + +namespace telcodatagen +{ + + [DataContract] + public class CDRrecord + { + [DataMember] + public String RecordType { get; set; } + + [DataMember] + public String SystemIdentity { get; set; } + + [DataMember] + public String FileNum { get; set; } + + [DataMember] + public String SwitchNum { get; set; } + + + [DataMember] + public String CallingNum { get; set; } + + [DataMember] + public String CallingIMSI { get; set; } + + [DataMember] + public String CalledNum { get; set; } + + [DataMember] + public String CalledIMSI { get; set; } + + [DataMember] + public String DateS { get; set; } + + + [DataMember] + public String TimeS { get; set; } + + + [DataMember] + public int TimeType { get; set; } + + [DataMember] + public int CallPeriod { get; set; } + + [DataMember] + public String CallingCellID { get; set; } + + [DataMember] + public String CalledCellID { get; set; } + + [DataMember] + public String ServiceType { get; set; } + + [DataMember] + public int Transfer { get; set; } + + [DataMember] + public String IncomingTrunk { get; set; } + + [DataMember] + public String OutgoingTrunk { get; set; } + + [DataMember] + public String MSRN { get; set; } + + [DataMember] + public String CalledNum2 { get; set; } + + [DataMember] + public String FCIFlag { get; set; } + + [DataMember] + public DateTime callrecTime { get; set; } + + + + + static string[] columns = {"RecordType","SystemIdentity","FileNum","SwitchNum","CallingNum","CallingIMSI", + "CalledNum","CalledIMSI","Date","Time","TimeType","CallPeriod","CallingCellID","CalledCellID", + "ServiceType","Transfer","IMEI","EndType","IncomingTrunk","OutgoingTrunk","MSRN","CalledNum2","FCIFlag","DateTime"}; + + static string[] ServiceTypeList = { "a", "b", "S", "V" }; + static string[] TimeTypeList = { "a", "d", "r", "s" }; + static string[] EndTypeList = { "0", "3", "4" }; + static string[] OutgoingTrunkList = { "F", "442", "623", "418", "425", "443", "426", "621", "614", "609", "419", "402", "411", "422", "420", "423", "421", "300", "400", "405", "409", "424" }; + static string[] IMSIList = { "466923300507919", "466921602131264", "466923200348594", "466922002560205", "466922201102759", "466922702346260", "466920400352400", "466922202546859", "466923000886460", "466921302209862", "466923101048691", "466921200135361", "466922202613463", "466921402416657", "466921402237651", "466922202679249", "466923300236137", "466921602343040", "466920403025604", "262021390056324", "466920401237309", "466922000696024", "466923100098619", "466922702341485", "466922200432822", "466923000464324", "466923200779222", "466923100807296", "466923200408045" }; + static string[] MSRNList = { "886932428687", "886932429021", "886932428306", "1415982715962", "886932429979", "1416916990491", "886937415371", "886932428876", "886932428688", "1412983121877", "886932429242", "1416955584542", "886932428258", "1412930064972", "886932429155", "886932423548", "1415980332015", "14290800303585", "14290800033338", "886932429626", "886932428112", "1417955696232", "1418986850453", "886932428927", "886932429827", "886932429507", "1416960750071", "886932428242", "886932428134", "886932429825", "" }; + + static Random coin = new Random(); + Hashtable data; + + public CDRrecord() + { + data = new Hashtable(); + _init(); + } + + public void _init() + { + int idx = 0; + // Initialize default values + data.Add("SystemIdentity", "d0"); + data.Add("RecordType", "MO"); + this.SystemIdentity = "d0"; + this.RecordType = "MO"; + + + idx = coin.Next(0, TimeTypeList.Length); + data.Add("TimeType", idx); + this.TimeType = idx; + + idx = coin.Next(0, ServiceTypeList.Length); + data.Add("ServiceType", ServiceTypeList[idx]); + this.ServiceType = ServiceTypeList[idx]; + + idx = coin.Next(0, EndTypeList.Length); + data.Add("EndType", EndTypeList[idx]); + + + idx = coin.Next(0, OutgoingTrunkList.Length); + data.Add("OutgoingTrunk", OutgoingTrunkList[idx]); + this.OutgoingTrunk = OutgoingTrunkList[idx]; + + data.Add("Transfer", coin.Next(0, 2)); + this.Transfer = coin.Next(0, 2); + + idx = coin.Next(0, IMSIList.Length); + data.Add("CallingIMSI", IMSIList[idx]); + this.CallingIMSI = IMSIList[idx]; + + idx = coin.Next(0, IMSIList.Length); + data.Add("CalledIMSI", IMSIList[idx]); + this.CalledIMSI = IMSIList[idx]; + + idx = coin.Next(0, MSRNList.Length); + data.Add("MSRN", MSRNList[idx]); + this.MSRN = MSRNList[idx]; + } + + // set the data for the CDR record + public void setData(string key, string value) + { + if (data.ContainsKey(key)) + data[key] = value; + else + data.Add(key, value); + + switch (key) + { + case "RecordType": + this.RecordType = value; + break; + case "SystemIdentity": + this.SystemIdentity = value; + break; + case "FileNum": + this.FileNum = value; + break; + case "SwitchNum": + this.SwitchNum = value; + break; + case "CallingNum": + this.CallingNum = value; + break; + case "CallingIMSI": + this.CallingIMSI = value; + break; + case "CalledNum": + this.CalledNum = value; + break; + case "CalledIMSI": + this.CalledIMSI = value; + break; + case "Date": + this.DateS = value; + break; + case "Time": + break; + this.TimeS = value; + case "TimeType": + this.TimeType = Int32.Parse(value); + break; + case "CallPeriod": + this.CallPeriod = Int32.Parse(value); + break; + case "CallingCellID": + this.CallingCellID = value; + break; + case "CalledCellID": + this.CalledCellID = value; + break; + case "ServiceType": + this.ServiceType = value; + break; + case "Transfer": + this.Transfer = Int32.Parse(value); + break; + case "IncomingTrunk": + this.IncomingTrunk = value; + break; + case "OutgoingTrunk": + this.OutgoingTrunk = value; + break; + case "MSRN": + this.MSRN = value; + break; + case "CalledNum2": + this.CalledNum2 = value; + break; + case "FCIFlag": + this.FCIFlag = value; + break; + case "DateTime": + if (value.Length > 13) + { + int hour = Int32.Parse(value.Substring(9, 2)); + int min = Int32.Parse(value.Substring(11, 2)); + int secs = Int32.Parse(value.Substring(13, 2)); + + int year = Int32.Parse(value.Substring(0, 4)); + int month = Int32.Parse(value.Substring(4, 2)); + int day = Int32.Parse(value.Substring(6, 2)); + + this.callrecTime = new DateTime(year, month, day, hour, min, secs).ToUniversalTime(); + } + + break; + } + } + + override public String ToString() + { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < columns.Length; i++) + { + if (!data.ContainsKey(columns[i]) || data[columns[i]] == null) + sb.Append(""); + else + sb.Append(data[columns[i]]); + + if (i < columns.Length - 1) + sb.Append(","); + } + + return sb.ToString(); + } + } +} diff --git a/DataGenerators/TelcoGeneratorCore/CallStore.cs b/DataGenerators/TelcoGeneratorCore/CallStore.cs new file mode 100644 index 0000000..4fb49c4 --- /dev/null +++ b/DataGenerators/TelcoGeneratorCore/CallStore.cs @@ -0,0 +1,39 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the Microsoft Public License. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +using System; + +namespace telcodatagen +{ + class CallStore + { + public string[] CallNos; + public string[] switchCountries = { "US", "China", "UK", "Germany", "Australia" }; + static string[] NumPrefix = { "0123", "1234", "2345", "3456", "4567", "5678", "6789", "7890" }; + + public CallStore(int size) + { + Random coin = new Random(); + + // CallNoStore + CallNos = new String[size]; + + // Start generating the n numbers and putting it into the store + for (int i = 0; i < size; i++) + { + int prefixIdx = coin.Next(0, NumPrefix.Length); + string prefix = NumPrefix[prefixIdx]; + CallNos[i] = prefix + String.Format("{0:00000}", i); + } + + + } + } +} diff --git a/DataGenerators/TelcoGeneratorCore/GenConfig.cs b/DataGenerators/TelcoGeneratorCore/GenConfig.cs new file mode 100644 index 0000000..afd467c --- /dev/null +++ b/DataGenerators/TelcoGeneratorCore/GenConfig.cs @@ -0,0 +1,50 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the Microsoft Public License. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +using System; + +namespace telcodatagen +{ + + class GenConfig + { + public int nSets { get; set; } + public int nFilesPerDump { get; set; } + public int nCDRPerFile { get; set; } + public float nCallBackPercent { get; set; } + public int nDurationHours { get; set; } + + // Constructor + public GenConfig(int _set, int _files, int _cdr, float _callback, int hours) + { + nSets = _set; + nFilesPerDump = _files; + nCDRPerFile = _cdr; + nCallBackPercent = _callback; + nDurationHours = hours; + } + + + // Assume there is only 1 file, and 1 set + public GenConfig(int _cdr, float _callback, int hours) + { + nSets = 1; + nFilesPerDump = 1; + nCDRPerFile = _cdr; + nCallBackPercent = _callback; + nDurationHours = hours; + } + + override public String ToString() + { + return "#Sets: " + nSets + ",#FilesDump: " + nFilesPerDump + ",#CDRPerFile: " + nCDRPerFile + ",%CallBack: " + nCallBackPercent + ", #DurationHours: " + nDurationHours; + } + } +} diff --git a/DataGenerators/TelcoGeneratorCore/Program.cs b/DataGenerators/TelcoGeneratorCore/Program.cs new file mode 100644 index 0000000..1323991 --- /dev/null +++ b/DataGenerators/TelcoGeneratorCore/Program.cs @@ -0,0 +1,322 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the Microsoft Public License. +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Azure.Messaging.EventHubs; +using Azure.Messaging.EventHubs.Producer; +using Newtonsoft.Json; + +namespace telcodatagen +{ + class Program + { + static TextWriter writer = null; + + static void Main(string[] args) + { + // Show Usage information + if (args.Length < 3) + Usage(); + + // Init + _init(); + + // Setup Event Hub producer + var eventHubName = ConfigurationManager.AppSettings["EventHubName"]; + var connectionString = ConfigurationManager.AppSettings["EventHubConnectionString"]; + if (string.IsNullOrEmpty(connectionString) || string.IsNullOrEmpty(eventHubName)) + { + Console.WriteLine("Did not find Eventhub name or connections string in appsettings (App.config)"); + return; + } + + // Assumes you already have the Event Hub created. + var producer = new EventHubProducerClient( + connectionString, + eventHubName, + new EventHubProducerClientOptions() + { + } + ); + + // Generate the data + GenerateData(producer, args); + + Console.ReadKey(); + } + + static void _init() + { + + } + + // Generate data + static void GenerateData(EventHubProducerClient producer, string[] args) + { + Queue callBackQ = new Queue(); + + // Parse parameters + // Number of cdr records, probability of fraud, and number of hours + GenConfig config = new GenConfig(Int32.Parse(args[0]), float.Parse(args[1]), Int32.Parse(args[2])); + + // print statistics + Console.Error.WriteLine(config); + + // Start the generation + + // Generate the call nos + CallStore mobileNos = new CallStore(100000); + + int numCallbackPerFile = (int)(config.nCallBackPercent * config.nCDRPerFile); + + // Data generation always start with the current time + + double timeAdvancementPerSet = (0.0 + config.nDurationHours) / config.nSets; + + Console.Error.WriteLine("Time Increment Per Set: " + timeAdvancementPerSet); + + // Start generating per set + DateTime simulationTime = DateTime.Now; + Random r = new Random(); + + bool invalidRec = false; + bool genCallback = false; + + + // TOOD: Update this to number of hours + DateTimeOffset ptTime = DateTimeOffset.Now; + DateTimeOffset endTime = ptTime.AddHours(config.nDurationHours); + + while (endTime.Subtract(ptTime) >= TimeSpan.Zero) + { + DateTimeOffset currentTime = ptTime; + + Console.WriteLine(String.Format("{0:yyyyMMdd HHmmss}", simulationTime)); + + + + for (int cdr = 0; cdr < config.nCDRPerFile; cdr++) + { + currentTime = ptTime; + + // Determine whether to generate an invalid CDR record + double pvalue = r.NextDouble(); + if (pvalue < 0.1) + invalidRec = true; + else + invalidRec = false; + + // Determine whether there will be a callback + pvalue = r.NextDouble(); + if (pvalue >= config.nCallBackPercent) + genCallback = true; + else + genCallback = false; + + + // Determine called and calling num + int calledIdx = r.Next(0, mobileNos.CallNos.Length); + int callingIdx = r.Next(0, mobileNos.CallNos.Length); + + + CDRrecord rec = new CDRrecord(); + rec.setData("FileNum", "" + cdr); + + int switchIdx = r.Next(0, mobileNos.switchCountries.Length); + int switchAltIdx = r.Next(0, mobileNos.switchCountries.Length); + + // Find an alternate switch + while (switchAltIdx == switchIdx) + { + switchAltIdx = r.Next(0, mobileNos.switchCountries.Length); + } + + rec.setData("SwitchNum", mobileNos.switchCountries[switchIdx]); + + + if (invalidRec) + { + rec.setData("Date", "F"); + rec.setData("Time", "F"); + rec.setData("DateTime", "F F"); + } + else + { + String callDate = String.Format("{0:yyyyMMdd}", currentTime); + String callTime = String.Format("{0:HHmmss}", currentTime); + + rec.setData("Date", callDate); + rec.setData("Time", callTime); + rec.setData("DateTime", callDate + " " + callTime); + + String calledNum = mobileNos.CallNos[calledIdx]; + String callingNum = mobileNos.CallNos[callingIdx]; + + rec.setData("CalledNum", calledNum); + rec.setData("CallingNum", callingNum); + + + // Sim card fraud record + if (genCallback) + { + // For call back the A->B end has duration 0 + rec.setData("CallPeriod", "0"); + + // need to generate another set of no + calledIdx = callingIdx; + callingIdx = r.Next(0, mobileNos.CallNos.Length); + + CDRrecord callbackRec = new CDRrecord(); + callbackRec.setData("FileNum", "" + cdr); + callbackRec.setData("SwitchNum", mobileNos.switchCountries[switchAltIdx]); + + //callbackRec.setData("SwitchNum", "" + (f + 1)); + + // Pertub second + int pertubs = r.Next(0, 30); + + callDate = String.Format("{0:yyyyMMdd}", currentTime); + callTime = String.Format("{0:HHmmss}", currentTime.AddMinutes(pertubs)); + + callbackRec.setData("Date", callDate); + callbackRec.setData("Time", callTime); + callbackRec.setData("DateTime", callDate + " " + callTime); + + // Set it as the same calling IMSI + callbackRec.setData("CallingIMSI", rec.CallingIMSI); + + calledNum = mobileNos.CallNos[calledIdx]; + callingNum = mobileNos.CallNos[callingIdx]; + + callbackRec.setData("CalledNum", calledNum); + callbackRec.setData("CallingNum", callingNum); + + + // Determine duration of call + int callPeriod = r.Next(1, 1000); + callbackRec.setData("CallPeriod", "" + callPeriod); + + // Enqueue the call back rec + callBackQ.Enqueue(callbackRec); + cdr++; + } + else + { + int callPeriod = r.Next(1, 800); + rec.setData("CallPeriod", "" + callPeriod); + } + } + + // send cdr rec to output + //if (genCallback) Console.Write("callback A->B "); + outputCDRRecs(producer, rec); + + if (callBackQ.Count > 0 && (cdr % 7 == 0)) + { + CDRrecord drec; + drec = (CDRrecord)callBackQ.Dequeue(); + outputCDRRecs(producer, drec); + + //Console.Write("callback C->A!"); + //outputCDRRecs(s, f, drec); + } + + // Sleep for 1000ms + System.Threading.Thread.Sleep(100); + + // get the current time after generation + ptTime = DateTimeOffset.Now; + } // cdr + + + // Clear the remaining entries in the call back queue + if (callBackQ.Count > 0) + { + // need to empty queue + while (callBackQ.Count > 0) + { + CDRrecord dr = (CDRrecord)callBackQ.Dequeue(); + outputCDRRecs(producer, dr); + //outputCDRRecs(s, f, dr); + } + } + + // close the file + if (writer != null) + { + writer.Flush(); + writer.Close(); + writer = null; + } + + + // Advance Time + if (timeAdvancementPerSet < 1.0) + simulationTime = simulationTime.AddMinutes(timeAdvancementPerSet * 60); + else + simulationTime = simulationTime.AddHours(timeAdvancementPerSet); + + // Sleep for 1000ms + System.Threading.Thread.Sleep(1000); + + } // while - within duration + + + } + + + // Print usage information + static void Usage() + { + // In this case, we treat the #FilesPerDump as the number of switch, which is not 100% true + + Console.WriteLine("Usage: telcodatagen [#NumCDRsPerHour] [SIM Card Fraud Probability] [#DurationHours]"); + System.Environment.Exit(-1); + } + + + // Handle output of cdr recs + static void outputCDRRecs(EventHubProducerClient producerClient, CDRrecord r) + { + //Console.WriteLine("RecordType,SystemIdentity,FileNum,SwitchNum,CallingNum,CallingIMSI,CalledNum,CalledIMSI,Date,Time,TimeType,CallPeriod,CallingCellID,CalledCellID,ServiceType"); + //Console.WriteLine(r); + + try + { + List tasks = new List(); + var serializedString = JsonConvert.SerializeObject(r); + EventData data = new EventData(Encoding.UTF8.GetBytes(serializedString)); + SendEventOptions option = new SendEventOptions() + { + PartitionKey = r.CallingIMSI + }; + + // Send the metric to Event Hub + tasks.Add(producerClient.SendAsync(new List() { data }, option)); + + Console.WriteLine(r); + + Task.WaitAll(tasks.ToArray()); + } + catch (Exception e) + { + Console.WriteLine("Error on send: " + e.Message); + } + } + + } +} diff --git a/DataGenerators/TelcoGeneratorCore/TelcoGeneratorCore.csproj b/DataGenerators/TelcoGeneratorCore/TelcoGeneratorCore.csproj new file mode 100644 index 0000000..1dadc0a --- /dev/null +++ b/DataGenerators/TelcoGeneratorCore/TelcoGeneratorCore.csproj @@ -0,0 +1,15 @@ + + + + telcodatagen + Exe + netcoreapp3.1 + + + + + + + + +