问:
Delphi: Store data in somekind of structure
For a simulation program I'm working in Delphi 2010. The simulation isn't a problem but I need to use large collection of data which gives a problem. The data is available in excel sheets, so there is no need to edit this data in Delphi, but collecting this data from the excel sheets takes around 10min. This isn't a problem as long as you don't need to collect the data  every time the program runs. So I made a program which collects all the data makes it visible, not problems here,and then store it. However I can't store it to a "Delphi format" , without losing the structure, so it can be loaded in a few seconds.

I'm not that experienced in Delphi and I searched a long time for the solution but couldn't understand what was best. I think my way of structuring the data is wrong but it was simple and worked. However if there are better ways of storing the data please say so, but remember that I need some more explanation than just use 'a xml file', 'generict, or 'Ttreeview'. (have read it but wasn't able to use it).

The data is for: I made this product, The next product I make is this, so do I need to clean? True or false.

The data is stores as a class(TObject) with Productnumber (integer) and a List which contains all products that could be made next.This list contains another class(TObject) with an Productnumber (integer) and a do I need to clean(boolean). I want to save this structure in a file, without losing the data and read it back to the same structure.

I hope someone could help. Thank you in advance.

Update: The code to provide a little more information (modified to English)

```<code>Clean_from = class(TObject)
public
  myfromNumber      : Integer;
  mylist            : TList;
published
  constructor Create;
End

Clean_To = class(TObject)
public
  myToNumber        : Integer;
  Clean             : Boolean;
End;

constructor Clean_from.Create;
begin
  inherited Create;
  myList := Tlist.Create;
end;

For i = 0 to 100 do
begin
  From:= Clean_from.create;
  for j := 0 to 10 do
  begin
    To := Clean_To.create;
    To.clean := true or false;
    From.myList.add(To);
  end;
  GlobalList.add(from);
end;
</code>```

And now I want to save the global list with all the content so I could load it with the same structure.

答:
Add SaveToStream() and LoadFromStream() methods to your data object which, well, save the data to a stream and load data from a stream.

```<code>type
  TMyData = class(TObject)
  private
    FChildProducts: TList;
    FProductnumber : integer;
    FClean: boolean;
  public
    procedure LoadFromStream(const aStream: TStream);
    procedure SaveToStream(const aStream: TStream);
  published
    property Productnumber: Integer read FProductnumber write FProductnumber;
    property Clean: Boolean reas FClean write FClean;
  end;

procedure TMyData.LoadFromStream(const aStream: TStream);
var x, cnt: Integer;
    cD: TMyData;
begin
  aStream.Read(FProductnumber, SizeOf(FProductnumber));
  aStream.Read(FClean, SizeOf(FClean));
  // read number of child products
  aStream.Read(cnt, SizeOf(cnt));
  // load child objects
  for x := 1 to cnt do begin
     cD := TMyData.create;
     cD.LoadFromStream(aStream);
     FChildProducts.Add(cD);
  end;
end;

procedure TMyData.SaveToStream(const aStream: TStream);
var x: Integer;
begin
  aStream.Write(FProductnumber, SizeOf(FProductnumber));
  aStream.Write(FClean, SizeOf(FClean));
  // save number of child products
  x := FChildProducts.Count;
  aStream.Write(x, SizeOf(x));
  // save child objects
  for x := 0 to FChildProducts.Count - 1 do
     (FChildProducts[x] as TMyData).SaveToStream(aStream);
end;
</code>```

I assume you have some list of "root objects" so you can make an function or method which saves/loads them to/from stream ie

```<code>function SaveDataList(const List: TList;const aFileName: string);
var x: Integer;
    FS: TFileStream;
begin
  FS := TFileStream.Create(aFileName, ...);
  try
     // save file version
     x := 1;
     FS.Write(x, SizeOf(x));
     // save number of products
     x := List.Count;
     FS.Write(x, SizeOf(x));
     // save objects
     for x := 0 to List.Count - 1 do
       (List[x] as TMyData).SaveToStream(FS);
  finally
     FS.Free;
  end;
end;
</code>```

This is the general idea... how to load data back should be clear too. The file version thing is there so that when the data object changes (ie you add some property) you can increment the version number so that in the loading code you can load data into right version of the data object.

Body:
For a simulation program I'm working in Delphi 2010. The simulation isn't a problem but I need to use large collection of data which gives a problem. The data is available in excel sheets, so there is no need to edit this data in Delphi, but collecting this data from the excel sheets takes around 10min. This isn't a problem as long as you don't need to collect the data  every time the program runs. So I made a program which collects all the data makes it visible, not problems here,and then store it. However I can't store it to a "Delphi format" , without losing the structure, so it can be loaded in a few seconds.

I'm not that experienced in Delphi and I searched a long time for the solution but couldn't understand what was best. I think my way of structuring the data is wrong but it was simple and worked. However if there are better ways of storing the data please say so, but remember that I need some more explanation than just use 'a xml file', 'generict, or 'Ttreeview'. (have read it but wasn't able to use it).

The data is for: I made this product, The next product I make is this, so do I need to clean? True or false.

The data is stores as a class(TObject) with Productnumber (integer) and a List which contains all products that could be made next.This list contains another class(TObject) with an Productnumber (integer) and a do I need to clean(boolean). I want to save this structure in a file, without losing the data and read it back to the same structure.

I hope someone could help. Thank you in advance.

Update: The code to provide a little more information (modified to English)

Clean_from = class(TObject)
public
  myfromNumber      : Integer;
  mylist            : TList;
published
  constructor Create;
End

Clean_To = class(TObject)
public
  myToNumber        : Integer;
  Clean             : Boolean;
End;

constructor Clean_from.Create;
begin
  inherited Create;
  myList := Tlist.Create;
end;

For i = 0 to 100 do
begin
  From:= Clean_from.create;
  for j := 0 to 10 do
  begin
    To := Clean_To.create;
    To.clean := true or false;
    From.myList.add(To);
  end;
  GlobalList.add(from);
end;

And now I want to save the global list with all the content so I could load it with the same structure.

Body:
Add SaveToStream() and LoadFromStream() methods to your data object which, well, save the data to a stream and load data from a stream.

type
  TMyData = class(TObject)
  private
    FChildProducts: TList;
    FProductnumber : integer;
    FClean: boolean;
  public
    procedure LoadFromStream(const aStream: TStream);
    procedure SaveToStream(const aStream: TStream);
  published
    property Productnumber: Integer read FProductnumber write FProductnumber;
    property Clean: Boolean reas FClean write FClean;
  end;

procedure TMyData.LoadFromStream(const aStream: TStream);
var x, cnt: Integer;
    cD: TMyData;
begin
  aStream.Read(FProductnumber, SizeOf(FProductnumber));
  aStream.Read(FClean, SizeOf(FClean));
  // read number of child products
  aStream.Read(cnt, SizeOf(cnt));
  // load child objects
  for x := 1 to cnt do begin
     cD := TMyData.create;
     cD.LoadFromStream(aStream);
     FChildProducts.Add(cD);
  end;
end;

procedure TMyData.SaveToStream(const aStream: TStream);
var x: Integer;
begin
  aStream.Write(FProductnumber, SizeOf(FProductnumber));
  aStream.Write(FClean, SizeOf(FClean));
  // save number of child products
  x := FChildProducts.Count;
  aStream.Write(x, SizeOf(x));
  // save child objects
  for x := 0 to FChildProducts.Count - 1 do
     (FChildProducts[x] as TMyData).SaveToStream(aStream);
end;

I assume you have some list of "root objects" so you can make an function or method which saves/loads them to/from stream ie

function SaveDataList(const List: TList;const aFileName: string);
var x: Integer;
    FS: TFileStream;
begin
  FS := TFileStream.Create(aFileName, ...);
  try
     // save file version
     x := 1;
     FS.Write(x, SizeOf(x));
     // save number of products
     x := List.Count;
     FS.Write(x, SizeOf(x));
     // save objects
     for x := 0 to List.Count - 1 do
       (List[x] as TMyData).SaveToStream(FS);
  finally
     FS.Free;
  end;
end;

This is the general idea... how to load data back should be clear too. The file version thing is there so that when the data object changes (ie you add some property) you can increment the version number so that in the loading code you can load data into right version of the data object.


来源: stackexchange

问:
How to make a table responsive, created in javascript
I have a js, which generates a table for me, I show it in the html, but I can't make it responsive; how could i fix it

The code is the following, I have modified with responsive table, but it still does not work for me

```<code>var tabla   = document.createElement("table");
tabla.className="table";

var thead = document.createElement("thead");

let row_1 = document.createElement('tr');
let heading_1 = document.createElement('th');
heading_1.scope="col";
heading_1.innerHTML = "Mes";
let heading_2 = document.createElement('th');
heading_2.innerHTML = "Cuota";
heading_2.scope="col";
let heading_3 = document.createElement('th');
heading_3.innerHTML = "Interes";
heading_3.scope="col";
let heading_4 = document.createElement('th');
heading_4.innerHTML = "Amorti.";
heading_4.scope="col";
let heading_5 = document.createElement('th');
heading_5.innerHTML = "Capital";
heading_5.scope="col";
let heading_6 = document.createElement('th');
heading_6.innerHTML = "Seguro Desgrav.";
heading_6.scope="col";
let heading_7 = document.createElement('th');
heading_7.innerHTML = "Seguro Inmobil.";
heading_7.scope="col";

let heading_8 = document.createElement('th');
heading_8.innerHTML = "Gastos Adm.";
heading_8.scope="col";

let heading_9 = document.createElement('th');
heading_9.innerHTML = "Cuota Final";
heading_9.scope="col";

row_1.appendChild(heading_1);
row_1.appendChild(heading_2);
row_1.appendChild(heading_3);
row_1.appendChild(heading_4);
row_1.appendChild(heading_5);
row_1.appendChild(heading_6);
row_1.appendChild(heading_7);
row_1.appendChild(heading_8);
row_1.appendChild(heading_9);
thead.appendChild(row_1);
</code>```

答:
Try creating the table in HTML.

    ...

```

Then populate the fields in Js.

ContentLicense: CC BY-SA 4.0

Body:
I have a js, which generates a table for me, I show it in the html, but I can't make it responsive; how could i fix it

The code is the following, I have modified with responsive table, but it still does not work for me

var tabla   = document.createElement("table");
tabla.className="table";

var thead = document.createElement("thead");

let row_1 = document.createElement('tr');
let heading_1 = document.createElement('th');
heading_1.scope="col";
heading_1.innerHTML = "Mes";
let heading_2 = document.createElement('th');
heading_2.innerHTML = "Cuota";
heading_2.scope="col";
let heading_3 = document.createElement('th');
heading_3.innerHTML = "Interes";
heading_3.scope="col";
let heading_4 = document.createElement('th');
heading_4.innerHTML = "Amorti.";
heading_4.scope="col";
let heading_5 = document.createElement('th');
heading_5.innerHTML = "Capital";
heading_5.scope="col";
let heading_6 = document.createElement('th');
heading_6.innerHTML = "Seguro Desgrav.";
heading_6.scope="col";
let heading_7 = document.createElement('th');
heading_7.innerHTML = "Seguro Inmobil.";
heading_7.scope="col";

let heading_8 = document.createElement('th');
heading_8.innerHTML = "Gastos Adm.";
heading_8.scope="col";

let heading_9 = document.createElement('th');
heading_9.innerHTML = "Cuota Final";
heading_9.scope="col";

row_1.appendChild(heading_1);
row_1.appendChild(heading_2);
row_1.appendChild(heading_3);
row_1.appendChild(heading_4);
row_1.appendChild(heading_5);
row_1.appendChild(heading_6);
row_1.appendChild(heading_7);
row_1.appendChild(heading_8);
row_1.appendChild(heading_9);
thead.appendChild(row_1);

Body:
Try creating the table in HTML.

<div style="overflow-x:auto;">
  <table>
    ...
  </table>
</div>

Then populate the fields in Js.


问:
Google Script taking long time to open a form in Google HTML Service
I created a form with google HTML service in Google Sheets, so, when I type the user id, JavaScript from HTML
<script>
  var idBox = document.getElementById("id_cpf");
  var nomeBox = document.getElementById("nome");
  document.getElementById("buscar").addEventListener("click", findData);

  function findData(){
    var id=idBox.value;

    if(id.length==0){
    M.toast({html: 'you need to type a value on ID'})

    }else{
      <? for (var j = 1; j <=SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Database").getLastRow() ; j++) { ?>
     var idDb = <?=
   SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Database").getRange('A'+j).getValue() ?>;
     var nomeDb = <?=
   SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Database").getRange('B'+j).getValue() ?>;
     var statusDb = <?=
   SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Database").getRange('C'+j).getValue() ?>;

      if(idDb == id){
        document.getElementById("nome").value = nomeDb;
        document.getElementById("status_geral").value = statusDb;
      }
    <? } ?>

    M.toast({html: 'Value Found!'+ lastRow})
    }

}
</script>

```
<p>My gs code:</p>
```function ShowAddInformation2() {
var userform= HtmlService.createTemplateFromFile("AddInformation2").evaluate().setTitle("Add or change Information")
SpreadsheetApp.getUi().showModalDialog(userform,"Add or change Information")}
```

Data Entry Image

Below you can also find the spreadsheet link. Feel free to make any changes.
Spreadsheet with data entry

I also tried a possibility to create a deploy with web app, but the code just doesn't work. You can see it on link Web App - Data Entry

So, sorry if I wasn't clear, English is not my first language.

If anyone can help with any possibility I will be very grateful!

答: You could replace your

Body:
I created a form with google HTML service in Google Sheets, so, when I type the user id, JavaScript from HTML

My gs code:

function ShowAddInformation2() {
var userform= HtmlService.createTemplateFromFile("AddInformation2").evaluate().setTitle("Add or change Information")
SpreadsheetApp.getUi().showModalDialog(userform,"Add or change Information")}

Data Entry Image

Below you can also find the spreadsheet link. Feel free to make any changes.
Spreadsheet with data entry

I also tried a possibility to create a deploy with web app, but the code just doesn't work. You can see it on link Web App - Data Entry

So, sorry if I wasn't clear, English is not my first language.

If anyone can help with any possibility I will be very grateful!

Body:
You could replace your <script> code with this.  There is an extra closing curly barce } after findData.

function findData(){
  var id=idBox.value;

  if(id.length==0){
    M.toast({html: 'you need to type a value on ID'})

  }
  else {
    google.script.run.withSuccessHandler( function (results) {
      document.getElementById("nome").value = results[1];
      document.getElementById("status_geral").value = results[2];
      M.toast({html: 'Value Found!'+ results[0]});
    }).findData(id);
  }
}

And add to your Code.gs.  I edited the Code.gs portion to change the getRange().  Your data contains dates and those can not be returned to the HTML client without using JSON.

function findData(id) {
  try {
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Database");
    var data = sheet.getRange(1,1,sheet.getLastRow(),3)().getValues();
    return data.find( function (row) { return row[0] === id; } );
  }
  catch(err) {
    console.log(err);
  }
}


问:
NJsonSchema C# - Change Generated Value Type
I am using NJsonSchema CsharpGenerator 10.1.24 and have the below schema I am using to generate a POCO:

```<code>    "description": "schema validating people and vehicles",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "required": [ "oneOf" ],
    "properties": { "oneOf": [
        {
            "firstName": {"type": "string"},
            "lastName": {"type": "string"},
            "sport": {"type": "string"}
        },
        {
            "vehicle": {"type": "string"},
            "price":{"type": "number"}
        }
     ]
   }
}
</code>```

How can I get the generated C# class to have a decimal type for price instead of the default double?

public double Price { get; set;}

I tried using a custom static method with the generator settings JsonSerializerSettingsTransformationMethod property but nothing changed.

答:
@tontonsevilla, How would you return both objects under oneOfs to be included in C# POCO? In example above by @user2966445 it will only generate the first item under oneOfs for me, I will only get the POCO with firstName, lastName and sport properties in the POCO & not include vehicle and price. So, when deseriazing the json to POCO it blows up if json payload contains vehicle & price.

One thing I noticed in the NJsonSchema.JsonSchema objects "Resolve" method, it also calls "RemoveNullability" method internally and this code which only returns first item in the oneOfs and not sure how to get around it.

```<code>public JsonSchema RemoveNullability( JsonSchema schema )
{
    return schema.OneOf.FirstOrDefault( ( JsonSchema o ) => !o.IsNullable( SchemaType.JsonSchema ) ) ?? schema;
}
</code>```

Body:
I am using NJsonSchema CsharpGenerator 10.1.24 and have the below schema I am using to generate a POCO:

    "description": "schema validating people and vehicles",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "required": [ "oneOf" ],
    "properties": { "oneOf": [
        {
            "firstName": {"type": "string"},
            "lastName": {"type": "string"},
            "sport": {"type": "string"}
        },
        {
            "vehicle": {"type": "string"},
            "price":{"type": "number"}
        }
     ]
   }
}

How can I get the generated C# class to have a decimal type for price instead of the default double?

public double Price { get; set;}

I tried using a custom static method with the generator settings JsonSerializerSettingsTransformationMethod property but nothing changed.

Body:
@tontonsevilla, How would you return both objects under oneOfs to be included in C# POCO? In example above by @user2966445 it will only generate the first item under oneOfs for me, I will only get the POCO with firstName, lastName and sport properties in the POCO & not include vehicle and price. So, when deseriazing the json to POCO it blows up if json payload contains vehicle & price.

One thing I noticed in the NJsonSchema.JsonSchema objects "Resolve" method, it also calls "RemoveNullability" method internally and this code which only returns first item in the oneOfs and not sure how to get around it.

public JsonSchema RemoveNullability( JsonSchema schema )
{
    return schema.OneOf.FirstOrDefault( ( JsonSchema o ) => !o.IsNullable( SchemaType.JsonSchema ) ) ?? schema;
}


问:
Handlebars - Nest objects in #each
I use express-handlebars with Node JS and I am trying to display informations from the array games on my HTML page using #each. But handlebars won't display the values inside my object. Even if it is not a nested object.

But if I only write {{this}}, it displays all the object like if it was a string. And if I do {{this.time}}, nothing is displayed.

I'm using Node JS v14.18.1, express v4.17.2 and express-handlebars v6.0.2.

Thank you in advance for your help !

    getHomePage: async (req, res) => {
        try {
            const games = await gameModel.find().sort({time: -1}).limit(3).populate('user');
            res.render('home', {title: 'Hello world', games});
        } catch (error) {
            console.error(error);
            res.status(500).json({error});
        }
    }
```
<pre class="lang-html prettyprint-override"><code>        <table>
            <thead>
                <th>Position</th>
                <th>Score</th>
                <th>Nom</th>
            </thead>
            <tbody>
                {{#each games}}

                    <tr>
                        <td>#{{@index}}</td>
                        <td>{{this}}</td>
                        <td>{{this.time}}</td>
                    </tr>

                {{/each}}
            </tbody>
        </table>
</code>```

答:
Either {{this.time}} or {{time}} should work, see snippet with output below, {{this.team}} and {{time}} is used.

If time still shows nothing, try confirming games is defined as expected.

// shortened data for brevity
const data = {
  games: [
    {team: 'Man U', time: '10am'},
    {team: 'Arsenal', time: '1pm'}
  ]
};

//inline template for snippet simplicity
const template = '' +
'
' +
'
' +
'
'+
'#	' +
'Team Name	' +
'Time	' +
'
' +
'
' +
'
' +
'{{#each games}}' +
'
' +
// BEGIN
'{{@index}}	' +
'{{this.team}}	' +
'{{time}}	' +
// END
'
' +
'{{/each}}' +
'
' +
'
';

var output = Handlebars.compile(template)(data);
console.log(output)
// for snippet simplicity
$('body').html(output);```
<pre class="snippet-code-html lang-html prettyprint-override"><code><script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script></code>```

Title: Handlebars - Nest objects in #each

Body:
I use express-handlebars with Node JS and I am trying to display informations from the array games on my HTML page using #each. But handlebars won't display the values inside my object. Even if it is not a nested object.

But if I only write {{this}}, it displays all the object like if it was a string. And if I do {{this.time}}, nothing is displayed.

I'm using Node JS v14.18.1, express v4.17.2 and express-handlebars v6.0.2.

Thank you in advance for your help !

    getHomePage: async (req, res) => {
        try {
            const games = await gameModel.find().sort({time: -1}).limit(3).populate('user');
            res.render('home', {title: 'Hello world', games});
        } catch (error) {
            console.error(error);
            res.status(500).json({error});
        }
    }

                Position
                Score
                Nom

                {{#each games}}

                        #{{@index}}
                        {{this}}
                        {{this.time}}

                {{/each}}

Body:
Either {{this.time}} or {{time}} should work, see snippet with output below, {{this.team}} and {{time}} is used.

If time still shows nothing, try confirming games is defined as expected.

// shortened data for brevity
const data = {
  games: [
    {team: 'Man U', time: '10am'},
    {team: 'Arsenal', time: '1pm'}
  ]
};

//inline template for snippet simplicity
const template = '' +
'<table>' +
'<thead>' +
'<tr>'+
'<th>#</th>' +
'<th>Team Name</th>' +
'<th>Time</th>' +
'</tr>' +
'</thead>' +
'<tbody>' +
'{{#each games}}' +
'<tr>' +
// BEGIN
'<td>{{@index}}</td>' +
'<td>{{this.team}}</td>' +
'<td>{{time}}</td>' +
// END
'</tr>' +
'{{/each}}' +
'</tbody>' +
'</table>';

var output = Handlebars.compile(template)(data);
console.log(output)
// for snippet simplicity
$('body').html(output);

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>


问:
Remove multiple spaces and new lines inside of String
Suppose we have string like this:

```<code>Hello, my\n       name is Michael.
</code>```

How can I remove that new line and strip those spaces after that into one inside of string to get this?

```<code>Hello, my name is Michael.
</code>```

答:
The simplest way would probably be</p>

```<code>s = "Hello, my\n       name is Michael."
s.split.join(' ') #=> "Hello, my name is Michael."
</code>```

ContentLicense: CC BY-SA 3.0

Body:
Suppose we have string like this:

Hello, my\n       name is Michael.

How can I remove that new line and strip those spaces after that into one inside of string to get this?

Hello, my name is Michael.

Body:
The simplest way would probably be

s = "Hello, my\n       name is Michael."
s.split.join(' ') #=> "Hello, my name is Michael."


问:
URL encode sees “&” (ampersand) as “&” HTML entity
I am encoding a string that will be passed in a URL (via GET). But if I use escape, encodeURI or encodeURIComponent, & will be replaced with %26amp%3B, but I want it to be replaced with %26. What am I doing wrong?

答:
Just to be clear, you should never be using encodeURI() and encodeURIComponent().  If you disagree, just look at its results...

console.log(encodeURIComponent('@#$%^&*'));```
</div>
</div>
</p>
<blockquote>
<p>Input: <code>^&*</code>.</p>
<p>Output: <code>%40%23%24%25%5E%26*</code>.</p>
</blockquote>
<p>That's not right, is it?  <code>*</code> did not get converted!  I hope you're not using this as a server-side cleansing function, because <code>*</code> will not be treated as input but as commands, i.e., imagine deleting a user's alleged file with <code>rm *</code>.  Well, I hope you're not using encodeURI() or encodeURIComponent()!</p>
<p>TLDR: You actually want <code>fixedEncodeURIComponent()</code> and <code>fixedEncodeURI()</code>.</p>
<p><strong>MDN encodeURI() Documentation</strong>...</p>
<blockquote>
```function fixedEncodeURI(str) {
   return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']');
}
```
</blockquote>
<p><strong>MDN encodeURIComponent() Documentation</strong>...</p>
<blockquote>
```function fixedEncodeURIComponent(str) {
 return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
   return '%' + c.charCodeAt(0).toString(16);
 });
}
```

With these functions, use fixedEncodeURI() to encode a single URL piece, whereas fixedEncodeURIComponent() will encode URL pieces and connectors; or, more simply, fixedEncodeURI() will not encode +@?=:#;,$& (as & and + are common URL operators), but fixedEncodeURIComponent() will.

Body:
Just to be clear, you should never be using encodeURI() and encodeURIComponent().  If you disagree, just look at its results...

console.log(encodeURIComponent('@#$%^&*'));

Input: ^&*.

Output: %40%23%24%25%5E%26*.

That's not right, is it?  * did not get converted!  I hope you're not using this as a server-side cleansing function, because * will not be treated as input but as commands, i.e., imagine deleting a user's alleged file with rm *.  Well, I hope you're not using encodeURI() or encodeURIComponent()!

TLDR: You actually want fixedEncodeURIComponent() and fixedEncodeURI().

MDN encodeURI() Documentation...

function fixedEncodeURI(str) {
   return encodeURI(str).replace(/%5B/g, '[').replace(/%5D/g, ']');
}

MDN encodeURIComponent() Documentation...

function fixedEncodeURIComponent(str) {
 return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
   return '%' + c.charCodeAt(0).toString(16);
 });
}

With these functions, use fixedEncodeURI() to encode a single URL piece, whereas fixedEncodeURIComponent() will encode URL pieces and connectors; or, more simply, fixedEncodeURI() will not encode +@?=:#;,$& (as & and + are common URL operators), but fixedEncodeURIComponent() will.


问:
Summary of models constructed for transfer learning in tensorflow keras
I'm using tensorflow 2.6 keras for transfer learning. Currently I take MobileNetV2. I take input, apply some preprocessing using Lambda layer, then feed this preprocessed input to MobileNetV2, then add Dense layer and train this thing. Training, inference etc actually work as expected.

However, the summary of the model looks as follows:

```<code>Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input (InputLayer)           [(None, 201, 189, 1)]     0
_________________________________________________________________
lambda (Lambda)              (None, 201, 189, None)    0
_________________________________________________________________
lambda_1 (Lambda)            (None, 201, 189, None)    0
_________________________________________________________________
mobilenetv2_1.00_224 (Functi (None, 7, 6, 1280)        2257984
_________________________________________________________________
flatten (Flatten)            (None, 53760)             0
_________________________________________________________________
output (Dense)               (None, 2)                 107522
=================================================================
Total params: 2,365,506
Trainable params: 2,331,394
Non-trainable params: 34,112
</code>```

So the MobileNetV2 structure is hidden and shown as one layer of type tensorflow.python.keras.engine.functional.Functional. If I print summary of this layer, I get all the internal layers of the model. I have a script for automatic GradCam visualizations which looks for the last Conv layer of the model. If the model is constructed by hand using Lambda, Conv2D, Dense layers, then everyhting works fine. If I use pretrained model, then currently it fails, because the Conv layer is hidden inside of this Functional layer.

How do I construct my modified MobileNetV2 model with my additional layers so that the full structure of the model is shown?

This is how I approximately construct my final model:

input = Input(shape=params.image_shape, name="input")
flow = input
flow = input_correction(flow, params) #some Lambda layers
keras_model = MobileNetV2(
            input_shape=image_shape,
            weights='imagenet',
            include_top=False)
keras_model_output=keras_model(flow)
keras_model_input=input
keras_model_output = Flatten()(keras_model_output)
output = Dense(units=len(params.classes),
                   activation=tf.nn.softmax,
                   name="output")(keras_model_output)
model = Model(inputs=keras_model_input, outputs=output)
model.compile(...)
```

答:
In default, summary doesnt show nested models. Just include expand_nested argument in the summary.

```<code>model.summary(expand_nested=True)
</code>```

Body:
I'm using tensorflow 2.6 keras for transfer learning. Currently I take MobileNetV2. I take input, apply some preprocessing using Lambda layer, then feed this preprocessed input to MobileNetV2, then add Dense layer and train this thing. Training, inference etc actually work as expected.

However, the summary of the model looks as follows:

Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input (InputLayer)           [(None, 201, 189, 1)]     0
_________________________________________________________________
lambda (Lambda)              (None, 201, 189, None)    0
_________________________________________________________________
lambda_1 (Lambda)            (None, 201, 189, None)    0
_________________________________________________________________
mobilenetv2_1.00_224 (Functi (None, 7, 6, 1280)        2257984
_________________________________________________________________
flatten (Flatten)            (None, 53760)             0
_________________________________________________________________
output (Dense)               (None, 2)                 107522
=================================================================
Total params: 2,365,506
Trainable params: 2,331,394
Non-trainable params: 34,112

So the MobileNetV2 structure is hidden and shown as one layer of type tensorflow.python.keras.engine.functional.Functional. If I print summary of this layer, I get all the internal layers of the model. I have a script for automatic GradCam visualizations which looks for the last Conv layer of the model. If the model is constructed by hand using Lambda, Conv2D, Dense layers, then everyhting works fine. If I use pretrained model, then currently it fails, because the Conv layer is hidden inside of this Functional layer.

How do I construct my modified MobileNetV2 model with my additional layers so that the full structure of the model is shown?

This is how I approximately construct my final model:

input = Input(shape=params.image_shape, name="input")
flow = input
flow = input_correction(flow, params) #some Lambda layers
keras_model = MobileNetV2(
            input_shape=image_shape,
            weights='imagenet',
            include_top=False)
keras_model_output=keras_model(flow)
keras_model_input=input
keras_model_output = Flatten()(keras_model_output)
output = Dense(units=len(params.classes),
                   activation=tf.nn.softmax,
                   name="output")(keras_model_output)
model = Model(inputs=keras_model_input, outputs=output)
model.compile(...)

Body:
In default, summary doesnt show nested models. Just include expand_nested argument in the summary.

model.summary(expand_nested=True)


问:
Problem in creating an alarm in Typescript but the alarm isn't working
I am creating an alarm clock using typescript and I am facing in issue. I am not being alarmed when the time passes.
I have taken three inputs from the HTML page – Hours, Minutes and Seconds.

After that I added them and subtracted the current time.

```<code>    let h = <HTMLInputElement>document.getElementById("h");//getting input values of hour and ...
    let m = <HTMLInputElement>document.getElementById("m");
    let s = <HTMLInputElement>document.getElementById("s");

    let h1 = parseFloat(h.value);//converting the input values from string to float
    let m1 = parseFloat(m.value);
    let s1 = parseFloat(s.value);

    var rHours = new Date().getHours();
    var rMinutes = new Date().getMinutes();
    var rSeconds = new Date().getMinutes();
    var calc = (h1) + (m1) + (s1) - rHours - rMinutes - rSeconds;

    if(calc<=0){
       alert("Alarm");
    }
}
</code>```

But it does not work properly.

答:
document.querySelector('p span').innerHTML = new Date().toString()

function startCountdown() {
/* In your code uncomment this section...
    let el_h = <HTMLInputElement>document.getElementById("h");
    let el_m = <HTMLInputElement>document.getElementById("m");
    let el_s = <HTMLInputElement>document.getElementById("s");
*/

  // in your code comment out these lines and use yours from above instead (for typescript typing)
  let el_h = document.getElementById("h");
  let el_m = document.getElementById("m");
  let el_s = document.getElementById("s");

  let h1 = parseFloat(el_h.value);
  let m1 = parseFloat(el_m.value);
  let s1 = parseFloat(el_s.value);

  //const [h1, m1, s1] = ( (new Date().getHours() ) + ":" + (new Date().getMinutes() + 2) + ":" + new Date().getSeconds()).split(":");

  // get todays date
  let today = new Date().getFullYear() + "-" + (new Date().getMonth() + 1) + "-" + new Date().getDate();

  // add on the hours from the inputs
  today += " " + h1 + ":" + m1 + ":" + s1;
  const myTime = new Date(today);

  console.log('countdown to:', myTime, 'from:', new Date());
  const interval = setInterval(() => {
    let diff = (myTime.getTime() - new Date().getTime()) / 1000; // seconds
    let h = Math.floor(diff / 3600);
    let m = Math.floor(diff / 60 % 60);
    let s = Math.floor(diff % 60)
    console.log(h + " hours, " + m + " minutes, " + s + " seconds")
    if (diff <= 0) {
      clearInterval(interval);
      console.log("ALARM");
    }
  }, 1000)
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><p>Cur time: <span></span></p>
<input id='h' placeholder='Hour (military time)'><input id='m' placeholder='Minute'><input id='s' placeholder='Seconds'><button onclick='startCountdown()'>Start</button></code>```

Body:
I am creating an alarm clock using typescript and I am facing in issue. I am not being alarmed when the time passes.
I have taken three inputs from the HTML page – Hours, Minutes and Seconds.

After that I added them and subtracted the current time.

    let h = <HTMLInputElement>document.getElementById("h");//getting input values of hour and ...
    let m = <HTMLInputElement>document.getElementById("m");
    let s = <HTMLInputElement>document.getElementById("s");

    let h1 = parseFloat(h.value);//converting the input values from string to float
    let m1 = parseFloat(m.value);
    let s1 = parseFloat(s.value);

    var rHours = new Date().getHours();
    var rMinutes = new Date().getMinutes();
    var rSeconds = new Date().getMinutes();
    var calc = (h1) + (m1) + (s1) - rHours - rMinutes - rSeconds;

    if(calc<=0){
       alert("Alarm");
    }
}

But it does not work properly.

Body:
document.querySelector('p span').innerHTML = new Date().toString()

function startCountdown() {
/* In your code uncomment this section...
    let el_h = <HTMLInputElement>document.getElementById("h");
    let el_m = <HTMLInputElement>document.getElementById("m");
    let el_s = <HTMLInputElement>document.getElementById("s");
*/

  // in your code comment out these lines and use yours from above instead (for typescript typing)
  let el_h = document.getElementById("h");
  let el_m = document.getElementById("m");
  let el_s = document.getElementById("s");

  let h1 = parseFloat(el_h.value);
  let m1 = parseFloat(el_m.value);
  let s1 = parseFloat(el_s.value);

  //const [h1, m1, s1] = ( (new Date().getHours() ) + ":" + (new Date().getMinutes() + 2) + ":" + new Date().getSeconds()).split(":");

  // get todays date
  let today = new Date().getFullYear() + "-" + (new Date().getMonth() + 1) + "-" + new Date().getDate();

  // add on the hours from the inputs
  today += " " + h1 + ":" + m1 + ":" + s1;
  const myTime = new Date(today);

  console.log('countdown to:', myTime, 'from:', new Date());
  const interval = setInterval(() => {
    let diff = (myTime.getTime() - new Date().getTime()) / 1000; // seconds
    let h = Math.floor(diff / 3600);
    let m = Math.floor(diff / 60 % 60);
    let s = Math.floor(diff % 60)
    console.log(h + " hours, " + m + " minutes, " + s + " seconds")
    if (diff <= 0) {
      clearInterval(interval);
      console.log("ALARM");
    }
  }, 1000)
}

<p>Cur time: <span></span></p>
<input id='h' placeholder='Hour (military time)'><input id='m' placeholder='Minute'><input id='s' placeholder='Seconds'><button onclick='startCountdown()'>Start</button>


问:
How to set a property value based on a variable in Javascript
The problem is I have this piece of code (Jquery UI):

```<code>    $("#dialog-confirm").dialog({
        resizable: false,
        modal: true,
        buttons: {
            "Remove": function() {
                $(this).dialog("close");
            },
            "Cancel": function() {
                $(this).dialog("close");
            }
        }
    });
</code>```

and now I have to internationalize it by giving to each button a word translation. I have the translation on the variables STR_REMOVE and STR_CANCEL, but if I do something like

```<code>        buttons: {
            STR_REMOVE: function() {
                $(this).dialog("close");
            },
            STR_CANCEL: function() {
                $(this).dialog("close");
            }
        }
</code>```

the buttons (the properties) take the value "STR_REMOVE" and "STR_CANCEL", not its content. So, the question is, what can I do?

答:
You can't do this inline.  You'll have to declare the object first, then use the square bracket member operator to set the properties:</p>

```<code>var buttons = {};
buttons[STR_REMOVE] = function() {
    $(this).dialog("close");
};
buttons[STR_CANCEL] = function() {
    $(this).dialog("close");
};

$("#dialog-confirm").dialog({
    resizable: false,
    modal: true,
    buttons: buttons
});
</code>```

Body:
The problem is I have this piece of code (Jquery UI):

    $("#dialog-confirm").dialog({
        resizable: false,
        modal: true,
        buttons: {
            "Remove": function() {
                $(this).dialog("close");
            },
            "Cancel": function() {
                $(this).dialog("close");
            }
        }
    });

and now I have to internationalize it by giving to each button a word translation. I have the translation on the variables STR_REMOVE and STR_CANCEL, but if I do something like

        buttons: {
            STR_REMOVE: function() {
                $(this).dialog("close");
            },
            STR_CANCEL: function() {
                $(this).dialog("close");
            }
        }

the buttons (the properties) take the value "STR_REMOVE" and "STR_CANCEL", not its content. So, the question is, what can I do?

Body:
You can't do this inline.  You'll have to declare the object first, then use the square bracket member operator to set the properties:

var buttons = {};
buttons[STR_REMOVE] = function() {
    $(this).dialog("close");
};
buttons[STR_CANCEL] = function() {
    $(this).dialog("close");
};

$("#dialog-confirm").dialog({
    resizable: false,
    modal: true,
    buttons: buttons
});


问:
Issue passing single quote as parameter from Jenkins to Ansible
The string parameter in jenkins dest_cmd works fine and gets passed and read by ansible as below:

Jenkins pipeline script:

```<code>ansible-playbook -i /web/runcmd/allmwhosts.hosts /web/runcmd/copyfiles.yml -e dest_user=$dest_user -e '{ dest_cmd: $dest_cmd }' --tags validate"
</code>```

The above works fine for all dest_cmd parameters however, it fails when the user enters single quotes ' as you can see below:

```<code>[Pipeline] sh
+ ansible-playbook -i /web/runcmd/allmwhosts.hosts /web/runcmd/copyfiles.yml -e dest_user=wluser -e '{ dest_cmd: arp `hostname` | cut -d' ' -f4 }' --tags validate
usage: ansible-playbook [-h] [--version] [-v] [-k]
                        [--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
                        [-c CONNECTION] [-T TIMEOUT]
                        [--ssh-common-args SSH_COMMON_ARGS]
                        [--sftp-extra-args SFTP_EXTRA_ARGS]
                        [--scp-extra-args SCP_EXTRA_ARGS]
                        [--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
</code>```

Can you please suggest how to resolve this issue?

答:
The problem is the use of quotes within the single-quoted string:

```<code>'{ dest_cmd: arp `hostname` | cut -d' ' -f4 }'
                     problem quotes ^ ^
</code>```

Try using double quotes:

```<code>'{ dest_cmd: arp `hostname` | cut -d" " -f4 }'
</code>```

Body:
The string parameter in jenkins dest_cmd works fine and gets passed and read by ansible as below:

Jenkins pipeline script:

ansible-playbook -i /web/runcmd/allmwhosts.hosts /web/runcmd/copyfiles.yml -e dest_user=$dest_user -e '{ dest_cmd: $dest_cmd }' --tags validate"

The above works fine for all dest_cmd parameters however, it fails when the user enters single quotes ' as you can see below:

[Pipeline] sh
+ ansible-playbook -i /web/runcmd/allmwhosts.hosts /web/runcmd/copyfiles.yml -e dest_user=wluser -e '{ dest_cmd: arp `hostname` | cut -d' ' -f4 }' --tags validate
usage: ansible-playbook [-h] [--version] [-v] [-k]
                        [--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
                        [-c CONNECTION] [-T TIMEOUT]
                        [--ssh-common-args SSH_COMMON_ARGS]
                        [--sftp-extra-args SFTP_EXTRA_ARGS]
                        [--scp-extra-args SCP_EXTRA_ARGS]
                        [--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]

Can you please suggest how to resolve this issue?

Body:
The problem is the use of quotes within the single-quoted string:

'{ dest_cmd: arp `hostname` | cut -d' ' -f4 }'
                     problem quotes ^ ^

Try using double quotes:

'{ dest_cmd: arp `hostname` | cut -d" " -f4 }'


问:
Returning an std::pair<std::shared_ptr, std::unique_ptr&> from a function results in weirdness
I'm having trouble understanding the (to me intricate) mechanisms executed behind the scenes in the following code example:

```<code>#include <utility>
#include <memory>
#include <iostream>

struct A {int a;};
struct B {int b;};

std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::unique_ptr<B> b = std::make_unique<B>();

    a->a = 12; b->b = 13;

    std::cout << "FuncA a: " << a.get() << std::endl;
    std::cout << "FuncA b: " << b.get() << std::endl;

    std::cout << "FuncA a.a: " << a->a << std::endl;
    std::cout << "FuncA b.b: " << b->b << std::endl;

    return {a,b};
}

void FuncC(std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> input) {
  std::cout << "FuncC a: " << input.first.get()  << std::endl;
  std::cout << "FuncC b: " << input.second.get() << std::endl;

  std::cout << "FuncC a.a: " << input.first->a  << std::endl;
  std::cout << "FuncC b.b: " << input.second->b << std::endl;
}

void FuncB() {
  auto ret = FuncA();

  std::cout << "FuncB a: " << ret.first.get()  << std::endl;
  std::cout << "FuncB b: " << ret.second.get() << std::endl;

  std::cout << "FuncC a.a: " << ret.first->a  << std::endl;
  std::cout << "FuncC b.b: " << ret.second->b << std::endl;

  FuncC(ret);
}

int main(){
  FuncB();
}
</code>```

I've compiled the code with both GCC and Clang which give similar results:

```<code>FuncA a: 0xfeaec0
FuncA b: 0xfeaed0
FuncA a.a: 12
FuncA b.b: 13
FuncB a: 0xfeaec0
FuncB b: 0x7ffd1c8e4a00
FuncC a.a: 12
FuncC b.b: 479087264
FuncC a: 0xfeaec0
FuncC b: 0x406100
FuncC a.a: 12
FuncC b.b: 1449378512
</code>```

As is clearly visible, the address of the std::unique_pointer reference (and of course also its value) are not the same as within FuncA, but the address and value of the std::shared_pointer are unchanged.

What's happening here, and what (if anything) could be done to make the reference-passing correct?

Is some form of copy-constructor being executed on the std::unique_ptr as a result of returning from FuncA?

答:
```<code>std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
    // ...
    std::unique_ptr<B> b = std::make_unique<B>();
    // ...
    return {a,b};
}
</code>```

A local std::unique_ptr is created and a reference to it is returned as the second element in the pair. This is a dangling reference and is later accessed, giving the program undefined behaviour.

Title: Returning an std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> from a function results in weirdness

Body:
I'm having trouble understanding the (to me intricate) mechanisms executed behind the scenes in the following code example:

#include <utility>
#include <memory>
#include <iostream>

struct A {int a;};
struct B {int b;};

std::pair<std::shared_ptr, std::unique_ptr&> FuncA() {
    std::shared_ptr a = std::make_shared();
    std::unique_ptr b = std::make_unique();

    a->a = 12; b->b = 13;

    std::cout << "FuncA a: " << a.get() << std::endl;
    std::cout << "FuncA b: " << b.get() << std::endl;

    std::cout << "FuncA a.a: " <a << std::endl;
    std::cout << "FuncA b.b: " <b << std::endl;

    return {a,b};
}

void FuncC(std::pair<std::shared_ptr, std::unique_ptr&> input) {
  std::cout << "FuncC a: " << input.first.get()  << std::endl;
  std::cout << "FuncC b: " << input.second.get() << std::endl;

  std::cout << "FuncC a.a: " << input.first->a  << std::endl;
  std::cout << "FuncC b.b: " << input.second->b << std::endl;
}

void FuncB() {
  auto ret = FuncA();

  std::cout << "FuncB a: " << ret.first.get()  << std::endl;
  std::cout << "FuncB b: " << ret.second.get() << std::endl;

  std::cout << "FuncC a.a: " << ret.first->a  << std::endl;
  std::cout << "FuncC b.b: " << ret.second->b << std::endl;

  FuncC(ret);
}

int main(){
  FuncB();
}

I've compiled the code with both GCC and Clang which give similar results:

FuncA a: 0xfeaec0
FuncA b: 0xfeaed0
FuncA a.a: 12
FuncA b.b: 13
FuncB a: 0xfeaec0
FuncB b: 0x7ffd1c8e4a00
FuncC a.a: 12
FuncC b.b: 479087264
FuncC a: 0xfeaec0
FuncC b: 0x406100
FuncC a.a: 12
FuncC b.b: 1449378512

As is clearly visible, the address of the std::unique_pointer reference (and of course also its value) are not the same as within FuncA, but the address and value of the std::shared_pointer are unchanged.

What's happening here, and what (if anything) could be done to make the reference-passing correct?

Is some form of copy-constructor being executed on the std::unique_ptr as a result of returning from FuncA?

Body:
std::pair<std::shared_ptr<A>, std::unique_ptr<B>&> FuncA() {
    // ...
    std::unique_ptr<B> b = std::make_unique<B>();
    // ...
    return {a,b};
}

A local std::unique_ptr<B> is created and a reference to it is returned as the second element in the pair. This is a dangling reference and is later accessed, giving the program undefined behaviour.


问:
Tooltips showing wrong data in ChartJS
I have a bar chart which shows data from an API, after data normalization i'm having issues with tooltip where if i hover a set like '9:00' the tooltip shows '8:00' data by adding to it other data which doesn't belong to that time set.

My code looks like this:

const API = [{
  "totpag": 98.04,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 96.17,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 307.87,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 164.22,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 382.21,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 56.39,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 62.16,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 270.42,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 31.62,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 126.09,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 260.54,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 289.46,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 448.67,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 595.38,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 378.44,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 226.74,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 165.18,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 154.11,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 201.39,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 24.26,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 227.75,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 10.01,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 32.51,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 253.36,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 133.95,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 101.15,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 166.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 298.99,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 82.96,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 68.47,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 164.06,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 36.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 16.2,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 15.5,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 25.43,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}]

const optionsPagamentiBar = {
  responsive: true,
  maintainAspectRatio: false,
  plugins: {
    legend: {
      display: false
    },
    tooltip: {
      mode: 'index',
      intersect: 0,
      usePointStyle: true,
      callbacks: {
        label: function(context) {
          return context.dataset.label + ": " + "€" + context.parsed.y.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,').replace(/[,.]/g, m => (m === ',' ? '.' : ','));
        }
      }
    }
  },
  scales: {
    y: {
      ticks: {
        display: true,
        beginAtZero: true,
        callback: function(value, index, values) {
          return "€" + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
        }
      },
      grid: {
        drawBorder: false,
        zeroLineColor: "transparent",
      }
    },
    x: {
      display: 1,
      ticks: {
        padding: 10,
        display: true,
        fontSize: 10
      },
      grid: {
        display: false
      }
    }
  }
}

const chartBarPayments = new Chart(document.getElementById("chartBarPayments").getContext('2d'), {
  type: 'bar',
  data: {
    labels: [],
    datasets: [{
      data: [],
    }]
  },
  options: optionsPagamentiBar
});

let periodo = 'giorno'

function pagamentiPerFascia(pagamenti) {
  let datasets = [];
  pagamenti.forEach((pagamento, i) => {
    if (pagamento.totpag !== 0) {
      let date = "";
      if (periodo == "anno") {
        date = moment(pagamento.data).format("MMM YYYY");
        labels.push();
      } else if (periodo == "mese") {
        date = moment(pagamento.data).format("DD MMM");
      } else {
        date = moment(pagamento.data).format('HH:mm');
      }

      let dataset = datasets.find(data => data.label === pagamento.descrpag)
      if (dataset) {
        dataset.data.push({
          x: date,
          y: pagamento.totpag
        })
      } else {
        datasets.push({
          label: pagamento.descrpag,
          data: [{
            x: date,
            y: pagamento.totpag
          }], backgroundColor: pagamento.backgroundColor
        })
      }

    }
  })

  chartBarPayments.data = {
    datasets
  };
  chartBarPayments.update();
}

pagamentiPerFascia(API)```
<pre class="snippet-code-html lang-html prettyprint-override"><code><script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js"></script>
<canvas id="chartBarPayments"></canvas></code>```

If you try to hover 4rd bar from '9:00' it will show tooltip on '8:00' with some data from '9:00' but even other datasets are bugged.

What is the issue and how should i fix it?

答:
This issue is caused by the gaps in the dataset. For some reason, this is confusing ChartJS. If you put in zero values for the missing values in "NON RISCOSSO" and remove the if that prevents these from being added to datasets if (pagamento.totpag !== 0) it works.

Let me know if that is an acceptable workaround. Otherwise could possibly dig a bit further into ChartJS to figure out what's going on.

Below is some code that adds zero values into the datasets so there are no gaps. I've had to rewrite your data normalization code.

const API = [{
  "totpag": 98.04,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 96.17,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 307.87,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 164.22,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 382.21,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 56.39,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 62.16,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 270.42,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 31.62,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 126.09,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 260.54,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 289.46,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 448.67,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 595.38,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 378.44,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 226.74,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 165.18,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 154.11,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 201.39,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 24.26,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 227.75,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 10.01,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 32.51,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 253.36,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 133.95,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 101.15,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 166.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 298.99,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 82.96,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 68.47,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 164.06,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 36.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 16.2,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 15.5,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 25.43,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}];

let periodo = "giorno";

const optionsPagamentiBar = {
  responsive: true,
  maintainAspectRatio: false,
  interaction: {
    intersect: false,
    mode: 'index'
  },
  plugins: {
    legend: {
      display: false
    },
    tooltip: {
      usePointStyle: true,
      callbacks: {
        label: function(context) {
          return context.dataset.label + ": " + "€" + context.parsed.y.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,').replace(/[,.]/g, m => (m === ',' ? '.' : ','));
        }
      }
    }
  },
  scales: {
    y: {
      ticks: {
        display: true,
        beginAtZero: true,
        callback: function(value, index, values) {
          return "€" + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
        }
      },
      grid: {
        drawBorder: false,
        zeroLineColor: "transparent",
      }
    },
    x: {
      display: 1,
      ticks: {
        padding: 10,
        display: true,
        fontSize: 10
      },
      grid: {
        display: false
      }
    }
  }
}

// Grafico pagamenti per fascia
const chartBarPayments = new Chart(document.getElementById("chartBarPayments").getContext('2d'), {
  type: 'bar',
  data: {
    labels: [],
    datasets: [{
      data: [],
    }]
  },
  options: optionsPagamentiBar
});

function getColorsByPayments(pagamenti) {
  const colorScale = d3.interpolateSinebow;
  const colorRangeInfo = {
    colorStart: 0.2,
    colorEnd: 1,
    useEndAsStart: true,
  };

  const tipiPagamenti = pagamenti.reduce((acc, pag) => {
    if (acc.includes(pag.descrpag)) return acc;
    acc.push(pag.descrpag);
    return acc
  }, [])
  let COLORS = interpolateColors(tipiPagamenti.length, colorScale, colorRangeInfo);

  return COLORS.map((color, index) => {
    return {
      pagamento: tipiPagamenti[index],
      backgroundColor: color
    }
  });
}

function pagamentiPerFascia(pagamenti) {
  //const COLORS = getColorsByPayments(pagamenti);
  let datasets = [];
  let timePeriods = [];
  let datasetLabels = [];
  let indexedData = {};
  let backgroundColors = {};

  pagamenti.forEach((pagamento, i) => {
    let date = "";
    if (periodo == "anno") {
      date = moment(pagamento.data).format("MMM YYYY");
      labels.push();
    } else if (periodo == "mese") {
      date = moment(pagamento.data).format("DD MMM");
    } else {
      date = moment(pagamento.data).format('HH:mm');
    }
    if (!timePeriods.includes(date)) {
       timePeriods.push(date);
    }
    if (!datasetLabels.includes(pagamento.descrpag)) {
       datasetLabels.push(pagamento.descrpag);
    }
    backgroundColors[pagamento.descrpag] = pagamento.backgroundColor;
    indexedData[pagamento.descrpag + date] = pagamento.totpag;
  });
  datasetLabels.forEach(label => {
    const dataset = {
      label: label,
      backgroundColor: backgroundColors[label],
      data: []
    };
    datasets.push(dataset);
    timePeriods.forEach(date => {
      dataset.data.push({
        x: date,
        y: indexedData[label+date] || 0
      })
    });
  })
  chartBarPayments.data = {
    datasets
  };
  chartBarPayments.update();
}

pagamentiPerFascia(API);```
<pre class="snippet-code-html lang-html prettyprint-override"><code><script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js"></script>
<canvas id="chartBarPayments"></canvas></code>```

Title: Tooltips showing wrong data in ChartJS

Body:
I have a bar chart which shows data from an API, after data normalization i'm having issues with tooltip where if i hover a set like '9:00' the tooltip shows '8:00' data by adding to it other data which doesn't belong to that time set.

My code looks like this:

const API = [{
  "totpag": 98.04,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 96.17,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 307.87,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 164.22,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 382.21,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 56.39,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 62.16,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 270.42,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 31.62,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 126.09,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 260.54,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 289.46,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 448.67,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 595.38,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 378.44,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 226.74,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 165.18,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 154.11,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 201.39,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 24.26,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 227.75,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 10.01,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 32.51,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 253.36,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 133.95,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 101.15,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 166.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 298.99,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 82.96,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 68.47,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 164.06,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 36.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 16.2,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 15.5,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 25.43,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}]

const optionsPagamentiBar = {
  responsive: true,
  maintainAspectRatio: false,
  plugins: {
    legend: {
      display: false
    },
    tooltip: {
      mode: 'index',
      intersect: 0,
      usePointStyle: true,
      callbacks: {
        label: function(context) {
          return context.dataset.label + ": " + "€" + context.parsed.y.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,').replace(/[,.]/g, m => (m === ',' ? '.' : ','));
        }
      }
    }
  },
  scales: {
    y: {
      ticks: {
        display: true,
        beginAtZero: true,
        callback: function(value, index, values) {
          return "€" + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
        }
      },
      grid: {
        drawBorder: false,
        zeroLineColor: "transparent",
      }
    },
    x: {
      display: 1,
      ticks: {
        padding: 10,
        display: true,
        fontSize: 10
      },
      grid: {
        display: false
      }
    }
  }
}

const chartBarPayments = new Chart(document.getElementById("chartBarPayments").getContext('2d'), {
  type: 'bar',
  data: {
    labels: [],
    datasets: [{
      data: [],
    }]
  },
  options: optionsPagamentiBar
});

let periodo = 'giorno'

function pagamentiPerFascia(pagamenti) {
  let datasets = [];
  pagamenti.forEach((pagamento, i) => {
    if (pagamento.totpag !== 0) {
      let date = "";
      if (periodo == "anno") {
        date = moment(pagamento.data).format("MMM YYYY");
        labels.push();
      } else if (periodo == "mese") {
        date = moment(pagamento.data).format("DD MMM");
      } else {
        date = moment(pagamento.data).format('HH:mm');
      }

      let dataset = datasets.find(data => data.label === pagamento.descrpag)
      if (dataset) {
        dataset.data.push({
          x: date,
          y: pagamento.totpag
        })
      } else {
        datasets.push({
          label: pagamento.descrpag,
          data: [{
            x: date,
            y: pagamento.totpag
          }], backgroundColor: pagamento.backgroundColor
        })
      }

    }
  })

  chartBarPayments.data = {
    datasets
  };
  chartBarPayments.update();
}

pagamentiPerFascia(API)

<canvas id="chartBarPayments"></canvas>

If you try to hover 4rd bar from '9:00' it will show tooltip on '8:00' with some data from '9:00' but even other datasets are bugged.

What is the issue and how should i fix it?

Body:
This issue is caused by the gaps in the dataset. For some reason, this is confusing ChartJS. If you put in zero values for the missing values in "NON RISCOSSO" and remove the if that prevents these from being added to datasets if (pagamento.totpag !== 0) it works.

Let me know if that is an acceptable workaround. Otherwise could possibly dig a bit further into ChartJS to figure out what's going on.

Below is some code that adds zero values into the datasets so there are no gaps. I've had to rewrite your data normalization code.

const API = [{
  "totpag": 98.04,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 96.17,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 307.87,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T08:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 164.22,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 382.21,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 56.39,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 62.16,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T09:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 270.42,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 31.62,
  "descrpag": "NON RISCOSSO",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(24, 244, 114)"
}, {
  "totpag": 126.09,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 260.54,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T10:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 289.46,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 448.67,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 595.38,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T11:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 378.44,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 226.74,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 165.18,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T12:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 154.11,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 201.39,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 24.26,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T13:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 227.75,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 10.01,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 32.51,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T16:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 253.36,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 133.95,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 101.15,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T17:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 166.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 298.99,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 82.96,
  "descrpag": "POS MANUALE",
  "data": "2022-02-05T18:00:00",
  "backgroundColor": "rgb(24, 114, 244)"
}, {
  "totpag": 68.47,
  "descrpag": "CONTANTI",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 164.06,
  "descrpag": "BANCOMAT",
  "data": "2022-02-05T19:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 36.33,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 16.2,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T08:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}, {
  "totpag": 15.5,
  "descrpag": "BANCOMAT",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(255, 64, 64)"
}, {
  "totpag": 25.43,
  "descrpag": "CONTANTI",
  "data": "2022-02-07T09:00:00",
  "backgroundColor": "rgb(167, 3, 213)"
}];

let periodo = "giorno";

const optionsPagamentiBar = {
  responsive: true,
  maintainAspectRatio: false,
  interaction: {
    intersect: false,
    mode: 'index'
  },
  plugins: {
    legend: {
      display: false
    },
    tooltip: {
      usePointStyle: true,
      callbacks: {
        label: function(context) {
          return context.dataset.label + ": " + "€" + context.parsed.y.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,').replace(/[,.]/g, m => (m === ',' ? '.' : ','));
        }
      }
    }
  },
  scales: {
    y: {
      ticks: {
        display: true,
        beginAtZero: true,
        callback: function(value, index, values) {
          return "€" + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
        }
      },
      grid: {
        drawBorder: false,
        zeroLineColor: "transparent",
      }
    },
    x: {
      display: 1,
      ticks: {
        padding: 10,
        display: true,
        fontSize: 10
      },
      grid: {
        display: false
      }
    }
  }
}

// Grafico pagamenti per fascia
const chartBarPayments = new Chart(document.getElementById("chartBarPayments").getContext('2d'), {
  type: 'bar',
  data: {
    labels: [],
    datasets: [{
      data: [],
    }]
  },
  options: optionsPagamentiBar
});

function getColorsByPayments(pagamenti) {
  const colorScale = d3.interpolateSinebow;
  const colorRangeInfo = {
    colorStart: 0.2,
    colorEnd: 1,
    useEndAsStart: true,
  };

  const tipiPagamenti = pagamenti.reduce((acc, pag) => {
    if (acc.includes(pag.descrpag)) return acc;
    acc.push(pag.descrpag);
    return acc
  }, [])
  let COLORS = interpolateColors(tipiPagamenti.length, colorScale, colorRangeInfo);

  return COLORS.map((color, index) => {
    return {
      pagamento: tipiPagamenti[index],
      backgroundColor: color
    }
  });
}

function pagamentiPerFascia(pagamenti) {
  //const COLORS = getColorsByPayments(pagamenti);
  let datasets = [];
  let timePeriods = [];
  let datasetLabels = [];
  let indexedData = {};
  let backgroundColors = {};

  pagamenti.forEach((pagamento, i) => {
    let date = "";
    if (periodo == "anno") {
      date = moment(pagamento.data).format("MMM YYYY");
      labels.push();
    } else if (periodo == "mese") {
      date = moment(pagamento.data).format("DD MMM");
    } else {
      date = moment(pagamento.data).format('HH:mm');
    }
    if (!timePeriods.includes(date)) {
       timePeriods.push(date);
    }
    if (!datasetLabels.includes(pagamento.descrpag)) {
       datasetLabels.push(pagamento.descrpag);
    }
    backgroundColors[pagamento.descrpag] = pagamento.backgroundColor;
    indexedData[pagamento.descrpag + date] = pagamento.totpag;
  });
  datasetLabels.forEach(label => {
    const dataset = {
      label: label,
      backgroundColor: backgroundColors[label],
      data: []
    };
    datasets.push(dataset);
    timePeriods.forEach(date => {
      dataset.data.push({
        x: date,
        y: indexedData[label+date] || 0
      })
    });
  })
  chartBarPayments.data = {
    datasets
  };
  chartBarPayments.update();
}

pagamentiPerFascia(API);

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.min.js"></script>
<canvas id="chartBarPayments"></canvas>


问:
Multithreaded Web Server for Android
I'm developing a multithreaded web server for an android app and I've some problems with a page that uses an external .css file, and a .js file, but only with Google Chrome! With Firefox and Opera the page is rendered fine, with Google Chrome sometimes the .css is loaded, sometimes the .js, sometime both or neither.

This is my app's structure:

WebServer.java

```<code>class WebServer implements Runnable{
protected boolean ON;

public void start(){
            if(!ON){
            ON=true;
            thread=new Thread(this,"WebServer");
            thread.start(); }}

public void run(){
while(ON){
listenSocket = new ServerSocket(port);
Socket connectionSocket = listenSocket.accept();
Thread t = new Thread(new Client(connectionSocket));
t.start();
listenSocket.close();}
}}
</code>```

Client.java

```<code>class Client implements Runnable {
public void start(){
        thread=new Thread(this,"Client");
        thread.start();}

public void run(){
//parse the request and send a file
}
}
</code>```

myApp.java

```<code>public class myApp extends Activity{

onCreate(){
WebServer ws=new WebServer(8080);
}

onClick(){
...
ws.start();
}}
</code>```

When I click a button on the activity, it call webserver.start(); In my opinion google chrome sends more requests concurrently and there's a problem with threads...
Can you help me?

[EDIT]
I had forgotten to write the loop in the run() method in the question

[EDIT 2]
I just tried with an other pc, and there are problems also with firefox..

答:
There is a general misunderstanding of the thread mechanism in your code.

A runnable has to override run. Not start. The run() method of the runnable will be called when the nesting thread will be started. In other words, the start method of your client will never be used, and hope fully, as it would create a thread inside a thread.. not very usefull.

Redesign your webser so that,  :

it's start method starts a new nesting thread as you did

it's run method does the following

your webserver binds to a port

in a loop : accept new connections and start new client thread for each.

the loop could be controlled by a boolean flag that you could rise to stop the server (ON would fit, even if the name of this variable doesn't follow java naming conventions and is rather poor semanticly speaking)

then each client would, in it's run (no more start method) :

read data from socket input stream

reply on socket outputstream

briefly, implement http protocole.

You could find some java code to inspire you on the web, some examples are well documented. Also, you could consider using java.nio package that is maybe less effective for a single request but much more effective at handling massive multiple connections. But code is harder.

You should consider reading more about runnables and also consider reading some stuff about synchronized key word to ensure that your web server doesn't start twice a connection for the same client or get confused in case of simultaneous requests.

Regards,
 Stéphane

Title: Multithreaded Web Server for Android

Body:
I'm developing a multithreaded web server for an android app and I've some problems with a page that uses an external .css file, and a .js file, but only with Google Chrome! With Firefox and Opera the page is rendered fine, with Google Chrome sometimes the .css is loaded, sometimes the .js, sometime both or neither.

This is my app's structure:

WebServer.java

class WebServer implements Runnable{
protected boolean ON;

public void start(){
            if(!ON){
            ON=true;
            thread=new Thread(this,"WebServer");
            thread.start(); }}

public void run(){
while(ON){
listenSocket = new ServerSocket(port);
Socket connectionSocket = listenSocket.accept();
Thread t = new Thread(new Client(connectionSocket));
t.start();
listenSocket.close();}
}}

Client.java

class Client implements Runnable {
public void start(){
        thread=new Thread(this,"Client");
        thread.start();}

public void run(){
//parse the request and send a file
}
}

myApp.java

public class myApp extends Activity{

onCreate(){
WebServer ws=new WebServer(8080);
}

onClick(){
...
ws.start();
}}

When I click a button on the activity, it call webserver.start(); In my opinion google chrome sends more requests concurrently and there's a problem with threads...
Can you help me?

[EDIT]
I had forgotten to write the loop in the run() method in the question

[EDIT 2]
I just tried with an other pc, and there are problems also with firefox..


问:
is a good approach defining 2 useEffect Hooks, see my use of case bellow
I tried to find the same case, but everyone is in a different situation.

I've created 2 useEffects in my component, one for initializing the component (1 execution) and another to fetch data when some state (filter) changes. (many executions)

```<code>const [filter1, setFilter1] = useState({});
const [filter2, setFilter2] = useState({});

//initialize filters, only once
useEffect(() => {
  //here i fetch all the data to fill the filter components.
  setFilter1(data1);
  setFilter2(data2);
}, []);
//everytime my filters change.
useEffect(() => {
  //here i fetch data using the filter as parameters.
}, [filter1,filter2]);
</code>```

The code above is my last approach and works fine. Every time I change the filters the useEffect fetch the data and load the table with that data.

I show below the old approach that I took, and the one I didn't like.

```<code>const loadData = useCallback((filter1,filter2) => {
   //here i fetch data using the filter as parameters.
   }, [filter1,filter2]);

 useEffect(() => {
   //here i fetch all the data to fill the filter components.
    setFilter1(data1);
    setFilter2(data2);
    loadData(filter1, filter2);
  },[]);
</code>```

and I used the loadData function in every filter change handler like:

```<code>  const onFilter1Change = (val) => {
     setFilter1(val);
     loadData(val, filter2)
  };
</code>```

The old approach above brought me some issues regarding how to use the hooks properly and that's why I find myself asking you React experts, how to improve my coding in the best way.

The new approach works fine for me, tho I wonder if it's right to use 2 useEffect in this case, or if there is a better way to do it.

Cheers

答:
Where data1 & data2 comes from?
If it's a prop, and you are using a useEffect only to initialize them, you don't need a useEffect for that:

const [filter1, setFilter1] = useState(data1);
const [filter2, setFilter2] = useState(data2);

useEffect(() => {
  //here i fetch data using the filter as parameters.
}, [filter1, filter2]);
```

Body:
I tried to find the same case, but everyone is in a different situation.

I've created 2 useEffects in my component, one for initializing the component (1 execution) and another to fetch data when some state (filter) changes. (many executions)

const [filter1, setFilter1] = useState({});
const [filter2, setFilter2] = useState({});

//initialize filters, only once
useEffect(() => {
  //here i fetch all the data to fill the filter components.
  setFilter1(data1);
  setFilter2(data2);
}, []);
//everytime my filters change.
useEffect(() => {
  //here i fetch data using the filter as parameters.
}, [filter1,filter2]);

The code above is my last approach and works fine. Every time I change the filters the useEffect fetch the data and load the table with that data.

I show below the old approach that I took, and the one I didn't like.

const loadData = useCallback((filter1,filter2) => {
   //here i fetch data using the filter as parameters.
   }, [filter1,filter2]);

 useEffect(() => {
   //here i fetch all the data to fill the filter components.
    setFilter1(data1);
    setFilter2(data2);
    loadData(filter1, filter2);
  },[]);

and I used the loadData function in every filter change handler like:

  const onFilter1Change = (val) => {
     setFilter1(val);
     loadData(val, filter2)
  };

The old approach above brought me some issues regarding how to use the hooks properly and that's why I find myself asking you React experts, how to improve my coding in the best way.

The new approach works fine for me, tho I wonder if it's right to use 2 useEffect in this case, or if there is a better way to do it.

Cheers


问:
How do I constraint a view to the center of another view in android studio?
```<code><androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <Button
        android:id="@+id/open_explanation_button"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="@drawable/open_dialog"
        app:layout_constraintEnd_toEndOf="parent"
        />
    <TextView
        android:id="@+id/movieRatingText"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:gravity="center"
        android:layout_weight="53"
        android:text="Rating: R"
        android:textColor="@color/white"
        android:textSize="20sp"
        app:autoSizeMaxTextSize="100sp"
        app:autoSizeMinTextSize="12sp"
        app:autoSizeStepGranularity="2sp"
        app:autoSizeTextType="uniform"
        app:layout_constraintTop_toBottomOf="@+id/inASeriesOrNoText"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />
</code>```

I have a button with an id of open_explanation_button, I need to place that button to the end of the movieRatingText. The problem is that I need the movieRatingText to be with a width of match_parent to make sure that it's an autoresizable text. In a more simpler way, I need to constraint the start of the open_explanation_button to the center of the movieRatingText, in addition to adding some margins.
Any help?

答:
You can create a dummy view and align that as the center point of movieRatingText. And use that to start of open_explanation_button

```<code>   <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
    android:id="@+id/open_explanation_button"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:background="@drawable/ic_add"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="@id/centerView" />

<TextView
    android:id="@+id/movieRatingText"
    android:layout_width="match_parent"
    android:layout_height="30dp"
    android:layout_weight="53"
    android:gravity="center"
    android:text="Rating: R"
    android:textColor="@color/white"
    android:textSize="20sp"
    app:autoSizeMaxTextSize="100sp"
    app:autoSizeMinTextSize="12sp"
    app:autoSizeStepGranularity="2sp"
    app:autoSizeTextType="uniform"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/inASeriesOrNoText"
    app:layout_constraintTop_toTopOf="parent" />

<View
    android:id="@+id/centerView"
    android:layout_width="1dp"
    android:layout_height="1dp"
    app:layout_constraintEnd_toEndOf="@id/movieRatingText"
    app:layout_constraintStart_toStartOf="@id/movieRatingText"
    app:layout_constraintTop_toTopOf="@+id/movieRatingText" />
</code>```

</androidx.constraintlayout.widget.ConstraintLayout>

Body:
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <Button
        android:id="@+id/open_explanation_button"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="@drawable/open_dialog"
        app:layout_constraintEnd_toEndOf="parent"
        />
    <TextView
        android:id="@+id/movieRatingText"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:gravity="center"
        android:layout_weight="53"
        android:text="Rating: R"
        android:textColor="@color/white"
        android:textSize="20sp"
        app:autoSizeMaxTextSize="100sp"
        app:autoSizeMinTextSize="12sp"
        app:autoSizeStepGranularity="2sp"
        app:autoSizeTextType="uniform"
        app:layout_constraintTop_toBottomOf="@+id/inASeriesOrNoText"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        />

I have a button with an id of open_explanation_button, I need to place that button to the end of the movieRatingText. The problem is that I need the movieRatingText to be with a width of match_parent to make sure that it's an autoresizable text. In a more simpler way, I need to constraint the start of the open_explanation_button to the center of the movieRatingText, in addition to adding some margins.
Any help?

Body:
You can create a dummy view and align that as the center point of movieRatingText. And use that to start of open_explanation_button

   <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
    android:id="@+id/open_explanation_button"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:background="@drawable/ic_add"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="@id/centerView" />

<TextView
    android:id="@+id/movieRatingText"
    android:layout_width="match_parent"
    android:layout_height="30dp"
    android:layout_weight="53"
    android:gravity="center"
    android:text="Rating: R"
    android:textColor="@color/white"
    android:textSize="20sp"
    app:autoSizeMaxTextSize="100sp"
    app:autoSizeMinTextSize="12sp"
    app:autoSizeStepGranularity="2sp"
    app:autoSizeTextType="uniform"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/inASeriesOrNoText"
    app:layout_constraintTop_toTopOf="parent" />

<View
    android:id="@+id/centerView"
    android:layout_width="1dp"
    android:layout_height="1dp"
    app:layout_constraintEnd_toEndOf="@id/movieRatingText"
    app:layout_constraintStart_toStartOf="@id/movieRatingText"
    app:layout_constraintTop_toTopOf="@+id/movieRatingText" />

</androidx.constraintlayout.widget.ConstraintLayout>


问:
Recursion: Collatz sequence -Could someone please explain how this code returns the total number of steps?
```<code>#include <cs50.h>

int collatz(int n);

int main(void)
{
    int n = get_int("Enter int: ");
    int steps = collatz(n);
    printf("%i\n", steps);
}

int collatz(int n)
{
    if (n==1)
    {
        return 0;
    }

    else if ((n%2)==0)
    {
        return 1 + collatz(n/2);
    }

    else
    {
        return 1 + collatz(3 * n + 1);
    }
}
</code>```

I am geting stuck trying to visualise how the 'return 1' on each iteration of the function gets 'carried through'.

I can write the steps out on paper to show that it does work, however I am struggling to make clear in my mind without going through step-by-step, why you have to +1 on every iteration of collatz.

答:
This code:

```<code>    if (n==1)
    {
        return 0;
    }
</code>```

says: If there are no steps to perform (because n is already 1), return zero.

Otherwise, this code:

```<code>    else if ((n%2)==0)
</code>```

selects one of the following:

```<code>        return 1 + collatz(n/2);
</code>```

or:

```<code>        return 1 + collatz(3 * n + 1);
</code>```

Each of those performs one step (either n/2 or 3 * n + 1) and then calls collatz to find out how many steps it takes to finish with that value. When collatz returns the number of steps needed for n/2 or 3 * n + 1, this code adds one for the step performed here. That gives the number of steps needed for n, which this code then returns.

Body:
#include <cs50.h>

int collatz(int n);

int main(void)
{
    int n = get_int("Enter int: ");
    int steps = collatz(n);
    printf("%i\n", steps);
}

int collatz(int n)
{
    if (n==1)
    {
        return 0;
    }

    else if ((n%2)==0)
    {
        return 1 + collatz(n/2);
    }

    else
    {
        return 1 + collatz(3 * n + 1);
    }
}

I am geting stuck trying to visualise how the 'return 1' on each iteration of the function gets 'carried through'.

I can write the steps out on paper to show that it does work, however I am struggling to make clear in my mind without going through step-by-step, why you have to +1 on every iteration of collatz.

Body:
This code:

    if (n==1)
    {
        return 0;
    }

says: If there are no steps to perform (because n is already 1), return zero.

Otherwise, this code:

    else if ((n%2)==0)

selects one of the following:

        return 1 + collatz(n/2);

or:

        return 1 + collatz(3 * n + 1);

Each of those performs one step (either n/2 or 3 * n + 1) and then calls collatz to find out how many steps it takes to finish with that value. When collatz returns the number of steps needed for n/2 or 3 * n + 1, this code adds one for the step performed here. That gives the number of steps needed for n, which this code then returns.


问:
Accessing data from list in python/django
I have this code:

```<code>list_of_objects = [{
"object": "a",
"object": "b",
"object": "c",
}]

list = []

for objects in list_of_object:
    list.append(objects['object'])

print(list)

</code>```

It only outputs:

{c}

I want to display every object on the list
like:
{a,b,c}

答:
You are using a dict incorrectly since dictionaries can only have one value per key. In this situation you just need to use a list:

```<code>list_of_objects = ["a","b","c"]
</code>```

In case you still want to use a dict for some reason we don't know about, you will have to store an array of objects with the "object" key:

```<code>list_of_objects = { "objects" : ["a","b","c"] }
</code>```

Body:
I have this code:

list_of_objects = [{
"object": "a",
"object": "b",
"object": "c",
}]

list = []

for objects in list_of_object:
    list.append(objects['object'])

print(list)

It only outputs:

{c}

I want to display every object on the list
like:
{a,b,c}

Body:
You are using a dict incorrectly since dictionaries can only have one value per key. In this situation you just need to use a list:

list_of_objects = ["a","b","c"]

In case you still want to use a dict for some reason we don't know about, you will have to store an array of objects with the "object" key:

list_of_objects = { "objects" : ["a","b","c"] }