问:
Taking a list as input from user
While taking a list as an input from the user, the input is SUPPOSED to be enclosed within square brackets as opposed to just typing the numbers
This is my code for taking multiple inputs from the user for a list

```<code>a = list(map(int,input().strip().split(', ')))
</code>```

The default input is [1, 2, 3, 4].
When I run my code, I get an error as:

```<code>ValueError: invalid literal for int() with base 10: '[1'
</code>```

I know the reason it's happening is because '[1' is a an element that cannot be converted into int and it  (the square bracket and 1) is being regarded as the first element of the list at index 0.
Having the square bracket is absolutely essential for me, how can I resolve the error or just ignore the square brackets? Is there an ignore method or something similar that might work?
Cheers!

答:
Strip off the brackets from the input:</p>

```<code>a = [int(n) for n in input().strip('[]').split(',')]
</code>```

Title: Taking a list as input from user

Body:
While taking a list as an input from the user, the input is SUPPOSED to be enclosed within square brackets as opposed to just typing the numbers
This is my code for taking multiple inputs from the user for a list

a = list(map(int,input().strip().split(', ')))

The default input is [1, 2, 3, 4].
When I run my code, I get an error as:

ValueError: invalid literal for int() with base 10: '[1'

I know the reason it's happening is because '[1' is a an element that cannot be converted into int and it  (the square bracket and 1) is being regarded as the first element of the list at index 0.
Having the square bracket is absolutely essential for me, how can I resolve the error or just ignore the square brackets? Is there an ignore method or something similar that might work?
Cheers!

Body:
Strip off the brackets from the input:

a = [int(n) for n in input().strip('[]').split(',')]


来源: stackexchange

问:
Integrating Facebook, but where's the best place to store variables like login status?
I have integrated Facebook into my site, but where is the best place to store things like current login status? For example,

```<code>window.fbAsyncInit = function() {
    DS.fb.sdk.init();
    DS.fb.user.login();
}
</code>```

gets the login status of the user, but do I save this status into cookies/databases or is there a more efficient way of saving it? If it's any help, I also want to store a lot of other things like current location etc.

Also, as a side question, are there good example links of sites that have Facebook integrated and show how they integrate Facebook and store data of the user?

答: Sessions are always very good to use. You can use information into session variables rather than storing them in database then extracting again from database.</p>

ContentLicense: CC BY-SA 3.0

Body:
I have integrated Facebook into my site, but where is the best place to store things like current login status? For example,

window.fbAsyncInit = function() {
    DS.fb.sdk.init();
    DS.fb.user.login();
}

gets the login status of the user, but do I save this status into cookies/databases or is there a more efficient way of saving it? If it's any help, I also want to store a lot of other things like current location etc.

Also, as a side question, are there good example links of sites that have Facebook integrated and show how they integrate Facebook and store data of the user?


问:
Reducer gets triggered but subscribe function not fetching the change [React-Redux]
reducer shows that I've received doc data from Firestore. docStore.subscribe is listening, but is not updating with latest doc data.

Expected outcome: upon page load, will get docId from URL, and query Firestore. Upon receiving data, update the store, and subscribe to populate the view with doc information.

homepage.js

```<code>const Homepage = ({ docId }) => {

  const [doc, setdoc] = useState(false);

  console.log(docId); // <-- 123

  docStore.subscribe(() => {
    console.log('docStore state changed:', docStore.getState()); // <-- docStore state changed: undefined
    setdoc(docStore.getState());
  })

  return (
    <div>
      <div>{docId}</div> {/* 123 */}
      <div>{doc.docName}</div> {/* blank */}
    </div>
  );
};
</code>```

reducer.js

```<code>export default function reducer(state = {}, action) {
  switch (action.type) {

    case docTypes.LOAD_DOC_PAGE:
      firebase.firestore().collection("docs")
        .where('docId', '==', action.payload.docId.toLowerCase())
        .get()
        .then(function (data) {

          if (data.docs.length === 1) {
            state = data.docs[0].data();
          }

          console.log('gotten doc', state) // <-- gotten doc data

          return state;
        });
  }
}
</code>```

答:
Your reducer is very broken.  Reducers must never make async calls!.  That API call needs to be moved somewhere else entirely, and then you should dispatch an action that will cause the reducer to run and calculate an updated state.

Also, you generally shouldn't subscribe to the store yourself.  Use the React-Redux connect and useSelector APIs to extract data needed by components from the store state.

ContentLicense: CC BY-SA 4.0

Body:
reducer shows that I've received doc data from Firestore. docStore.subscribe is listening, but is not updating with latest doc data.

Expected outcome: upon page load, will get docId from URL, and query Firestore. Upon receiving data, update the store, and subscribe to populate the view with doc information.

homepage.js

const Homepage = ({ docId }) => {

  const [doc, setdoc] = useState(false);

  console.log(docId); // <-- 123

  docStore.subscribe(() => {
    console.log('docStore state changed:', docStore.getState()); // <-- docStore state changed: undefined
    setdoc(docStore.getState());
  })

  return (

{docId}
 {/* 123 */}

{doc.docName}
 {/* blank */}

  );
};

reducer.js

export default function reducer(state = {}, action) {
  switch (action.type) {

    case docTypes.LOAD_DOC_PAGE:
      firebase.firestore().collection("docs")
        .where('docId', '==', action.payload.docId.toLowerCase())
        .get()
        .then(function (data) {

          if (data.docs.length === 1) {
            state = data.docs[0].data();
          }

          console.log('gotten doc', state) // <-- gotten doc data

          return state;
        });
  }
}


问:
Programming Language needed to create google chrome extensions
I'm trying to create a google chrome extension that communicates with com ports. I have no idea what language to use though. Any suggestions will be welcome. Thank you.</p>

答:
Extensions are small software programs that can modify and enhance the functionality of the Chrome browser. You write them using web technologies such as HTML, JavaScript, and CSS.

One can create extensions with the enough knowledge of HTML,CSS, JAVASCRIPT, JQUERY.

HTML is used as a content markup language, CSS is used for styling, and JavaScript for scripting. Because Chrome supports HTML5 and CSS3, developers can use the latest open web technologies such as canvas and CSS animations in their extensions. Extensions also have access to several JavaScript APIs that help perform functions like JSON encoding and interacting with the browser.


问:
CakePhp 1.3 and 2.0 API for offline use
Is there any link to download cakePHP 1.3 and 2.0 API for offline reading? I searched the web a lot but everybody is talking about to generate API by https://github.com/cakephp/api_generator

Is there no solution for persons like me who are not able to or don't want to use such a tool?

答: You can build a copy of the http://api.cakephp.org website locally for offline use by cloning the git repository for the site and following the instructions in the README found here: https://github.com/cakephp/cakephp-api-docs/tree/2.x</p>

Title: CakePhp 1.3 and 2.0 API for offline use


问:
C# unsafe value type array to byte array conversions
I use an extension method to convert float arrays into byte arrays:

```<code>public static unsafe byte[] ToByteArray(this float[] floatArray, int count)
{
    int arrayLength = floatArray.Length > count ? count : floatArray.Length;
    byte[] byteArray = new byte[4 * arrayLength];
    fixed (float* floatPointer = floatArray)
    {
        fixed (byte* bytePointer = byteArray)
        {
            float* read = floatPointer;
            float* write = (float*)bytePointer;
            for (int i = 0; i < arrayLength; i++)
            {
                *write++ = *read++;
            }
        }
    }
    return byteArray;
}
</code>```

I understand that an array is a pointer to memory associated with information on the type and number of elements. Also, it seems to me that there is no way of doing a conversion from and to a byte array without copying the data as above.

Have I understood this? Would it even be impossible to write IL to create an array from a pointer, type and length without copying data?

EDIT: Thanks for the answers, I learned some fundamentals and got to try out new tricks!

After initially accepting Davy Landman's answer I found out that while his brilliant StructLayout hack does convert byte arrays into float arrays, it does not work the other way around. To demonstrate:

```<code>[StructLayout(LayoutKind.Explicit)]
struct UnionArray
{
    [FieldOffset(0)]
    public Byte[] Bytes;

    [FieldOffset(0)]
    public float[] Floats;
}

static void Main(string[] args)
{
    // From bytes to floats - works
    byte[] bytes = { 0, 1, 2, 4, 8, 16, 32, 64 };
    UnionArray arry = new UnionArray { Bytes = bytes };
    for (int i = 0; i < arry.Bytes.Length / 4; i++)
        Console.WriteLine(arry.Floats[i]);

    // From floats to bytes - index out of range
    float[] floats = { 0.1f, 0.2f, 0.3f };
    arry = new UnionArray { Floats = floats };
    for (int i = 0; i < arry.Floats.Length * 4; i++)
        Console.WriteLine(arry.Bytes[i]);
}
</code>```

It seems that the CLR sees both arrays as having the same length. If the struct is created from float data, the byte array's length is just too short.

答:
I've written something similar for quick conversion between arrays. It's basically an ugly proof-of-concept more than a handsome solution. ;)</p>

```<code>public static TDest[] ConvertArray<TSource, TDest>(TSource[] source)
    where TSource : struct
    where TDest : struct {

    if (source == null)
        throw new ArgumentNullException("source");

        var sourceType = typeof(TSource);
        var destType = typeof(TDest);

        if (sourceType == typeof(char) || destType == typeof(char))
            throw new NotSupportedException(
                "Can not convert from/to a char array. Char is special " +
                "in a somewhat unknown way (like enums can't be based on " +
                "char either), and Marshal.SizeOf returns 1 even when the " +
                "values held by a char can be above 255."
            );

        var sourceByteSize = Buffer.ByteLength(source);
        var destTypeSize = Marshal.SizeOf(destType);
        if (sourceByteSize % destTypeSize != 0)
            throw new Exception(
                "The source array is " + sourceByteSize + " bytes, which can " +
                "not be transfered to chunks of " + destTypeSize + ", the size " +
                "of type " + typeof(TDest).Name + ". Change destination type or " +
                "pad the source array with additional values."
            );

        var destCount = sourceByteSize / destTypeSize;
        var destArray = new TDest[destCount];

        Buffer.BlockCopy(source, 0, destArray, 0, sourceByteSize);

        return destArray;
    }
}
</code>```

OwnerDisplayName: Ville Koskinen

ContentLicense: CC BY-SA 2.5

Body:
I use an extension method to convert float arrays into byte arrays:

public static unsafe byte[] ToByteArray(this float[] floatArray, int count)
{
    int arrayLength = floatArray.Length > count ? count : floatArray.Length;
    byte[] byteArray = new byte[4 * arrayLength];
    fixed (float* floatPointer = floatArray)
    {
        fixed (byte* bytePointer = byteArray)
        {
            float* read = floatPointer;
            float* write = (float*)bytePointer;
            for (int i = 0; i < arrayLength; i++)
            {
                *write++ = *read++;
            }
        }
    }
    return byteArray;
}

I understand that an array is a pointer to memory associated with information on the type and number of elements. Also, it seems to me that there is no way of doing a conversion from and to a byte array without copying the data as above.

Have I understood this? Would it even be impossible to write IL to create an array from a pointer, type and length without copying data?

EDIT: Thanks for the answers, I learned some fundamentals and got to try out new tricks!

After initially accepting Davy Landman's answer I found out that while his brilliant StructLayout hack does convert byte arrays into float arrays, it does not work the other way around. To demonstrate:

[StructLayout(LayoutKind.Explicit)]
struct UnionArray
{
    [FieldOffset(0)]
    public Byte[] Bytes;

    [FieldOffset(0)]
    public float[] Floats;
}

static void Main(string[] args)
{
    // From bytes to floats - works
    byte[] bytes = { 0, 1, 2, 4, 8, 16, 32, 64 };
    UnionArray arry = new UnionArray { Bytes = bytes };
    for (int i = 0; i < arry.Bytes.Length / 4; i++)
        Console.WriteLine(arry.Floats[i]);

    // From floats to bytes - index out of range
    float[] floats = { 0.1f, 0.2f, 0.3f };
    arry = new UnionArray { Floats = floats };
    for (int i = 0; i < arry.Floats.Length * 4; i++)
        Console.WriteLine(arry.Bytes[i]);
}

It seems that the CLR sees both arrays as having the same length. If the struct is created from float data, the byte array's length is just too short.

LastEditorDisplayName: Ville Koskinen

Body:
I've written something similar for quick conversion between arrays. It's basically an ugly proof-of-concept more than a handsome solution. ;)

public static TDest[] ConvertArray<TSource, TDest>(TSource[] source)
    where TSource : struct
    where TDest : struct {

    if (source == null)
        throw new ArgumentNullException("source");

        var sourceType = typeof(TSource);
        var destType = typeof(TDest);

        if (sourceType == typeof(char) || destType == typeof(char))
            throw new NotSupportedException(
                "Can not convert from/to a char array. Char is special " +
                "in a somewhat unknown way (like enums can't be based on " +
                "char either), and Marshal.SizeOf returns 1 even when the " +
                "values held by a char can be above 255."
            );

        var sourceByteSize = Buffer.ByteLength(source);
        var destTypeSize = Marshal.SizeOf(destType);
        if (sourceByteSize % destTypeSize != 0)
            throw new Exception(
                "The source array is " + sourceByteSize + " bytes, which can " +
                "not be transfered to chunks of " + destTypeSize + ", the size " +
                "of type " + typeof(TDest).Name + ". Change destination type or " +
                "pad the source array with additional values."
            );

        var destCount = sourceByteSize / destTypeSize;
        var destArray = new TDest[destCount];

        Buffer.BlockCopy(source, 0, destArray, 0, sourceByteSize);

        return destArray;
    }
}


问:
How do I call variables with similar names using a for loop?
I have the following code:

```<code>var projectNumbers = [];
projectNumbers.push(project0[0]);
projectNumbers.push(project1[0]);
projectNumbers.push(project2[0]);
projectNumbers.push(project3[0]);
projectNumbers.push(project4[0]);
projectNumbers.push(project5[0]);
</code>```

This adds 6 different numbers from other arrays to the projectNumbers array.

However, I want the code to automatically add numbers to the projectNumbers array based off the number of projects. I tried doing this using:

```<code>var projectNumbers = [];
for (var i=0;i<projects.length+1;i++{
projectNumbers.push("project"+i+"[0]")
}
</code>```

but this ended up displaying project0[0], project1[0], project2[0] etc. instead of getting the values of these and displaying 0,1,2 etc.

How can I fix this?

答:
I agree with the comments that this seems a bit odd. You could achieve what you want by using eval(), but you shouldn't:

projectNumbers.push(eval("project"+i+"[0]"))
```

Body:
I have the following code:

var projectNumbers = [];
projectNumbers.push(project0[0]);
projectNumbers.push(project1[0]);
projectNumbers.push(project2[0]);
projectNumbers.push(project3[0]);
projectNumbers.push(project4[0]);
projectNumbers.push(project5[0]);

This adds 6 different numbers from other arrays to the projectNumbers array.

However, I want the code to automatically add numbers to the projectNumbers array based off the number of projects. I tried doing this using:

var projectNumbers = [];
for (var i=0;i<projects.length+1;i++{
projectNumbers.push("project"+i+"[0]")
}

but this ended up displaying project0[0], project1[0], project2[0] etc. instead of getting the values of these and displaying 0,1,2 etc.

How can I fix this?


问:
(Why) can we assign non-static class members to static variables in initialization?
In a larger code base I have encountered code like this (see on godbolt):

```<code>struct Foo {};

struct Base {
    Foo* a;
};

struct Bar : public Base {
    static Foo* Bar::*mybar[];
};

Foo* Bar::Bar::*mybar[] = {
    &Base::a
};
</code>```

To be honest, I'm baffled. This looks like it's initializing a static array of Foo pointers in Bar with a non-static member variable of Base. How is that even possible without an object?

(Disclaimer: This is found in production code that actually works - hopefully not relying on UB?)

Also, is there any problem if I remove the qualified name lookup like here? I'd like to refactor the code and make it more readable. All these Bar::s seem quite superfluous, but since I'm not feeling so comfortable with the code I'd rather understand the implications first.

答:
Unlike normal pointers, class member pointers can be though of as an offset into the class, where they are telling you which member of an object they point to.  So in your code, mybar is an array of class member pointers.  When you do

```<code>Foo *Bar::Bar::*mybar[] = {
    &Base::a
};
</code>```

you initialize the array with a pointer to the a member of Base.  This isn't actually pointing to an a, it just tells the compiler which member of the object to return if you access it with an object.  That would look like

```<code>Base foo; // now we have an actual object
foo.*mybar[0]; // access the `a` member of `foo` by using the "offset"
</code>```

Body:
In a larger code base I have encountered code like this (see on godbolt):

struct Foo {};

struct Base {
    Foo* a;
};

struct Bar : public Base {
    static Foo* Bar::*mybar[];
};

Foo* Bar::Bar::*mybar[] = {
    &Base::a
};

To be honest, I'm baffled. This looks like it's initializing a static array of Foo pointers in Bar with a non-static member variable of Base. How is that even possible without an object?

(Disclaimer: This is found in production code that actually works - hopefully not relying on UB?)

Also, is there any problem if I remove the qualified name lookup like here? I'd like to refactor the code and make it more readable. All these Bar::s seem quite superfluous, but since I'm not feeling so comfortable with the code I'd rather understand the implications first.

Body:
Unlike normal pointers, class member pointers can be though of as an offset into the class, where they are telling you which member of an object they point to.  So in your code, mybar is an array of class member pointers.  When you do

Foo *Bar::Bar::*mybar[] = {
    &Base::a
};

you initialize the array with a pointer to the a member of Base.  This isn't actually pointing to an a, it just tells the compiler which member of the object to return if you access it with an object.  That would look like

Base foo; // now we have an actual object
foo.*mybar[0]; // access the `a` member of `foo` by using the "offset"


问:
"InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden]'"
I've deployed my API and Client app on Docker, but for the life of me, the web app cannot call the API, I keep getting an exception.

I added the following line suggested in other posts, but it did not work.

```<code>IdentityModelEventSource.ShowPII = true;
</code>```

Exception:

```<code>System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden]'.
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.InvokeCore(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
</code>```

答:
If anyone is experiencing this during development, I was able to solve this by clearing my developer certs then recreating them.

dotnet dev-certs https --clean
dotnet dev-certs https --trust
```

Body:
I've deployed my API and Client app on Docker, but for the life of me, the web app cannot call the API, I keep getting an exception.

I added the following line suggested in other posts, but it did not work.

IdentityModelEventSource.ShowPII = true;

Exception:

System.InvalidOperationException: IDX20803: Unable to obtain configuration from: '[PII is hidden]'.
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.InvokeCore(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)


问:
How to delete multiple images from firebase storage at a time in android studio
I’m using android studio with firebase, Is there a way to delete multiple images at a time from firebase storage for android</p>

答: There is no API for bulk or batch deleting files in Cloud Storage.  You will have to delete each one individually as described in the documentation.</p>


问:
How to Convert User input to Encoder value type
I have MVC 5 project that use System.Drawing; System.Drawing.Imaging; I want the user to select image quality when it is jpeg This is my approach:

```<code>   Encoder quality = Encoder.Quality; //quality should be user input
                    var ratio = new EncoderParameter(quality, 100L);
                    var codecParams = new EncoderParameters(1);
                    codecParams.Param[0] = ratio;
                    convertedImage.Save(outputImagePath, GetEncoder(ImageFormat.Jpeg), codecParams);
</code>```

Due to some use cases I have  public async Task bool and I can't declare encoder parameter.
Thus my question: How to convert string(user input) to encoder.
If we want to convert string to Int, simple:

```<code>var name = Convert.ToInt32(userinput);
</code>```

答:
Based on @snow_FFFFFF answer I used this approach:                     </p>

```<code>byte[] bytes = new byte[16];
//If you pass quality as int then you won't need to parse it                                         BitConverter.GetBytes(int.Parse(quality)).CopyTo(bytes, 0);
result=new Guid(bytes);
Encoder qquality = new Encoder(result);
var ratio = new EncoderParameter(qquality, 100L);
var codecParams = new EncoderParameters(1);
codecParams.Param[0] = ratio;
string outputPNGPath = Path.Combine(fileNameResultDirectory, "00" + pageNumber.ToString() + ".jpeg");
pdf2PNG.Save(outputPNGPath, GetEncoder(ImageFormat.Jpeg), codecParams);
</code>```

Body:
I have MVC 5 project that use System.Drawing; System.Drawing.Imaging; I want the user to select image quality when it is jpeg This is my approach:

   Encoder quality = Encoder.Quality; //quality should be user input
                    var ratio = new EncoderParameter(quality, 100L);
                    var codecParams = new EncoderParameters(1);
                    codecParams.Param[0] = ratio;
                    convertedImage.Save(outputImagePath, GetEncoder(ImageFormat.Jpeg), codecParams);

Due to some use cases I have  public async Task bool and I can't declare encoder parameter.
Thus my question: How to convert string(user input) to encoder.
If we want to convert string to Int, simple:

var name = Convert.ToInt32(userinput);

Body:
Based on @snow_FFFFFF answer I used this approach:

byte[] bytes = new byte[16];
//If you pass quality as int then you won't need to parse it                                         BitConverter.GetBytes(int.Parse(quality)).CopyTo(bytes, 0);
result=new Guid(bytes);
Encoder qquality = new Encoder(result);
var ratio = new EncoderParameter(qquality, 100L);
var codecParams = new EncoderParameters(1);
codecParams.Param[0] = ratio;
string outputPNGPath = Path.Combine(fileNameResultDirectory, "00" + pageNumber.ToString() + ".jpeg");
pdf2PNG.Save(outputPNGPath, GetEncoder(ImageFormat.Jpeg), codecParams);


问:
Code condensing/efficiency
I'm writing a string replacing function to replace smiles with there actual image location but the code is going to be very big and messy because of all the nested ifs but i cant think of a more efficient way of writing the code.</p>

```<code>Public Function exchangeSmilies(ByVal postString As String) As String
    Dim ChangedString = postString
    ChangedString.ToLower()
    If ChangedString.Contains(":)") Then
        ChangedString = ChangedString.Replace(":)", GetSmilieMapPath("smile.gif"))
        If ChangedString.Contains(":p") Then
            ChangedString = ChangedString.Replace(":p", GetSmilieMapPath("toungue.gif"))
            If ChangedString.Contains(";)") Then
                ChangedString = ChangedString.Replace(";)", GetSmilieMapPath("wink.gif"))
                If ChangedString.Contains("<3") Then
                    ChangedString = ChangedString.Replace("<3", GetSmilieMapPath("heart.gif"))
                End If
            End If
        End If
    End If
    Return ChangedString
End Function

Public Function GetSmilieMapPath(ByVal SmilieImage As String) As String
    GetSmilieMapPath = "<img src=" & Chr(34) & "../Images/Smilies/" & SmilieImage & Chr(34) & ">"
    Return GetSmilieMapPath
End Function
</code>```

答: Have a Dictionary(Of String, String) that contains each of your emoticons and replacement. Use a loop to do the actual replacement.

Title: Code condensing/efficiency

Body:
I'm writing a string replacing function to replace smiles with there actual image location but the code is going to be very big and messy because of all the nested ifs but i cant think of a more efficient way of writing the code.

Public Function exchangeSmilies(ByVal postString As String) As String
    Dim ChangedString = postString
    ChangedString.ToLower()
    If ChangedString.Contains(":)") Then
        ChangedString = ChangedString.Replace(":)", GetSmilieMapPath("smile.gif"))
        If ChangedString.Contains(":p") Then
            ChangedString = ChangedString.Replace(":p", GetSmilieMapPath("toungue.gif"))
            If ChangedString.Contains(";)") Then
                ChangedString = ChangedString.Replace(";)", GetSmilieMapPath("wink.gif"))
                If ChangedString.Contains("<3") Then
                    ChangedString = ChangedString.Replace("<3", GetSmilieMapPath("heart.gif"))
                End If
            End If
        End If
    End If
    Return ChangedString
End Function

Public Function GetSmilieMapPath(ByVal SmilieImage As String) As String
    GetSmilieMapPath = ""
    Return GetSmilieMapPath
End Function


问:
Validation error adornment not clearing when HasError is false
INTRODUCTION

I have created a DecimalTextBox user control which has ValidationRules attached to it to prevent nulls, have a minimum and maximum range and it has event handlers to prevent non-decimal values. I have used

```<code>ValidatesOnTargetUpdated="True"
</code>```

on the bindings because I want the validation to be activated immediately (and I had an issue before where the min and max values were changing but the validation wasn't being reevaluated).

The null validation I have done is dependent on the value of an "AllowNull" dependency property: If the control specifies true then the control is valid even when the value is null. When false then null is not allowed. The default of this property is False

THE PROBLEM

I am setting the AllowNull to true when using it in a certain UserControl. Unfortunately because the ValidatesOnTargetUpdated is set to true, the control is validated before the xaml sets the AllowNull to true, while it is still in its default false setting.

This causes an error before loading, as the binding to the text of the TextBox is also not resolved yet, so before loading it doesn't allow null, and the value of the text is null.

This is all fine and dandy because after the loading the validation is reevaluated with the new AllowNull value (of true) and the error is removed.

However the red validation adornment remains. Not entirely sure how to get rid of it.

THE CODE
The xaml for the textbox usercontrol:

```<code><UserControl x:Class="WPFTest.DecimalTextBox"
         x:Name="DecimalBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:v="clr-namespace:ValidationRules"
         mc:Ignorable="d"
         d:DesignHeight="25" d:DesignWidth="100" Initialized="DecimalBox_Initialized" >

    <TextBox x:Name="textbox">
        <TextBox.Text>
            <Binding ElementName="DecimalBox" TargetNullValue="" Path="Text" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" NotifyOnValidationError="True">
                <Binding.ValidationRules>
                    <v:DecimalRangeRule  ValidatesOnTargetUpdated="True">
                        <v:DecimalRangeRule.MinMaxRange>
                            <v:MinMaxValidationBindings x:Name="minMaxValidationBindings"/>
                        </v:DecimalRangeRule.MinMaxRange>
                    </v:DecimalRangeRule>
                    <v:NotEmptyRule  ValidatesOnTargetUpdated="True">
                        <v:NotEmptyRule.AllowNull>
                            <v:AllowNullValidationBinding x:Name="allowNullValidationBindings"></v:AllowNullValidationBinding>
                        </v:NotEmptyRule.AllowNull>
                    </v:NotEmptyRule>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
</UserControl>
</code>```

The code behind for the control:

```<code>    public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(textboxcontrol), new PropertyMetadata());
    public static DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(decimal), typeof(DecimalTextBox), new PropertyMetadata(0M));
    public static DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(decimal), typeof(DecimalTextBox), new PropertyMetadata(0M));
    public static DependencyProperty AllowNullProperty = DependencyProperty.Register("AllowNull", typeof(bool), typeof(DecimalTextBox), new UIPropertyMetadata(false));

    public bool AllowNull
    {
        get { return (bool)GetValue(AllowNullProperty); }
        set { SetValue(AllowNullProperty, value); }
    }
    public decimal Minimum
    {
        get { return (decimal)GetValue(MinimumProperty); }
        set { SetValue(MinimumProperty, value); }
    }
    public decimal Maximum
    {
        get { return (decimal)GetValue(MaximumProperty); }
        set { SetValue(MaximumProperty, value); }
    }
    public string Text
    {
        get
        {
            return (string)GetValue(TextProperty);
        }
        set
        {
            SetValue(TextProperty, value);
        }
    }

    private void DecimalBox_Initialized(object sender, EventArgs e)
    {
        Binding minBinding = new Binding("Minimum");
        minBinding.Source = this;
        Binding maxBinding = new Binding("Maximum");
        maxBinding.Source = this;
        Binding allownullBinding = new Binding("AllowNull");
        allownullBinding.Source = this;

        minMaxValidationBindings.SetBinding(ValidationRules.MinMaxValidationBindings.minProperty, minBinding);
        BindingOperations.SetBinding(minMaxValidationBindings, ValidationRules.MinMaxValidationBindings.maxProperty, maxBinding);
        BindingOperations.SetBinding(allowNullValidationBindings, ValidationRules.AllowNullValidationBinding.allowNullProperty, allownullBinding);
    }
</code>```

And the Validation Rules (#Note: They are inside the ValidationRules namespace):

```<code>public class NotEmptyRule : ValidationRule
{

    public NotEmptyRule()
    {
    }
    private AllowNullValidationBinding _allowNullBinding;

    public AllowNullValidationBinding AllowNull
    {
        get { return _allowNullBinding; }
        set { _allowNullBinding = value; }
    }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (!_allowNullBinding.AllowNull)
            if (string.IsNullOrEmpty((string)value))
                return new ValidationResult(false,
                  "Value cannot be null or empty.");
            else
                return new ValidationResult(true, null);

        else
           return new ValidationResult(true, null);

    }
}

public class DecimalRangeRule : ValidationRule
{
    private MinMaxValidationBindings _bindableMinMax;
    public MinMaxValidationBindings MinMaxRange
    {
        get { return _bindableMinMax; }
        set
        {
            _bindableMinMax = value;

        }
    }

    public DecimalRangeRule()
    {

    }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {

        decimal number = 0;

        if(decimal.TryParse((string)value,out number))
            if (_bindableMinMax.Min != _bindableMinMax.Max || _bindableMinMax.Min != 0)
            {
                if ((number < _bindableMinMax.Min) || (number > _bindableMinMax.Max))
                {
                    return new ValidationResult(false,
                      "Please enter an decimal in the range: " + _bindableMinMax.Min + " - " + _bindableMinMax.Max + ".");
                }
                else
                {
                    return new ValidationResult(true, null);
                }
            }
            else
                return new ValidationResult(true, null);
        else
            return new ValidationResult(true, null);
    }
}

public class AllowNullValidationBinding:FrameworkElement
{
     public static readonly DependencyProperty allowNullProperty = DependencyProperty.Register(
        "AllowNull", typeof(bool), typeof(AllowNullValidationBinding), new UIPropertyMetadata(false));

    public bool AllowNull
    {
        get{return (bool)GetValue(allowNullProperty);}
        set{SetValue(allowNullProperty,value);}
    }
    public AllowNullValidationBinding()
    {}
}

public class MinMaxValidationBindings : FrameworkElement
{
    public static readonly DependencyProperty minProperty = DependencyProperty.Register(
        "Min", typeof(decimal), typeof(MinMaxValidationBindings), new UIPropertyMetadata(0.0m));

    public static readonly DependencyProperty maxProperty = DependencyProperty.Register(
        "Max", typeof(decimal), typeof(MinMaxValidationBindings), new UIPropertyMetadata(0.0m));

    public decimal Min
    {
        get { return (decimal)GetValue(minProperty); }
        set { SetValue(minProperty, value); }
    }

    public decimal Max
    {
        get { return (decimal)GetValue(maxProperty); }
        set { SetValue(maxProperty, value); }
    }

    public MinMaxValidationBindings() { }

}
</code>```

The FrameworkElement bindings are used so my ValidationRules can have dependency properties to bind to. This allows me to specify a min and max value outside the control.

SUMMARY

I've checked the HasError by using the Validation.GetHasError(DecimalBox) (for both the control itself as well as it's inner TextBox) after load and it produces false.

I know that if I remove the ValidatesOnTargetUpdated="True" The red wont appear, but I need it. So why is the validation being reevaluated but the red border adornment not dissapearing?

I don't know much about the Validation class or its static methods, but is there something in there to remove the adornment. The ClearInvalid method isn't gonna help cause I don't have an error to supply it.

Any ideas?

u_u

EDIT

I've done some more investigating and found the following things:

If I change the text after the load to to an amount greater then the maximum and then change it back the error adorner dissapears

If I change the value of the Text dependency property inside the controls load event programically to an amount greater then the maximum and change it back, the adorner is still there.

If I change the text after the load to a null value and then change it back the adorner is still there.

If I change the value of the viewmodel's property bound to the text inside the constructor of the view model, the adorner is still there

If I change the value of the viewmodel's property bound to the text inside the constructor of the view model to a value greater than the maximum, and then change it back, the adorner is still there.

If I change the value of the viewmodel's property bound to the text with a button to a different value, and then change it back, the adorner dissapears

If I change the value of the viewmodel's property bound to the text with a button to a value greater than the maximum, and then change it back, the adorner dissapears

I'm still fairly stumped. Ive tried methods like UpdateLayout() and tried moving the adorner to different controls and moving it back using the Validation.SetValidationAdornerSite. Ima keep trying but I dont know what to do really.

u_u

2ND EDIT

Ok what I had done in the meantime was place an AdornerDecorator around the TextBox and then in the textboxes load event change the maximum to 1 and the value to 2, then change it back in order to get the textbox to refresh.

This was working, but I hated the idea cause its horrible code.

However this solution is no longer viable. I had some code that was doing stuff on the property changed of one of the properties bound to one of these DecimalTextBoxes. Then because the property was being changed and changed back in the load event, the other code was also being run and causing errors. I have to find a better solution then this.

Does anyone know how to refresh the validation adorner?

u_u

答:
I had an issue similar to this where the adorner was not going away even though the underlying error did.

The ultimate workaround that I discovered was to force the layout to be updated by calling

```<code>Control.UpdateLayout()
</code>```

which somehow forced WPF to sync-back up.  I did the Update on a Control_Loaded event handler, but it might fix the issue at other times as well.

Body:
INTRODUCTION

I have created a DecimalTextBox user control which has ValidationRules attached to it to prevent nulls, have a minimum and maximum range and it has event handlers to prevent non-decimal values. I have used

ValidatesOnTargetUpdated="True"

on the bindings because I want the validation to be activated immediately (and I had an issue before where the min and max values were changing but the validation wasn't being reevaluated).

The null validation I have done is dependent on the value of an "AllowNull" dependency property: If the control specifies true then the control is valid even when the value is null. When false then null is not allowed. The default of this property is False

THE PROBLEM

I am setting the AllowNull to true when using it in a certain UserControl. Unfortunately because the ValidatesOnTargetUpdated is set to true, the control is validated before the xaml sets the AllowNull to true, while it is still in its default false setting.

This causes an error before loading, as the binding to the text of the TextBox is also not resolved yet, so before loading it doesn't allow null, and the value of the text is null.

This is all fine and dandy because after the loading the validation is reevaluated with the new AllowNull value (of true) and the error is removed.

However the red validation adornment remains. Not entirely sure how to get rid of it.

THE CODE
The xaml for the textbox usercontrol:

<UserControl x:Class="WPFTest.DecimalTextBox"
         x:Name="DecimalBox"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:v="clr-namespace:ValidationRules"
         mc:Ignorable="d"
         d:DesignHeight="25" d:DesignWidth="100" Initialized="DecimalBox_Initialized" >

    <TextBox x:Name="textbox">
        <TextBox.Text>
            <Binding ElementName="DecimalBox" TargetNullValue="" Path="Text" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" NotifyOnValidationError="True">
                <Binding.ValidationRules>
                    <v:DecimalRangeRule  ValidatesOnTargetUpdated="True">
                        <v:DecimalRangeRule.MinMaxRange>
                            <v:MinMaxValidationBindings x:Name="minMaxValidationBindings"/>
                        </v:DecimalRangeRule.MinMaxRange>
                    </v:DecimalRangeRule>
                    <v:NotEmptyRule  ValidatesOnTargetUpdated="True">
                        <v:NotEmptyRule.AllowNull>
                            <v:AllowNullValidationBinding x:Name="allowNullValidationBindings"></v:AllowNullValidationBinding>
                        </v:NotEmptyRule.AllowNull>
                    </v:NotEmptyRule>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
</UserControl>

The code behind for the control:

    public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(textboxcontrol), new PropertyMetadata());
    public static DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(decimal), typeof(DecimalTextBox), new PropertyMetadata(0M));
    public static DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(decimal), typeof(DecimalTextBox), new PropertyMetadata(0M));
    public static DependencyProperty AllowNullProperty = DependencyProperty.Register("AllowNull", typeof(bool), typeof(DecimalTextBox), new UIPropertyMetadata(false));

    public bool AllowNull
    {
        get { return (bool)GetValue(AllowNullProperty); }
        set { SetValue(AllowNullProperty, value); }
    }
    public decimal Minimum
    {
        get { return (decimal)GetValue(MinimumProperty); }
        set { SetValue(MinimumProperty, value); }
    }
    public decimal Maximum
    {
        get { return (decimal)GetValue(MaximumProperty); }
        set { SetValue(MaximumProperty, value); }
    }
    public string Text
    {
        get
        {
            return (string)GetValue(TextProperty);
        }
        set
        {
            SetValue(TextProperty, value);
        }
    }

    private void DecimalBox_Initialized(object sender, EventArgs e)
    {
        Binding minBinding = new Binding("Minimum");
        minBinding.Source = this;
        Binding maxBinding = new Binding("Maximum");
        maxBinding.Source = this;
        Binding allownullBinding = new Binding("AllowNull");
        allownullBinding.Source = this;

        minMaxValidationBindings.SetBinding(ValidationRules.MinMaxValidationBindings.minProperty, minBinding);
        BindingOperations.SetBinding(minMaxValidationBindings, ValidationRules.MinMaxValidationBindings.maxProperty, maxBinding);
        BindingOperations.SetBinding(allowNullValidationBindings, ValidationRules.AllowNullValidationBinding.allowNullProperty, allownullBinding);
    }

And the Validation Rules (#Note: They are inside the ValidationRules namespace):

public class NotEmptyRule : ValidationRule
{

    public NotEmptyRule()
    {
    }
    private AllowNullValidationBinding _allowNullBinding;

    public AllowNullValidationBinding AllowNull
    {
        get { return _allowNullBinding; }
        set { _allowNullBinding = value; }
    }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (!_allowNullBinding.AllowNull)
            if (string.IsNullOrEmpty((string)value))
                return new ValidationResult(false,
                  "Value cannot be null or empty.");
            else
                return new ValidationResult(true, null);

        else
           return new ValidationResult(true, null);

    }
}

public class DecimalRangeRule : ValidationRule
{
    private MinMaxValidationBindings _bindableMinMax;
    public MinMaxValidationBindings MinMaxRange
    {
        get { return _bindableMinMax; }
        set
        {
            _bindableMinMax = value;

        }
    }

    public DecimalRangeRule()
    {

    }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {

        decimal number = 0;

        if(decimal.TryParse((string)value,out number))
            if (_bindableMinMax.Min != _bindableMinMax.Max || _bindableMinMax.Min != 0)
            {
                if ((number < _bindableMinMax.Min) || (number > _bindableMinMax.Max))
                {
                    return new ValidationResult(false,
                      "Please enter an decimal in the range: " + _bindableMinMax.Min + " - " + _bindableMinMax.Max + ".");
                }
                else
                {
                    return new ValidationResult(true, null);
                }
            }
            else
                return new ValidationResult(true, null);
        else
            return new ValidationResult(true, null);
    }
}

public class AllowNullValidationBinding:FrameworkElement
{
     public static readonly DependencyProperty allowNullProperty = DependencyProperty.Register(
        "AllowNull", typeof(bool), typeof(AllowNullValidationBinding), new UIPropertyMetadata(false));

    public bool AllowNull
    {
        get{return (bool)GetValue(allowNullProperty);}
        set{SetValue(allowNullProperty,value);}
    }
    public AllowNullValidationBinding()
    {}
}

public class MinMaxValidationBindings : FrameworkElement
{
    public static readonly DependencyProperty minProperty = DependencyProperty.Register(
        "Min", typeof(decimal), typeof(MinMaxValidationBindings), new UIPropertyMetadata(0.0m));

    public static readonly DependencyProperty maxProperty = DependencyProperty.Register(
        "Max", typeof(decimal), typeof(MinMaxValidationBindings), new UIPropertyMetadata(0.0m));

    public decimal Min
    {
        get { return (decimal)GetValue(minProperty); }
        set { SetValue(minProperty, value); }
    }

    public decimal Max
    {
        get { return (decimal)GetValue(maxProperty); }
        set { SetValue(maxProperty, value); }
    }

    public MinMaxValidationBindings() { }

}

The FrameworkElement bindings are used so my ValidationRules can have dependency properties to bind to. This allows me to specify a min and max value outside the control.

SUMMARY

I've checked the HasError by using the Validation.GetHasError(DecimalBox) (for both the control itself as well as it's inner TextBox) after load and it produces false.

I know that if I remove the ValidatesOnTargetUpdated="True" The red wont appear, but I need it. So why is the validation being reevaluated but the red border adornment not dissapearing?

I don't know much about the Validation class or its static methods, but is there something in there to remove the adornment. The ClearInvalid method isn't gonna help cause I don't have an error to supply it.

Any ideas?

u_u

EDIT

I've done some more investigating and found the following things:

If I change the text after the load to to an amount greater then the maximum and then change it back the error adorner dissapears

If I change the value of the Text dependency property inside the controls load event programically to an amount greater then the maximum and change it back, the adorner is still there.

If I change the text after the load to a null value and then change it back the adorner is still there.

If I change the value of the viewmodel's property bound to the text inside the constructor of the view model, the adorner is still there

If I change the value of the viewmodel's property bound to the text inside the constructor of the view model to a value greater than the maximum, and then change it back, the adorner is still there.

If I change the value of the viewmodel's property bound to the text with a button to a different value, and then change it back, the adorner dissapears

If I change the value of the viewmodel's property bound to the text with a button to a value greater than the maximum, and then change it back, the adorner dissapears

I'm still fairly stumped. Ive tried methods like UpdateLayout() and tried moving the adorner to different controls and moving it back using the Validation.SetValidationAdornerSite. Ima keep trying but I dont know what to do really.

u_u

2ND EDIT

Ok what I had done in the meantime was place an AdornerDecorator around the TextBox and then in the textboxes load event change the maximum to 1 and the value to 2, then change it back in order to get the textbox to refresh.

This was working, but I hated the idea cause its horrible code.

However this solution is no longer viable. I had some code that was doing stuff on the property changed of one of the properties bound to one of these DecimalTextBoxes. Then because the property was being changed and changed back in the load event, the other code was also being run and causing errors. I have to find a better solution then this.

Does anyone know how to refresh the validation adorner?

u_u

Body:
I had an issue similar to this where the adorner was not going away even though the underlying error did.

The ultimate workaround that I discovered was to force the layout to be updated by calling

Control.UpdateLayout()

which somehow forced WPF to sync-back up.  I did the Update on a Control_Loaded event handler, but it might fix the issue at other times as well.


问:
SSL handshake failure after ClientHello in Ubuntu 20.04 and Debian 10 (works in Ubuntu 18.04 and Debian 9)
I have been trying to use Oracle Cloud Email Delivery Service. Once configured it provides SMTP credentials which you can use to send email from approved senders.

I am stuck with few interesting scenarios.
It works in Ubuntu 18.04 but fails in docker container(running Debian 10) running on same machine.

I was testing handshake with openssl s_client

```<code>echo QUIT | openssl s_client -starttls smtp -crlf -connect smtp.email.ap-mumbai-1.oci.oraclecloud.com:587
</code>```

This command works fine in Ubuntu 18.04 but fails with handshake failure in docker container running Debian 10

Output from Docker Container

```<code>root@06369bfe7c16:/var/www/html# echo QUIT | openssl s_client -starttls smtp -crlf -connect smtp.email.ap-mumbai-1.oci.oraclecloud.com:587
CONNECTED(00000003)
140491098481792:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1544:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 199 bytes and written 367 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
root@06369bfe7c16:/var/www/html#
</code>```

I tried to check openssl versions in both.

18.04 is having openssl version OpenSSL 1.1.1  11 Sep 2018

Docker container is having openssl version OpenSSL 1.1.1d  10 Sep 2019

Can it be something related to versions?

I tried to debug more via Wireshark to see how ClientHello messages are sent -

ClientHello from Ubuntu 18.04 ( which returns in success)

```<code>TLSv1.2 Record Layer: Handshake Protocol: Client Hello
    Content Type: Handshake (22)
    Version: TLS 1.0 (0x0301)
    Length: 339
    Handshake Protocol: Client Hello
        Handshake Type: Client Hello (1)
        Length: 335
        Version: TLS 1.2 (0x0303)
        Random: e595f987b8d92387f7114d9dee4df7bc3f00b5b082ba0ec8…
        Session ID Length: 32
        Session ID: 74c873d7894514a047e0763cd14c01fb19a4f238cb9085f2…
        Cipher Suites Length: 62
        Cipher Suites (31 suites)
            Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
            Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
            Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
            Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
            Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
            Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
            Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
            Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
        Compression Methods Length: 1
        Compression Methods (1 method)
            Compression Method: null (0)
        Extensions Length: 200
        Extension: server_name (len=47)
            Type: server_name (0)
            Length: 47
            Server Name Indication extension
        Extension: ec_point_formats (len=4)
            Type: ec_point_formats (11)
            Length: 4
            EC point formats Length: 3
            Elliptic curves point formats (3)
                EC point format: uncompressed (0)
                EC point format: ansiX962_compressed_prime (1)
                EC point format: ansiX962_compressed_char2 (2)
        Extension: supported_groups (len=12)
            Type: supported_groups (10)
            Length: 12
            Supported Groups List Length: 10
            Supported Groups (5 groups)
        Extension: session_ticket (len=0)
            Type: session_ticket (35)
            Length: 0
            Data (0 bytes)
        Extension: encrypt_then_mac (len=0)
            Type: encrypt_then_mac (22)
            Length: 0
        Extension: extended_master_secret (len=0)
            Type: extended_master_secret (23)
            Length: 0
        Extension: signature_algorithms (len=48)
            Type: signature_algorithms (13)
            Length: 48
            Signature Hash Algorithms Length: 46
            Signature Hash Algorithms (23 algorithms)
                Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
                Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503)
                Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603)
                Signature Algorithm: ed25519 (0x0807)
                Signature Algorithm: ed448 (0x0808)
                Signature Algorithm: rsa_pss_pss_sha256 (0x0809)
                Signature Algorithm: rsa_pss_pss_sha384 (0x080a)
                Signature Algorithm: rsa_pss_pss_sha512 (0x080b)
                Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
                Signature Algorithm: rsa_pss_rsae_sha384 (0x0805)
                Signature Algorithm: rsa_pss_rsae_sha512 (0x0806)
                Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
                Signature Algorithm: rsa_pkcs1_sha384 (0x0501)
                Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
                Signature Algorithm: SHA224 ECDSA (0x0303)
                Signature Algorithm: ecdsa_sha1 (0x0203)
                Signature Algorithm: SHA224 RSA (0x0301)
                Signature Algorithm: rsa_pkcs1_sha1 (0x0201)
                Signature Algorithm: SHA224 DSA (0x0302)
                Signature Algorithm: SHA1 DSA (0x0202)
                Signature Algorithm: SHA256 DSA (0x0402)
                Signature Algorithm: SHA384 DSA (0x0502)
                Signature Algorithm: SHA512 DSA (0x0602)
        Extension: supported_versions (len=9)
            Type: supported_versions (43)
            Length: 9
            Supported Versions length: 8
            Supported Version: TLS 1.3 (0x0304)
            Supported Version: TLS 1.2 (0x0303)
            Supported Version: TLS 1.1 (0x0302)
            Supported Version: TLS 1.0 (0x0301)
        Extension: psk_key_exchange_modes (len=2)
            Type: psk_key_exchange_modes (45)
            Length: 2
            PSK Key Exchange Modes Length: 1
            PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)
        Extension: key_share (len=38)
            Type: key_share (51)
            Length: 38
            Key Share extension
</code>```

ClientHello message from Docker Container (which results in handshake failure SSL alert number 40)

```<code>TLSv1.2 Record Layer: Handshake Protocol: Client Hello
    Content Type: Handshake (22)
    Version: TLS 1.0 (0x0301)
    Length: 234
    Handshake Protocol: Client Hello
        Handshake Type: Client Hello (1)
        Length: 230
        Version: TLS 1.2 (0x0303)
        Random: 20375888f578157f3989533cc8d2c6e5b1db2795dba56ff2…
        Session ID Length: 0
        Cipher Suites Length: 56
        Cipher Suites (28 suites)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
            Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
            Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
            Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
            Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
            Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
        Compression Methods Length: 1
        Compression Methods (1 method)
            Compression Method: null (0)
        Extensions Length: 133
        Extension: server_name (len=47)
            Type: server_name (0)
            Length: 47
            Server Name Indication extension
        Extension: ec_point_formats (len=4)
            Type: ec_point_formats (11)
            Length: 4
            EC point formats Length: 3
            Elliptic curves point formats (3)
                EC point format: uncompressed (0)
                EC point format: ansiX962_compressed_prime (1)
                EC point format: ansiX962_compressed_char2 (2)
        Extension: supported_groups (len=12)
            Type: supported_groups (10)
            Length: 12
            Supported Groups List Length: 10
            Supported Groups (5 groups)
        Extension: session_ticket (len=0)
            Type: session_ticket (35)
            Length: 0
            Data (0 bytes)
        Extension: encrypt_then_mac (len=0)
            Type: encrypt_then_mac (22)
            Length: 0
        Extension: extended_master_secret (len=0)
            Type: extended_master_secret (23)
            Length: 0
        Extension: signature_algorithms (len=42)
            Type: signature_algorithms (13)
            Length: 42
            Signature Hash Algorithms Length: 40
            Signature Hash Algorithms (20 algorithms)
                Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
                Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503)
                Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603)
                Signature Algorithm: ed25519 (0x0807)
                Signature Algorithm: ed448 (0x0808)
                Signature Algorithm: rsa_pss_pss_sha256 (0x0809)
                Signature Algorithm: rsa_pss_pss_sha384 (0x080a)
                Signature Algorithm: rsa_pss_pss_sha512 (0x080b)
                Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
                Signature Algorithm: rsa_pss_rsae_sha384 (0x0805)
                Signature Algorithm: rsa_pss_rsae_sha512 (0x0806)
                Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
                Signature Algorithm: rsa_pkcs1_sha384 (0x0501)
                Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
                Signature Algorithm: SHA224 ECDSA (0x0303)
                Signature Algorithm: SHA224 RSA (0x0301)
                Signature Algorithm: SHA224 DSA (0x0302)
                Signature Algorithm: SHA256 DSA (0x0402)
                Signature Algorithm: SHA384 DSA (0x0502)
                Signature Algorithm: SHA512 DSA (0x0602)

</code>```

This is ServerHello message from Ubuntu 18.04

```<code>TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 4345
    Handshake Protocol: Server Hello
        Handshake Type: Server Hello (2)
        Length: 81
        Version: TLS 1.2 (0x0303)
        Random: 5ecea16938ffb32685dee0d46241ab4533820a178f3766e6…
        Session ID Length: 32
        Session ID: 5ecea169972b4c49269218eb6d64fbdeedb76539703d48e5…
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
        Compression Method: null (0)
        Extensions Length: 9
        Extension: renegotiation_info (len=1)
        Extension: extended_master_secret (len=0)
    Handshake Protocol: Certificate
    Handshake Protocol: Server Key Exchange
        Handshake Type: Server Key Exchange (12)
        Length: 329
        EC Diffie-Hellman Server Params
            Curve Type: named_curve (0x03)
            Named Curve: secp256r1 (0x0017)
            Pubkey Length: 65
            Pubkey: 048f81fb0fcd06c8f1d50620af144965cae3dd3804df3454…
            Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
            Signature Length: 256
            Signature: 76bf06d1a887440d01be65938a92094510ae52e031463d58…
    Handshake Protocol: Server Hello Done
</code>```

Server seems to use CipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 which happens to be present in Docker Container ClientHello as well.

So What I am missing in this case. I am new to SSL debugging.

If Ciphersuites are matching what could be different so that servers returns handshake failure?

Please provide me directions what can I investigate next.

I have uploaded wireshark captures at https://gofile.io/d/ERJXNe

There is one capture from docker container running Debian-9,(openssl 1.1.0l) which results in handshake success.

Update:
I tried to use openssl s_client in latest Ubuntu 20.04 VM, it fails with handshake failure.

答:
FYI, the server was updated to use a SHA-2 root certificate to resolve this issue. But here's an analysis of the issue and underlying standards:

The actual issue is that the certificate chain for this server has a SHA-1 root certificate, and the client has stated that it doesn't support validation of SHA-1 certificates in the certificate chain. Reading the TLS 1.2 specification (https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.4.1), the server's behavior is correct under a reasonable interpretation:

```<code>   The client uses the "signature_algorithms" extension to indicate to
   the server which signature/hash algorithm pairs may be used in
   digital signatures.
</code>```

The TLS 1.3 specification has more to say about this situation (https://www.rfc-editor.org/rfc/rfc8446#section-4.4.2.2):

```<code>   All certificates provided by the server MUST be signed by a signature
   algorithm advertised by the client if it is able to provide such a
   chain (see Section 4.2.3).  Certificates that are self-signed or
   certificates that are expected to be trust anchors are not validated
   as part of the chain and therefore MAY be signed with any algorithm.

   If the server cannot produce a certificate chain that is signed only
   via the indicated supported algorithms, then it SHOULD continue the
   handshake by sending the client a certificate chain of its choice
   that may include algorithms that are not known to be supported by the
   client.  This fallback chain SHOULD NOT use the deprecated SHA-1 hash
   algorithm in general, but MAY do so if the client's advertisement
   permits it, and MUST NOT do so otherwise.
</code>```

With this text, the interpretation depends on the word "use". If it means "use in certificate chain", the server's behavior is correct and the TLS 1.3 spec is self-contradictory. If it means "use to validate certificate chain", then the server's behavior is wrong (under TLS 1.3 rules) and the TLS 1.3 spec is consistent. I'm going to assume the latter is the better interpretation.

So the server follows the TLS 1.2 rules but has not been updated to follow TLS 1.3 rules. As one of the engineers working on the server in question, I consider this a bug since TLS 1.3 supersedes TLS 1.2 but as it's a behavior change between two versions of the standard, it's not a particularly serious bug.

Body:
I have been trying to use Oracle Cloud Email Delivery Service. Once configured it provides SMTP credentials which you can use to send email from approved senders.

I am stuck with few interesting scenarios.
It works in Ubuntu 18.04 but fails in docker container(running Debian 10) running on same machine.

I was testing handshake with openssl s_client

echo QUIT | openssl s_client -starttls smtp -crlf -connect smtp.email.ap-mumbai-1.oci.oraclecloud.com:587

This command works fine in Ubuntu 18.04 but fails with handshake failure in docker container running Debian 10

Output from Docker Container

root@06369bfe7c16:/var/www/html# echo QUIT | openssl s_client -starttls smtp -crlf -connect smtp.email.ap-mumbai-1.oci.oraclecloud.com:587
CONNECTED(00000003)
140491098481792:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1544:SSL alert number 40
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 199 bytes and written 367 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
root@06369bfe7c16:/var/www/html#

I tried to check openssl versions in both.

18.04 is having openssl version OpenSSL 1.1.1  11 Sep 2018

Docker container is having openssl version OpenSSL 1.1.1d  10 Sep 2019

Can it be something related to versions?

I tried to debug more via Wireshark to see how ClientHello messages are sent -

ClientHello from Ubuntu 18.04 ( which returns in success)

TLSv1.2 Record Layer: Handshake Protocol: Client Hello
    Content Type: Handshake (22)
    Version: TLS 1.0 (0x0301)
    Length: 339
    Handshake Protocol: Client Hello
        Handshake Type: Client Hello (1)
        Length: 335
        Version: TLS 1.2 (0x0303)
        Random: e595f987b8d92387f7114d9dee4df7bc3f00b5b082ba0ec8…
        Session ID Length: 32
        Session ID: 74c873d7894514a047e0763cd14c01fb19a4f238cb9085f2…
        Cipher Suites Length: 62
        Cipher Suites (31 suites)
            Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302)
            Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303)
            Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
            Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
            Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
            Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
            Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
            Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
        Compression Methods Length: 1
        Compression Methods (1 method)
            Compression Method: null (0)
        Extensions Length: 200
        Extension: server_name (len=47)
            Type: server_name (0)
            Length: 47
            Server Name Indication extension
        Extension: ec_point_formats (len=4)
            Type: ec_point_formats (11)
            Length: 4
            EC point formats Length: 3
            Elliptic curves point formats (3)
                EC point format: uncompressed (0)
                EC point format: ansiX962_compressed_prime (1)
                EC point format: ansiX962_compressed_char2 (2)
        Extension: supported_groups (len=12)
            Type: supported_groups (10)
            Length: 12
            Supported Groups List Length: 10
            Supported Groups (5 groups)
        Extension: session_ticket (len=0)
            Type: session_ticket (35)
            Length: 0
            Data (0 bytes)
        Extension: encrypt_then_mac (len=0)
            Type: encrypt_then_mac (22)
            Length: 0
        Extension: extended_master_secret (len=0)
            Type: extended_master_secret (23)
            Length: 0
        Extension: signature_algorithms (len=48)
            Type: signature_algorithms (13)
            Length: 48
            Signature Hash Algorithms Length: 46
            Signature Hash Algorithms (23 algorithms)
                Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
                Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503)
                Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603)
                Signature Algorithm: ed25519 (0x0807)
                Signature Algorithm: ed448 (0x0808)
                Signature Algorithm: rsa_pss_pss_sha256 (0x0809)
                Signature Algorithm: rsa_pss_pss_sha384 (0x080a)
                Signature Algorithm: rsa_pss_pss_sha512 (0x080b)
                Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
                Signature Algorithm: rsa_pss_rsae_sha384 (0x0805)
                Signature Algorithm: rsa_pss_rsae_sha512 (0x0806)
                Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
                Signature Algorithm: rsa_pkcs1_sha384 (0x0501)
                Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
                Signature Algorithm: SHA224 ECDSA (0x0303)
                Signature Algorithm: ecdsa_sha1 (0x0203)
                Signature Algorithm: SHA224 RSA (0x0301)
                Signature Algorithm: rsa_pkcs1_sha1 (0x0201)
                Signature Algorithm: SHA224 DSA (0x0302)
                Signature Algorithm: SHA1 DSA (0x0202)
                Signature Algorithm: SHA256 DSA (0x0402)
                Signature Algorithm: SHA384 DSA (0x0502)
                Signature Algorithm: SHA512 DSA (0x0602)
        Extension: supported_versions (len=9)
            Type: supported_versions (43)
            Length: 9
            Supported Versions length: 8
            Supported Version: TLS 1.3 (0x0304)
            Supported Version: TLS 1.2 (0x0303)
            Supported Version: TLS 1.1 (0x0302)
            Supported Version: TLS 1.0 (0x0301)
        Extension: psk_key_exchange_modes (len=2)
            Type: psk_key_exchange_modes (45)
            Length: 2
            PSK Key Exchange Modes Length: 1
            PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)
        Extension: key_share (len=38)
            Type: key_share (51)
            Length: 38
            Key Share extension

ClientHello message from Docker Container (which results in handshake failure SSL alert number 40)

TLSv1.2 Record Layer: Handshake Protocol: Client Hello
    Content Type: Handshake (22)
    Version: TLS 1.0 (0x0301)
    Length: 234
    Handshake Protocol: Client Hello
        Handshake Type: Client Hello (1)
        Length: 230
        Version: TLS 1.2 (0x0303)
        Random: 20375888f578157f3989533cc8d2c6e5b1db2795dba56ff2…
        Session ID Length: 0
        Cipher Suites Length: 56
        Cipher Suites (28 suites)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
            Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
            Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
            Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
            Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
            Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
            Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
            Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
            Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
            Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
        Compression Methods Length: 1
        Compression Methods (1 method)
            Compression Method: null (0)
        Extensions Length: 133
        Extension: server_name (len=47)
            Type: server_name (0)
            Length: 47
            Server Name Indication extension
        Extension: ec_point_formats (len=4)
            Type: ec_point_formats (11)
            Length: 4
            EC point formats Length: 3
            Elliptic curves point formats (3)
                EC point format: uncompressed (0)
                EC point format: ansiX962_compressed_prime (1)
                EC point format: ansiX962_compressed_char2 (2)
        Extension: supported_groups (len=12)
            Type: supported_groups (10)
            Length: 12
            Supported Groups List Length: 10
            Supported Groups (5 groups)
        Extension: session_ticket (len=0)
            Type: session_ticket (35)
            Length: 0
            Data (0 bytes)
        Extension: encrypt_then_mac (len=0)
            Type: encrypt_then_mac (22)
            Length: 0
        Extension: extended_master_secret (len=0)
            Type: extended_master_secret (23)
            Length: 0
        Extension: signature_algorithms (len=42)
            Type: signature_algorithms (13)
            Length: 42
            Signature Hash Algorithms Length: 40
            Signature Hash Algorithms (20 algorithms)
                Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
                Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503)
                Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603)
                Signature Algorithm: ed25519 (0x0807)
                Signature Algorithm: ed448 (0x0808)
                Signature Algorithm: rsa_pss_pss_sha256 (0x0809)
                Signature Algorithm: rsa_pss_pss_sha384 (0x080a)
                Signature Algorithm: rsa_pss_pss_sha512 (0x080b)
                Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
                Signature Algorithm: rsa_pss_rsae_sha384 (0x0805)
                Signature Algorithm: rsa_pss_rsae_sha512 (0x0806)
                Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
                Signature Algorithm: rsa_pkcs1_sha384 (0x0501)
                Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
                Signature Algorithm: SHA224 ECDSA (0x0303)
                Signature Algorithm: SHA224 RSA (0x0301)
                Signature Algorithm: SHA224 DSA (0x0302)
                Signature Algorithm: SHA256 DSA (0x0402)
                Signature Algorithm: SHA384 DSA (0x0502)
                Signature Algorithm: SHA512 DSA (0x0602)

This is ServerHello message from Ubuntu 18.04

TLSv1.2 Record Layer: Handshake Protocol: Multiple Handshake Messages
    Content Type: Handshake (22)
    Version: TLS 1.2 (0x0303)
    Length: 4345
    Handshake Protocol: Server Hello
        Handshake Type: Server Hello (2)
        Length: 81
        Version: TLS 1.2 (0x0303)
        Random: 5ecea16938ffb32685dee0d46241ab4533820a178f3766e6…
        Session ID Length: 32
        Session ID: 5ecea169972b4c49269218eb6d64fbdeedb76539703d48e5…
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
        Compression Method: null (0)
        Extensions Length: 9
        Extension: renegotiation_info (len=1)
        Extension: extended_master_secret (len=0)
    Handshake Protocol: Certificate
    Handshake Protocol: Server Key Exchange
        Handshake Type: Server Key Exchange (12)
        Length: 329
        EC Diffie-Hellman Server Params
            Curve Type: named_curve (0x03)
            Named Curve: secp256r1 (0x0017)
            Pubkey Length: 65
            Pubkey: 048f81fb0fcd06c8f1d50620af144965cae3dd3804df3454…
            Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
            Signature Length: 256
            Signature: 76bf06d1a887440d01be65938a92094510ae52e031463d58…
    Handshake Protocol: Server Hello Done

Server seems to use CipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 which happens to be present in Docker Container ClientHello as well.

So What I am missing in this case. I am new to SSL debugging.

If Ciphersuites are matching what could be different so that servers returns handshake failure?

Please provide me directions what can I investigate next.

I have uploaded wireshark captures at https://gofile.io/d/ERJXNe

There is one capture from docker container running Debian-9,(openssl 1.1.0l) which results in handshake success.

Update:
I tried to use openssl s_client in latest Ubuntu 20.04 VM, it fails with handshake failure.

Body:
FYI, the server was updated to use a SHA-2 root certificate to resolve this issue. But here's an analysis of the issue and underlying standards:

The actual issue is that the certificate chain for this server has a SHA-1 root certificate, and the client has stated that it doesn't support validation of SHA-1 certificates in the certificate chain. Reading the TLS 1.2 specification (https://www.rfc-editor.org/rfc/rfc5246#section-7.4.1.4.1), the server's behavior is correct under a reasonable interpretation:

   The client uses the "signature_algorithms" extension to indicate to
   the server which signature/hash algorithm pairs may be used in
   digital signatures.

The TLS 1.3 specification has more to say about this situation (https://www.rfc-editor.org/rfc/rfc8446#section-4.4.2.2):

   All certificates provided by the server MUST be signed by a signature
   algorithm advertised by the client if it is able to provide such a
   chain (see Section 4.2.3).  Certificates that are self-signed or
   certificates that are expected to be trust anchors are not validated
   as part of the chain and therefore MAY be signed with any algorithm.

   If the server cannot produce a certificate chain that is signed only
   via the indicated supported algorithms, then it SHOULD continue the
   handshake by sending the client a certificate chain of its choice
   that may include algorithms that are not known to be supported by the
   client.  This fallback chain SHOULD NOT use the deprecated SHA-1 hash
   algorithm in general, but MAY do so if the client's advertisement
   permits it, and MUST NOT do so otherwise.

With this text, the interpretation depends on the word "use". If it means "use in certificate chain", the server's behavior is correct and the TLS 1.3 spec is self-contradictory. If it means "use to validate certificate chain", then the server's behavior is wrong (under TLS 1.3 rules) and the TLS 1.3 spec is consistent. I'm going to assume the latter is the better interpretation.

So the server follows the TLS 1.2 rules but has not been updated to follow TLS 1.3 rules. As one of the engineers working on the server in question, I consider this a bug since TLS 1.3 supersedes TLS 1.2 but as it's a behavior change between two versions of the standard, it's not a particularly serious bug.


问:
How to get String from Mono<String> in reactive java
I have a method which accepts Mono as a param.
All I want is to get the actual String from it. Googled but didn't find answer except calling block() over Mono object but it will make a blocking call so want to avoid using block(). Please suggest other way if possible.
The reason why I need this String is because inside this method I need to call another method say print() with the actual String value.
I understand this is easy but I am new to reactive programming.

Code:

```<code>public String getValue(Mono<String> monoString) {
    // How to get actual String from param monoString
    // and call print(String) method
}

public void print(String str) {
    System.out.println(str);
}
</code>```

答:
Simplest answer is:</p>

```<code> String returnVal = mono.block();
</code>```

Body:
I have a method which accepts Mono as a param.
All I want is to get the actual String from it. Googled but didn't find answer except calling block() over Mono object but it will make a blocking call so want to avoid using block(). Please suggest other way if possible.
The reason why I need this String is because inside this method I need to call another method say print() with the actual String value.
I understand this is easy but I am new to reactive programming.

Code:

public String getValue(Mono<String> monoString) {
    // How to get actual String from param monoString
    // and call print(String) method
}

public void print(String str) {
    System.out.println(str);
}

Body:
Simplest answer is:

 String returnVal = mono.block();


问:
Hibernate JPA 2 Metamodel Generator Turkish Char problem
```<code>    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-jpamodelgen</artifactId>
        <version>6.0.0.Alpha2</version>
    </dependency>
</code>```

When I add hibernate-jpamodelgen dependency to the project. Everything works properly until the compilation process. I can see generated metamodel classes under target folder. But because of my system defaults (that are related to my operating system), the field name constants on metamodel classes are converted wrong.

```<code>public static final String TRANST�ME = "transtime";
public static final String NOTE = "note";
public static final String �SACT�VE = "isactive";
</code>```

-

```<code>[ERROR] /C:/Users/*/IdeaProjects/*/target/generated-sources/annotations/*/model/acc/InvtypeView_.java:[20,37] illegal character: '\ufffd'
</code>```

And that causes a compile error. When I analyzed the code generation process I can see org.hibernate.jpamodelgen.util.StringUtil classes' getUpperUnderscoreCaseFromLowerCamelCase method causes this.

```<code>public static String getUpperUnderscoreCaseFromLowerCamelCase(String lowerCamelCaseString){
    return lowerCamelCaseString.replaceAll("(.)(\\p{Upper})", "$1_$2").toUpperCase();
}
</code>```

toUpperCase method should have parameter Locale.ROOT.

I've created an issue on Hibernate issue tracker system.

Any quick solution/workaround would be great.

答:
I had the same problems. My problem was solved with the following plugins</p>

```<code><plugin>
            <inherited>true</inherited>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <compilerArgument>-proc:none</compilerArgument>
                <encoding>UTF-8</encoding>
                <showWarnings>true</showWarnings>
                <showDeprecation>true</showDeprecation>

            </configuration>
        </plugin>

        <plugin>
            <groupId>org.bsc.maven</groupId>
            <artifactId>maven-processor-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>process</goal>
                    </goals>
                    <phase>generate-sources</phase>
                    <configuration>
                        <compilerArguments>-AaddGeneratedAnnotation=false</compilerArguments> <!-- suppress java.annotation -->
                        <processors>
                            <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
                        </processors>
                        <outputDirectory>generated</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
</code>```

Body:
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-jpamodelgen</artifactId>
        <version>6.0.0.Alpha2</version>
    </dependency>

When I add hibernate-jpamodelgen dependency to the project. Everything works properly until the compilation process. I can see generated metamodel classes under target folder. But because of my system defaults (that are related to my operating system), the field name constants on metamodel classes are converted wrong.

public static final String TRANST�ME = "transtime";
public static final String NOTE = "note";
public static final String �SACT�VE = "isactive";

-

[ERROR] /C:/Users/*/IdeaProjects/*/target/generated-sources/annotations/*/model/acc/InvtypeView_.java:[20,37] illegal character: '\ufffd'

And that causes a compile error. When I analyzed the code generation process I can see org.hibernate.jpamodelgen.util.StringUtil classes' getUpperUnderscoreCaseFromLowerCamelCase method causes this.

public static String getUpperUnderscoreCaseFromLowerCamelCase(String lowerCamelCaseString){
    return lowerCamelCaseString.replaceAll("(.)(\\p{Upper})", "$1_$2").toUpperCase();
}

toUpperCase method should have parameter Locale.ROOT.

I've created an issue on Hibernate issue tracker system.

Any quick solution/workaround would be great.

Body:
I had the same problems. My problem was solved with the following plugins

<plugin>
            <inherited>true</inherited>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <source>${java.version}</source>
                <target>${java.version}</target>
                <compilerArgument>-proc:none</compilerArgument>
                <encoding>UTF-8</encoding>
                <showWarnings>true</showWarnings>
                <showDeprecation>true</showDeprecation>

            </configuration>
        </plugin>

        <plugin>
            <groupId>org.bsc.maven</groupId>
            <artifactId>maven-processor-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>process</goal>
                    </goals>
                    <phase>generate-sources</phase>
                    <configuration>
                        <compilerArguments>-AaddGeneratedAnnotation=false</compilerArguments> <!-- suppress java.annotation -->
                        <processors>
                            <processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
                        </processors>
                        <outputDirectory>generated</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>


答:
You are attempting to determine a variable name dynamically.

While there is a way to do this with eval(), it's a bad idea, as it opens up code to malicious hacking.

let project0 = [1,2,3];
let val = eval('project' + '0' + '[1]');
console.log(val); // 2
```

<p>If you really want to access names dynamically, you could alternatively store them as properties in a object:</p>

<pre class="lang-js prettyprint-override"><code>let myObj = {
  project0: ['zero'],
  project1: ['one'],
  project2: ['two']
}
</code>```

Then, since object properties are strings, you can access them easily:

```<code>let i = 0;
let pName = 'project' + i;
let project = myObj[pName];
console.log(project[0]); // 'zero'
</code>```

Finally, you can loop through the properties in myObj to form your desired result:

let projectNumbers = [];
for (let i = 0; myObj["project"+i]; i++) {
  projectNumbers.push(myObj["project"+i][0])
}
console.log(projectNumbers);  // [ 'zero', 'one', 'two' ]
```

Title: How do I call variables with similar names using a for loop?

Body:
You are attempting to determine a variable name dynamically.

While there is a way to do this with eval(), it's a bad idea, as it opens up code to malicious hacking.

let project0 = [1,2,3];
let val = eval('project' + '0' + '[1]');
console.log(val); // 2

If you really want to access names dynamically, you could alternatively store them as properties in a object:

let myObj = {
  project0: ['zero'],
  project1: ['one'],
  project2: ['two']
}

Then, since object properties are strings, you can access them easily:

let i = 0;
let pName = 'project' + i;
let project = myObj[pName];
console.log(project[0]); // 'zero'

Finally, you can loop through the properties in myObj to form your desired result:

let projectNumbers = [];
for (let i = 0; myObj["project"+i]; i++) {
  projectNumbers.push(myObj["project"+i][0])
}
console.log(projectNumbers);  // [ 'zero', 'one', 'two' ]