diff --git a/Core/Core.csproj b/Core/Core.csproj
index b92abb41..4e96f1c7 100644
--- a/Core/Core.csproj
+++ b/Core/Core.csproj
@@ -24,15 +24,13 @@
-
+
-
-
diff --git a/Materials/chemistry.png b/Materials/chemistry.png
deleted file mode 100644
index b64d3e3d..00000000
Binary files a/Materials/chemistry.png and /dev/null differ
diff --git a/Materials/cmd.png b/Materials/cmd.png
deleted file mode 100644
index 1909b974..00000000
Binary files a/Materials/cmd.png and /dev/null differ
diff --git a/Materials/maths.png b/Materials/maths.png
deleted file mode 100644
index 39532ebf..00000000
Binary files a/Materials/maths.png and /dev/null differ
diff --git a/Materials/messages.png b/Materials/messages.png
deleted file mode 100644
index 44a8a74a..00000000
Binary files a/Materials/messages.png and /dev/null differ
diff --git a/Materials/web.png b/Materials/web.png
deleted file mode 100644
index 86ea5b01..00000000
Binary files a/Materials/web.png and /dev/null differ
diff --git a/Messages/Data/Code128.cs b/Messages/Data/Code128.cs
deleted file mode 100644
index ddf18da0..00000000
--- a/Messages/Data/Code128.cs
+++ /dev/null
@@ -1,188 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Trivial.Data;
-
-///
-/// The code-128, which is a high-density linear barcode symbology defined in ISO/IEC 15417:2007.
-/// It is used for alphanumeric or numeric-only barcodes.
-///
-public partial class Code128
-{
- ///
- /// The sub-types.
- ///
- public enum Subtypes : byte
- {
- ///
- /// Code A.
- ///
- A = 1,
-
- ///
- /// Code B.
- ///
- B = 2,
-
- ///
- /// Code C.
- ///
- C = 3
- }
-
- ///
- /// The output string format.
- ///
- public enum Formats : byte
- {
- ///
- /// Regular format.
- ///
- Regular = 0,
-
- ///
- /// Text only.
- ///
- Text = 1,
-
- ///
- /// Symbol values.
- ///
- Values = 2,
-
- ///
- /// Hex values.
- ///
- Hex = 3,
-
- ///
- /// The barcode areas that white represented as 0 and black represented as 1.
- ///
- Barcode = 4,
-
- ///
- /// The stroke path data used in SVG and XAML.
- ///
- Path = 5
- }
-
- ///
- /// All patterns.
- ///
- private readonly static List patterns = new() { "11011001100", "11001101100", "11001100110", "10010011000", "10010001100", "10001001100", "10011001000", "10011000100", "10001100100", "11001001000", "11001000100", "11000100100", "10110011100", "10011011100", "10011001110", "10111001100", "10011101100", "10011100110", "11001110010", "11001011100", "11001001110", "11011100100", "11001110100", "11101101110", "11101001100", "11100101100", "11100100110", "11101100100", "11100110100", "11100110010", "11011011000", "11011000110", "11000110110", "10100011000", "10001011000", "10001000110", "10110001000", "10001101000", "10001100010", "11010001000", "11000101000", "11000100010", "10110111000", "10110001110", "10001101110", "10111011000", "10111000110", "10001110110", "11101110110", "11010001110", "11000101110", "11011101000", "11011100010", "11011101110", "11101011000", "11101000110", "11100010110", "11101101000", "11101100010", "11100011010", "11101111010", "11001000010", "11110001010", "10100110000", "10100001100", "10010110000", "10010000110", "10000101100", "10000100110", "10110010000", "10110000100", "10011010000", "10011000010", "10000110100", "10000110010", "11000010010", "11001010000", "11110111010", "11000010100", "10001111010", "10100111100", "10010111100", "10010011110", "10111100100", "10011110100", "10011110010", "11110100100", "11110010100", "11110010010", "11011011110", "11011110110", "11110110110", "10101111000", "10100011110", "10001011110", "10111101000", "10111100010", "11110101000", "11110100010", "10111011110", "10111101110", "11101011110", "11110101110", "11010000100", "11010010000", "11010011100", "11000111010" };
-
- ///
- /// Gets the pattern of the specific symbol value.
- /// White represented as false, black represented as true.
- ///
- /// The symbol value.
- /// The areas in boolean collection.
- /// The value was greater than 106.
- public static List GetPattern(byte value)
- => GetPatternInternal(value).ToList();
-
- ///
- /// Gets the pattern of the specific symbol value.
- ///
- /// The symbol value.
- /// The barcode string.
- /// The value was greater than 106.
- public static string GetPatternString(byte value)
- => value < 107 ? patterns[value] : throw new ArgumentOutOfRangeException(nameof(value), "value should be less than 107.");
-
- ///
- /// Gets the pattern of the specific symbol value.
- ///
- /// The symbol value.
- /// The value of black represented.
- /// The value of white represented.
- /// The barcode string.
- /// The value was greater than 106.
- public static string ToBarcodeString(byte value, char black, char white)
- => ToBarcodeString(value, ele => ele ? black : white);
-
- ///
- /// Gets the pattern of the specific symbol value.
- ///
- /// The symbol value.
- /// The selector to convert boolean array to a string. Per boolean value, white represented as false, black represented as true.
- /// The barcode string.
- /// The value was greater than 106.
- public static string ToBarcodeString(byte value, Func selector)
- => string.Join(string.Empty, GetPatternInternal(value).Select(selector));
-
- ///
- /// Gets the pattern of the specific symbol value.
- ///
- /// The symbol value.
- /// The selector to convert boolean array to a string. Per boolean value, white represented as false, black represented as true.
- /// The barcode string.
- /// The value was greater than 106.
- public static string ToBarcodeString(byte value, Func selector)
- => string.Join(string.Empty, GetPatternInternal(value).Select(selector));
-
- ///
- /// Converts a symbol value to string.
- ///
- /// The sub-type.
- /// The symbol value.
- /// A string represented.
- ///
- public static string ToString(Subtypes subtype, byte value)
- {
- if (value > 101) return value switch
- {
- 102 => "[FNC1]",
- 103 => "[Start A]",
- 104 => "[Start B]",
- 105 => "[Start C]",
- 106 => "[Stop]",
- _ => string.Empty
- };
- if (subtype == Subtypes.C)
- return value < 100 ? value.ToString("g") : value switch
- {
- 100 => "[Code B]",
- 101 => "[Code A]",
- _ => string.Empty
- };
-
- var isA = subtype == Subtypes.A;
- if (!isA && subtype != Subtypes.B)
- throw new InvalidOperationException("subtype is not valid.");
- if (value < 64 || (!isA && value < 96))
- return new string((char)(value + 32), 1);
- if (value < 96)
- return new string((char)(value - 64), 1);
- return value switch
- {
- 96 => "[FNC3]",
- 97 => "[FNC2]",
- 98 => isA ? "[Shift B]" : "[Shift A]",
- 99 => "[Code C]",
- 100 => isA ? "[Code B]" : "[FNC4]",
- 101 => isA ? "[FNC4]" : "[Code A]",
- _ => string.Empty
- };
- }
-
- ///
- /// Gets the pattern of the specific symbol value.
- ///
- /// The symbol value.
- ///
- /// The value was greater than 106.
- private static IEnumerable GetPatternInternal(byte value)
- {
- if (value > 106) throw new ArgumentOutOfRangeException(nameof(value), "value should be less than 107.");
- var item = patterns[value];
- return item.Select(c => c switch
- {
- '0' => false,
- _ => true
- });
- }
-}
diff --git a/Messages/Data/Code128AI.cs b/Messages/Data/Code128AI.cs
deleted file mode 100644
index ea5792c0..00000000
--- a/Messages/Data/Code128AI.cs
+++ /dev/null
@@ -1,770 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Trivial.Data;
-
-///
-/// The code-128, which is a high-density linear barcode symbology defined in ISO/IEC 15417:2007.
-/// It is used for alphanumeric or numeric-only barcodes.
-///
-public partial class Code128
-{
-#pragma warning disable IDE0056
- ///
- /// Commonly used GS1-128 generator which identifies data with Application Identifiers.
- ///
- public static class Gs1Generator
- {
- /* https://www.gs1.org/standards/barcodes/application-identifiers */
-
- ///
- /// Creates serial shipping container code.
- ///
- /// The data without AI, length should be 18.
- /// The code 128 instance.
- public static Code128 Sscc(string data)
- => CreateGs1(0, data);
-
- ///
- /// Creates global trade item number.
- ///
- /// The data without AI, length should be 14.
- /// The code 128 instance.
- public static Code128 Gtin(string data)
- => CreateGs1(1, data);
-
- ///
- /// Creates global trade item number of contained trade items.
- ///
- /// The data without AI, length should be 14.
- /// The code 128 instance.
- public static Code128 GtinOfContainedTradeItems(string data)
- => CreateGs1(2, data);
-
- ///
- /// Creates batch number or lot number.
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 Batch(string data)
- => CreateGs1(10, data);
-
- ///
- /// Creates production date.
- ///
- /// The data without AI.
- /// The code 128 instance.
- public static Code128 Production(DateTime data)
- => CreateGs1Date(11, data);
-
- ///
- /// Creates due date.
- ///
- /// The data without AI.
- /// The code 128 instance.
- public static Code128 Due(DateTime data)
- => CreateGs1Date(12, data);
-
- ///
- /// Creates packaging date.
- ///
- /// The data without AI.
- /// The code 128 instance.
- public static Code128 Packaging(DateTime data)
- => CreateGs1Date(13, data);
-
- ///
- /// Creates best before date.
- ///
- /// The data without AI.
- /// The code 128 instance.
- public static Code128 BestBefore(DateTime data)
- => CreateGs1Date(15, data);
-
- ///
- /// Creates expiration date.
- ///
- /// The data without AI.
- /// The code 128 instance.
- public static Code128 Expiration(DateTime data)
- => CreateGs1Date(17, data);
-
- ///
- /// Creates internal product variant.
- ///
- /// The data without AI, should be less than 100.
- /// The code 128 instance.
- public static Code128 ProductVariant(byte data)
- => CreateGs1(20, data.ToString("g"));
-
- ///
- /// Creates serial number.
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 Sn(string data)
- => CreateGs1(21, data);
-
- ///
- /// Creates secondary data fields.
- ///
- /// The data without AI, length should be 29.
- /// The code 128 instance.
- public static Code128 SecondaryData(string data)
- => CreateGs1(22, data);
-
- ///
- /// Creates additional product identification.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 AdditionalProductIdentification(string data)
- => CreateGs1(240, data);
-
- ///
- /// Creates customer part number.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 CustomerPart(string data)
- => CreateGs1(241, data);
-
- ///
- /// Creates Made-to-Order Variation Number.
- ///
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- public static Code128 MadeToOrderVariation(int data)
- => CreateGs1(242, data.ToString("g"));
-
- ///
- /// Creates packaging component number.
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 PackagingComponent(string data)
- => CreateGs1(243, data);
-
- ///
- /// Creates secondary serial number.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 Sn2(string data)
- => CreateGs1(250, data);
-
- ///
- /// Creates reference to source entity.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 SourceEntity(string data)
- => CreateGs1(251, data);
-
- ///
- /// Creates global document type identifier.
- ///
- /// The data without AI, length is variable from 13 to 17.
- /// The code 128 instance.
- public static Code128 DocumentTypeId(string data)
- => CreateGs1(253, data);
-
- ///
- /// Creates GLN extension component.
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 GlnExtensionComponent(string data)
- => CreateGs1(254, data);
-
- ///
- /// Creates global coupon number.
- ///
- /// The data without AI, length is variable from 13 to 25.
- /// The code 128 instance.
- public static Code128 Gcn(string data)
- => CreateGs1(255, data);
-
- ///
- /// Creates count of items.
- ///
- /// The data without AI, should be less than 1_000_000_000.
- /// The code 128 instance.
- public static Code128 Count(int data)
- => CreateGs1(30, data.ToString("g"));
-
- ///
- /// Creates product net weight in kilo gram (kg).
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ProductWeight(byte y, int data)
- => CreateGs1Decimal(3100, y, data);
-
- ///
- /// Creates container gross weight in kilo gram (kg).
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ContainerWeight(byte y, int data)
- => CreateGs1Decimal(3300, y, data);
-
- ///
- /// Creates product length in meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ProductLength(byte y, int data)
- => CreateGs1Decimal(3110, y, data);
-
- ///
- /// Creates container length in meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ContainerLength(byte y, int data)
- => CreateGs1Decimal(3310, y, null, data);
-
- ///
- /// Creates product width/diamete in meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ProductWidth(byte y, int data)
- => CreateGs1Decimal(3120, y, data);
-
- ///
- /// Creates container width/diamete in meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ContainerWidth(byte y, int data)
- => CreateGs1Decimal(3320, y, data);
-
- ///
- /// Creates product depth/thickness/height in meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ProductDepth(byte y, int data)
- => CreateGs1Decimal(3130, y, data);
-
- ///
- /// Creates container depth/thickness/height in meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ContainerDepth(byte y, int data)
- => CreateGs1Decimal(3330, y, data);
-
- ///
- /// Creates product area in square meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ProductArea(byte y, int data)
- => CreateGs1Decimal(3140, y, data);
-
- ///
- /// Creates container area in square meters.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ContainerArea(byte y, int data)
- => CreateGs1Decimal(3340, y, data);
-
- ///
- /// Creates product net volume in liters.
- ///
- /// A number of decimal places in the following value.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ProductVolume(byte y, int data)
- => y > 9 ? CreateGs1Decimal(3160, (byte)(y - 10), data) : CreateGs1Decimal(3150, y, data);
-
- ///
- /// Creates container gross volume in liters.
- ///
- /// A number of decimal places in the following value.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 ContainerVolume(byte y, int data)
- => y > 9 ? CreateGs1Decimal(3360, (byte)(y - 10), data) : CreateGs1Decimal(3350, y, data);
-
- ///
- /// Creates count of units contained.
- ///
- /// The data without AI, should be less than 1,000,000,000.
- /// The code 128 instance.
- public static Code128 UnitCount(int data)
- => CreateGs1(37, data.ToString("g"));
-
- ///
- /// Creates applicable amount payable.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000,000,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 AmountPayable(byte y, long data)
- => CreateGs1Decimal(3900, y, null, data);
-
- ///
- /// Creates applicable amount payable with optional ISO currency code.
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The ISO currency code.
- /// The data without AI, should be less than 1,000,000,000,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 AmountPayable(byte y, string currencyCode, long data)
- => CreateGs1Decimal(string.IsNullOrEmpty(currencyCode) ? 3900 : 3910, y, currencyCode, data);
-
- ///
- /// Creates applicable amount payable (variable measure trade item).
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000,000,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 TradeItemAmountPayable(byte y, long data)
- => CreateGs1Decimal(3920, y, null, data);
-
- ///
- /// Creates applicable amount payable with optional ISO currency code (variable measure trade item).
- ///
- /// A number of decimal places in the following value, should be less than 10.
- /// The ISO currency code.
- /// The data without AI, should be less than 1,000,000,000,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- public static Code128 TradeItemAmountPayable(byte y, string currencyCode, long data)
- => CreateGs1Decimal(string.IsNullOrEmpty(currencyCode) ? 3920 : 3930, y, currencyCode, data);
-
- ///
- /// Creates customer purchase order number.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 Order(string data)
- => CreateGs1(400, data);
-
- ///
- /// Creates consignment number.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 Consignment(string data)
- => CreateGs1(401, data);
-
- ///
- /// Creates bill of lading number.
- ///
- /// The data without AI, length should be 17.
- /// The code 128 instance.
- public static Code128 LadingBill(string data)
- => CreateGs1(402, data);
-
- ///
- /// Creates routing code.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 Routing(string data)
- => CreateGs1(403, data);
-
- ///
- /// Creates ship/deliver to postal code (single postal authority).
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 ToSinglePostalAuthorityCode(string data)
- => CreateGs1(420, data);
-
- ///
- /// Creates ship/deliver to postal code (with ISO country code).
- ///
- /// The data without AI, length is variable from 3 to 15.
- /// The code 128 instance.
- public static Code128 ToPostalCode(string data)
- => CreateGs1(421, data);
-
- ///
- /// Creates ISO country code of origin.
- ///
- /// The data without AI, length should be 3.
- /// The code 128 instance.
- public static Code128 OriginCountry(string data)
- => CreateGs1(422, data);
-
- ///
- /// Creates one or more ISO country code of initial processing.
- ///
- /// The data without AI, length is variable from 3 to 15.
- /// The code 128 instance.
- public static Code128 InitialProcessingCountries(string data)
- => CreateGs1(423, data);
-
- ///
- /// Creates ISO country code of processing.
- ///
- /// The data without AI, length should be 3.
- /// The code 128 instance.
- public static Code128 ProcessingCountry(string data)
- => CreateGs1(424, data);
-
- ///
- /// Creates ISO country code of disassembly.
- ///
- /// The data without AI, length should be 3.
- /// The code 128 instance.
- public static Code128 DisassemblyCountry(string data)
- => CreateGs1(425, data);
-
- ///
- /// Creates ISO country code of full process chain.
- ///
- /// The data without AI, length should be 3.
- /// The code 128 instance.
- public static Code128 FullProcessChainCountry(string data)
- => CreateGs1(426, data);
-
- ///
- /// Creates service code description.
- ///
- /// The data without AI, length is up to 35.
- /// The code 128 instance.
- public static Code128 ServiceCodeDescription(string data)
- => CreateGs1(3420, data);
-
- ///
- /// Creates dangerous goods flag.
- ///
- /// true if the data without AI is yes (as 1); otherwise, false.
- /// The code 128 instance.
- public static Code128 Dangerous(bool data)
- => CreateGs1(3421, data ? "1" : "0");
-
- ///
- /// Creates authority to leave.
- ///
- /// true if the data without AI is yes (as 1); otherwise, false.
- /// The code 128 instance.
- public static Code128 AuthorityToLeave(bool data)
- => CreateGs1(3422, data ? "1" : "0");
-
- ///
- /// Creates signature required flag.
- ///
- /// true if the data without AI is yes (as 1); otherwise, false.
- /// The code 128 instance.
- public static Code128 SignatureRequired(bool data)
- => CreateGs1(3423, data ? "1" : "0");
-
- ///
- /// Creates release date.
- ///
- /// The data without AI, length should be 13.
- /// The code 128 instance.
- public static Code128 Release(DateTime data)
- => CreateGs1Date(3426, data);
-
- ///
- /// Creates NATO stock number.
- ///
- /// The data without AI, length should be 13.
- /// The code 128 instance.
- public static Code128 Nsn(string data)
- => CreateGs1(7001, data);
-
- ///
- /// Creates active potency.
- ///
- /// The data without AI, length is up to 4.
- /// The code 128 instance.
- public static Code128 ActivePotency(int data)
- => CreateGs1(7004, data.ToString("g"));
-
- ///
- /// Creates catch area.
- ///
- /// The data without AI, length is up to 12.
- /// The code 128 instance.
- public static Code128 CatchArea(string data)
- => CreateGs1(7005, data);
-
- ///
- /// Creates first freeze date.
- ///
- /// The data without AI, length should be 13.
- /// The code 128 instance.
- public static Code128 FirstFreeze(DateTime data)
- => CreateGs1Date(7006, data);
-
- ///
- /// Creates harvest date.
- ///
- /// The data without AI, length should be 13.
- /// The code 128 instance.
- public static Code128 Harvest(DateTime data)
- => CreateGs1Date(7007, data);
-
- ///
- /// Creates production method.
- ///
- /// The data without AI, length is up to 2.
- /// The code 128 instance.
- public static Code128 ProductionMethod(string data)
- => CreateGs1(7010, data);
-
- ///
- /// Creates certification reference.
- ///
- /// The certification number, should be 0-9.
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- /// y ws greater than 9.
- public static Code128 Certification(byte y, string data)
- => y < 10 ? CreateGs1(7230 + y, data) : throw new ArgumentOutOfRangeException(nameof(y), "y should be less than 10.");
-
- ///
- /// Creates protocol ID.
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 Protocol(string data)
- => CreateGs1(7240, data);
-
- ///
- /// Creates roll products: width/length/core diameter/direction/splices.
- ///
- /// The data without AI, length should be 14.
- /// The code 128 instance.
- public static Code128 RollProducts(string data)
- => CreateGs1(8001, data);
-
- ///
- /// Creates mobile phone identifier.
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 PhoneId(string data)
- => CreateGs1(8002, data);
-
- ///
- /// Creates global returnable asset identifier.
- ///
- /// The data without AI, length is variable from 14 to 30.
- /// The code 128 instance.
- public static Code128 GlobalReturnableAsset(string data)
- => CreateGs1(8003, data);
-
- ///
- /// Creates global individual asset identifier.
- ///
- /// The data without AI, length should be 30.
- /// The code 128 instance.
- public static Code128 GlobalIndividualAsset(string data)
- => CreateGs1(8004, data);
-
- ///
- /// Creates international bank account number.
- ///
- /// The data without AI, length should be 30.
- /// The code 128 instance.
- public static Code128 BankAccount(string data)
- => CreateGs1(8007, data);
-
- ///
- /// Creates software version.
- ///
- /// The data without AI, length is up to 20.
- /// The code 128 instance.
- public static Code128 SoftwareVersion(string data)
- => CreateGs1(8012, data);
-
- ///
- /// Creates global model number.
- ///
- /// The data without AI, length is up to 25.
- /// The code 128 instance.
- public static Code128 Gmn(string data)
- => CreateGs1(8013, data);
-
- ///
- /// Creates global service relationship number.
- ///
- /// true if identify the relationship between an organisation offering services and the recipient of services; otherwise, false, provider.
- /// The data without AI, length should be 18.
- /// The code 128 instance.
- public static Code128 GlobalServiceRelationship(bool recipient, string data)
- => CreateGs1(recipient ? 8018 : 8017, data);
-
- ///
- /// Creates service relation instance number.
- ///
- /// The data without AI, length is up to 10.
- /// The code 128 instance.
- public static Code128 Srin(string data)
- => CreateGs1(8019, data);
-
- ///
- /// Creates payment slip reference number.
- ///
- /// The data without AI, length is variable from 13 to 25.
- /// The code 128 instance.
- public static Code128 PaymentSlip(string data)
- => CreateGs1(8020, data);
-
- ///
- /// Creates extended packaging URL.
- ///
- /// The data without AI, length tp to 70.
- /// The code 128 instance.
- public static Code128 ExtendedPackagingURL(string data)
- => CreateGs1(8200, data);
-
- ///
- /// Creates mutually agreed between trading partners.
- ///
- /// The data without AI, length is up to 30.
- /// The code 128 instance.
- public static Code128 MutuallyAgreedBetweenTradingPartners(string data)
- => CreateGs1(90, data);
-
- ///
- /// Creates internal company codes (AI 91).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes1(string data)
- => CreateGs1(91, data);
-
- ///
- /// Creates internal company codes (AI 92).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes2(string data)
- => CreateGs1(92, data);
-
- ///
- /// Creates internal company codes (AI 93).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes3(string data)
- => CreateGs1(93, data);
-
- ///
- /// Creates internal company codes (AI 94).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes4(string data)
- => CreateGs1(94, data);
-
- ///
- /// Creates internal company codes (AI 95).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes5(string data)
- => CreateGs1(95, data);
-
- ///
- /// Creates internal company codes (AI 96).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes6(string data)
- => CreateGs1(96, data);
-
- ///
- /// Creates internal company codes (AI 97).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes7(string data)
- => CreateGs1(97, data);
-
- ///
- /// Creates internal company codes (AI 98).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes8(string data)
- => CreateGs1(98, data);
-
- ///
- /// Creates internal company codes (AI 99).
- ///
- /// The data without AI, length is up to 90.
- /// The code 128 instance.
- public static Code128 InternalCompanyCodes9(string data)
- => CreateGs1(99, data);
-
- ///
- /// Creates for decimal.
- ///
- /// The application identifier.
- /// A number of decimal places in the following value, should be less than 10.
- /// The data without AI, should be less than 1,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- private static Code128 CreateGs1Decimal(int ai, byte y, int data)
- {
- if (y > 9) throw new ArgumentOutOfRangeException(nameof(y), "y should be less than 10.");
- if (data < 0) throw new ArgumentOutOfRangeException(nameof(data), "data should be in 0-999,999 but it is negative currently.");
- if (data > 999_999) throw new ArgumentOutOfRangeException(nameof(data), "data should be in 0-999,999 but it is greater than 999,999 currently.");
- return CreateGs1(ai + y, data.ToString("000000"));
- }
-
- ///
- /// Creates for decimal.
- ///
- /// The application identifier.
- /// A number of decimal places in the following value, should be less than 10.
- /// The prefix of data.
- /// The data without AI, should be less than 1,000,000,000.
- /// The code 128 instance.
- /// y or data was out of range.
- private static Code128 CreateGs1Decimal(int ai, byte y, string prefix, long data)
- {
- if (y > 9) throw new ArgumentOutOfRangeException(nameof(y), "y should be less than 10.");
- if (data < 0) throw new ArgumentOutOfRangeException(nameof(data), "data should be in 0-999,999,999,999,999 but it is negative currently.");
- if (data > 999_999_999_999_999) throw new ArgumentOutOfRangeException(nameof(data), "data should be in 0-999,999,999,999,999, but it is greater than 999,999,999,999,999 currently.");
- return CreateGs1(ai + y, string.IsNullOrEmpty(prefix) ? data.ToString("g") : $"{prefix}{data:g}");
- }
- }
-#pragma warning restore IDE0056
-
- private static Code128 CreateGs1Date(int ai, DateTime date)
- => CreateGs1(ai, date.ToString("yyMMdd"));
-}
diff --git a/Messages/Data/Code128Builder.cs b/Messages/Data/Code128Builder.cs
deleted file mode 100644
index 32595c36..00000000
--- a/Messages/Data/Code128Builder.cs
+++ /dev/null
@@ -1,1063 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Trivial.Data;
-
-///
-/// The code-128, which is a high-density linear barcode symbology defined in ISO/IEC 15417:2007.
-/// It is used for alphanumeric or numeric-only barcodes.
-///
-public partial class Code128 : IReadOnlyList
-{
-#pragma warning disable IDE0056
- private readonly List v;
-
- ///
- /// Initializes a new instance of Code128 class.
- ///
- /// The byte array of symbol.
- private Code128(List values)
- {
- v = values ?? new List();
- }
-
- ///
- /// Gets the count of symbol.
- ///
- public int Count => v.Count;
-
- ///
- /// Gets the start sub-type.
- ///
- public Subtypes Subtype => v.Count > 3 ? v[0] switch
- {
- 103 => Subtypes.A,
- 104 => Subtypes.B,
- 105 => Subtypes.C,
- _ => (Subtypes)0
- } : 0;
-
- ///
- /// Gets the checksum; or 255, if not available.
- ///
- public byte Checksum => v.Count > 3 ? v[v.Count - 2] : (byte)255;
-
- ///
- /// Gets the value of the specific symbol.
- ///
- /// The index of symbol.
- /// The value of the symbol.
- /// The index was out of range.
- public byte this[int index] => v[index];
-
- ///
- /// Returns symbol values without start code, checksum, and stop code.
- ///
- /// A collection of symbol value without start code, checksum, and stop code.
- public IEnumerable TakeData()
- => v.Count > 3 ? v.Skip(1).Take(v.Count - 3) : new List();
-
- ///
- /// Converts to boolean list.
- /// White represented as false, black represented as true.
- ///
- /// The boolean list of barcode.
- public List ToBarcode()
- {
- var list = v.SelectMany(GetPattern).ToList();
- if (list.Count > 10)
- {
- list.Add(true);
- list.Add(true);
- }
-
- return list;
- }
-
- ///
- /// Gets all information of application identifier and its data value.
- ///
- /// A collection with application identifiers and their data value.
- public IEnumerable GetAiData()
- {
- if (v.Count < 4) yield break;
- var subtype = v[0] switch
- {
- 103 => Subtypes.A,
- 104 => Subtypes.B,
- 105 => Subtypes.C,
- _ => (Subtypes)0
- };
- if (subtype == 0) yield break;
- var sb = new StringBuilder();
- var subtype2 = subtype;
- var high = false;
- var rec = false;
- foreach (var b in v.Skip(1).Take(v.Count - 3))
- {
- if (b > 101)
- {
- if (b > 102) break;
- rec = true;
- if (sb.Length > 0)
- {
- yield return sb.ToString();
- sb.Clear();
- }
-
- continue;
- }
-
- var st = subtype;
- subtype = subtype2;
- if (st == Subtypes.C)
- {
- high = false;
- if (b < 100 || b == 102)
- {
- if (rec) sb.Append(b.ToString("00"));
- continue;
- }
-
- switch (b)
- {
- case 100:
- subtype = subtype2 = Subtypes.B;
- break;
- case 101:
- subtype = subtype2 = Subtypes.A;
- break;
- }
-
- continue;
- }
-
- var isA = st == Subtypes.A;
- if (!isA && st != Subtypes.B)
- {
- high = false;
- continue;
- }
-
- if (b < 96)
- {
- if (high)
- {
- high = false;
- var c = (char)(ToString(st, b).FirstOrDefault() + 128);
- if (rec) sb.Append(c);
- }
- else
- {
- if (rec) sb.Append(ToString(st, b));
- }
-
- continue;
- }
-
- switch (b)
- {
- case 96:
- rec = false;
- if (sb.Length > 0)
- {
- yield return sb.ToString();
- sb.Clear();
- }
-
- break;
- case 97:
- rec = false;
- if (sb.Length > 0)
- {
- yield return sb.ToString();
- sb.Clear();
- }
-
- break;
- case 98:
- subtype = isA ? Subtypes.B : Subtypes.A;
- continue;
- case 99:
- subtype = subtype2 = Subtypes.C;
- break;
- case 100:
- if (!isA)
- {
- high = !high;
- continue;
- }
-
- subtype = subtype2 = Subtypes.B;
- break;
- case 101:
- if (isA)
- {
- high = !high;
- continue;
- }
-
- subtype = subtype2 = Subtypes.A;
- break;
- }
-
- high = false;
- }
-
- if (sb.Length > 0) yield return sb.ToString();
- }
-
- ///
- /// Returns a string that represents the barcode in stroke path for SVG or XAML.
- ///
- /// The bar height.
- /// A stroke path string that represents the barcode.
- public string ToPathString(int height = 40)
- {
- var sb = new StringBuilder();
- var i = 9;
- sb.Append("M0,0 ");
- foreach (var b in v)
- {
- if (b > 106) continue;
- var binary = patterns[b];
- foreach (var c in binary)
- {
- i++;
- if (c == '1')
- sb.Append($"M{i},0 L{i},{height} ");
- }
- }
-
- sb.Append($"M{i + 1},{0} L{i + 1},{height} M{i + 2},{0} L{i + 2},{height} M{i + 12},0");
- return sb.ToString();
- }
-
- ///
- /// Returns a string that represents the current object.
- ///
- /// A string that represents the current object.
- public override string ToString()
- => ToString(Formats.Regular);
-
- ///
- /// Returns a string that represents the current object.
- ///
- /// The output string format.
- /// A string that represents the current object.
- public string ToString(Formats format)
- {
- if (v.Count < 4) return string.Empty;
- var subtype = v[0] switch
- {
- 103 => Subtypes.A,
- 104 => Subtypes.B,
- 105 => Subtypes.C,
- _ => (Subtypes)0
- };
- if (subtype == 0) return string.Empty;
- var sb = new StringBuilder();
- switch (format)
- {
- case Formats.Regular:
- case Formats.Text:
- break;
- case Formats.Hex:
- foreach (var b in v)
- {
- sb.Append(b.ToString("x2"));
- }
-
- return sb.ToString();
- case Formats.Values:
- foreach (var b in v.Take(v.Count - 2))
- {
- if (subtype == Subtypes.C && b < 100)
- {
- sb.Append(b);
- sb.Append(' ');
- continue;
- }
-
- switch (b)
- {
- case 96:
- sb.Append("[FNC3] ");
- break;
- case 97:
- sb.Append("[FNC2] ");
- break;
- case 98:
- sb.Append(subtype == Subtypes.A ? "[Shift B] " : "[Shift A] ");
- break;
- case 99:
- subtype = Subtypes.C;
- sb.Append("[Code C] ");
- break;
- case 100:
- if (subtype == Subtypes.B)
- {
- sb.Append("[FNC4] ");
- }
- else
- {
- subtype = Subtypes.B;
- sb.Append("[Code B] ");
- }
-
- break;
- case 101:
- if (subtype == Subtypes.A)
- {
- sb.Append("[FNC4] ");
- }
- else
- {
- subtype = Subtypes.A;
- sb.Append("[Code A] ");
- }
-
- break;
- case 102:
- sb.Append("[FNC1] ");
- break;
- case 103:
- sb.Append("[Start A] ");
- break;
- case 104:
- sb.Append("[Start B] ");
- break;
- case 105:
- sb.Append("[Start C] ");
- break;
- default:
- sb.Append(b);
- sb.Append(' ');
- break;
- }
- }
-
- sb.Append($"[Check symbol {v[v.Count - 2]:g}] [Stop]");
- return sb.ToString().Trim();
- case Formats.Barcode:
- return ToBarcodeString();
- case Formats.Path:
- return ToPathString(40);
- }
-
- var appendFunc = format == Formats.Regular;
- var subtype2 = subtype;
- var high = false;
- var high2 = false;
- foreach (var b in v.Skip(1).Take(v.Count - 3))
- {
- if (b > 101)
- {
- if (b > 102) break;
- if (appendFunc) sb.Append("[FNC1]");
- high = high2 = false;
- continue;
- }
-
- var st = subtype;
- subtype = subtype2;
- if (st == Subtypes.C)
- {
- high = high2 = false;
- if (b < 100 || b == 102)
- {
- sb.Append(b.ToString("00"));
- continue;
- }
-
- switch (b)
- {
- case 100:
- subtype = subtype2 = Subtypes.B;
- break;
- case 101:
- subtype = subtype2 = Subtypes.A;
- break;
- }
-
- continue;
- }
-
- var isA = st == Subtypes.A;
- if (!isA && st != Subtypes.B)
- {
- high = high2 = false;
- continue;
- }
-
- if (b < 96)
- {
- if (high)
- {
- high = high2;
- var c = (char)(ToString(st, b).FirstOrDefault() + 128);
- sb.Append(c);
- }
- else
- {
- high = high2;
- sb.Append(ToString(st, b));
- }
-
- continue;
- }
-
- switch (b)
- {
- case 96:
- if (appendFunc) sb.Append("[FNC3]");
- break;
- case 97:
- if (appendFunc) sb.Append("[FNC2]");
- break;
- case 98:
- subtype = isA ? Subtypes.B : Subtypes.A;
- continue;
- case 99:
- subtype = subtype2 = Subtypes.C;
- break;
- case 100:
- if (!isA)
- {
- if (high != high2) high2 = high;
- else high = !high;
- continue;
- }
-
- subtype = subtype2 = Subtypes.B;
- break;
- case 101:
- if (isA)
- {
- if (high != high2) high2 = high;
- else high = !high;
- continue;
- }
-
- subtype = subtype2 = Subtypes.A;
- break;
- }
-
- high = high2;
- }
-
- return sb.ToString();
- }
-
- ///
- /// Converts to a string.
- ///
- /// The barcode string.
- public string ToBarcodeString()
- {
- var sb = new StringBuilder();
- foreach (var b in v)
- {
- sb.Append(GetPattern(b));
- }
-
- if (sb.Length > 10) sb.Append("11");
- return sb.ToString();
- }
-
- ///
- /// Converts to a string.
- ///
- /// The value of black represented.
- /// The value of white represented.
- /// The barcode string.
- public string ToBarcodeString(char black, char white)
- => string.Join(string.Empty, ToBarcode().Select(ele => ele ? black : white));
-
- ///
- /// Converts to a string.
- ///
- /// The selector to convert boolean array to a string. Per boolean value, white represented as false, black represented as true.
- /// The barcode string.
- public string ToBarcodeString(Func selector)
- => selector != null ? string.Join(string.Empty, ToBarcode().Select(selector)) : ToBarcodeString();
-
- ///
- /// Converts to a string.
- ///
- /// The selector to convert boolean array to a string. Per boolean value, white represented as false, black represented as true.
- /// The barcode string.
- public string ToBarcodeString(Func selector)
- => selector != null ? string.Join(string.Empty, ToBarcode().Select(selector)) : ToBarcodeString();
-
- ///
- /// Gets all sub-types used in value.
- ///
- /// A collection of sub-type.
- public IEnumerable GetSubtypesUsed()
- {
- var subtype = Subtype;
- yield return subtype;
- foreach (var b in v.Skip(1).Take(v.Count - 3))
- {
- if (b < 98) continue;
- if (b > 102) break;
- switch (b)
- {
- case 99:
- if (subtype == Subtypes.C) break;
- subtype = Subtypes.C;
- yield return subtype;
- break;
- case 100:
- if (subtype == Subtypes.B) break;
- subtype = Subtypes.B;
- yield return subtype;
- break;
- case 101:
- if (subtype == Subtypes.A) break;
- subtype = Subtypes.A;
- yield return subtype;
- break;
- }
- }
- }
-
- ///
- /// Returns an enumerator that iterates through the symbol collection.
- ///
- /// A enumerator of the symbol collection.
- public IEnumerator GetEnumerator()
- => v.GetEnumerator();
-
- ///
- /// Returns an enumerator that iterates through the symbol collection.
- ///
- /// A enumerator of the symbol collection.
- IEnumerator IEnumerable.GetEnumerator()
- => ((IEnumerable)v).GetEnumerator();
-
- ///
- /// Creates with Start Code A.
- ///
- /// The value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateA(IEnumerable values)
- => Create(values, 103);
-
- ///
- /// Creates with Start Code A.
- ///
- /// The string value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateA(string s)
- => Create(Subtypes.A, s);
-
- ///
- /// Creates with Start Code B.
- ///
- /// The value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateB(IEnumerable values)
- => Create(values, 104);
-
- ///
- /// Creates with Start Code B.
- ///
- /// The string value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateB(string s)
- => Create(Subtypes.B, s);
-
- ///
- /// Creates with Start Code C.
- ///
- /// The value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateC(IEnumerable values)
- => Create(values, 105);
-
- ///
- /// Creates with Start Code C.
- ///
- /// The string value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateC(string s)
- => Create(Subtypes.C, s);
-
- ///
- /// Creates with Start Code C.
- ///
- /// The integer value of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateC(long s)
- => Create(Subtypes.C, s.ToString("g"));
-
- ///
- /// Creates GS1-128 code.
- ///
- /// The application identifier.
- /// The data value.
- /// The Code 128 instance.
- /// values was null.
- /// ai was less than 0.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateGs1(int ai, string data)
- {
- if (ai < 0) throw new ArgumentOutOfRangeException(nameof(ai), "ai should not be less than zero.");
- var col = new List { 102 };
- Fill(col, Subtypes.C, $"{ai:00}{data}");
- return Create(Subtypes.C, col);
- }
-
- ///
- /// Creates GS1-128 code.
- ///
- /// The string 1 with application identifier and its data value.
- /// The string 2 with application identifier and its data value.
- /// The string 3 with application identifier and its data value.
- /// The string 4 with application identifier and its data value.
- /// The string 5 with application identifier and its data value.
- /// The string 6 with application identifier and its data value.
- /// The string 7 with application identifier and its data value.
- /// The string 8 with application identifier and its data value.
- /// The Code 128 instance.
- /// values was null.
- /// ai was less than 0.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 CreateGs1(string part1, string part2, string part3 = null, string part4 = null, string part5 = null, string part6 = null, string part7 = null, string part8 = null)
- {
- var col = new List();
- var subtype = Subtypes.C;
- if (!string.IsNullOrEmpty(part1))
- {
- col.Add(102);
- subtype = Fill(col, Subtypes.C, part1);
- }
-
- if (!string.IsNullOrEmpty(part2))
- {
- if (subtype != Subtypes.C) col.Add(99);
- col.Add(102);
- subtype = Fill(col, Subtypes.C, part2);
- }
-
- if (!string.IsNullOrEmpty(part3))
- {
- if (subtype != Subtypes.C) col.Add(99);
- col.Add(102);
- subtype = Fill(col, Subtypes.C, part3);
- }
-
- if (!string.IsNullOrEmpty(part4))
- {
- if (subtype != Subtypes.C) col.Add(99);
- col.Add(102);
- subtype = Fill(col, Subtypes.C, part4);
- }
-
- if (!string.IsNullOrEmpty(part5))
- {
- if (subtype != Subtypes.C) col.Add(99);
- col.Add(102);
- subtype = Fill(col, Subtypes.C, part5);
- }
-
- if (!string.IsNullOrEmpty(part6))
- {
- if (subtype != Subtypes.C) col.Add(99);
- col.Add(102);
- subtype = Fill(col, Subtypes.C, part6);
- }
-
- if (!string.IsNullOrEmpty(part7))
- {
- if (subtype != Subtypes.C) col.Add(99);
- col.Add(102);
- subtype = Fill(col, Subtypes.C, part7);
- }
-
- if (!string.IsNullOrEmpty(part8))
- {
- if (subtype != Subtypes.C) col.Add(99);
- col.Add(102);
- Fill(col, Subtypes.C, part8);
- }
-
- return Create(Subtypes.C, col);
- }
-
- ///
- /// Creates with the specific sub-type.
- ///
- /// The sub-type to use.
- /// The value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 Create(Subtypes subtype, IEnumerable values)
- => Create(values, subtype switch
- {
- Subtypes.A => 103,
- Subtypes.B => 104,
- Subtypes.C => 105,
- _ => throw new InvalidOperationException("subtype is not valid.")
- });
-
- ///
- /// Creates by boolean collection that white represented as false and black represented as true..
- ///
- /// The value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 Create(IEnumerable values)
- {
- if (values == null) throw new ArgumentNullException(nameof(values), "values should not be null.");
- var s = string.Join(string.Empty, values.Select(b => b ? '1' : '0')).Trim('0');
- if (s.Length < 25) throw new ArgumentException("The count of values is too less.", nameof(values));
- if (s.StartsWith("1100011101011")) s = new string(s.Reverse().ToArray());
- var col = new List();
- var first = s.Substring(0, 7) switch
- {
- "11010000100" => 103,
- "11010010000" => 104,
- "11010011100" => 105,
- _ => throw new InvalidOperationException("The start code is not valid.")
- };
- for (var i = 1; i < s.Length; i += 7)
- {
- try
- {
- var item = s.Substring(i, 7);
- var j = patterns.IndexOf(item);
- if (j < 0) throw new InvalidOperationException($"Contains invalid symbol at position {i}.");
- if (j > 102)
- {
- if (j == 106) break;
- throw new InvalidOperationException($"Contains invalid symbol at position {i}.");
- }
- }
- catch (ArgumentException)
- {
- }
- }
-
- return Create(col, (byte)first);
- }
-
- ///
- /// Creates by symbols.
- ///
- /// The value collection of symbol.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 Create(IEnumerable values)
- {
- if (values == null) throw new ArgumentNullException(nameof(values), "values should not be null.");
- var first = values.First();
- if (first < 103 || first > 105) throw new InvalidOperationException("The start code is not valid.");
- return Create(values.Skip(1), first);
- }
-
- ///
- /// Creates with the specific sub-type.
- ///
- /// The sub-type of start code.
- /// The string to encode.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- public static Code128 Create(Subtypes subtype, string s)
- {
- var col = new List();
- Fill(col, subtype, s);
- return Create(subtype, col);
- }
-
- ///
- /// Fills symbols.
- ///
- /// The byte array of symbol value to fill.
- /// The sub-type of start code.
- /// The string to encode.
- /// The subtype of last one.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- private static Subtypes Fill(List col, Subtypes subtype, string s)
- {
- if (s == null) return subtype;
- var bytes = Encoding.ASCII.GetBytes(s);
- byte? reserved = null;
- foreach (var b in bytes)
- {
- if (subtype == Subtypes.A)
- {
- if (reserved.HasValue)
- {
- col.Add((byte)(reserved.Value + 16));
- reserved = null;
- }
-
- if (b > 31 && b < 96)
- {
- col.Add((byte)(b - 32));
- }
- else if (b < 32)
- {
- col.Add((byte)(b + 64));
- }
- else if (b > 127)
- {
- col.Add(101);
- var b2 = b - 128;
- if (b2 > 31 && b2 < 96)
- {
- col.Add((byte)(b2 - 32));
- }
- else if (b2 < 32)
- {
- col.Add((byte)(b2 + 64));
- }
- else
- {
- subtype = Subtypes.B;
- col.Add(100);
- col.Add((byte)(b2 - 32));
- }
- }
- else
- {
- subtype = Subtypes.B;
- col.Add(100);
- col.Add((byte)(b - 32));
- }
- }
- else if (subtype == Subtypes.B)
- {
- if (reserved.HasValue)
- {
- col.Add((byte)(reserved.Value + 16));
- reserved = null;
- }
-
- if (b > 31 && b < 128)
- {
- col.Add((byte)(b - 32));
- }
- else if (b > 127)
- {
- col.Add(100);
- var b2 = b - 128;
- if (b2 > 31)
- {
- col.Add((byte)(b - 32));
- }
- else
- {
- subtype = Subtypes.A;
- col.Add(101);
- col.Add((byte)(b2 + 64));
- }
- }
- else
- {
- subtype = Subtypes.A;
- col.Add(101);
- col.Add((byte)(b + 64));
- }
- }
- else if (subtype == Subtypes.C)
- {
- if (b < 48)
- {
- if (b < 32)
- {
- subtype = Subtypes.A;
- col.Add(101);
- col.Add((byte)(b + 64));
- }
- else
- {
- subtype = Subtypes.B;
- col.Add(100);
- col.Add((byte)(b - 32));
- }
- }
- else if (b > 57)
- {
- if (b > 159)
- {
- subtype = Subtypes.A;
- col.Add(100);
- col.Add(100);
- col.Add((byte)(b - 160));
- }
- else if (b > 127)
- {
- subtype = Subtypes.A;
- col.Add(101);
- col.Add(101);
- col.Add((byte)(b - 64));
- }
- else
- {
- subtype = Subtypes.B;
- col.Add(100);
- col.Add((byte)(b - 32));
- }
- }
- else if (reserved.HasValue)
- {
- col.Add((byte)(reserved.Value * 10 + b - 48));
- reserved = null;
- }
- else
- {
- reserved = (byte)(b - 48);
- }
- }
- else
- {
- throw new InvalidOperationException($"The subtype is not valid.");
- }
- }
-
- if (reserved.HasValue)
- {
- if (subtype == Subtypes.C)
- col.Add(101);
- col.Add((byte)(reserved.Value + 16));
- }
-
- return subtype;
- }
-
- ///
- /// Creates with the specific start code.
- ///
- /// The value collection of symbol.
- /// The value of start code.
- /// The Code 128 instance.
- /// values was null.
- /// values was empty.
- /// Any value is invalid.
- private static Code128 Create(IEnumerable values, byte startCode)
- {
- if (values == null) throw new ArgumentNullException(nameof(values), "values should not be null.");
- var col = values.ToList();
- if (col.Count < 1) throw new ArgumentException("values should not be empty.", nameof(values));
- if (col[0] != startCode)
- {
- if (col[0] > 102) throw new InvalidOperationException($"The first value {col[0]} is not valid.");
- col.Insert(0, startCode);
- }
-
- if (col[col.Count - 1] != 106)
- {
- long check = startCode;
- for (var i = 1; i < col.Count; i++)
- {
- check += col[i] * i;
- }
-
- col.Add((byte)(check % 103));
- col.Add(106);
- }
-
- var count = col.Count - 1;
- for (var i = 1; i < count; i++)
- {
- if (col[i] > 102) throw new InvalidOperationException($"The value {col[i]} at position {i} is not valid.");
- }
-
- return new Code128(col);
- }
-
- ///
- /// Adds all code 128 instances into one.
- ///
- /// The collection to combine.
- /// A code 128 instance combined.
- public static Code128 Join(IEnumerable col)
- {
- if (col is null) return null;
- var list = col.Where(ele => ele != null && ele.Count > 3).ToList();
- if (list.Count < 2) return list.Count == 1 ? list[0] : null;
- var first = list[0];
- var subtype = first.GetSubtypesUsed().Last();
- var bytes = first.TakeData().ToList();
- foreach (var c in list.Skip(1))
- {
- var rightSubtype = c.Subtype;
- if (subtype != rightSubtype) bytes.Add(rightSubtype switch
- {
- Subtypes.A => 101,
- Subtypes.B => 100,
- _ => 99
- });
- bytes.AddRange(c.TakeData());
- subtype = c.GetSubtypesUsed().Last();
- }
-
- return Create(first.Subtype, bytes);
- }
-
- ///
- /// Adds.
- /// leftValue + rightValue
- ///
- /// The left value.
- /// The right value.
- /// A result after Add operation.
- public static Code128 operator +(Code128 leftValue, Code128 rightValue)
- {
- if (rightValue is null) return leftValue;
- if (leftValue is null) return rightValue;
- var subtype = leftValue.GetSubtypesUsed().Last();
- var bytes = leftValue.TakeData().ToList();
- var rightSubtype = rightValue.Subtype;
- if (subtype != rightSubtype) bytes.Add(rightSubtype switch
- {
- Subtypes.A => 101,
- Subtypes.B => 100,
- _ => 99
- });
- bytes.AddRange(rightValue.TakeData());
- return Create(leftValue.Subtype, bytes);
- }
-#pragma warning restore IDE0056
-}
diff --git a/Messages/Data/Ean.cs b/Messages/Data/Ean.cs
deleted file mode 100644
index 31fd4d90..00000000
--- a/Messages/Data/Ean.cs
+++ /dev/null
@@ -1,706 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Trivial.Data;
-
-///
-/// The International Article Number, a.k.a. European Article Number or EAN.
-///
-public partial class InternationalArticleNumber
-{
- ///
- /// All digits.
- ///
- private string value;
-
- ///
- /// Converts the value of the current object to its equivalent string representation.
- ///
- /// The string representation of the value of this object, which consists of a sequence of 7 digits of 0 and 1.
- public override string ToString()
- => value ?? string.Empty;
-
- ///
- /// Gets the checksum of EAN13.
- ///
- /// The checksum.
- /// The digits was not valid.
- public byte Checksum()
- {
- if (string.IsNullOrEmpty(value))
- throw new InvalidOperationException("The value should not be null.");
- return Checksum(value);
- }
-
- ///
- /// Converts to code list.
- ///
- /// The code list.
- public List ToList()
- {
- if (value == null) return new();
- return value.Select(ele => ele switch
- {
- '0' => Zero,
- '1' => One,
- '2' => Two,
- '3' => Three,
- '4' => Four,
- '5' => Five,
- '6' => Six,
- '7' => Seven,
- '8' => Eight,
- '9' => Nine,
- _ => null
- }).Where(ele => ele != null).ToList();
- }
-
- ///
- /// Returns a string that represents the barcode in stroke path for SVG or XAML.
- ///
- /// The bar height.
- /// A stroke path string that represents the barcode.
- public string ToPathString(int height = 40)
- {
- var sb = new StringBuilder();
- var i = 6;
- sb.Append("M0,0 ");
- foreach (var b in ToBarcode())
- {
- i++;
- if (b) sb.Append($"M{i},0 L{i},{height} ");
- }
-
- sb.Append($"M{i + 6},0");
- return sb.ToString();
- }
-
- ///
- /// Converts to boolean list.
- /// White represented as false, black represented as true.
- ///
- /// The boolean list of barcode.
- /// It was not an EAN-13 ro EAN-8 code.
- public List ToBarcode()
- {
- var codes = ToList();
- var col = new List();
- if (codes.Count == 13)
- {
- col.Add(true);
- col.Add(false);
- col.Add(true);
- switch (value.FirstOrDefault())
- {
- case '0':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.L));
- col.AddRange(codes[3].ToList(Encodings.L));
- col.AddRange(codes[4].ToList(Encodings.L));
- col.AddRange(codes[5].ToList(Encodings.L));
- col.AddRange(codes[6].ToList(Encodings.L));
- break;
- case '1':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.L));
- col.AddRange(codes[3].ToList(Encodings.G));
- col.AddRange(codes[4].ToList(Encodings.L));
- col.AddRange(codes[5].ToList(Encodings.G));
- col.AddRange(codes[6].ToList(Encodings.G));
- break;
- case '2':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.L));
- col.AddRange(codes[3].ToList(Encodings.G));
- col.AddRange(codes[4].ToList(Encodings.G));
- col.AddRange(codes[5].ToList(Encodings.L));
- col.AddRange(codes[6].ToList(Encodings.G));
- break;
- case '3':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.L));
- col.AddRange(codes[3].ToList(Encodings.G));
- col.AddRange(codes[4].ToList(Encodings.G));
- col.AddRange(codes[5].ToList(Encodings.G));
- col.AddRange(codes[6].ToList(Encodings.L));
- break;
- case '4':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.G));
- col.AddRange(codes[3].ToList(Encodings.L));
- col.AddRange(codes[4].ToList(Encodings.L));
- col.AddRange(codes[5].ToList(Encodings.G));
- col.AddRange(codes[6].ToList(Encodings.G));
- break;
- case '5':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.G));
- col.AddRange(codes[3].ToList(Encodings.G));
- col.AddRange(codes[4].ToList(Encodings.L));
- col.AddRange(codes[5].ToList(Encodings.L));
- col.AddRange(codes[6].ToList(Encodings.G));
- break;
- case '6':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.G));
- col.AddRange(codes[3].ToList(Encodings.G));
- col.AddRange(codes[4].ToList(Encodings.G));
- col.AddRange(codes[5].ToList(Encodings.L));
- col.AddRange(codes[6].ToList(Encodings.L));
- break;
- case '7':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.G));
- col.AddRange(codes[3].ToList(Encodings.L));
- col.AddRange(codes[4].ToList(Encodings.G));
- col.AddRange(codes[5].ToList(Encodings.L));
- col.AddRange(codes[6].ToList(Encodings.G));
- break;
- case '8':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.G));
- col.AddRange(codes[3].ToList(Encodings.L));
- col.AddRange(codes[4].ToList(Encodings.G));
- col.AddRange(codes[5].ToList(Encodings.G));
- col.AddRange(codes[6].ToList(Encodings.L));
- break;
- case '9':
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.G));
- col.AddRange(codes[3].ToList(Encodings.G));
- col.AddRange(codes[4].ToList(Encodings.L));
- col.AddRange(codes[5].ToList(Encodings.G));
- col.AddRange(codes[6].ToList(Encodings.L));
- break;
- }
-
- col.Add(false);
- col.Add(true);
- col.Add(false);
- col.Add(true);
- col.Add(false);
- col.AddRange(codes[7].ToList(Encodings.R));
- col.AddRange(codes[8].ToList(Encodings.R));
- col.AddRange(codes[9].ToList(Encodings.R));
- col.AddRange(codes[10].ToList(Encodings.R));
- col.AddRange(codes[11].ToList(Encodings.R));
- col.AddRange(codes[12].ToList(Encodings.R));
- col.Add(true);
- col.Add(false);
- col.Add(true);
- return col;
- }
- else if (codes.Count == 8)
- {
- col.Add(true);
- col.Add(false);
- col.Add(true);
- col.AddRange(codes[0].ToList(Encodings.L));
- col.AddRange(codes[1].ToList(Encodings.L));
- col.AddRange(codes[2].ToList(Encodings.L));
- col.AddRange(codes[3].ToList(Encodings.L));
- col.Add(false);
- col.Add(true);
- col.Add(false);
- col.Add(true);
- col.Add(false);
- col.AddRange(codes[4].ToList(Encodings.R));
- col.AddRange(codes[5].ToList(Encodings.R));
- col.AddRange(codes[6].ToList(Encodings.R));
- col.AddRange(codes[7].ToList(Encodings.R));
- col.Add(true);
- col.Add(false);
- col.Add(true);
- return col;
- }
- else if (codes.Count == 5)
- {
- var checksum = Checksum();
- col.Add(false);
- col.Add(true);
- col.Add(false);
- col.Add(true);
- col.Add(true);
- col.AddRange(codes[0].ToList(checksum < 4 ? Encodings.G : Encodings.L));
- col.Add(false);
- col.Add(true);
- col.AddRange(codes[1].ToList(checksum == 0 || checksum == 4 || checksum == 7 || checksum == 8 ? Encodings.G : Encodings.L));
- col.Add(false);
- col.Add(true);
- col.AddRange(codes[2].ToList(checksum == 1 || checksum == 4 || checksum == 5 || checksum == 9 ? Encodings.G : Encodings.L));
- col.Add(false);
- col.Add(true);
- col.AddRange(codes[3].ToList(checksum == 2 || checksum == 5 || checksum == 6 || checksum == 7 ? Encodings.G : Encodings.L));
- col.Add(false);
- col.Add(true);
- col.AddRange(codes[4].ToList(checksum == 3 || checksum == 6 || checksum == 8 || checksum == 9 ? Encodings.G : Encodings.L));
- return col;
- }
- else if (codes.Count == 2)
- {
- var checksum = Checksum();
- col.Add(false);
- col.Add(true);
- col.Add(false);
- col.Add(true);
- col.Add(true);
- col.AddRange(codes[0].ToList(checksum % 4 < 2 ? Encodings.L : Encodings.G));
- col.Add(false);
- col.Add(true);
- col.AddRange(codes[1].ToList(checksum % 2 == 0 ? Encodings.L : Encodings.G));
- return col;
- }
-
- throw new InvalidOperationException("The count of digit is not any of 7, 8, 12 or 13.");
- }
-
- ///
- /// Converts to a string.
- ///
- /// The barcode string.
- /// It was not an EAN-13 ro EAN-8 code.
- public string ToBarcodeString()
- => string.Join(string.Empty, ToBarcode().Select(ele => ele ? '1' : '0'));
-
- ///
- /// Converts to a string.
- ///
- /// The value of black represented.
- /// The value of white represented.
- /// The barcode string.
- /// It was not an EAN-13 ro EAN-8 code.
- public string ToBarcodeString(char black, char white)
- => string.Join(string.Empty, ToBarcode().Select(ele => ele ? black : white));
-
- ///
- /// Converts to a string.
- ///
- /// The selector to convert boolean array to a string. Per boolean value, white represented as false, black represented as true.
- /// The barcode string.
- /// It was not an EAN-13 ro EAN-8 code.
- public string ToBarcodeString(Func selector)
- => selector != null ? string.Join(string.Empty, ToBarcode().Select(selector)) : ToBarcodeString();
-
- ///
- /// Converts to a string.
- ///
- /// The selector to convert boolean array to a string. Per boolean value, white represented as false, black represented as true.
- /// The barcode string.
- /// It was not an EAN-13 ro EAN-8 code.
- public string ToBarcodeString(Func selector)
- => selector != null ? string.Join(string.Empty, ToBarcode().Select(selector)) : ToBarcodeString();
-
- ///
- /// Creates an EAN.
- ///
- /// The digits.
- /// An instance of the EAN.
- /// The input sequence was null.
- /// The digits was not valid.
- public static InternationalArticleNumber Create(params byte[] digits)
- {
- if (digits.Length < 6)
- {
- foreach (var d in digits)
- {
- if (d > 9) throw new InvalidOperationException("The digit should be less than 10.");
- }
-
- if (digits.Length == 5 || digits.Length == 2)
- return new InternationalArticleNumber
- {
- value = string.Join(string.Empty, digits)
- };
-
- throw new InvalidOperationException("The count of digit is too less.");
- }
-
- var check = Checksum(digits);
- var col = digits.Length switch
- {
- 13 => digits[12] == check ? digits.Take(12) : null,
- 8 => digits[7] == check ? digits.Take(7) : null,
- 18 => digits[17] == check ? digits.Take(17) : null,
- _ => digits
- };
- if (col == null)
- throw new InvalidOperationException($"Check failed. Expects {check} but {digits.LastOrDefault()}.");
- return new InternationalArticleNumber
- {
- value = string.Join(string.Empty, col) + check
- };
- }
-
- ///
- /// Creates an EAN.
- ///
- /// The digits.
- /// An instance of the EAN.
- /// The input sequence was null.
- /// The digits was not valid.
- public static InternationalArticleNumber Create(IEnumerable digits)
- => Create(digits?.ToArray());
-
- ///
- /// Creates an EAN.
- ///
- /// The EAN digits; or barcode areas that white represented as 0 and black represented as 1.
- /// An instance of the EAN.
- /// The input sequence was null.
- /// The digits was not valid.
- public static InternationalArticleNumber Create(string sequence)
- {
- if (sequence == null) throw new ArgumentNullException(nameof(sequence), "sequence should not be null.");
- sequence = sequence.Trim();
- if (sequence.Length < 21 || sequence.Contains('9') || sequence.Replace("0", string.Empty).Replace("1", string.Empty).Replace("-", string.Empty).Trim().Length > 0)
- return Create(ToList(sequence));
- var col = new List();
- foreach (var c in sequence)
- {
- if (c == '0') col.Add(false);
- else if (c == '1') col.Add(true);
- }
-
- return Create(col);
- }
-
- ///
- /// Creates an EAN.
- ///
- /// The barcode. White represented as false, black represented as true.
- /// An instance of the EAN.
- /// The barcode was null.
- /// The barcode was not valid.
- public static InternationalArticleNumber Create(IEnumerable barcode)
- {
-#pragma warning disable IDE0056
- if (barcode == null) throw new ArgumentNullException(nameof(barcode), "barcode should not be null.");
- var col = barcode?.ToList();
- var sb = new StringBuilder();
- if (col.Count < 49)
- {
- if (col.Count != 21 && col.Count != 48)
- throw new InvalidOperationException("The count of barcode area is too less.");
- if (col[0] || !col[1] || col[2] || !col[3] || !col[4])
- throw new InvalidOperationException("The start marker is not invalid.");
- for (var i = 5; i < col.Count; i += 9)
- {
- var n = GetLeftDigitNumber(col, i, out _);
- sb.Append(n);
- }
-
- return Create(sb.ToString());
- }
-
- if (!col[0] || col[1] || !col[2] || col[3])
- throw new InvalidOperationException("The start marker is not invalid.");
- if (!col[col.Count - 1] || col[col.Count - 2] || !col[col.Count - 3] || col[col.Count - 4])
- throw new InvalidOperationException("The end marker is not invalid.");
- if (col.Count == 95)
- {
- {
- var n = GetLeftDigitNumber(col, 3, out var e);
- if (e == Encodings.G)
- {
- col.Reverse();
- n = GetLeftDigitNumber(col, 3, out e);
- }
-
- if (e != Encodings.L) throw new InvalidOperationException("The format of the first digit is invalid.");
- sb.Append(n);
- }
-
- var left = new List { false };
- for (var i = 10; i < 45; i += 7)
- {
- var n = GetLeftDigitNumber(col, i, out var e);
- left.Add(e == Encodings.G);
- sb.Append(n);
- }
-
- sb.Insert(0, GetFirstDigitNumber(left));
- for (var i = 50; i < 92; i += 7)
- {
- var n = GetRightDigitNumber(col, i);
- sb.Append(n);
- }
- }
- else if (col.Count == 67)
- {
- {
- var n = GetLeftDigitNumber(col, 3, out var e);
- if (e == Encodings.G)
- {
- col.Reverse();
- n = GetLeftDigitNumber(col, 3, out e);
- }
-
- if (e != Encodings.L) throw new InvalidOperationException("The format of the first digit is invalid.");
- sb.Append(n);
- }
-
- for (var i = 10; i < 31; i += 7)
- {
- var n = GetLeftDigitNumber(col, i, out _);
- sb.Append(n);
- }
-
- for (var i = 36; i < 64; i += 7)
- {
- var n = GetRightDigitNumber(col, i);
- sb.Append(n);
- }
- }
- else if (col.Count == 84)
- {
- {
- var n = GetLeftDigitNumber(col, 0, out var e);
- if (e == Encodings.G)
- {
- col.Reverse();
- n = GetLeftDigitNumber(col, 0, out e);
- }
-
- if (e != Encodings.L) throw new InvalidOperationException("The format of the first digit is invalid.");
- sb.Append(n);
- }
-
- var left = new List { false };
- for (var i = 7; i < 42; i += 7)
- {
- var n = GetLeftDigitNumber(col, i, out var e);
- left.Add(e == Encodings.G);
- sb.Append(n);
- }
-
- sb.Insert(0, GetFirstDigitNumber(left));
- for (var i = 42; i < 84; i += 7)
- {
- var n = GetRightDigitNumber(col, i);
- sb.Append(n);
- }
- }
- else
- {
- throw new InvalidOperationException("The count of barcode is invalid. Should be 95 or 67.");
- }
-
- return Create(sb.ToString());
-#pragma warning restore IDE0056
- }
-
- ///
- /// Gets the checksum.
- ///
- /// The digits.
- /// The checksum.
- /// The input sequence was null.
- /// The digits was not valid.
- public static byte Checksum(params byte[] digits)
- {
- if (digits == null) throw new ArgumentNullException(nameof(digits), "digits should not be null.");
- foreach (var d in digits)
- {
- if (d > 9) throw new InvalidOperationException("The digit should be less than 10.");
- }
-
- return (byte)(digits.Length switch
- {
- 12 or 13 => (10 - ((digits[0] + digits[2] + digits[4] + digits[6] + digits[8] + digits[10] + (digits[1] + digits[3] + digits[5] + digits[7] + digits[9] + digits[11]) * 3) % 10)) % 10,
- 7 or 8 => (10 - ((digits[1] + digits[3] + digits[5] + (digits[0] + digits[2] + digits[4] + digits[6]) * 3) % 10)) % 10,
- 17 or 18 => (10 - ((digits[1] + digits[3] + digits[5] + digits[7] + digits[9] + digits[11] + digits[13] + digits[15] + (digits[0] + digits[2] + digits[4] + digits[6] + digits[8] + digits[10] + digits[12] + digits[14] + digits[16]) * 3) % 10)) % 10,
- 5 => ((digits[0] + digits[2] + digits[4]) * 3 + (digits[1] + digits[3]) * 9) % 10,
- 2 => (digits[0] * 2 + digits[1]) % 4,
- _ => throw new InvalidOperationException("The count of digit is not any of 7, 8, 12 or 13.")
- });
- }
-
- ///
- /// Gets the checksum.
- ///
- /// The digits.
- /// The checksum.
- /// The input sequence was null.
- /// The digits was not valid.
- public static byte Checksum(IEnumerable digits)
- => Checksum(digits?.ToArray());
-
- ///
- /// Gets the checksum.
- ///
- /// The EAN digits.
- /// The checksum.
- /// The input sequence was null.
- /// The input sequence was not valid.
- public static byte Checksum(string sequence)
- => Checksum(ToList(sequence));
-
- ///
- /// Validates the checksum.
- ///
- /// The digits.
- /// true if checksum is correct; otherwise, false.
- public static bool Validate(params byte[] digits)
- => digits != null && digits.Length switch
- {
- 13 => (10 - ((digits[0] + digits[2] + digits[4] + digits[6] + digits[8] + digits[10] + (digits[1] + digits[3] + digits[5] + digits[7] + digits[9] + digits[11]) * 3) % 10)) % 10 == digits[12],
- 8 => (10 - ((digits[1] + digits[3] + digits[5] + (digits[0] + digits[2] + digits[4] + digits[6]) * 3) % 10)) % 10 == digits[7],
- 18 => (10 - ((digits[1] + digits[3] + digits[5] + digits[7] + digits[9] + digits[11] + digits[13] + digits[15] + (digits[0] + digits[2] + digits[4] + digits[6] + digits[8] + digits[10] + digits[12] + digits[14] + digits[16]) * 3) % 10)) % 10 == digits[17],
- 5 or 2 => true,
- _ => false
- };
-
- ///
- /// Validates the checksum.
- ///
- /// The digits.
- /// true if checksum is correct; otherwise, false.
- public static bool Validate(IEnumerable digits)
- => Validate(digits?.ToArray());
-
- ///
- /// Validates the checksum.
- ///
- /// The EAN digits.
- /// true if checksum is correct; otherwise, false.
- public static bool Validate(string sequence)
- {
- if (string.IsNullOrEmpty(sequence)) return false;
- try
- {
- return Validate(ToList(sequence));
- }
- catch (InvalidOperationException)
- {
- }
-
- return false;
- }
-
- private static byte GetFirstDigitNumber(List col)
- => string.Join(string.Empty, col.Select(ele => ele ? 'G' : 'L')) switch
- {
- "LLLLLL" => 0,
- "LLGLGG" => 1,
- "LLGGLG" => 2,
- "LLGGGL" => 3,
- "LGLLGG" => 4,
- "LGGLLG" => 5,
- "LGGGLL" => 6,
- "LGLGLG" => 7,
- "LGLGGL" => 8,
- "LGGLGL" => 9,
- _ => throw new InvalidOperationException("The encoding of first group is invalid.")
- };
-
- private static byte GetLeftDigitNumber(List col, int i, out Encodings encoding)
- {
- if (col[i]) throw new InvalidOperationException($"Position {i} should be white (false or 0) but is black in fact.");
- if (!col[i + 6]) throw new InvalidOperationException($"Position {i + 6} should be black (true or 1) but is white in fact.");
- var b = (byte)(0b1
- + (col[i + 1] ? 0b100000 : 0)
- + (col[i + 2] ? 0b10000 : 0)
- + (col[i + 3] ? 0b1000 : 0)
- + (col[i + 4] ? 0b100 : 0)
- + (col[i + 5] ? 0b10 : 0));
- try
- {
- return GetDigitNumber(b, out encoding);
- }
- catch (InvalidOperationException)
- {
- throw new InvalidOperationException($"Code {Code.ToString(b)} at position {i} is not a valid digit.");
- }
- }
-
- private static byte GetRightDigitNumber(List col, int i)
- {
- if (!col[i]) throw new InvalidOperationException($"Position {i} should be black (true or 1) but is white in fact.");
- if (col[i + 6]) throw new InvalidOperationException($"Position {i + 6} should be white (false or 0) but is black in fact.");
- var b = (byte)(0b1000000
- + (col[i + 1] ? 0b100000 : 0)
- + (col[i + 2] ? 0b10000 : 0)
- + (col[i + 3] ? 0b1000 : 0)
- + (col[i + 4] ? 0b100 : 0)
- + (col[i + 5] ? 0b10 : 0));
- byte r;
- Encodings encoding;
- try
- {
- r = GetDigitNumber(b, out encoding);
- }
- catch (InvalidOperationException)
- {
- throw new InvalidOperationException($"Code {Code.ToString(b)} at position {i} is not a valid digit.");
- }
-
- if (encoding != Encodings.R)
- throw new InvalidOperationException($"Code {Code.ToString(b)} ({r}) at position {i} is not R-column.");
- return r;
- }
-
- ///
- /// Creates a byte list.
- ///
- /// The EAN digits.
- /// The byte list.
- /// The input sequence was null.
- /// The input sequence was not valid.
- private static List ToList(string sequence)
- {
- if (sequence == null) throw new ArgumentNullException(nameof(sequence), "sequence should not be null.");
- var arr = new List();
- var i = -1;
- foreach (var c in sequence)
- {
- i++;
- switch (c)
- {
- case '-':
- case ' ':
- case '(':
- case ')':
- continue;
- case '0':
- arr.Add(0);
- break;
- case '1':
- arr.Add(1);
- break;
- case '2':
- arr.Add(2);
- break;
- case '3':
- arr.Add(3);
- break;
- case '4':
- arr.Add(4);
- break;
- case '5':
- arr.Add(5);
- break;
- case '6':
- arr.Add(6);
- break;
- case '7':
- arr.Add(7);
- break;
- case '8':
- arr.Add(8);
- break;
- case '9':
- arr.Add(9);
- break;
- default:
- throw new InvalidOperationException(
- $"The input sequence is not valid. Character at index {i} is {c} but expects a digit.",
- new ArgumentException("sequence format is not valid.", nameof(sequence)));
- }
- }
-
- return arr;
- }
-}
diff --git a/Messages/Data/EanCli.cs b/Messages/Data/EanCli.cs
deleted file mode 100644
index f4eeef4d..00000000
--- a/Messages/Data/EanCli.cs
+++ /dev/null
@@ -1,255 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-using Trivial.Collection;
-using Trivial.CommandLine;
-
-namespace Trivial.Data;
-
-///
-/// The International Article Number, a.k.a. European Article Number or EAN.
-///
-public partial class InternationalArticleNumber
-{
- ///
- /// Converts to boolean list and writes to the standard output stream.
- /// White represented as false, black represented as true.
- ///
- /// The command line interface proxy.
- /// The style that foreground represents black and background represents white.
- /// The boolean list.
- /// It was not an EAN-13 ro EAN-8 code.
- public List ToBarcode(StyleConsole cli, ConsoleTextStyle style = null)
- {
- List barcode;
- try
- {
- barcode = ToBarcode();
- }
- catch (InvalidOperationException)
- {
- cli.WriteLine(style, value);
- throw;
- }
-
- var col = new List();
- if (style == null) style = new ConsoleTextStyle(System.Drawing.Color.FromArgb(16, 16, 16), ConsoleColor.Black, System.Drawing.Color.FromArgb(206, 206, 206), ConsoleColor.Gray);
- var black = new ConsoleTextStyle(style.ForegroundRgbColor, style.ForegroundConsoleColor, style.ForegroundRgbColor, style.ForegroundConsoleColor);
- var white = new ConsoleTextStyle(style.BackgroundRgbColor, style.BackgroundConsoleColor, style.BackgroundRgbColor, style.BackgroundConsoleColor);
- var bg = new string(' ', 12 + barcode.Count);
- col.Add(bg, white);
- col.Add(Environment.NewLine);
- var s = value;
- cli.Flush();
- if (cli.Mode == StyleConsole.Modes.Text && cli.Handler == null)
- {
- cli.WriteLine(style, s);
- return barcode;
- }
- else if (barcode.Count + 12 > GetBufferSafeWidth(cli))
- {
- col.Clear();
- foreach (var b in barcode)
- {
- col.Add(' ', 1, b ? black : white);
- }
-
- col.Add(Environment.NewLine);
- col.Add(s, style);
- cli.WriteLine(col);
- return barcode;
- }
- else if (barcode.Count == 95 && s.Length == 13)
- {
- for (var i = 0; i < 4; i++)
- {
- col.Add(' ', 7, white);
- foreach (var b in barcode)
- {
- col.Add(' ', 1, b ? black : white);
- }
-
- col.Add(' ', 5, white);
- col.Add(Environment.NewLine);
- }
-
- var isbn = false;
- if (s.StartsWith("97"))
- {
- if (s.StartsWith("9790"))
- {
- isbn = true;
- col.Add("ISMN 9 ", style);
- }
- else if (s.StartsWith("978") || s.StartsWith("979"))
- {
- isbn = true;
- col.Add("ISBN 9 ", style);
- }
- else if (s.StartsWith("977"))
- {
- isbn = true;
- col.Add("ISSN 9 ", style);
- }
- }
-
- if (!isbn)
- {
- col.Add(' ', 4, white);
- col.Add(s[0], 1, style);
- col.Add(' ', 2, white);
- }
-
- for (var i = 0; i < 3; i++)
- {
- col.Add(' ', 1, barcode[i] ? black : white);
- }
-
- for (var i = 1; i < 7; i++)
- {
- col.Add(' ', 3, white);
- col.Add(s[i], 1, style);
- col.Add(' ', 3, white);
- }
-
- for (var i = 45; i < 50; i++)
- {
- col.Add(' ', 1, barcode[i] ? black : white);
- }
-
- for (var i = 7; i < 13; i++)
- {
- col.Add(' ', 3, white);
- col.Add(s[i], 1, style);
- col.Add(' ', 3, white);
- }
-
- for (var i = 92; i < 95; i++)
- {
- col.Add(' ', 1, barcode[i] ? black : white);
- }
-
- col.Add(' ', 5, white);
- col.Add(Environment.NewLine);
- }
- else if (barcode.Count == 67 && s.Length == 8)
- {
- for (var i = 0; i < 4; i++)
- {
- col.Add(' ', 6, white);
- foreach (var b in barcode)
- {
- col.Add(' ', 1, b ? black : white);
- }
-
- col.Add(' ', 6, white);
- col.Add(Environment.NewLine);
- }
-
- col.Add(' ', 6, white);
- for (var i = 0; i < 3; i++)
- {
- col.Add(' ', 1, barcode[i] ? black : white);
- }
-
- for (var i = 0; i < 4; i++)
- {
- col.Add(' ', 3, white);
- col.Add(s[i], 1, style);
- col.Add(' ', 3, white);
- }
-
- for (var i = 31; i < 36; i++)
- {
- col.Add(' ', 1, barcode[i] ? black : white);
- }
-
- for (var i = 4; i < 8; i++)
- {
- col.Add(' ', 3, white);
- col.Add(s[i], 1, style);
- col.Add(' ', 3, white);
- }
-
- for (var i = 64; i < 67; i++)
- {
- col.Add(' ', 1, barcode[i] ? black : white);
- }
-
- col.Add(' ', 6, white);
- col.Add(Environment.NewLine);
- }
- else if ((barcode.Count == 48 && s.Length == 5) || (barcode.Count == 21 && s.Length == 2))
- {
- col.Add(' ', 14, white);
- foreach (var c in s)
- {
- col.Add(c, 1, style);
- col.Add(' ', 8, white);
- }
-
- col.Add(' ', 1, white);
- col.Add(Environment.NewLine);
- for (var i = 0; i < 4; i++)
- {
- col.Add(' ', 6, white);
- foreach (var b in barcode)
- {
- col.Add(' ', 1, b ? black : white);
- }
-
- col.Add(' ', 6, white);
- col.Add(Environment.NewLine);
- }
- }
- else
- {
- for (var i = 0; i < 4; i++)
- {
- col.Add(' ', 6, white);
- foreach (var b in barcode)
- {
- col.Add(' ', 1, b ? black : white);
- }
-
- col.Add(' ', 6, white);
- col.Add(Environment.NewLine);
- }
- }
-
- col.Add(bg, white);
- (cli ?? StyleConsole.Default).WriteLine(col);
- return barcode;
- }
-
- private static int GetBufferSafeWidth(StyleConsole cli)
- {
- try
- {
- return (cli ?? StyleConsole.Default).BufferWidth - 1;
- }
- catch (System.IO.IOException)
- {
- }
- catch (InvalidOperationException)
- {
- }
- catch (NotSupportedException)
- {
- }
- catch (System.Security.SecurityException)
- {
- }
- catch (System.Runtime.InteropServices.ExternalException)
- {
- }
- catch (ArgumentException)
- {
- }
-
- return 70;
- }
-}
diff --git a/Messages/Data/EanCode.cs b/Messages/Data/EanCode.cs
deleted file mode 100644
index 1eae7942..00000000
--- a/Messages/Data/EanCode.cs
+++ /dev/null
@@ -1,415 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Trivial.Data;
-
-///
-/// The International Article Number, a.k.a. European Article Number or EAN.
-///
-public partial class InternationalArticleNumber
-{
- ///
- /// The encoding for Code.
- ///
- public enum Encodings : byte
- {
- ///
- /// Odd parity for first group.
- ///
- L = 1,
-
- ///
- /// Even parity for first group.
- ///
- G = 2,
-
- ///
- /// Last group.
- ///
- R = 3
- }
-
- ///
- /// The code of a Code.
- ///
- public class Code : IEquatable, IEquatable
- {
- ///
- /// Initializes a new instance of the InternationalArticleNumber.Code class.
- ///
- /// The code.
- public Code(byte code)
- {
- int r;
- int rg;
- if (code > 0b111111)
- {
- if (code > 0b1111111)
- R = (byte)(code >> 1);
- else
- R = code;
- rg = ((~code) + 128) % 128;
- L = (byte)(rg);
- r = code;
- }
- else
- {
- L = code;
- r = ((~code) + 128) % 128;
- R = (byte)r;
- rg = code;
- }
-
- G = Reverse(r);
- RG = Reverse(rg);
- }
-
- ///
- /// Gets the binary (last 7 bits) of the Code encoded using odd parity for first group.
- ///
- public byte L { get; }
-
- ///
- /// Gets the binary (last 7 bits) of the Code encoded using even parity for first group.
- ///
- public byte G { get; }
-
- ///
- /// Gets the binary (last 7 bits) of the Code encoded for last group.
- ///
- public byte R { get; }
-
- internal byte RG { get; }
-
- ///
- /// Gets the value.
- ///
- /// The encoding.
- /// The value in byte (last 7 bit).
- /// encoding is not valid.
- public byte Get(Encodings encoding)
- => encoding switch
- {
- Encodings.L => L,
- Encodings.R => R,
- Encodings.G => G,
- (Encodings)4 => RG,
- _ => throw new InvalidOperationException("encoding is invalid.", new ArgumentOutOfRangeException(nameof(encoding), "encoding is not the one of supported."))
- };
-
- ///
- /// Indicates whether the current object is equal to another object of the same type.
- ///
- /// An object to compare with this object.
- ///
- /// true if the current object is equal to the parameter; otherwise, false.
- ///
- public bool Equals(byte other)
- {
- return other == L || other == R || other == G || other == RG;
- }
-
- ///
- /// Indicates whether the current object is equal to another object of the same type.
- ///
- /// An object to compare with this object.
- ///
- /// true if the current object is equal to the parameter; otherwise, false.
- ///
- public bool Equals(Code other)
- {
- return other != null && L == other.L && G == other.G;
- }
-
- ///
- /// Indicates whether the current object is equal to another object of the same type.
- ///
- /// An object to compare with this object.
- ///
- /// true if the current object is equal to the parameter; otherwise, false.
- ///
- public override bool Equals(object obj)
- {
- if (obj is null) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj is byte b) return Equals(b);
- return Equals(obj as Code);
- }
-
- ///
- public override int GetHashCode()
- => L.GetHashCode();
-
- ///
- /// Gets the encoding if the specific value is the current object; otherwise, 0.
- ///
- /// An object to compare with this object.
- /// The enocding used in this object.
- public Encodings GetEncoding(byte other)
- {
- if (other == L) return Encodings.L;
- if (other == R) return Encodings.R;
- if (other == G) return Encodings.G;
- if (other == RG) return (Encodings)4;
- return 0;
- }
-
- ///
- /// Converts to a list of boolean about areas.
- ///
- /// The encoding.
- /// The areas. White represented as false, black represented as true.
- /// encoding is not valid.
- public List ToList(Encodings encoding)
- => encoding switch
- {
- Encodings.L => ToList(L),
- Encodings.R => ToList(R),
- Encodings.G => ToList(G),
- (Encodings)4 => ToList(RG),
- _ => throw new InvalidOperationException("encoding is invalid.", new ArgumentOutOfRangeException(nameof(encoding), "encoding is not the one of supported."))
- };
-
- ///
- /// Converts to a list of boolean.
- ///
- /// The encoding.
- /// The boolean array.
- /// encoding is not valid.
- public string ToString(Encodings encoding)
- => encoding switch
- {
- Encodings.L => ToString(L),
- Encodings.R => ToString(R),
- Encodings.G => ToString(G),
- (Encodings)4 => ToString(RG),
- _ => throw new InvalidOperationException("encoding is invalid.", new ArgumentOutOfRangeException(nameof(encoding), "encoding is not the one of supported."))
- };
-
- ///
- /// Converts the value of the current object to its equivalent string representation.
- ///
- /// The string representation of the value of this object, which consists of a sequence of 7 digits of 0 and 1.
- public override string ToString()
- {
- return ToString(Encodings.L);
- }
-
- internal static string ToString(byte value)
- {
- var s = Maths.Numbers.ToPositionalNotationString((long)value, 2);
- return s.Length < 7 ? s.PadLeft(7 - s.Length, '0') : s;
- }
-
- private static List ToList(int value)
- => new()
- {
- (value & 0b1000000) > 0,
- (value & 0b100000) > 0,
- (value & 0b10000) > 0,
- (value & 0b1000) > 0,
- (value & 0b100) > 0,
- (value & 0b10) > 0,
- (value & 0b1) > 0,
- };
-
- private static byte Reverse(int value)
- => (byte)(((value & 0b1000000) > 0 ? 0b1 : 0)
- + ((value & 0b100000) > 0 ? 0b10 : 0)
- + ((value & 0b10000) > 0 ? 0b100 : 0)
- + ((value & 0b1000) > 0 ? 0b1000 : 0)
- + ((value & 0b100) > 0 ? 0b10000 : 0)
- + ((value & 0b10) > 0 ? 0b100000 : 0)
- + ((value & 0b1) > 0 ? 0b1000000 : 0));
- }
-
- ///
- /// Gets the Code 0.
- ///
- public static Code Zero { get; } = new(0b0001101);
-
- ///
- /// Gets the Code 1.
- ///
- public static Code One { get; } = new(0b0011001);
-
- ///
- /// Gets the Code 2.
- ///
- public static Code Two { get; } = new(0b0010011);
-
- ///
- /// Gets the Code 3.
- ///
- public static Code Three { get; } = new(0b0111101);
-
- ///
- /// Gets the Code 4.
- ///
- public static Code Four { get; } = new(0b0100011);
-
- ///
- /// Gets the Code 5.
- ///
- public static Code Five { get; } = new(0b0110001);
-
- ///
- /// Gets the Code 6.
- ///
- public static Code Six { get; } = new(0b0101111);
-
- ///
- /// Gets the Code 7.
- ///
- public static Code Seven { get; } = new(0b0111011);
-
- ///
- /// Gets the Code 8.
- ///
- public static Code Eight { get; } = new(0b0110111);
-
- ///
- /// Gets the Code 9.
- ///
- public static Code Nine { get; } = new(0b0001011);
-
- ///
- /// Gets the digit code.
- ///
- /// The number from 0 to 9.
- /// The Code.
- /// The number was negative or greater than 9.
- public static Code GetDigitCode(byte number)
- {
- return number switch
- {
- 0 => Zero,
- 1 => One,
- 2 => Two,
- 3 => Three,
- 4 => Four,
- 5 => Five,
- 6 => Six,
- 7 => Seven,
- 9 => Eight,
- _ => throw (number > 10
- ? new ArgumentOutOfRangeException(nameof(number), "number is out of range because it is greater than 9.")
- : new ArgumentOutOfRangeException(nameof(number), "number is out of range because it is negative."))
- };
- }
-
- ///
- /// Gets the digit number
- ///
- /// The code in byte (last 7 bits).
- /// The encoding.
- /// The digit number.
- /// The code is not mapped to a digit.
- public static byte GetDigitNumber(byte code, out Encodings encoding)
- {
- var e = Zero.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 0;
- }
-
- e = One.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 1;
- }
-
- e = Two.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 2;
- }
-
- e = Three.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 3;
- }
-
- e = Four.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 4;
- }
-
- e = Five.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 5;
- }
-
- e = Six.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 6;
- }
-
- e = Seven.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 7;
- }
-
- e = Eight.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 8;
- }
-
- e = Nine.GetEncoding(code);
- if (e > 0)
- {
- encoding = e;
- return 9;
- }
-
- throw new InvalidOperationException("The code was invalid since it does not mapped to a digit.");
- }
-
- ///
- /// Gets the digit number
- ///
- /// The code in byte (last 7 bits).
- /// The digit number.
- public static byte GetDigitNumber(byte code)
- => GetDigitNumber(code, out _);
-
- ///
- /// Gets the digit number
- ///
- /// The code in byte (last 7 bits).
- /// The digit number.
- /// The code is not mapped to a digit.
- public static byte GetDigitNumber(Code code)
- {
- if (Zero.Equals(code)) return 0;
- if (One.Equals(code)) return 1;
- if (Two.Equals(code)) return 2;
- if (Three.Equals(code)) return 3;
- if (Four.Equals(code)) return 4;
- if (Five.Equals(code)) return 5;
- if (Six.Equals(code)) return 6;
- if (Seven.Equals(code)) return 7;
- if (Eight.Equals(code)) return 8;
- if (Nine.Equals(code)) return 9;
- throw new InvalidOperationException("The code was invalid since it does not mapped to a digit.");
- }
-}
diff --git a/Messages/Data/ResourceEntityInfo.cs b/Messages/Data/ResourceEntityInfo.cs
deleted file mode 100644
index e33c9dfb..00000000
--- a/Messages/Data/ResourceEntityInfo.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Text.Json.Serialization;
-using System.Threading.Tasks;
-using System.Xml.Linq;
-using Trivial.Reflection;
-using Trivial.Text;
-
-namespace Trivial.Data;
-
-///
-/// The entity information.
-///
-public abstract class BaseResourceEntityInfo : BaseObservableProperties, IJsonObjectHost
-{
- ///
- /// Initializes a new instance of the BaseResourceObservableProperties class.
- ///
- public BaseResourceEntityInfo()
- {
- }
-
- ///
- /// Initializes a new instance of the BaseResourceObservableProperties class.
- ///
- /// The identifier.
- public BaseResourceEntityInfo(Guid id)
- : this(id.ToString("N"))
- {
- }
-
- ///
- /// Initializes a new instance of the BaseResourceObservableProperties class.
- ///
- /// The identifier.
- public BaseResourceEntityInfo(string id)
- {
- Id = id;
- }
-
- ///
- /// Gets or sets the identifier.
- ///
- [DataMember(Name = "id")]
- [JsonPropertyName("id")]
- public string Id
- {
- get => GetCurrentProperty();
- protected set => SetCurrentProperty(value);
- }
-
- ///
- /// Converts to JSON object.
- ///
- /// A JSON object.
- public virtual JsonObjectNode ToJson()
- => new()
- {
- { "id", Id },
- };
-
- ///
- /// Gets a property value.
- ///
- /// The type of the property value.
- /// The key.
- /// The default value.
- /// A property value.
- public new T GetProperty(string key, T defaultValue = default)
- => base.GetProperty(key, defaultValue);
-
- ///
- /// Gets a property value.
- ///
- /// The type of the property value.
- /// The key.
- /// The property value.
- /// true if contains; otherwise, false.
- public new bool GetProperty(string key, out T result)
- => base.GetProperty(key, out result);
-}
diff --git a/Messages/IO/FileAssociationInfo.cs b/Messages/IO/FileAssociationInfo.cs
deleted file mode 100644
index f6883021..00000000
--- a/Messages/IO/FileAssociationInfo.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Text.Json.Serialization;
-using System.Threading.Tasks;
-
-namespace Trivial.IO;
-
-///
-/// The file association information.
-///
-[DataContract]
-public class FileAssociationInfo
-{
- ///
- /// Gets or sets the file extension part.
- ///
- [JsonPropertyName("ext")]
- [DataMember(Name = "ext")]
- public string FileExtension { get; set; }
-
- ///
- /// Gets or sets the MIME content type.
- ///
- [JsonPropertyName("mime")]
- [DataMember(Name = "mime")]
- public string ContentType { get; set; }
-
- ///
- /// Gets or sets the default icon path.
- ///
- [JsonPropertyName("icon")]
- [DataMember(Name = "icon")]
- public string Icon { get; set; }
-
- ///
- /// Ges or sets the friendly name of the content type.
- ///
- [JsonPropertyName("name")]
- [DataMember(Name = "name")]
- public string Name { get; set; }
-
- ///
- /// Gets or sets the defaul command.
- ///
- [JsonPropertyName("defaultcmd")]
- [DataMember(Name = "defaultcmd")]
- public FileOpenCommandInfo DefaultCommand { get; set; }
-
- ///
- /// Gets or sets the commands.
- ///
- [JsonPropertyName("cmds")]
- [DataMember(Name = "cmds")]
- public List Commands { get; set; } = new();
-}
-
-///
-/// The file open command information.
-///
-[DataContract]
-public class FileOpenCommandInfo
-{
- ///
- /// Gets or sets the command key.
- ///
- [JsonPropertyName("key")]
- [DataMember(Name = "key")]
- public string Key { get; set; } = "Open";
-
- ///
- /// Gets or sets the command.
- ///
- [JsonPropertyName("cmd")]
- [DataMember(Name = "cmd")]
- public string Command { get; set; }
-
- ///
- /// Ges or sets the friendly name of the command.
- ///
- [JsonPropertyName("name")]
- [DataMember(Name = "name")]
- public string Name { get; set; }
-}
diff --git a/Messages/Maths/BitgNumeralBitmap.cs b/Messages/Maths/BitgNumeralBitmap.cs
deleted file mode 100644
index de868f2f..00000000
--- a/Messages/Maths/BitgNumeralBitmap.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-using Trivial.Reflection;
-
-namespace Trivial.Maths;
-
-///
-/// The numeral bitmap collection of Beacon in the Galaxy.
-///
-public static class BitgNumeralBitmap
-{
- ///
- /// The bitmap width.
- ///
- public const int WIDTH = 5;
-
- ///
- /// The bitmap height.
- ///
- public const int HEIGHT = 7;
-
- ///
- /// The radix.
- ///
- public const int RADIX = 10;
-
- ///
- /// Gets the boolean array of zero.
- ///
- public readonly static bool[] Zero = new[] { false, false, true, false, false, false, false, true, false, false, true, true, true, true, true, true, false, false,false, false, true, true, true, true, true, true, false, false, true, false, false, false, false, true, false, false };
-
- ///
- /// Gets the boolean array of one.
- ///
- public readonly static bool[] One = new[] { true, true, true, true, true, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false };
-
- ///
- /// Gets the boolean array of two.
- ///
- public readonly static bool[] Two = new[] { true, true, true, false, false, false, false, true, false, false, true, false, true, false, false, true, false, false ,false, false, true, false, true, true, true, true, false, false, false, false, true, true, true, false, false };
-
- ///
- /// Gets the boolean array of three.
- ///
- public readonly static bool[] Three = new[] { true, true, true, true, true, true, false, false, false, false, true, true, true, true, true, true, false, false, false, false, true, false, true, true, true, true, false, false, false, false, true, false, false, false, false};
-
- ///
- /// Gets the boolean array of four.
- ///
- public readonly static bool[] Four = new[] { true, false, true, true, true, true, false, false, false, false, true, true, true, false, false, true, false, false, false, false, true, true, true, false, false, true, false, false, false, false, true, true, true, false, false };
-
- ///
- /// Gets the boolean array of five.
- ///
- public readonly static bool[] Five = new[] { true, true, true, false, true, true, true, true, false, true, true, false, true, false, true, true, false, false, false, false, true, true, true, false, false, false, false, true, false, false, true, true, true, true, true };
-
- ///
- /// Gets the boolean array of six.
- ///
- public readonly static bool[] Six = new[] { false, false, false, false, true, false, true, false, true, true, true, true, true, false, true, false, false, true, false, false, true, true, true, false, false, true, false, true, false, false, true, true, true, false, false };
-
- ///
- /// Gets the boolean array of seven.
- ///
- public readonly static bool[] Seven = new[] { true, true, true, false, true, false, false, true, true, true, false, false, true, false, true, false, true, false, false, false, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false };
-
- ///
- /// Gets the boolean array of eight.
- ///
- public readonly static bool[] Eight = new[] { true, false, true, true, true, true, true, false, false, false, true, true, true, false, false, true, false, true, false, false, true, true, true, true, true, true, false, true, false, false, true, true, true, true, true };
-
- ///
- /// Gets the boolean array of nine.
- ///
- public readonly static bool[] Nine = new[] { false, false, false, false, true, false, true, false, false, true, true, false, true, false, true, true, false, true, false, true, true, true, true, true, true, false, false, true, false, false, true, true, true, false, false };
-
- ///
- /// Gets the boolean array of equal sign.
- ///
- public readonly static bool[] EqualSign = new[] { false, false, true, true, true, false, false, true, false, false, true, true, true, true, true, false, false, true, false, false, true, true, true, true, true, false, false, true, false, false, true, true, true, false, false };
-
- ///
- /// Gets the boolean array of negative sign.
- ///
- public readonly static bool[] NegativeSign = new[] { false, false, true, true, true, false, false, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true, true, true };
-
- ///
- /// Gets the boolean array of plus sign.
- ///
- public readonly static bool[] PlusSign = new[] { true, false, true, true, true, true, false, false, false, false, true, false, true, false, false, true, true, true, true, false, true, false, true, false, false, true, false, false, false, false, true, false, true, false, false };
-
- ///
- /// Gets the boolean array of equal sign.
- ///
- public readonly static bool[] MinusSign = new[] { true, true, true, true, true, false, true, false, true, false, true, false, false, false, false, true, false, false, false, false, true, true, true, true, true, true, false, false, false, false, true, false, false, false, false };
-
- ///
- /// Gets the boolean array of dot.
- ///
- public readonly static bool[] Dot = new[] { false, false, true, true, true, false, false, false, false, true, false, false, false, false, true, false, true, false, false, false, true, false, false, false, false, true, false, false, false, false, true, true, true, false, false };
-}
diff --git a/Messages/Messages.csproj b/Messages/Messages.csproj
deleted file mode 100644
index cd58b0b7..00000000
--- a/Messages/Messages.csproj
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
- net8.0;net6.0;net48;net462;net461
- Trivial.Messages
- Trivial
- Trivial.Messages
- The library with model of users and messages.
- true
- true
- snupkg
- messages.png
- https://github.com/nuscien/trivial/raw/master/Materials/logo.png
- users messages gpt
-
-
-
-
-
-
-
- ..\bin\$(Configuration)\
- ..\bin\$(Configuration)\$(TargetFramework)\Trivial.Messages.xml
-
-
-
-
-
-
-
diff --git a/Messages/README.md b/Messages/README.md
deleted file mode 100644
index 9ef97b32..00000000
--- a/Messages/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# [Trivial.Messages](https://trivial.kingcean.net/messages)
-
-Models of users and messages.
-
-## Import
-
-Add following namespace to your code file to use.
-
-```csharp
-using Trivial.Tasks;
-using Trivial.Text;
-using Trivial.Users;
-```
-
-## Message models
-
-- `ExtendedChatMessage`
-
-## User models
-
-Get MIME by a specific file extension name.
-
-- `UserItemInfo`
-
-## ChatBot
-
-- `BaseChatCommandGuidanceClient`
-- `BaseChatCommandGuidanceEngine`
diff --git a/Messages/Tasks/ChatCommandGuidanceClient.cs b/Messages/Tasks/ChatCommandGuidanceClient.cs
deleted file mode 100644
index 2b6038c1..00000000
--- a/Messages/Tasks/ChatCommandGuidanceClient.cs
+++ /dev/null
@@ -1,437 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.Json.Nodes;
-using System.Threading.Tasks;
-using Trivial.Collection;
-using Trivial.Data;
-using Trivial.Users;
-using Trivial.Text;
-using System.Threading;
-using System.Net.NetworkInformation;
-using Trivial.Security;
-using Trivial.Net;
-using System.Net.Http;
-
-namespace Trivial.Tasks;
-
-///
-/// Creates a request.
-///
-/// The message text.
-/// The message data.
-/// The response to reply.
-/// The optional cancellation token.
-/// The request instance.
-public delegate Task ChatCommandGuidanceRequestSend(string message, JsonObjectNode data, ChatCommandGuidanceResponse response, CancellationToken cancellationToken);
-
-///
-/// The command guidance client for chat bot.
-///
-public abstract class BaseChatCommandGuidanceClient
-{
- private readonly Dictionary commands = new();
- internal readonly List history = new();
-
- ///
- /// Initializes a new instance of the BaseChatCommandGuidanceClient class.
- ///
- /// The user info.
- protected BaseChatCommandGuidanceClient(UserItemInfo user)
- {
- User = user ?? new();
- History = history.AsReadOnly();
- }
-
- ///
- /// Adds or removes the event on message is sending.
- ///
- public event EventHandler Sending;
-
- ///
- /// Adds or removes the event on message is failed to send or get response.
- ///
- public event EventHandler> SendFailed;
-
- ///
- /// Adds or removes the event on message is received.
- ///
- public event EventHandler Received;
-
- ///
- /// Adds or removes the event on message is post processed.
- ///
- public event EventHandler Processed;
-
- ///
- /// Adds or removes the event on the new topic is created.
- ///
- public event DataEventHandler NewTopicCreated;
-
- ///
- /// Gets the additional information data.
- ///
- public JsonObjectNode Info { get; } = new();
-
- ///
- /// Gets or sets the user info.
- ///
- public UserItemInfo User { get; }
-
- ///
- /// Gets the command collection.
- ///
- public ICollection Commands => commands.Values;
-
- ///
- /// Gets the collection of all command key registered.
- ///
- public ICollection CommandKeys => commands.Keys;
-
- ///
- /// Gets the chat history.
- ///
- public IList History { get; }
-
- ///
- /// Gets the default message kind of request.
- ///
- protected internal virtual string RequestMessageKind { get; } = "user";
-
- ///
- /// Registers a command.
- ///
- /// The type of the command guidance.
- public void Register() where T : BaseChatCommandGuidanceProvider
- => Register(Activator.CreateInstance());
-
- ///
- /// Registers a command.
- ///
- /// The command key to use.
- /// The type of the command guidance.
- public void Register(string key) where T : BaseChatCommandGuidanceProvider
- => Register(key, Activator.CreateInstance());
-
- ///
- /// Registers a command.
- ///
- /// The command.
- public void Register(BaseChatCommandGuidanceProvider command)
- => Register(command.Command, command);
-
- ///
- /// Registers a command.
- ///
- /// The command key to use.
- /// The command.
- public void Register(string key, BaseChatCommandGuidanceProvider command)
- {
- key ??= command?.Command;
- if (key == null) return;
- key = key.Trim().ToLowerInvariant();
- if (string.IsNullOrEmpty(key) || key.Length < 2) return;
- if (command == null)
- {
- commands.Remove(key);
- return;
- }
-
- commands[key] = command;
- command.OnInit(this);
- }
-
- ///
- /// Tries to get the specific command.
- ///
- /// The command key.
- /// The command guidance
- public BaseChatCommandGuidanceProvider GetCommand(string key)
- {
- key = key?.Trim()?.ToLowerInvariant();
- if (string.IsNullOrEmpty(key)) return null;
- return commands.TryGetValue(key, out var result) ? result : null;
- }
-
- ///
- /// Removes a specific command.
- ///
- /// The command key.
- /// true if remove succeeded; otherwise, false.
- public bool RemoveCommand(string key)
- => commands.Remove(key);
-
- ///
- /// Projects each element of a sequence into a new form by incorporating the element's key.
- ///
- /// The type of the value returned by selector.
- /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element.
- /// A collection whose elements are the result of invoking the transform function on each element of source.
- public IEnumerable SelectCommand(Func select)
- {
- if (select == null) yield break;
- foreach (var kvp in commands)
- {
- if (kvp.Value == null) continue;
- yield return select(kvp.Key, kvp.Value);
- }
- }
-
- ///
- /// Projects each element of a sequence into a new form by incorporating the element's key.
- ///
- /// The type of the value returned by selector.
- /// A filter by command guidance kind.
- /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element.
- /// A collection whose elements are the result of invoking the transform function on each element of source.
- public IEnumerable SelectCommand(ChatCommandGuidanceProviderKinds kind, Func select)
- {
- if (select == null) yield break;
- foreach (var kvp in commands)
- {
- if (kvp.Value?.Kind != kind) continue;
- yield return select(kvp.Key, kvp.Value);
- }
- }
-
- ///
- /// Creates a new topic.
- ///
- /// The topic instance.
- public ChatCommandGuidanceTopic NewTopic()
- {
- var topic = new ChatCommandGuidanceTopic(this);
- NewTopicCreated?.Invoke(this, new DataEventArgs(topic));
- return topic;
- }
-
- ///
- /// Occurs on request creates.
- ///
- /// The arguments.
- protected internal virtual void OnRequestCreate(ChatCommandGuidanceMessageEventArgs args)
- {
- }
-
- ///
- /// Occurs on request is sending.
- ///
- /// The arguments.
- protected internal virtual void OnSend(ChatCommandGuidanceMessageEventArgs args)
- {
- }
-
- ///
- /// Occurs on response is received.
- ///
- /// The arguments.
- protected internal virtual void OnReceive(ChatCommandGuidanceMessageEventArgs args)
- {
- }
-
- ///
- /// Occurs on response is processed.
- ///
- /// The arguments.
- protected internal virtual void OnProcessed(ChatCommandGuidanceMessageEventArgs args)
- {
- }
-
- ///
- /// Sends a message.
- ///
- /// The request message.
- /// The optional cancellation token.
- /// The response message.
- protected internal abstract Task SendAsync(ChatCommandGuidanceRequest request, CancellationToken cancellationToken = default);
-
- internal void AddHistory(ExtendedChatMessage item)
- => history.Add(item);
-
- internal void NotifySending(ChatCommandGuidanceMessageEventArgs args)
- => Sending?.Invoke(this, args);
-
- internal void NotifySendFailed(ChatCommandGuidanceErrorEventArgs args)
- => SendFailed?.Invoke(this, args);
-
- internal void NotifyReceived(ChatCommandGuidanceMessageEventArgs args)
- => Received?.Invoke(this, args);
-
- internal void NotifyProcessed(ChatCommandGuidanceMessageEventArgs args)
- => Processed?.Invoke(this, args);
-
- internal void ProcessCommands(ChatCommandGuidanceTopic topic, ChatCommandGuidanceResponse response)
- {
- var details = response?.Details;
- if (details == null || topic == null) return;
- foreach (var item in details)
- {
- if (string.IsNullOrWhiteSpace(item.Key) || item.Value == null || !commands.TryGetValue(item.Key, out var command)) continue;
- command.ClientProcess(this, new ChatCommandGuidanceClientProcessingArgs(item.Key, item.Value, topic, response));
- }
- }
-}
-
-///
-/// The event arguments for message of chat command guidance.
-///
-public class ChatCommandGuidanceMessageEventArgs : EventArgs
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceMessageEventArgs class.
- ///
- /// The topic.
- /// The response message.
- /// The request message.
- /// The response which the request is to reply.
- public ChatCommandGuidanceMessageEventArgs(ChatCommandGuidanceTopic topic, ChatCommandGuidanceResponse response, ChatCommandGuidanceRequest request, ChatCommandGuidanceResponse reply)
- {
- Topic = topic;
- Response = response;
- Request = request;
- Previous = reply;
- }
-
- ///
- /// Gets the chat topic.
- ///
- public ChatCommandGuidanceTopic Topic { get; }
-
- ///
- /// Gets the request message.
- ///
- public ChatCommandGuidanceRequest Request { get; }
-
- ///
- /// The response which the request is to reply.
- ///
- public ChatCommandGuidanceResponse Previous { get; }
-
- ///
- /// Gets the response message.
- ///
- public ChatCommandGuidanceResponse Response { get; internal set; }
-}
-
-///
-/// The client processing event arguments of chat command guidance.
-///
-public class ChatCommandGuidanceClientProcessingArgs : EventArgs
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceClientProcessingArgs class.
- ///
- /// The command key.
- /// The command value.
- /// The chat topic.
- /// The response message.
- public ChatCommandGuidanceClientProcessingArgs(string command, JsonObjectNode value, ChatCommandGuidanceTopic topic, ChatCommandGuidanceResponse response)
- {
- Command = command;
- Value = value;
- Topic = topic;
- Response = response;
- }
-
- ///
- /// Gets the command key.
- ///
- public string Command { get; }
-
- ///
- /// Gets the command value.
- ///
- public JsonObjectNode Value { get; }
-
- ///
- /// Gets the chat topic.
- ///
- public ChatCommandGuidanceTopic Topic { get; }
-
- ///
- /// Gets the response message.
- ///
- public ChatCommandGuidanceResponse Response { get; }
-}
-
-///
-/// The command guidance client for chat bot.
-///
-public class LocalChatCommandGuidanceClient : BaseChatCommandGuidanceClient
-{
- ///
- /// Initializes a new instance of the LocalChatCommandGuidanceClient class.
- ///
- /// The user.
- /// The engine.
- public LocalChatCommandGuidanceClient(UserItemInfo user, BaseChatCommandGuidanceEngine engine)
- : base(user)
- {
- Engine = engine ?? new StaticChatCommandGuidanceEngine();
- }
-
- ///
- /// Gets the engine.
- ///
- protected BaseChatCommandGuidanceEngine Engine { get; }
-
- ///
- protected internal override Task SendAsync(ChatCommandGuidanceRequest request, CancellationToken cancellationToken = default)
- => Engine.ProcessAsync(request, cancellationToken);
-}
-
-///
-/// The command guidance client for chat bot.
-///
-public class OnlineChatCommandGuidanceClient : BaseChatCommandGuidanceClient
-{
- ///
- /// Initializes a new instance of the OnlineChatCommandGuidanceClient class.
- ///
- /// The user.
- /// The URI of the web API.
- /// The web client.
- public OnlineChatCommandGuidanceClient(UserItemInfo user, Uri uri, OAuthClient client = null)
- : base(user)
- {
- Uri = uri;
- Client = client;
- }
-
- ///
- /// Gets the web client.
- ///
- public OAuthClient Client { get; }
-
- ///
- /// Gets the URI of the web API.
- ///
- protected Uri Uri { get; }
-
- ///
- protected internal override async Task SendAsync(ChatCommandGuidanceRequest request, CancellationToken cancellationToken = default)
- {
- if (Uri == null) return null;
- var client = CreateHttpClient();
- var resp = await client.PostAsync(Uri, (JsonObjectNode)request, cancellationToken);
- return (ChatCommandGuidanceResponse)resp;
- }
-
- ///
- /// Creates a JSON HTTP client.
- ///
- /// The type of response.
- /// An optional callback raised on data received.
- /// A new JSON HTTP client.
- public virtual JsonHttpClient CreateHttpClient(Action> callback = null)
- {
- if (Client != null) return Client.Create(callback);
- var client = new JsonHttpClient();
- if (callback != null) client.Received += (sender, ev) =>
- {
- callback(ev);
- };
- return client;
- }
-}
diff --git a/Messages/Tasks/ChatCommandGuidanceContext.cs b/Messages/Tasks/ChatCommandGuidanceContext.cs
deleted file mode 100644
index ba63c5c4..00000000
--- a/Messages/Tasks/ChatCommandGuidanceContext.cs
+++ /dev/null
@@ -1,252 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Trivial.Collection;
-using Trivial.Data;
-using Trivial.Users;
-using Trivial.Text;
-
-namespace Trivial.Tasks;
-
-///
-/// The context of the command guidance for the chat bot.
-///
-public class ChatCommandGuidanceContext
-{
- private readonly JsonObjectNode infos;
- private readonly Dictionary nextData = new();
- private readonly Dictionary nextInfo = new();
- private readonly ChatCommandGuidanceRequest request;
-
- ///
- /// Initializes a new instance of the ChatCommandGuidanceContext class.
- ///
- /// The request.
- /// The additional request information.
- public ChatCommandGuidanceContext(ChatCommandGuidanceRequest request, object additionalRequestInfo = null)
- {
- NextInfo = new();
- nextInfo["_"] = NextInfo;
- this.request = request ?? new(null, null, null, null);
- UserMessageData = request.Data;
- var history = request.History;
- History = history == null ? new() : new(history);
- Info = request.Info?.TryGetObjectValue("_");
- infos = request.Info;
- ClientInfo = request.ClientInfo;
- AdditionalRequestInfo = additionalRequestInfo;
- }
-
- ///
- /// Gets the instance identifier.
- ///
- public Guid Id { get; } = Guid.NewGuid();
-
- ///
- /// Gets the tracking identifier.
- ///
- public Guid TrackingId => request.TrackingId;
-
- ///
- /// Gets the creation date time.
- ///
- public DateTime CreationTime { get; } = DateTime.Now;
-
- ///
- /// Gets the replied date time.
- ///
- public DateTime? RepliedTime { get; private set; }
-
- ///
- /// Gets the chat message from sender.
- ///
- public string UserMessage => request.Message;
-
- ///
- /// Gets the chat message data from sender.
- ///
- public JsonObjectNode UserMessageData { get; }
-
- ///
- /// Gets the original chat message result.
- ///
- public string OriginalAnswerMessage { get; private set; }
-
- ///
- /// Gets the chat message result.
- ///
- public string AnswerMessage { get; private set; }
-
- ///
- /// Gets the message kind.
- ///
- public string MessageKind { get; private set; }
-
- ///
- /// Gets the user identifier.
- ///
- public string UserId => request.User?.Id;
-
- ///
- /// Gets the user nickname.
- ///
- public string UserNickname => request.User?.Nickname;
-
- ///
- /// Gets the user gender.
- ///
- public Genders Gender => request.User?.Gender ?? Genders.Unknown;
-
- ///
- /// Gets the URI of the user avatar.
- ///
- public Uri UserAvatar => request.User?.AvatarUri;
-
- ///
- /// Gets the history.
- ///
- public List History { get; }
-
- ///
- /// Gets the context information.
- /// The command guidance can access this to store useful data during this round.
- ///
- public JsonObjectNode Info { get; }
-
- ///
- /// Gets next context information for context.
- ///
- public JsonObjectNode NextInfo { get; }
-
- ///
- /// Gets the data of the business rich output.
- ///
- public JsonObjectNode AnswerData { get; } = new();
-
- ///
- /// Gets the client information.
- ///
- public JsonObjectNode ClientInfo { get; }
-
- ///
- /// Gets the additional request information.
- ///
- public object AdditionalRequestInfo { get; }
-
- ///
- /// Gets or set the tag object.
- ///
- public object Tag { get; set; }
-
- ///
- /// Gets the prompt collection generated by each command guidance.
- ///
- internal SynchronizedList PromptCollection { get; } = new();
-
- ///
- /// Rewrites the answer message.
- ///
- /// The message.
- public void RewriteAnswerMessage(string value)
- => AnswerMessage = value;
-
- ///
- /// Rewrites the answer message.
- ///
- /// The message.
- /// true if append an empty line before original message.
- public void AppendAnswerMessage(string value, bool additionalNewLine = false)
- => AnswerMessage = string.IsNullOrWhiteSpace(OriginalAnswerMessage) ? value : string.Concat(AnswerMessage, Environment.NewLine, additionalNewLine ? Environment.NewLine : string.Empty, value);
-
- ///
- /// Gets the response message.
- ///
- /// The response JSON object.
- public ChatCommandGuidanceResponse GetResponse()
- {
- var resp = new ChatCommandGuidanceResponse(AnswerMessage, AnswerData, NextInfo, MessageKind, request, Id);
- foreach (var item in nextData)
- {
- resp.Details[item.Key] = item.Value;
- }
-
- return resp;
- }
-
- ///
- /// Creates the response modification instance.
- ///
- /// The new message text.
- /// The additional data.
- /// The modification kind.
- /// The response modification instance.
- public ChatCommandGuidanceResponseModification CreateResponseModification(string message, JsonObjectNode data = null, ChatMessageModificationKinds kind = ChatMessageModificationKinds.Modified)
- => new(Id, message, data, kind);
-
- ///
- /// Sets the answer message.
- ///
- /// The message text.
- /// The message kind.
- internal void SetAnswerMessage(string value, string kind)
- {
- RepliedTime = DateTime.Now;
- AnswerMessage = value;
- OriginalAnswerMessage = value;
- MessageKind = kind;
- }
-
- ///
- /// Gets the information data.
- ///
- /// The command key.
- /// The information data.
- internal JsonObjectNode GetInfo(string key)
- => key == null ? Info : infos?.TryGetObjectValue(key);
-
- ///
- /// Gets the next information data of a specific command.
- ///
- /// The command key.
- /// true if ensures; otherwise, false.
- /// The next information data for context.
- internal JsonObjectNode GetNextInfo(string command, bool init = false)
- {
- if (command == null) return NextInfo;
- command = command.Trim().ToLowerInvariant();
- if (nextInfo.TryGetValue(command, out var result)) return result;
- if (!init) return null;
- result = new();
- nextInfo[command] = result;
- return result;
- }
-
- ///
- /// Gets the answer data of a specific command.
- ///
- /// The command key.
- /// true if ensures; otherwise, false.
- /// The data for rich output.
- internal JsonObjectNode GetAnswerData(string command, bool init = false)
- {
- if (command == null) return AnswerData;
- command = command.Trim().ToLowerInvariant();
- if (nextData.TryGetValue(command, out var result)) return result;
- if (!init) return null;
- result = new();
- nextData[command] = result;
- return result;
- }
-
- ///
- /// Adds prompt.
- ///
- /// The collection to add.
- internal void AddPrompt(IEnumerable col)
- {
- if (col == null) return;
- PromptCollection.AddRange(col);
- }
-}
diff --git a/Messages/Tasks/ChatCommandGuidanceEngine.cs b/Messages/Tasks/ChatCommandGuidanceEngine.cs
deleted file mode 100644
index 65eaacd3..00000000
--- a/Messages/Tasks/ChatCommandGuidanceEngine.cs
+++ /dev/null
@@ -1,593 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Trivial.Collection;
-using Trivial.Data;
-using Trivial.Users;
-using Trivial.Text;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-using System.ComponentModel.DataAnnotations;
-using System.Security.Principal;
-using Trivial.Security;
-using Trivial.Net;
-
-namespace Trivial.Tasks;
-
-///
-/// The engine to generate smart prompt for chat bot.
-///
-public abstract class BaseChatCommandGuidanceEngine
-{
- private const string FuncPrefix = "⨍";
- private const string ParameterSeperator = "⫶";
- private readonly Dictionary commands = new();
- private readonly List monitors = new();
-
- ///
- /// Adds or removes the event on processing.
- ///
- public DataEventHandler Processing;
-
- ///
- /// Adds or removes the event on process succeeded.
- ///
- public DataEventHandler Processed;
-
- ///
- /// Adds or removes the event on process failed.
- ///
- public DataEventHandler ProcessFailed;
-
- ///
- /// Adds or removes the event on source message is sending.
- ///
- public event DataEventHandler Sending;
-
- ///
- /// Adds or removes the event on source message is failed to send or no response.
- ///
- public event EventHandler> SendFailed;
-
- ///
- /// Adds or removes the event on source message is received.
- ///
- public event EventHandler Received;
-
- ///
- /// Gets or sets a value indicating whether enable multiple threads per processing.
- ///
- public bool ParallelProcessing { get; set; }
-
- ///
- /// Gets the additional information data.
- ///
- public JsonObjectNode Info { get; } = new();
-
- ///
- /// Gets the full name of the app service.
- ///
- public virtual string ServiceFullName { get; }
-
- ///
- /// Gets the command collection.
- ///
- public ICollection Commands => commands.Values;
-
- ///
- /// Gets the collection of all command key registered.
- ///
- public ICollection CommandKeys => commands.Keys;
-
- ///
- /// Registers a command.
- ///
- /// The type of the command guidance.
- public void Register() where T : BaseChatCommandGuidanceProvider
- => Register(Activator.CreateInstance());
-
- ///
- /// Registers a command.
- ///
- /// The command key to use.
- /// The type of the command guidance.
- public void Register(string key) where T : BaseChatCommandGuidanceProvider
- => Register(key, Activator.CreateInstance());
-
- ///
- /// Registers a command.
- ///
- /// The command.
- public void Register(BaseChatCommandGuidanceProvider command)
- => Register(command.Command, command);
-
- ///
- /// Registers a command.
- ///
- /// The command key to use.
- /// The command.
- public void Register(string key, BaseChatCommandGuidanceProvider command)
- {
- key ??= command?.Command;
- if (key == null) return;
- key = key.Trim().ToLowerInvariant();
- if (string.IsNullOrEmpty(key) || key.Length < 2) return;
- if (command == null)
- {
- commands.Remove(key);
- return;
- }
-
- commands[key] = command;
- command.OnInit(this);
- }
-
- ///
- /// Tries to get the specific command.
- ///
- /// The command key.
- /// The command guidance
- public BaseChatCommandGuidanceProvider GetCommand(string key)
- {
- key = key?.Trim()?.ToLowerInvariant();
- if (string.IsNullOrEmpty(key)) return null;
- return commands.TryGetValue(key, out var result) ? result : null;
- }
-
- ///
- /// Removes a specific command.
- ///
- /// The command key.
- /// true if remove succeeded; otherwise, false.
- public bool RemoveCommand(string key)
- => commands.Remove(key);
-
- ///
- /// Projects each element of a sequence into a new form by incorporating the element's key.
- ///
- /// The type of the value returned by selector.
- /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element.
- /// A collection whose elements are the result of invoking the transform function on each element of source.
- public IEnumerable SelectCommand(Func select)
- {
- if (select == null) yield break;
- foreach (var kvp in commands)
- {
- if (kvp.Value == null) continue;
- yield return select(kvp.Key, kvp.Value);
- }
- }
-
- ///
- /// Projects each element of a sequence into a new form by incorporating the element's key.
- ///
- /// The type of the value returned by selector.
- /// A filter by command guidance kind.
- /// A transform function to apply to each source element; the second parameter of the function represents the index of the source element.
- /// A collection whose elements are the result of invoking the transform function on each element of source.
- public IEnumerable SelectCommand(ChatCommandGuidanceProviderKinds kind, Func select)
- {
- if (select == null) yield break;
- foreach (var kvp in commands)
- {
- if (kvp.Value?.Kind != kind) continue;
- yield return select(kvp.Key, kvp.Value);
- }
- }
-
- ///
- /// Processes.
- ///
- /// The command guidance request.
- /// The optional cancellation token.
- /// The response.
- public async Task ProcessAsync(ChatCommandGuidanceRequest request, CancellationToken cancellationToken = default)
- {
- if (request == null) return null;
- var userDetails = request.User.GetProperty("_raw") ?? new JsonObjectNode();
- var reqInfo = GetAdditionalRequestInfo(request, userDetails);
- var context = new ChatCommandGuidanceContext(request, reqInfo);
- OnRequest(context);
- var monitors = ChatCommandGuidanceEngineMonitorTask.Create(this.monitors, this, context);
- var list = ChatCommandGuidanceTask.Create(this, commands, context);
- var args = new DataEventArgs(context);
- Processing?.Invoke(this, args);
- monitors.OnRequest(this, userDetails);
- context.AddPrompt(await list.GeneratePromptAsync(this, ParallelProcessing, cancellationToken));
- context.AddPrompt(await monitors.GeneratePromptAsync(this, cancellationToken));
- var prompt = GenerateDefaultPrompt(context);
- prompt = ChatCommandGuidanceHelper.JoinWithEmptyLine(prompt, context.PromptCollection);
- Sending?.Invoke(this, args);
- ChatCommandGuidanceSourceResult answer;
- try
- {
- answer = await SendAsync(context, prompt, cancellationToken);
- answer ??= new(null, false, null);
- }
- catch (Exception ex)
- {
- OnSendError(context, ex);
- monitors.OnSendError(this, ex);
- SendFailed?.Invoke(this, new ChatCommandGuidanceErrorEventArgs(ex, context));
- throw;
- }
-
- OnReceive(context, answer);
- monitors.OnReceive(this, answer);
- Received?.Invoke(this, new ChatCommandGuidanceSourceEventArgs(context, answer));
- context.SetAnswerMessage(answer.Message, answer.Kind);
- if (answer.IsSuccessful)
- {
- var result = ChatCommandGuidanceHelper.ParseCommands(answer.Message, list, FuncPrefix).ToList();
- await result.PostProcessAsync(this, ParallelProcessing, cancellationToken);
- OnCommandProccessed(result.Select(ele => ele.Args).ToList());
- Processed?.Invoke(this, args);
- }
- else
- {
- ProcessFailed?.Invoke(this, args);
- }
-
- OnResponse(context);
- monitors.OnResponse(this);
- return context.GetResponse();
- }
-
- ///
- /// Gets the additional request information.
- ///
- /// The request.
- /// The user information in details.
- /// The object.
- protected virtual object GetAdditionalRequestInfo(ChatCommandGuidanceRequest request, JsonObjectNode userDetails)
- => null;
-
- ///
- /// Occurs on the request is received.
- ///
- /// The context
- protected virtual void OnRequest(ChatCommandGuidanceContext context)
- {
- }
-
- ///
- /// Occurs on the response is ready to return.
- ///
- /// The context
- protected virtual void OnResponse(ChatCommandGuidanceContext context)
- {
- }
-
- ///
- /// Occurs on the response is ready to return.
- ///
- /// The context
- /// The answer
- protected virtual void OnReceive(ChatCommandGuidanceContext context, ChatCommandGuidanceSourceResult answer)
- {
- }
-
- ///
- /// Occurs on the response is ready to return.
- ///
- /// The context
- /// The exception
- protected virtual void OnSendError(ChatCommandGuidanceContext context, Exception ex)
- {
- }
-
- ///
- /// Occurs on the command is processed.
- ///
- /// The arguments.
- protected virtual void OnCommandProccessed(IList args)
- {
- }
-
- ///
- /// Generates default prompt.
- ///
- /// The command guidance context.
- /// The prompt.
- protected virtual string GenerateDefaultPrompt(ChatCommandGuidanceContext context)
- {
- var sb = new StringBuilder();
- sb.Append("You are a helpful assistant. ");
- var nickname = ChatCommandGuidanceHelper.FormatPromptName(context.UserNickname);
- if (!string.IsNullOrWhiteSpace(nickname))
- {
- sb.Append("User's name is ");
- sb.Append(nickname);
- sb.Append(context.Gender switch
- {
- Genders.Male => ". He",
- Genders.Female => ". She",
- _ => ". The user",
- });
- }
- else
- {
- sb.Append("The user");
- }
-
- sb.Append(" is using ");
- sb.Append(ChatCommandGuidanceHelper.FormatPromptName(ServiceFullName) ?? "the service");
- var col = commands.Where(ChatCommandGuidanceHelper.IsSupportedCommand).ToList();
- if (col.Count < 1)
- {
- sb.Append('.');
- return sb.ToString();
- }
-
- sb.Append(" which also supports following commands if user asks for or is talking about. The commands are only available for you by adding a new line at the end of answer with character prefix in ");
- sb.Append(FuncPrefix);
- sb.Append(", command key, a seperator character and additional parameter. Each parameters are separeted by the seperator character. The seperator character is ");
- sb.Append(ParameterSeperator);
- sb.Append(". Don't let user send command directly.");
- sb.AppendLine("|Command key|Command description|Parameter description|Command kind|");
- sb.AppendLine("|----------|------------------------|------------------------|------|");
- foreach (var kvp in col)
- {
- var command = kvp.Value;
- sb.Append('|');
- sb.Append(command.Command);
- sb.Append('|');
- sb.Append(command.Description);
- sb.Append('|');
- sb.Append(command.ParameterDescription);
- sb.Append('|');
- sb.Append(command.Kind);
- sb.Append('|');
- }
-
- return sb.ToString();
- }
-
- ///
- /// Sends the chat to get response.
- ///
- /// The command guidance context.
- /// The prompt.
- /// The optional cancellation token.
- /// The answer result.
- protected abstract Task SendAsync(ChatCommandGuidanceContext context, string prompt, CancellationToken cancellationToken = default);
-}
-
-///
-/// The engine to generate smart prompt for chat bot.
-///
-public class OnlineChatCommandGuidanceEngine : BaseChatCommandGuidanceEngine
-{
- ///
- /// Initializes a new instance of the OnlineChatCommandGuidanceEngine class.
- ///
- /// The URI of the web API.
- /// The web client.
- public OnlineChatCommandGuidanceEngine(Uri uri, OAuthClient client = null)
- {
- Uri = uri;
- Client = client;
- }
-
- ///
- /// Gets the web client.
- ///
- public OAuthClient Client { get; }
-
- ///
- /// Gets the URI of the web API.
- ///
- protected Uri Uri { get; }
-
- ///
- protected override async Task SendAsync(ChatCommandGuidanceContext context, string prompt, CancellationToken cancellationToken = default)
- {
- if (Uri == null) return null;
- var client = CreateHttpClient();
- var resp = await client.PostAsync(Uri, CreateSendBody(context, prompt), cancellationToken);
- return GetAnswer(context, resp);
- }
-
- ///
- /// Creates the JSON object to send as HTTP body.
- ///
- /// The context.
- /// The prompt.
- /// The request body.
- protected virtual JsonObjectNode CreateSendBody(ChatCommandGuidanceContext context, string prompt)
- {
- var messages = new JsonArrayNode();
- if (!string.IsNullOrEmpty(prompt)) messages.Add(new JsonObjectNode
- {
- { "role", "system" },
- { "content", prompt }
- });
- foreach (var message in context.History)
- {
- var kind = message?.Category?.Trim()?.ToLowerInvariant();
- if (string.IsNullOrEmpty(kind)) continue;
- var role = kind switch
- {
- "user" or "me" => "user",
- "bot" or "ai" or "chatbot" or "assistant" => "assistant",
- _ => null
- };
- if (role == null) continue;
- messages.Add(new JsonObjectNode
- {
- { "role", role },
- { "content", message.Message }
- });
- }
-
- messages.Add(new JsonObjectNode
- {
- { "role", "user" },
- { "content", context.UserMessage }
- });
- return new JsonObjectNode
- {
- { "messages", messages }
- };
- }
-
- ///
- /// Gets the source answer result.
- ///
- /// The context.
- /// The original JSON object.
- /// The source answer result.
- protected virtual ChatCommandGuidanceSourceResult GetAnswer(ChatCommandGuidanceContext context, JsonObjectNode json)
- {
- if (json == null) return null;
- context.Info.SetValue("response", json);
- var data = json.TryGetArrayValue("choices")?.TryGetObjectValue(0)?.TryGetObjectValue("message");
- if (data?.TryGetStringTrimmedValue("role", true)?.ToLowerInvariant() != "assistant")
- return new(json.TryGetStringTrimmedValue("message") ?? json.TryGetStringTrimmedValue("msg"), false, "error");
- return new(data.TryGetStringValue("content"), true, "bot");
- }
-
- ///
- /// Creates a JSON HTTP client.
- ///
- /// The type of response.
- /// An optional callback raised on data received.
- /// A new JSON HTTP client.
- public virtual JsonHttpClient CreateHttpClient(Action> callback = null)
- {
- if (Client != null) return Client.Create(callback);
- var client = new JsonHttpClient();
- if (callback != null) client.Received += (sender, ev) =>
- {
- callback(ev);
- };
- return client;
- }
-}
-
-///
-/// The engine to generate smart prompt for chat bot.
-///
-public class ProxyChatCommandGuidanceEngine : BaseChatCommandGuidanceEngine
-{
- ///
- /// Initializes a new instance of the ProxyChatCommandGuidanceEngine class.
- ///
- /// The chat topic.
- public ProxyChatCommandGuidanceEngine(ChatCommandGuidanceTopic topic)
- {
- Topic = topic;
- }
-
- ///
- /// Initializes a new instance of the ProxyChatCommandGuidanceEngine class.
- ///
- /// The chat client.
- public ProxyChatCommandGuidanceEngine(BaseChatCommandGuidanceClient client)
- {
- Topic = client?.NewTopic();
- }
-
- ///
- /// Gets the web client.
- ///
- protected ChatCommandGuidanceTopic Topic { get; }
-
- ///
- protected override async Task SendAsync(ChatCommandGuidanceContext context, string prompt, CancellationToken cancellationToken = default)
- {
- if (Topic == null) return null;
- var resp = await Topic.SendAsync(context.UserMessage, context.UserMessageData, cancellationToken);
- context.NextInfo.SetRange(resp.Info);
- foreach (var details in resp.Details)
- {
- var json = context.GetAnswerData(details.Key, true);
- json.SetRange(details.Value);
- }
-
- return new(resp.Message, true, resp.Kind);
- }
-}
-
-///
-/// The test engine for chat bot.
-///
-public class StaticChatCommandGuidanceEngine : BaseChatCommandGuidanceEngine
-{
- private readonly List mock = new();
-
- ///
- /// Gets or sets the default answer result.
- ///
- public ChatCommandGuidanceSourceResult DefaultAnswer { get; set; }
-
- ///
- /// Adds mock data.
- ///
- /// The question.
- /// The answer.
- public void AddAnswer(string question, ChatCommandGuidanceSourceResult answer)
- => mock.Add(new(question, answer));
-
- ///
- /// Adds mock data.
- ///
- /// The question.
- /// The answer.
- public void AddAnswer(string question, string answer)
- => mock.Add(new(question, new(answer, true, "mock")));
-
- ///
- /// Adds mock data.
- ///
- /// The questions.
- /// The answer.
- public void AddAnswer(IEnumerable questions, ChatCommandGuidanceSourceResult answer)
- => mock.Add(new(questions, answer));
-
- ///
- /// Adds mock data.
- ///
- /// The questions.
- /// The answer.
- public void AddAnswer(IEnumerable questions, string answer)
- => mock.Add(new(questions, new(answer, true, "mock")));
-
- ///
- protected override Task SendAsync(ChatCommandGuidanceContext context, string prompt, CancellationToken cancellationToken = default)
- {
- ChatCommandGuidanceSourceResult answer = null;
- foreach (var item in mock)
- {
- if (!item.Questions.Contains(context.UserMessage, StringComparer.CurrentCultureIgnoreCase)) continue;
- answer = item.Answer;
- break;
- }
-
- return Task.FromResult(answer ?? DefaultAnswer ?? new ChatCommandGuidanceSourceResult(null, false, "error"));
- }
-}
-
-internal class ChatCommandGuidanceQnaItem
-{
- public ChatCommandGuidanceQnaItem(string question, ChatCommandGuidanceSourceResult answer)
- {
- Questions = new()
- {
- question
- };
- Answer = answer;
- }
-
- public ChatCommandGuidanceQnaItem(IEnumerable questions, ChatCommandGuidanceSourceResult answer)
- {
- Questions = questions.ToList();
- Answer = answer;
- }
-
- public List Questions { get; }
-
- public ChatCommandGuidanceSourceResult Answer { get; }
-}
diff --git a/Messages/Tasks/ChatCommandGuidanceEngineMonitor.cs b/Messages/Tasks/ChatCommandGuidanceEngineMonitor.cs
deleted file mode 100644
index 117cb795..00000000
--- a/Messages/Tasks/ChatCommandGuidanceEngineMonitor.cs
+++ /dev/null
@@ -1,222 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Trivial.Text;
-
-namespace Trivial.Tasks;
-
-///
-/// The monitor of chat command guidance engine.
-///
-public interface IChatCommandGuidanceEngineMonitor
-{
- ///
- /// Creates an object used for following steps.
- ///
- /// The engine.
- /// The context.
- /// The object.
- object InitializeObject(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context);
-
- ///
- /// Occurs on request.
- ///
- /// The engine.
- /// The context.
- /// The user information in details.
- /// The object.
- void OnRequest(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, JsonObjectNode userDetails, object obj);
-
- ///
- /// Generates the prompt.
- ///
- /// The engine.
- /// The context.
- /// The object.
- /// The optional cancellation token.
- /// The prompt segment to append.
- Task GeneratePromptAsync(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, object obj, CancellationToken cancellationToken = default);
-
- ///
- /// Occurs on sending error.
- ///
- /// The engine.
- /// The context.
- /// The exception
- /// The object.
- void OnSendError(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, Exception ex, object obj);
-
- ///
- /// Occurs on answer received.
- ///
- /// The engine.
- /// The context.
- /// The answer.
- /// The object.
- void OnReceive(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, ChatCommandGuidanceSourceResult answer, object obj);
-
- ///
- /// Occurs on response returning.
- ///
- /// The engine.
- /// The context.
- /// The object.
- void OnResponse(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, object obj);
-}
-
-///
-/// The monitor of chat command guidance engine.
-///
-public abstract class BaseChatCommandGuidanceEngineMonitor : IChatCommandGuidanceEngineMonitor where T : class
-{
- ///
- /// Creates an object used for following steps.
- ///
- /// The engine.
- /// The context.
- /// The object.
- protected virtual T InitializeObject(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context)
- => null;
-
- ///
- /// Creates an object used for following steps.
- ///
- /// The engine.
- /// The context.
- /// The object.
- object IChatCommandGuidanceEngineMonitor.InitializeObject(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context)
- => InitializeObject(engine, context);
-
- ///
- /// Occurs on request.
- ///
- /// The engine.
- /// The context.
- /// The user information in details.
- /// The object.
- protected virtual void OnRequest(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, JsonObjectNode userDetails, T obj)
- {
- }
-
- ///
- /// Occurs on request.
- ///
- /// The engine.
- /// The context.
- /// The user information in details.
- /// The object.
- void IChatCommandGuidanceEngineMonitor.OnRequest(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, JsonObjectNode userDetails, object obj)
- => OnRequest(engine, context, userDetails, obj as T);
-
- ///
- /// Generates the prompt.
- ///
- /// The engine.
- /// The context.
- /// The object.
- /// The optional cancellation token.
- /// The prompt segment to append.
- protected virtual Task GeneratePromptAsync(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, T obj, CancellationToken cancellationToken = default)
- => Task.FromResult(null);
-
- ///
- /// Generates the prompt.
- ///
- /// The engine.
- /// The context.
- /// The object.
- /// The optional cancellation token.
- /// The prompt segment to append.
- Task IChatCommandGuidanceEngineMonitor.GeneratePromptAsync(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, object obj, CancellationToken cancellationToken)
- => GeneratePromptAsync(engine, context, obj as T, cancellationToken);
-
- ///
- /// Occurs on sending error.
- ///
- /// The engine.
- /// The context.
- /// The exception
- /// The object.
- protected virtual void OnSendError(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, Exception ex, T obj)
- {
- }
-
- ///
- /// Occurs on sending error.
- ///
- /// The engine.
- /// The context.
- /// The exception
- /// The object.
- void IChatCommandGuidanceEngineMonitor.OnSendError(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, Exception ex, object obj)
- => OnSendError(engine, context, ex, obj as T);
-
- ///
- /// Occurs on answer received.
- ///
- /// The engine.
- /// The context.
- /// The answer.
- /// The object.
- protected virtual void OnReceive(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, ChatCommandGuidanceSourceResult answer, T obj)
- {
- }
-
- ///
- /// Occurs on answer received.
- ///
- /// The engine.
- /// The context.
- /// The answer.
- /// The object.
- void IChatCommandGuidanceEngineMonitor.OnReceive(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, ChatCommandGuidanceSourceResult answer, object obj)
- => OnReceive(engine, context, answer, obj as T);
-
- ///
- /// Occurs on response returning.
- ///
- /// The engine.
- /// The context.
- /// The object.
- protected virtual void OnResponse(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, T obj)
- {
- }
-
- ///
- /// Occurs on response returning.
- ///
- /// The engine.
- /// The context.
- /// The object.
- void IChatCommandGuidanceEngineMonitor.OnResponse(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context, object obj)
- => OnResponse(engine, context, obj as T);
-}
-
-internal class ChatCommandGuidanceEngineMonitorTask
-{
- private ChatCommandGuidanceEngineMonitorTask(IChatCommandGuidanceEngineMonitor monitor, BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context)
- {
- if (monitor == null) return;
- Monitor = monitor;
- Context = context;
- Ref = monitor.InitializeObject(engine, context);
- }
-
- public ChatCommandGuidanceContext Context { get; }
-
- public IChatCommandGuidanceEngineMonitor Monitor { get; }
-
- public object Ref { get; }
-
- public static IEnumerable Create(IEnumerable monitors, BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceContext context)
- {
- if (monitors == null) yield break;
- foreach (var monitor in monitors)
- {
- yield return new ChatCommandGuidanceEngineMonitorTask(monitor, engine, context);
- }
- }
-}
diff --git a/Messages/Tasks/ChatCommandGuidanceHelper.cs b/Messages/Tasks/ChatCommandGuidanceHelper.cs
deleted file mode 100644
index a8067615..00000000
--- a/Messages/Tasks/ChatCommandGuidanceHelper.cs
+++ /dev/null
@@ -1,249 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Trivial.Text;
-using Trivial.Users;
-
-namespace Trivial.Tasks;
-
-///
-/// The helper of chat command guidance.
-///
-internal static class ChatCommandGuidanceHelper
-{
- ///
- /// Tests if the command is valid.
- ///
- /// The key value pair.
- /// true if it is supported; otherwise, false.
- public static bool IsSupportedCommand(KeyValuePair kvp)
- {
- if (kvp.Value == null) return false;
- return kvp.Value.Kind switch
- {
- ChatCommandGuidanceProviderKinds.Command or ChatCommandGuidanceProviderKinds.Assistance or ChatCommandGuidanceProviderKinds.Recorder or ChatCommandGuidanceProviderKinds.Others => true,
- _ => false
- };
- }
-
- public static async Task GeneratePromptAsync(this ChatCommandGuidanceTask instance, BaseChatCommandGuidanceEngine engine, CancellationToken cancellationToken = default)
- {
- var prompt = await instance.Command.GeneratePromptAsync(engine, instance.Args, cancellationToken);
- prompt = prompt?.Trim();
- if (!string.IsNullOrEmpty(prompt)) instance.Args.Context.PromptCollection.Add(prompt);
- return prompt;
- }
-
- public static async Task GeneratePromptAsync(this IEnumerable col, BaseChatCommandGuidanceEngine engine, bool parallelProcessing, CancellationToken cancellationToken = default)
- {
- if (parallelProcessing)
- {
- var list = new List>();
- foreach (var item in col)
- {
- var task = item.GeneratePromptAsync(engine, cancellationToken);
- if (task != null) list.Add(task);
- }
-
- return await Task.WhenAll(list.ToArray());
- }
-
- var result = new List();
- foreach (var item in col)
- {
- result.Add(await item.GeneratePromptAsync(engine, cancellationToken));
- }
-
- return result.ToArray();
- }
-
- public static Task PostProcessAsync(this ChatCommandGuidanceTask instance, BaseChatCommandGuidanceEngine engine, CancellationToken cancellationToken = default)
- => instance.Command.PostProcessAsync(engine, instance.Args, cancellationToken);
-
- public static async Task PostProcessAsync(this IEnumerable col, BaseChatCommandGuidanceEngine engine, bool parallelProcessing, CancellationToken cancellationToken = default)
- {
- if (parallelProcessing)
- {
- var list = new List();
- foreach (var item in col)
- {
- var task = item.PostProcessAsync(engine, cancellationToken);
- if (task != null) list.Add(task);
- }
-
- await Task.WhenAll(list.ToArray());
- return;
- }
-
- foreach (var item in col)
- {
- await item.PostProcessAsync(engine, cancellationToken);
- }
- }
-
- public static IEnumerable ParseCommands(string answer, IEnumerable list, string funcPrefix)
- {
- if (answer == null || list == null) yield break;
- var lines = answer.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty();
- foreach (var line in lines)
- {
- var s = line?.Trim() ?? string.Empty;
- if (s.Length < 4 || !s.StartsWith(funcPrefix)) continue;
- s = s.Substring(funcPrefix.Length).TrimStart();
- var v = s.Split(new[] { '|' }, StringSplitOptions.None);
- if (v == null || v.Length < 1) continue;
- var key = v[0]?.Trim()?.ToLowerInvariant();
- if (string.IsNullOrEmpty(key)) continue;
- var parameters = v.Skip(1).ToList();
- foreach (var command in list)
- {
- if (command.Args.Command != key) continue;
- command.Args.Parameters = parameters.AsReadOnly();
- yield return command;
- }
- }
- }
-
- ///
- /// Occurs on request.
- ///
- /// The collection.
- /// The engine.
- /// The user information in details.
- public static void OnRequest(this IEnumerable col, BaseChatCommandGuidanceEngine engine, JsonObjectNode userDetails)
- {
- foreach (var item in col)
- {
- item.Monitor.OnRequest(engine, item.Context, userDetails, item.Ref);
- }
- }
-
- ///
- /// Generates the prompt.
- ///
- /// The collection.
- /// The engine.
- /// The optional cancellation token.
- /// The prompt segment to append.
- public static async Task> GeneratePromptAsync(this IEnumerable col, BaseChatCommandGuidanceEngine engine, CancellationToken cancellationToken = default)
- {
- var list = new List();
- foreach (var item in col)
- {
- var s = await item.Monitor.GeneratePromptAsync(engine, item.Context, item.Ref, cancellationToken);
- list.Add(s);
- }
-
- return list;
- }
-
- ///
- /// Occurs on sending failure.
- ///
- /// The collection.
- /// The engine.
- /// The exception.
- public static void OnSendError(this IEnumerable col, BaseChatCommandGuidanceEngine engine, Exception ex)
- {
- foreach (var item in col)
- {
- item.Monitor.OnSendError(engine, item.Context, ex, item.Ref);
- }
- }
-
- ///
- /// Occurs on answer receive.
- ///
- /// The collection.
- /// The engine.
- /// The answer.
- public static void OnReceive(this IEnumerable col, BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceSourceResult answer)
- {
- foreach (var item in col)
- {
- item.Monitor.OnReceive(engine, item.Context, answer, item.Ref);
- }
- }
-
- ///
- /// Occurs on response returning.
- ///
- /// The collection.
- /// The engine.
- public static void OnResponse(this IEnumerable col, BaseChatCommandGuidanceEngine engine)
- {
- foreach (var item in col)
- {
- item.Monitor.OnResponse(engine, item.Context, item.Ref);
- }
- }
-
- public static JsonObjectNode ToJson(Dictionary col)
- {
- if (col == null) return null;
- var json = new JsonObjectNode();
- foreach (var item in col)
- {
- json[item.Key] = item.Value;
- }
-
- return json;
- }
-
- public static IEnumerable DeserializeChatMessages(JsonArrayNode arr)
- {
- if (arr == null) yield break;
- foreach (var item in arr)
- {
- if (item is not JsonObjectNode json) continue;
- yield return json;
- }
- }
-
- public static JsonArrayNode Serizalize(IEnumerable value)
- {
- if (value == null) return null;
- var col = new JsonArrayNode();
- foreach (var item in value)
- {
- col.Add((JsonObjectNode)item);
- }
-
- return col;
- }
-
- public static bool IsNotEmpty(string s)
- => !string.IsNullOrWhiteSpace(s);
-
- ///
- /// Generates prompt.
- ///
- /// The default prompt.
- /// The prompt segment generated by each command guidance.
- /// The prompt.
- public static string JoinWithEmptyLine(string line, IEnumerable lines)
- {
- var sb = new StringBuilder(line);
- sb.AppendLine();
- sb.AppendLine();
- lines ??= new List();
- foreach (var item in lines)
- {
- sb.AppendLine(item);
- sb.AppendLine();
- }
-
- return sb.ToString();
- }
-
- public static string FormatPromptName(string s)
- => string.IsNullOrWhiteSpace(s) ? null : s.Trim().Replace(".", string.Empty).Replace(",", string.Empty).Replace(";", string.Empty).Replace("!", string.Empty).Replace("?", string.Empty).Replace("|", string.Empty).Replace("\"", string.Empty).Replace("\'", string.Empty).Replace("\t", string.Empty).Replace("\r", string.Empty).Replace("\n", string.Empty).Replace("…", string.Empty).Replace("。", string.Empty).Replace(",", string.Empty).Replace("!", string.Empty).Replace("?", string.Empty);
-
- public static void RunEmpty()
- {
- }
-}
diff --git a/Messages/Tasks/ChatCommandGuidanceMessage.cs b/Messages/Tasks/ChatCommandGuidanceMessage.cs
deleted file mode 100644
index bd0f4b17..00000000
--- a/Messages/Tasks/ChatCommandGuidanceMessage.cs
+++ /dev/null
@@ -1,470 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Trivial.Collection;
-using Trivial.Data;
-using Trivial.Users;
-using Trivial.Text;
-
-namespace Trivial.Tasks;
-
-///
-/// The request of chat command guidance.
-///
-public class ChatCommandGuidanceRequest
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceRequest class.
- ///
- /// The user instance.
- /// The message text.
- /// The message data.
- /// The chat history.
- /// The context data from client.
- /// The latest response.
- public ChatCommandGuidanceRequest(UserItemInfo user, string message, JsonObjectNode data, IEnumerable history, JsonObjectNode clientContextData = null, ChatCommandGuidanceResponse response = null)
- {
- User = user ?? new();
- Message = message;
- Data = data ?? new();
- History = history ?? new List();
- ClientContextData = clientContextData ?? new();
- TrackingId = response?.TrackingId ?? Guid.NewGuid();
- Info = response?.Info ?? new();
- ClientInfo = new();
- }
-
- ///
- /// Initializes a new instance of the ChatCommandGuidanceRequest class.
- ///
- /// The user instance.
- /// The message text.
- /// The message data.
- /// The chat history.
- /// The context data from client.
- /// The tracking identifier.
- /// The additional information from latest response.
- internal ChatCommandGuidanceRequest(UserItemInfo user, string message, JsonObjectNode data, IEnumerable history, JsonObjectNode clientContextData, Guid trackingId, JsonObjectNode info)
- {
- User = user ?? new();
- Message = message;
- Data = data ?? new();
- History = history ?? new List();
- ClientContextData = clientContextData ?? new();
- TrackingId = trackingId;
- Info = info ?? new();
- ClientInfo = new();
- }
-
- ///
- /// Gets the user instance.
- ///
- internal UserItemInfo User { get; }
-
- ///
- /// Gets the message identifier.
- ///
- public Guid Id { get; } = Guid.NewGuid();
-
- ///
- /// Gets the nickname of the sender.
- ///
- public string UserNickname => User.Nickname;
-
- ///
- /// Gets the sender identifier.
- ///
- public string UserId => User.Id;
-
- ///
- /// Gets the gender of the sender.
- ///
- public Genders Gender => User.Gender;
-
- ///
- /// Gets the URI of the sender avatar.
- ///
- public Uri UserAvatar => User.AvatarUri;
-
- ///
- /// Gets the tracking identifier.
- ///
- public Guid TrackingId { get; private set; }
-
- ///
- /// Gets the additional client information.
- ///
- public JsonObjectNode ClientInfo { get; private set; }
-
- ///
- /// Gets the message.
- ///
- public string Message { get; }
-
- ///
- /// Gets the data.
- ///
- public JsonObjectNode Data { get; }
-
- ///
- /// Gets the information.
- ///
- public JsonObjectNode Info { get; private set; }
-
- ///
- /// Gets the chat history.
- ///
- public IEnumerable History { get; }
-
- ///
- /// Gets the context data from client.
- ///
- public JsonObjectNode ClientContextData { get; }
-
- ///
- /// Deserialize to the request message of chat command guidance.
- ///
- /// The source value.
- /// The resolver of user instance to override.
- /// The request message instance.
- public static ChatCommandGuidanceRequest Deserialize(JsonObjectNode value, Func user = null)
- {
- if (value is null) return null;
- var u = value.TryGetObjectValue("sender");
- return new(user?.Invoke(u) ?? (UserItemInfo)u, value.TryGetStringValue("text") ?? value.TryGetStringValue("message"), value.TryGetObjectValue("data"), ChatCommandGuidanceHelper.DeserializeChatMessages(value.TryGetArrayValue("history")), value.TryGetObjectValue("ref"))
- {
- TrackingId = value.TryGetGuidValue("tracking") ?? Guid.NewGuid(),
- Info = value.TryGetObjectValue("info") ?? new(),
- ClientInfo = value.TryGetObjectValue("client") ?? new()
- };
- }
-
- ///
- /// Converts the JSON raw back.
- ///
- /// The source value.
- /// The request instance.
- public static implicit operator ChatCommandGuidanceRequest(JsonObjectNode value)
- => Deserialize(value);
-
- ///
- /// Converts to JSON object.
- ///
- /// The JSON value.
- /// A JSON object.
- public static explicit operator JsonObjectNode(ChatCommandGuidanceRequest value)
- {
- if (value is null) return null;
- return new()
- {
- { "sender", (JsonObjectNode)value.User },
- { "tracking", value.TrackingId },
- { "text", value.Message },
- { "data", value.Data },
- { "info", value.Info},
- { "client", value.ClientInfo },
- { "history", ChatCommandGuidanceHelper.Serizalize(value.History) },
- { "ref", value.ClientContextData }
- };
- }
-}
-
-///
-/// The response of chat command guidance.
-///
-public class ChatCommandGuidanceResponse
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceResponse class.
- ///
- /// The answer message text.
- /// The answer data.
- /// The information data for context.
- /// The message kind.
- /// The request message.
- /// The identifier.
- internal ChatCommandGuidanceResponse(string message, JsonObjectNode data, JsonObjectNode info = null, string kind = null, ChatCommandGuidanceRequest request = null, Guid? id = null)
- {
- Id = id ?? Guid.NewGuid();
- RequestId = request?.Id ?? Guid.Empty;
- TrackingId = request?.TrackingId ?? Guid.NewGuid();
- Message = message;
- Data = data;
- Info = info;
- Kind = kind;
- ClientContextData = request?.ClientContextData;
- }
-
- ///
- /// Gets the message identifier.
- ///
- public Guid Id { get; }
-
- ///
- /// Gets the identifier of request message.
- ///
- public Guid RequestId { get; private set; }
-
- ///
- /// Gets the tracking identifier.
- ///
- public Guid TrackingId { get; private set; }
-
- ///
- /// Gets the message.
- ///
- public string Message { get; }
-
- ///
- /// Gets the response data.
- ///
- public JsonObjectNode Data { get; }
-
- ///
- /// Gets the details.
- ///
- public Dictionary Details { get; } = new();
-
- ///
- /// Gets the information.
- ///
- public JsonObjectNode Info { get; }
-
- ///
- /// Gets the message kind.
- ///
- public string Kind { get; }
-
- ///
- /// Gets the context data from client.
- ///
- public JsonObjectNode ClientContextData { get; private set; }
-
- ///
- /// Converts the JSON raw back.
- ///
- /// The source value.
- /// The response instance.
- public static implicit operator ChatCommandGuidanceResponse(JsonObjectNode value)
- {
- if (value is null) return null;
- var result = new ChatCommandGuidanceResponse(
- value.TryGetStringValue("text") ?? value.TryGetStringValue("message"),
- value.TryGetObjectValue("data"),
- value.TryGetObjectValue("info"),
- value.TryGetStringTrimmedValue("kind", true),
- null,
- value.TryGetGuidValue("id") ?? Guid.NewGuid())
- {
- RequestId = value.TryGetGuidValue("request") ?? Guid.Empty,
- ClientContextData = value.TryGetObjectValue("ref")
- };
- var detailsArr = value.TryGetObjectValue("details") ?? new();
- foreach (var item in detailsArr)
- {
- if (item.Value is not JsonObjectNode json) continue;
- result.Details[item.Key] = json;
- }
-
- return result;
- }
-
- ///
- /// Converts to JSON object.
- ///
- /// The JSON value.
- /// A JSON object.
- public static explicit operator JsonObjectNode(ChatCommandGuidanceResponse value)
- {
- if (value is null) return null;
- return new()
- {
- { "id", value.Id },
- { "tracking", value.TrackingId },
- { "text", value.Message },
- { "data", value.Data },
- { "details", ChatCommandGuidanceHelper.ToJson(value.Details) },
- { "info", value.Info},
- { "ref", value.ClientContextData }
- };
- }
-}
-
-///
-/// The response modification of chat command guidance.
-///
-public class ChatCommandGuidanceResponseModification
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceResponseModification class.
- ///
- /// The response message.
- /// The message text
- public ChatCommandGuidanceResponseModification(ChatCommandGuidanceResponse response, string message)
- {
- Id = response?.Id ?? Guid.NewGuid();
- Data = response?.Data ?? new();
- Message = message;
- ModificationKind = message == null ? ChatMessageModificationKinds.Removed : ChatMessageModificationKinds.Modified;
- }
-
- ///
- /// Initializes a new instance of the ChatCommandGuidanceResponseModification class.
- ///
- /// The identifier of the response message.
- /// The message text
- /// The message data.
- /// The modification kind.
- public ChatCommandGuidanceResponseModification(Guid id, string message, JsonObjectNode data = null, ChatMessageModificationKinds kind = ChatMessageModificationKinds.Modified)
- {
- Id = id;
- Data = data ?? new();
- Message = message;
- ModificationKind = kind;
- }
-
- ///
- /// Gets the message identifier.
- ///
- public Guid Id { get; }
-
- ///
- /// Gets the creation data and time.
- ///
- public DateTime CreationTime { get; }
-
- ///
- /// Gets the message text.
- ///
- public string Message { get; }
-
- ///
- /// Gets the response data.
- ///
- public JsonObjectNode Data { get; }
-
- ///
- /// Gets the modification kind.
- ///
- public ChatMessageModificationKinds ModificationKind { get; }
-
- ///
- /// Converts to JSON object.
- ///
- /// The JSON value.
- /// A JSON object.
- public static explicit operator JsonObjectNode(ChatCommandGuidanceResponseModification value)
- {
- if (value is null) return null;
- return new()
- {
- { "id", value.Id },
- { "text", value.Message },
- { "data", value.Data },
- { "created", value.CreationTime },
- { "modify", value.ModificationKind.ToString() }
- };
- }
-}
-
-///
-/// The result of chat command guidance.
-///
-public class ChatCommandGuidanceSourceResult
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceSourceResult class.
- ///
- /// The message text.
- /// A flag indicating whether the result is successful.
- /// The message kind.
- public ChatCommandGuidanceSourceResult(string message, bool success, string kind)
- {
- Message = message;
- IsSuccessful = success;
- Kind = ChatCommandGuidanceHelper.FormatPromptName(kind);
- }
-
- ///
- /// Gets the message text.
- ///
- public string Message { get; }
-
- ///
- /// Gets a value indicating whether the result is successful.
- ///
- public bool IsSuccessful { get; }
-
- ///
- /// Gets the message kind.
- ///
- public string Kind { get; }
-}
-
-///
-/// The event arguments of command guidance source request.
-///
-public class ChatCommandGuidanceSourceEventArgs : EventArgs
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceSourceEventArgs class.
- ///
- /// The context.
- /// The result.
- public ChatCommandGuidanceSourceEventArgs(ChatCommandGuidanceContext context, ChatCommandGuidanceSourceResult result)
- {
- Context = context;
- Message = result?.Message;
- IsSuccessful = result?.IsSuccessful ?? false;
- Kind = result.Kind;
- }
-
- ///
- /// Gets the context.
- ///
- public ChatCommandGuidanceContext Context { get; }
-
- ///
- /// Gets the message text.
- ///
- public string Message { get; }
-
- ///
- /// Gets a value indicating whether the result is successful.
- ///
- public bool IsSuccessful { get; }
-
- ///
- /// Gets the message kind.
- ///
- public string Kind { get; }
-}
-
-///
-/// The error event arguments.
-///
-public class ChatCommandGuidanceErrorEventArgs
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceErrorEventArgs class.
- ///
- /// The exception.
- /// The context
- public ChatCommandGuidanceErrorEventArgs(Exception ex, T context)
- {
- Exception = ex;
- Context = context;
- }
-
- ///
- /// Gets the exception.
- ///
- public Exception Exception { get; }
-
- ///
- /// Gets the context.
- ///
- public T Context { get; }
-}
diff --git a/Messages/Tasks/ChatCommandGuidanceProvider.cs b/Messages/Tasks/ChatCommandGuidanceProvider.cs
deleted file mode 100644
index d201178b..00000000
--- a/Messages/Tasks/ChatCommandGuidanceProvider.cs
+++ /dev/null
@@ -1,271 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net.Security;
-using System.Text;
-using System.Threading.Tasks;
-using Trivial.Collection;
-using Trivial.Data;
-using Trivial.Users;
-using Trivial.Text;
-using System.Threading;
-
-namespace Trivial.Tasks;
-
-///
-/// The types of command guidance for chat bot.
-///
-public enum ChatCommandGuidanceProviderKinds : byte
-{
- ///
- /// Invalid.
- ///
- None = 0,
-
- ///
- /// The command.
- ///
- Command = 1,
-
- ///
- /// The assistance.
- ///
- Assistance = 2,
-
- ///
- /// The recording operator.
- ///
- Recorder = 7,
-
- ///
- /// The others.
- ///
- Others = 15
-}
-
-///
-/// The arguments of the command guidance for the chat bot.
-///
-public class ChatCommandGuidanceArgs : EventArgs
-{
- ///
- /// Initializes a new instance of the ChatCommandGuidanceArgs class.
- ///
- /// The context.
- /// The command key.
- public ChatCommandGuidanceArgs(ChatCommandGuidanceContext context, string command)
- {
- Context = context;
- Command = command;
- AnswerData = context?.GetAnswerData(command) ?? new();
- Info = context?.GetInfo(command) ?? new();
- NextInfo = context?.GetNextInfo(command) ?? new();
- }
-
- ///
- /// Gets the additional object.
- ///
- public object AdditionalObject { get; internal set; }
-
- ///
- /// Gets the context.
- ///
- public ChatCommandGuidanceContext Context { get; }
-
- ///
- /// Gets the context information.
- /// The command guidance can access this to store useful data during this round.
- ///
- public JsonObjectNode Info { get; }
-
- ///
- /// Gets the shared context information.
- /// The command guidance can access this to store useful data during this round.
- ///
- public JsonObjectNode SharedInfo => Context?.Info;
-
- ///
- /// Gets the command key.
- ///
- public string Command { get; }
-
- ///
- /// Gets the parameters.
- ///
- public IList Parameters { get; internal set; }
-
- ///
- /// Gets the data of the business rich output.
- ///
- public JsonObjectNode AnswerData { get; }
-
- ///
- /// Gets the shared data of the business rich output.
- ///
- public JsonObjectNode SharedAnswerData => Context?.AnswerData;
-
- ///
- /// Gets the next context information so that the command guidance can access.
- ///
- public JsonObjectNode NextInfo { get; } = new();
-
- ///
- /// Gets the shared next context information.
- ///
- public JsonObjectNode SharedNextInfo => Context?.NextInfo;
-
- ///
- /// Gets the original chat message result.
- ///
- public string OriginalAnswerMessage => Context?.OriginalAnswerMessage;
-
- ///
- /// Gets the chat message result.
- ///
- public string AnswerMessage => Context?.AnswerMessage;
-
- ///
- /// Gets the creation date and time.
- ///
- public DateTime CreationTime { get; } = DateTime.Now;
-}
-
-///
-/// The command guidance provider for chat bot.
-///
-public abstract class BaseChatCommandGuidanceProvider
-{
- ///
- /// Initializes a new instance of the BaseChatCommandGuidance class.
- ///
- /// The command key.
- /// The command description.
- /// The command parameter description.
- /// The command type.
- protected BaseChatCommandGuidanceProvider(string command, string description, string parameterDescription, ChatCommandGuidanceProviderKinds type)
- {
- Command = command;
- Description = description;
- ParameterDescription = parameterDescription;
- Kind = type;
- }
-
- ///
- /// Gets the command key.
- ///
- public virtual string Command { get; }
-
- ///
- /// Gets the command description.
- ///
- public virtual string Description { get; }
-
- ///
- /// Gets the command parameter description.
- ///
- public virtual string ParameterDescription { get; }
-
- ///
- /// Gets the kind of the command.
- ///
- public virtual ChatCommandGuidanceProviderKinds Kind { get; }
-
- ///
- /// Occurs on initialized.
- ///
- protected internal virtual void OnInit(BaseChatCommandGuidanceEngine engine)
- {
- }
-
- ///
- /// Occurs on initialized.
- ///
- /// The client.
- protected internal virtual void OnInit(BaseChatCommandGuidanceClient client)
- {
- }
-
- ///
- /// Creates an object used for following steps.
- ///
- /// The engine.
- /// The arguments.
- /// The object.
- protected internal virtual object InitializeObject(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceArgs args)
- => null;
-
- ///
- /// Tests if the command guidance is available.
- ///
- /// The engine.
- /// The arguments.
- /// true if the command guidance is available; otherwise, false.
- protected internal virtual bool IsAvailable(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceArgs args)
- => args != null;
-
- ///
- /// Generates the prompt.
- ///
- /// The engine.
- /// The arguments.
- /// The optional cancellation token.
- /// The prompt segment to append.
- protected internal virtual Task GeneratePromptAsync(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceArgs args, CancellationToken cancellationToken = default)
- => Task.FromResult(null);
-
- ///
- /// Post processes.
- ///
- /// The engine.
- /// The arguments.
- /// The optional cancellation token.
- /// A Task that represents the work queued to execute in the ThreadPool.
- protected internal abstract Task PostProcessAsync(BaseChatCommandGuidanceEngine engine, ChatCommandGuidanceArgs args, CancellationToken cancellationToken = default);
-
- ///
- /// Post processes on client side.
- ///
- /// The client.
- /// The arguments.
- protected internal virtual void ClientProcess(BaseChatCommandGuidanceClient client, ChatCommandGuidanceClientProcessingArgs args)
- {
- }
-
- ///
- /// Runs empty logic.
- ///
- /// The optional cancellation token.
- /// A Task that represents the work queued to execute in the ThreadPool.
- protected static Task RunEmptyAsync(CancellationToken cancellationToken = default)
- => Task.Run(ChatCommandGuidanceHelper.RunEmpty, cancellationToken);
-}
-
-internal class ChatCommandGuidanceTask
-{
- private ChatCommandGuidanceTask(BaseChatCommandGuidanceEngine engine, string key, BaseChatCommandGuidanceProvider command, ChatCommandGuidanceContext context)
- {
- Command = command;
- Args = new ChatCommandGuidanceArgs(context, key);
- Args.AdditionalObject = command.InitializeObject(engine, Args);
- IsAvailable = command.IsAvailable(engine, Args);
- }
-
- public BaseChatCommandGuidanceProvider Command { get; }
-
- public ChatCommandGuidanceArgs Args { get; }
-
- public bool IsAvailable { get; }
-
- public static IEnumerable Create(BaseChatCommandGuidanceEngine engine, IDictionary collection, ChatCommandGuidanceContext context)
- {
- if (collection == null || context == null) yield break;
- foreach (var kvp in collection)
- {
- var key = kvp.Key;
- var command = kvp.Value;
- if (string.IsNullOrEmpty(key) || command == null) continue;
- var task = new ChatCommandGuidanceTask(engine, key, command, context);
- if (task.IsAvailable) yield return task;
- }
- }
-}
diff --git a/Messages/Tasks/ChatCommandGuidanceTopic.cs b/Messages/Tasks/ChatCommandGuidanceTopic.cs
deleted file mode 100644
index e8ddfca0..00000000
--- a/Messages/Tasks/ChatCommandGuidanceTopic.cs
+++ /dev/null
@@ -1,237 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.Json.Nodes;
-using System.Threading.Tasks;
-using Trivial.Collection;
-using Trivial.Data;
-using Trivial.Users;
-using Trivial.Text;
-using System.Threading;
-using System.Net.NetworkInformation;
-
-namespace Trivial.Tasks;
-
-///
-/// The chat topic.
-///
-public class ChatCommandGuidanceTopic
-{
- private readonly BaseChatCommandGuidanceClient client;
- internal readonly List history = new();
-
- ///
- /// Initializes a new instance of the ChatCommandGuidanceTopic class.
- ///
- /// The client.
- internal ChatCommandGuidanceTopic(BaseChatCommandGuidanceClient client)
- {
- this.client = client;
- History = history.AsReadOnly();
- }
-
- ///
- /// Adds or removes the event on message is sending.
- ///
- public event EventHandler Sending;
-
- ///
- /// Adds or removes the event on message is failed to send or no response.
- ///
- public event EventHandler> SendFailed;
-
- ///
- /// Adds or removes the event on message is received.
- ///
- public event EventHandler Received;
-
- ///
- /// Adds or removes the event on message is post processed.
- ///
- public event EventHandler Processed;
-
- ///
- /// Gets the additional information data.
- ///
- public JsonObjectNode Info { get; } = new();
-
- ///
- /// Gets the shared information data.
- ///
- public JsonObjectNode SharedInfo => client.Info;
-
- ///
- /// Gets the current user info.
- ///
- public UserItemInfo User => client.User;
-
- ///
- /// Gets the chat history.
- ///
- public IList History { get; }
-
- ///
- /// Gets the latest request.
- ///
- public ChatCommandGuidanceRequest LatestRequest { get; private set; }
-
- ///
- /// Gets the latest response.
- ///
- public ChatCommandGuidanceResponse LatestResponse { get; private set; }
-
- ///
- /// Creates a new topic.
- ///
- /// The topic instance.
- public ChatCommandGuidanceTopic NewTopic()
- => client.NewTopic();
-
- ///
- /// Sends a request to get response.
- ///
- /// The message text.
- /// The message data.
- /// The optional cancellation token.
- /// The response instance.
- public async Task SendAsync(string message, JsonObjectNode data, CancellationToken cancellationToken = default)
- {
- var result = await SendAsync(message, data, LatestResponse, cancellationToken);
- return result?.Response;
- }
-
- ///
- /// Sends a request to get response.
- ///
- /// The message text.
- /// The message data.
- /// The callback.
- /// The optional cancellation token.
- /// The reply instance with response.
- public async Task SendAsync(string message, JsonObjectNode data, Action callback, CancellationToken cancellationToken = default)
- {
- var result = await SendAsync(message, data, LatestResponse, cancellationToken);
- callback?.Invoke(result);
- return result?.Response;
- }
-
- ///
- /// Sends a request to get response.
- ///
- /// The message text.
- /// The message data.
- /// The response message to reply; or null, if starts a new topic.
- /// The optional cancellation token.
- /// The response instance.
- internal async Task SendAsync(string message, JsonObjectNode data, ChatCommandGuidanceResponse reply, CancellationToken cancellationToken = default)
- {
- var user = client.User;
- var request = new ChatCommandGuidanceRequest(user, message, data, new List(history), null, reply);
- var args = new ChatCommandGuidanceMessageEventArgs(this, null, request, reply);
- client.OnRequestCreate(args);
- Sending?.Invoke(this, args);
- client.NotifySending(args);
- LatestRequest = request;
- var record = new ExtendedChatMessage(request.Id, user, message, DateTime.Now, data)
- {
- Category = client.RequestMessageKind
- };
- history.Add(record);
- client.AddHistory(record);
- client.OnSend(args);
- ChatCommandGuidanceResponse response;
- try
- {
- response = await client.SendAsync(request, cancellationToken);
- }
- catch (Exception ex)
- {
- var exArgs = new ChatCommandGuidanceErrorEventArgs(ex, args);
- SendFailed?.Invoke(this, exArgs);
- client.NotifySendFailed(exArgs);
- throw;
- }
-
- args.Response = response;
- Received?.Invoke(this, args);
- client.NotifyReceived(args);
- LatestResponse = response;
- record = new ExtendedChatMessage(response.Id, user, response.Message, DateTime.Now, response.Data)
- {
- Category = response.Kind
- };
- history.Add(record);
- client.AddHistory(record);
- client.OnReceive(args);
- client.ProcessCommands(this, response);
- client.OnProcessed(args);
- Processed?.Invoke(this, args);
- client.NotifyProcessed(args);
- return new(this, response);
- }
-}
-
-///
-/// The reply information for chat command guidance topic.
-///
-public class ChatCommandGuidanceReply
-{
- private readonly ChatCommandGuidanceTopic topic;
-
- ///
- /// Initializes a new instance of the ChatCommandGuidanceReply class.
- ///
- ///
- ///
- internal ChatCommandGuidanceReply(ChatCommandGuidanceTopic topic, ChatCommandGuidanceResponse response)
- {
- this.topic = topic;
- Response = response;
- }
-
- ///
- /// Gets the response.
- ///
- public ChatCommandGuidanceResponse Response { get; }
-
- ///
- /// Gets a value indicating whether the response has replied.
- ///
- public bool HasReplied { get; private set; }
-
- ///
- /// Gets the creation date and time.
- ///
- public DateTime CreationTime { get; } = DateTime.Now;
-
- ///
- /// Creates a request.
- ///
- /// The message text.
- /// The message data.
- /// The optional cancellation token.
- /// The request instance.
- public async Task SendAsync(string message, JsonObjectNode data, CancellationToken cancellationToken = default)
- {
- HasReplied = true;
- var result = await topic.SendAsync(message, data, Response, cancellationToken);
- return result.Response;
- }
-
- ///
- /// Creates a request.
- ///
- /// The message text.
- /// The message data.
- /// The callback.
- /// The optional cancellation token.
- /// The request instance.
- public async Task SendAsync(string message, JsonObjectNode data, Action callback, CancellationToken cancellationToken = default)
- {
- HasReplied = true;
- var result = await topic.SendAsync(message, data, Response, cancellationToken);
- callback?.Invoke(result);
- return result.Response;
- }
-}
diff --git a/Messages/Text/ExtendedChatClient.cs b/Messages/Text/ExtendedChatClient.cs
deleted file mode 100644
index 4a01cddc..00000000
--- a/Messages/Text/ExtendedChatClient.cs
+++ /dev/null
@@ -1,330 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Trivial.Data;
-using Trivial.Users;
-
-namespace Trivial.Text;
-
-///
-/// The states of send result for chat message.
-///
-public enum ExtendedChatMessageSendResultStates : byte
-{
- ///
- /// Not send.
- ///
- NotSend = 0,
-
- ///
- /// Success.
- ///
- Success = 1,
-
- ///
- /// Network issue or timeout.
- ///
- NetworkIssue = 2,
-
- ///
- /// Unauthorized or fobidden to send.
- ///
- Forbidden = 3,
-
- ///
- /// Traffic limitation for connection.
- ///
- Throttle = 4,
-
- ///
- /// Format error or invalid request.
- ///
- RequestError = 5,
-
- ///
- /// Client error.
- ///
- ClientError = 6,
-
- ///
- /// Unknown server-side error.
- ///
- ServerError = 7,
-
- ///
- /// Other error.
- ///
- OtherError = 10
-}
-
-///
-/// The provider for chat client.
-///
-public interface IExtendedChatClientProvider
-{
- ///
- /// Adds or removes the event occurs on message received.
- ///
- event DataEventHandler MessageReceived;
-
- ///
- /// Gets the current user.
- ///
- UserItemInfo User { get; }
-
- ///
- /// Sends the message.
- ///
- /// The thread to send message.
- /// The message to send.
- /// The optional cancellation token.
- /// The result state and other information.
- Task SendAsync(IExtendedChatThread to, ExtendedChatMessage message, CancellationToken cancellationToken = default);
-
- ///
- /// Tries to get the user.
- ///
- /// The user identifier.
- /// The optional cancellation token.
- /// The user information instance; or null, if not exists.
- Task TryGetUserAsync(string id, CancellationToken cancellationToken = default);
-
- ///
- /// Gets latest threads.
- ///
- /// The optional cancellation token.
- /// The thread list.
- Task> ListThreadAsync(CancellationToken cancellationToken = default);
-
- ///
- /// Searches threads.
- ///
- /// The search query.
- /// The optional cancellation token.
- /// The thread list.
- Task> ListThreadAsync(string q, CancellationToken cancellationToken = default);
-}
-
-///
-/// The chat client.
-///
-public class ExtendedChatClient
-{
- ///
- /// Initializes a new instance of the ExtendedChatClient class.
- ///
- /// The chat client provider.
- public ExtendedChatClient(IExtendedChatClientProvider provider)
- {
- Provider = provider;
- }
-
- ///
- /// Gets or sets the user info.
- ///
- public UserItemInfo User => Provider.User;
-
- ///
- /// Gets the i.
- ///
- protected IExtendedChatClientProvider Provider { get; }
-
- ///
- /// Sends the message.
- ///
- /// The thread to send message.
- /// The message text to send.
- /// The additional data to send.
- /// The optional cancellation token.
- /// The message request.
- public ExtendedChatMessageRequest Send(IExtendedChatThread to, string message, JsonObjectNode info, CancellationToken cancellationToken = default)
- {
- var req = new ExtendedChatMessageRequest(Provider, to, new ExtendedChatMessage(User, message, null, info));
- _ = req.GetResultAsync(cancellationToken);
- return req;
- }
-
- ///
- /// Tries to get the user.
- ///
- /// The user identifier.
- /// The optional cancellation token.
- /// The user information instance; or null, if not exists.
- public Task TryGetUserAsync(string id, CancellationToken cancellationToken = default)
- => Provider?.TryGetUserAsync(id, cancellationToken) ?? Task.FromResult(null);
-
- ///
- /// Gets latest threads.
- ///
- /// The optional cancellation token.
- /// The thread list.
- public async Task> ListThreadAsync(CancellationToken cancellationToken = default)
- {
- if (Provider == null) return new();
- return await Provider.ListThreadAsync(cancellationToken) ?? new();
- }
-
- ///
- /// Searches threads.
- ///
- /// The search query.
- /// The optional cancellation token.
- /// The thread list.
- public async Task> ListThreadAsync(string q, CancellationToken cancellationToken = default)
- {
- if (Provider == null) return new();
- return await Provider.ListThreadAsync(q, cancellationToken) ?? new();
- }
-}
-
-///
-/// The sending result of chat message.
-///
-public class ExtendedChatMessageSendResult
-{
- ///
- /// Initializes a new instance of the ExtendedChatMessageSendResult class.
- ///
- /// The result state.
- public ExtendedChatMessageSendResult(ExtendedChatMessageSendResultStates state)
- {
- State = state;
- Info = new();
- }
-
- ///
- /// Initializes a new instance of the ExtendedChatMessageSendResult class.
- ///
- /// The result state.
- ///
- ///
- public ExtendedChatMessageSendResult(ExtendedChatMessageSendResultStates state, string message, JsonObjectNode info = null)
- {
- State = state;
- Message = message;
- Info = info ?? new();
- }
-
- ///
- /// Gets the result state.
- ///
- public ExtendedChatMessageSendResultStates State { get; }
-
- ///
- /// Gets the additional response message, such like error message or result notes.
- ///
- public string Message { get; }
-
- ///
- /// Gets the additional information.
- ///
- public JsonObjectNode Info { get; }
-
- ///
- /// Gets a value indicating whether the state is a retry-able one.
- ///
- internal bool CanRetry => State == ExtendedChatMessageSendResultStates.NotSend || State == ExtendedChatMessageSendResultStates.Throttle || State == ExtendedChatMessageSendResultStates.NetworkIssue;
-}
-
-///
-/// The chat message request.
-///
-public class ExtendedChatMessageRequest
-{
- private Task task;
- private readonly IExtendedChatClientProvider client;
-
- ///
- /// Initializies a new instance of the ExtendedChatMessageRequest class.
- ///
- /// The client provider.
- /// The thread to send message.
- /// The message to send.
- public ExtendedChatMessageRequest(IExtendedChatClientProvider client, IExtendedChatThread to, ExtendedChatMessage message)
- {
- this.client = client;
- Thread = to;
- Message = message;
- }
-
- ///
- /// Gets the message sent.
- ///
- public ExtendedChatMessage Message { get; }
-
- ///
- /// Gets the thread to send message.
- ///
- public IExtendedChatThread Thread { get; }
-
- ///
- /// Gets the result.
- ///
- public ExtendedChatMessageSendResult Result { get; private set; } = new(ExtendedChatMessageSendResultStates.NotSend);
-
- ///
- /// Gets a value indicating whether the message is sending.
- ///
- public bool IsSending => task != null;
-
- ///
- /// Gets the result.
- ///
- /// The result state and other information.
- public Task GetResultAsync()
- => GetResultAsync(false);
-
- ///
- /// Gets the result.
- ///
- /// true if resend for networking issue; otherwise, false.
- /// The result state and other information.
- public async Task GetResultAsync(bool retry)
- {
- var t = task;
- if (t != null)
- {
- try
- {
- Result = await t;
- }
- finally
- {
- task = null;
- Result ??= new(ExtendedChatMessageSendResultStates.OtherError);
- }
-
- return Result;
- }
-
- if (!retry || Result == null || !Result.CanRetry) return Result ?? new(ExtendedChatMessageSendResultStates.OtherError);
- await GetResultAsync(default(CancellationToken));
- return Result;
- }
-
- ///
- /// Gets the result.
- ///
- /// The optional cancellation token.
- /// The result state and other information.
- internal async Task GetResultAsync(CancellationToken cancellationToken)
- {
- if (client == null || Thread == null) return Result = new(ExtendedChatMessageSendResultStates.ClientError);
- task = client.SendAsync(Thread, Message, cancellationToken);
- try
- {
- Result = await task;
- }
- finally
- {
- Result ??= new(ExtendedChatMessageSendResultStates.OtherError);
- task = null;
- }
-
- return Result;
- }
-}
diff --git a/Messages/Text/ExtendedChatMessage.cs b/Messages/Text/ExtendedChatMessage.cs
deleted file mode 100644
index 3f9509bd..00000000
--- a/Messages/Text/ExtendedChatMessage.cs
+++ /dev/null
@@ -1,951 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Text.Json;
-using System.Threading.Tasks;
-using Trivial.Collection;
-using Trivial.Data;
-using Trivial.Reflection;
-using Trivial.Tasks;
-using Trivial.Users;
-
-namespace Trivial.Text;
-
-///
-/// The modification kinds of the message.
-///
-public enum ChatMessageModificationKinds : byte
-{
- ///
- /// The message is neve modified.
- ///
- Original = 0,
-
- ///
- /// The streaming message which means the message is transferring by continious updating.
- ///
- Streaming = 1,
-
- ///
- /// The message has been modified by sender.
- ///
- Modified = 2,
-
- ///
- /// The message has been modified and is open to update by others.
- ///
- Collaborative = 3,
-
- ///
- /// The message has been removed by sender.
- ///
- Removed = 5,
-
- ///
- /// The message is banned by system.
- ///
- Ban = 6,
-
- ///
- /// Others.
- ///
- Others = 15
-}
-
-///
-/// The chat message record.
-///
-public class ExtendedChatMessage : BaseResourceEntityInfo
-{
- ///
- /// Initializes a new instance of the ExtendedChatMessage class.
- ///
- /// The nickname of the sender.
- /// The message text.
- /// The creation date time; or null if use now.
- /// The additional information; or null if create a new one.
- public ExtendedChatMessage(UserItemInfo sender, string message, DateTime? creation = null, JsonObjectNode info = null)
- : this(Guid.NewGuid(), sender, message, creation, info, null)
- {
- }
-
- ///
- /// Initializes a new instance of the ExtendedChatMessage class.
- ///
- /// The message identifier.
- /// The nickname of the sender.
- /// The message text.
- /// The creation date time; or null if use now.
- /// The additional information; or null if create a new one.
- /// The message type.
- public ExtendedChatMessage(Guid id, UserItemInfo sender, string message, DateTime? creation = null, JsonObjectNode info = null, string type = null)
- : this(ExtendedChatMessages.ToIdString(id), sender, message, creation, info, type)
- {
- }
-
- ///
- /// Initializes a new instance of the ExtendedChatMessage class.
- ///
- /// The message identifier.
- /// The nickname of the sender.
- /// The message text.
- /// The creation date time; or null if use now.
- /// The additional information; or null if create a new one.
- /// The message type.
- public ExtendedChatMessage(string id, UserItemInfo sender, string message, DateTime? creation = null, JsonObjectNode info = null, string type = null)
- : base(id)
- {
- var time = creation ?? DateTime.Now;
- SetProperty(nameof(Sender), sender);
- SetProperty(nameof(Message), message);
- if (!string.IsNullOrEmpty(type)) SetProperty(nameof(MessageType), type);
- SetProperty(nameof(CreationTime), time);
- SetProperty(nameof(LastModificationTime), time);
- Info = info ?? new();
- }
-
- ///
- /// Initializes a new instance of the ExtendedChatMessage class.
- ///
- /// The JSON object to parse.
- public ExtendedChatMessage(JsonObjectNode json)
- {
- if (json is null) return;
- Id = json.TryGetStringTrimmedValue("id", true) ?? json.Id;
- SetProperty(nameof(Sender), (UserItemInfo)json.TryGetObjectValue("sender"));
- SetProperty(nameof(Message), json.TryGetStringValue("text") ?? json.TryGetStringValue("message"));
- SetProperty(nameof(MessageType), json.TryGetStringTrimmedValue("type", true));
- SetProperty(nameof(CreationTime), json.TryGetDateTimeValue("created") ?? DateTime.Now);
- SetProperty(nameof(LastModificationTime), json.TryGetDateTimeValue("modified") ?? DateTime.Now);
- Info = json.TryGetObjectValue("info") ?? new();
- Category = json.TryGetStringTrimmedValue("category", true);
- SetProperty("Data", json.TryGetObjectValue("data"));
- }
-
- ///
- /// Gets the sender.
- ///
- public UserItemInfo Sender => GetCurrentProperty();
-
- ///
- /// Gets the plain text of the message.
- ///
- public string Message
- {
- get
- {
- return GetCurrentProperty();
- }
-
- set
- {
- if (!SetCurrentProperty(value)) return;
- if (GetProperty(nameof(ModificationKind)) != ChatMessageModificationKinds.Original)
- SetProperty(nameof(ModificationKind), ChatMessageModificationKinds.Modified);
- SetProperty(nameof(LastModificationTime), DateTime.Now);
- }
- }
-
- ///
- /// Gets or sets the modification kind.
- ///
- public ChatMessageModificationKinds ModificationKind
- {
- get => GetCurrentProperty();
- set => SetCurrentProperty(value);
- }
-
- ///
- /// Gets the message type.
- ///
- public string MessageType => GetCurrentProperty();
-
- ///
- /// Gets the creation date time.
- ///
- public DateTime CreationTime => GetCurrentProperty();
-
- ///
- /// Gets the creation date time.
- ///
- public DateTime LastModificationTime
- {
- get => GetCurrentProperty();
- set => SetCurrentProperty(value);
- }
-
- ///
- /// Gets the category.
- ///
- public string Category
- {
- get => GetCurrentProperty();
- set => SetCurrentProperty(value);
- }
-
- ///
- /// Gets the additional data.
- ///
- public JsonObjectNode Info { get; }
-
- ///
- /// Converts to JSON object.
- ///
- /// A JSON object.
- public override JsonObjectNode ToJson()
- {
- var json = base.ToJson();
- json.SetValue("sender", Sender);
- json.SetValue("text", Message);
- json.SetValue("created", CreationTime);
- json.SetValue("modified", LastModificationTime);
- json.SetValue("type", MessageType);
- if (Info.Count > 0) json.SetValue("info", Info);
- if (!string.IsNullOrWhiteSpace(Category)) json.SetValue("category", Category);
- var data = GetProperty