问:
Can't get data from Googlesheet using esp32 and Arduinojson
I'm new to esp32 and now I'm trying to Get data using ArduinoJson,
In my googlesheet "A1" have a number and I want to let esp32 to get it,
I send my googlesheet to internet and use the url:https://spreadsheets.google.com/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1.
and my number is at object > feed > entry > 0 > content > $t.

Here's a problem:When I use esp32 to get this json data,I can't get it,even my esp32 connected to googlesheet

Here is my full code if you need:

```<code>#include <ArduinoJson.h>
#include <WiFi.h>
#include <SPI.h>

WiFiClient client;

const char* ssid = "wwwwwwwww";
const char* password = "wwwwwwww";
const char* server = "spreadsheets.google.com";
const char* resource = "/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1";

const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 1024;       // max size of the HTTP response

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

struct clientData {
  char item[8];
};

void setup() {
  Serial.begin(9600);
  while (!Serial) {

  }
  Serial.println("Serial ready");
  Serial.print("Connecting to wifi: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  if(connect(server)) {
    if(sendRequest(server, resource) && skipResponseHeaders()) {
      clientData clientData;
      if(readReponseContent(&clientData)) {
        printclientData(&clientData);
      }
    }
  }
  disconnect();
  wait();
}

bool connect(const char* hostName) {
  Serial.print("Connect to ");
  Serial.println(hostName);

  bool ok = client.connect(hostName, 80);

  Serial.println(ok ? "Connected" : "Connection Failed!");
  return ok;
}

bool sendRequest(const char* host, const char* resource) {
  Serial.print("GET ");
  Serial.println(resource);

  client.print("GET ");
  client.print(resource);
  client.println(" HTTP/1.1");
  client.print("Host: ");
  client.println(host);
  client.println("Connection: close");
  client.println();

  return true;
}

bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  char endOfHeaders[] = "\r\n\r\n";

  client.setTimeout(HTTP_TIMEOUT);
  bool ok = client.find(endOfHeaders);

  if (!ok) {
    Serial.println("No response or invalid response!");
  }
  return ok;
}

bool readReponseContent(struct clientData* clientData) {
  const size_t bufferSize = 5*JSON_ARRAY_SIZE(1) +
  JSON_ARRAY_SIZE(5) + 10*JSON_OBJECT_SIZE(1) +
  6*JSON_OBJECT_SIZE(2) + 7*JSON_OBJECT_SIZE(3) +
  JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(15);
  DynamicJsonBuffer jsonBuffer(bufferSize);

  JsonObject& root = jsonBuffer.parseObject(client);

  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  strcpy(clientData->item, root["feed"]["entry"][0]["content"]["$t"]);

  return true;
}

void printclientData(const struct clientData* clientData) {
  Serial.print("Time = ");
  Serial.println(clientData->item);

}

void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

void wait() {
  Serial.println("Wait 20 seconds");
  delay(20000);
}
</code>```

Serial Output:

```<code>Connecting to wifi: wwwwwwwwww
..
WiFi connected
IP address:
xxx.xxx.x.xx
Connect to spreadsheets.google.com
Connected
GET /feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1
JSON parsing failed!
Disconnect
Wait 20 seconds

</code>```

答:
If I based on your json output and calculate the bufferSize using ArduinoJson Assistant, I get this:

```<code>const size_t capacity = 5*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(5) + 10*JSON_OBJECT_SIZE(1) + 6*JSON_OBJECT_SIZE(2) + 7*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(15) + 2270;
</code>```

Noticed the + 2270 at the end? Your parsing json failed because your are short of 2270 bytes in bufferSize (i.e. your bufferSize is too small).

Updte

I didn't try to debug your code, but I have my web client code handy with me so I just run and it works for me.

My code is based on HTTPClient which is part of ESP32 Arduino Core that you can further read about it at ESP-Arduino github. It is based on Arduino WifiClient that you used but with much simpler and easy to use API, especially for getting response payload. I would recommend you take a look.

I add ArduinoJson to my code to see if there is any issue on parsing the received json, but mines is based on v6 syntax, you can convert it to v5 syntax if you still feel it is easier for you to use v5. BTW, the json document contains Unicode, I have to add #define ARDUINOJSON_DECODE_UNICODE 1 on the top of the program in oder to make it work, otherwise I will get an deserialization error: NotSupported.

```<code>#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>

HTTPClient http;

const char* ssid = "your_SSID";
const char* password = "your_password";

const char* url = "https://spreadsheets.google.com/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1";

void setup() {
  Serial.begin(115200);
  while (!Serial) {}

  Serial.print("Connecting to wifi: "); Serial.print(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("IP address: "); Serial.println(WiFi.localIP());

  http.begin(url);
  int httpCode = http.GET();  //send GET request

  if (httpCode != 200) {
    Serial.print("Error on HTTP request: ");
    Serial.println(httpCode);
  } else {
    String payload = http.getString();
    Serial.println(payload);

    // the following is based on ArduinoJson v6 API
    StaticJsonDocument<4000> doc;
    DeserializationError err = deserializeJson(doc, payload);
    if (err) {
      Serial.print("deserialization error ");
      Serial.println(err.c_str());
    }

    JsonObject feed = doc["feed"];
    const char* clientData = feed["entry"][0]["content"]["$t"];
    Serial.println(clientData);
  }

  http.end(); //Free the resources

}

void loop() {

}
</code>```

Body:
I'm new to esp32 and now I'm trying to Get data using ArduinoJson,
In my googlesheet "A1" have a number and I want to let esp32 to get it,
I send my googlesheet to internet and use the url:https://spreadsheets.google.com/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1.
and my number is at object > feed > entry > 0 > content > $t.

Here's a problem:When I use esp32 to get this json data,I can't get it,even my esp32 connected to googlesheet

Here is my full code if you need:

#include <ArduinoJson.h>
#include <WiFi.h>
#include <SPI.h>

WiFiClient client;

const char* ssid = "wwwwwwwww";
const char* password = "wwwwwwww";
const char* server = "spreadsheets.google.com";
const char* resource = "/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1";

const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 1024;       // max size of the HTTP response

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};

struct clientData {
  char item[8];
};

void setup() {
  Serial.begin(9600);
  while (!Serial) {

  }
  Serial.println("Serial ready");
  Serial.print("Connecting to wifi: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  if(connect(server)) {
    if(sendRequest(server, resource) && skipResponseHeaders()) {
      clientData clientData;
      if(readReponseContent(&clientData)) {
        printclientData(&clientData);
      }
    }
  }
  disconnect();
  wait();
}

bool connect(const char* hostName) {
  Serial.print("Connect to ");
  Serial.println(hostName);

  bool ok = client.connect(hostName, 80);

  Serial.println(ok ? "Connected" : "Connection Failed!");
  return ok;
}

bool sendRequest(const char* host, const char* resource) {
  Serial.print("GET ");
  Serial.println(resource);

  client.print("GET ");
  client.print(resource);
  client.println(" HTTP/1.1");
  client.print("Host: ");
  client.println(host);
  client.println("Connection: close");
  client.println();

  return true;
}

bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  char endOfHeaders[] = "\r\n\r\n";

  client.setTimeout(HTTP_TIMEOUT);
  bool ok = client.find(endOfHeaders);

  if (!ok) {
    Serial.println("No response or invalid response!");
  }
  return ok;
}

bool readReponseContent(struct clientData* clientData) {
  const size_t bufferSize = 5*JSON_ARRAY_SIZE(1) +
  JSON_ARRAY_SIZE(5) + 10*JSON_OBJECT_SIZE(1) +
  6*JSON_OBJECT_SIZE(2) + 7*JSON_OBJECT_SIZE(3) +
  JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(15);
  DynamicJsonBuffer jsonBuffer(bufferSize);

  JsonObject& root = jsonBuffer.parseObject(client);

  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  strcpy(clientData->item, root["feed"]["entry"][0]["content"]["$t"]);

  return true;
}

void printclientData(const struct clientData* clientData) {
  Serial.print("Time = ");
  Serial.println(clientData->item);

}

void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

void wait() {
  Serial.println("Wait 20 seconds");
  delay(20000);
}

Serial Output:

Connecting to wifi: wwwwwwwwww
..
WiFi connected
IP address:
xxx.xxx.x.xx
Connect to spreadsheets.google.com
Connected
GET /feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1
JSON parsing failed!
Disconnect
Wait 20 seconds

Body:
If I based on your json output and calculate the bufferSize using ArduinoJson Assistant, I get this:

const size_t capacity = 5*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(5) + 10*JSON_OBJECT_SIZE(1) + 6*JSON_OBJECT_SIZE(2) + 7*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(15) + 2270;

Noticed the + 2270 at the end? Your parsing json failed because your are short of 2270 bytes in bufferSize (i.e. your bufferSize is too small).

Updte

I didn't try to debug your code, but I have my web client code handy with me so I just run and it works for me.

My code is based on HTTPClient which is part of ESP32 Arduino Core that you can further read about it at ESP-Arduino github. It is based on Arduino WifiClient that you used but with much simpler and easy to use API, especially for getting response payload. I would recommend you take a look.

I add ArduinoJson to my code to see if there is any issue on parsing the received json, but mines is based on v6 syntax, you can convert it to v5 syntax if you still feel it is easier for you to use v5. BTW, the json document contains Unicode, I have to add #define ARDUINOJSON_DECODE_UNICODE 1 on the top of the program in oder to make it work, otherwise I will get an deserialization error: NotSupported.

#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>

HTTPClient http;

const char* ssid = "your_SSID";
const char* password = "your_password";

const char* url = "https://spreadsheets.google.com/feeds/cells/1RICYSv0y0wEEu-PhcCL45jZmh7DlFSAsbW8Bie0inbA/1/public/values?alt=json&range=A1";

void setup() {
  Serial.begin(115200);
  while (!Serial) {}

  Serial.print("Connecting to wifi: "); Serial.print(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(200);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("IP address: "); Serial.println(WiFi.localIP());

  http.begin(url);
  int httpCode = http.GET();  //send GET request

  if (httpCode != 200) {
    Serial.print("Error on HTTP request: ");
    Serial.println(httpCode);
  } else {
    String payload = http.getString();
    Serial.println(payload);

    // the following is based on ArduinoJson v6 API
    StaticJsonDocument<4000> doc;
    DeserializationError err = deserializeJson(doc, payload);
    if (err) {
      Serial.print("deserialization error ");
      Serial.println(err.c_str());
    }

    JsonObject feed = doc["feed"];
    const char* clientData = feed["entry"][0]["content"]["$t"];
    Serial.println(clientData);
  }

  http.end(); //Free the resources

}

void loop() {

}


来源: stackexchange

问:
InDesign Socket HTTP response is missing sections
I am automating Adobe InDesign to create documents using JSON data gathered from a web API with a SQL Server backend.  I am using the Sockets object to make an HTTP 1.0 call to our server.  Sometimes the response received is missing about 1700 characters from various points within the JSON string, yet when I call the same API endpoint using curl or Postman I get a complete and valid response.

The response should be about 150k characters long, and I'm using conn.read(99999999) to read it.  In addition, the appearance of the end of the string looks correct, so I don't believe it's any kind of truncation problem.

The problem only seems to occur when I request a UTF-8 encoding.  If I request ASCII I get a complete and valid response, but missing various Unicode characters.  If I request BINARY I get a complete and valid response but the JavaScript/ExtendScript seems to be handling any multi-byte Unicode characters received as individual bytes, rather than as the Unicode characters we want to display.

Here is an illustration of the behavior I'm seeing, using bogus data...

"Expected" response...

[{"Id":1, "name":"Random Name", "Text":"A bunch of text", "AnotherId": 1}]

"Actual" response...

[{"Id":1, "name":"Random Name", "Text":"A bunc": 1}]

The problem first manifested itself as a JSON2 parsing error, for obvious reasons, but the root of it seems to be the fact that parts of the data are going missing in-transit.

So far we've only seen this problem when making the call using the InDesign Sockets object, and not every response exhibits this behavior.

Any help or insights you could offer would be appreciated.

Here is the function I'm using to call for data...

```<code>function httpRequest(url, encoding) {
   try {
      var response = "";

      var hostName = getHostFromUrl(url);
      var pathAndQuery = getPathAndQueryFromUrl(url);

      var httpGet = "GET ";
         httpGet += pathAndQuery;
         httpGet += " HTTP/1.0\r\nHost: ";
         httpGet += hostName;
         httpGet += "\r\n";

      var conn = new Socket;

      conn.timeout = 30;
     //conn.encoding = encoding || "UTF-8";
     //conn.charset = "UTF-16";

      if (conn.open(hostName + ":80", encoding || "UTF-8")) {
         // send a HTTP GET request
         conn.writeln(httpGet);

         // and read the server's response
         response = conn.read(99999999);

         conn.close();
      }

      return parseHttpResponse(response);
   }
   catch (e) {
      $.writeln(e);
      $.global.alert("There was a problem making an HTTP Request: " + e);
      return null;
   }
}
</code>```

答:
It turns out my handling of the HTTP response was too simplistic and needed extra logic to handle Unicode characters properly.

The solution, in my case, was to use the GetURL method made available by Kris Coppieter here.

ContentLicense: CC BY-SA 4.0

Body:
I am automating Adobe InDesign to create documents using JSON data gathered from a web API with a SQL Server backend.  I am using the Sockets object to make an HTTP 1.0 call to our server.  Sometimes the response received is missing about 1700 characters from various points within the JSON string, yet when I call the same API endpoint using curl or Postman I get a complete and valid response.

The response should be about 150k characters long, and I'm using conn.read(99999999) to read it.  In addition, the appearance of the end of the string looks correct, so I don't believe it's any kind of truncation problem.

The problem only seems to occur when I request a UTF-8 encoding.  If I request ASCII I get a complete and valid response, but missing various Unicode characters.  If I request BINARY I get a complete and valid response but the JavaScript/ExtendScript seems to be handling any multi-byte Unicode characters received as individual bytes, rather than as the Unicode characters we want to display.

Here is an illustration of the behavior I'm seeing, using bogus data...

"Expected" response...

[{"Id":1, "name":"Random Name", "Text":"A bunch of text", "AnotherId": 1}]

"Actual" response...

[{"Id":1, "name":"Random Name", "Text":"A bunc": 1}]

The problem first manifested itself as a JSON2 parsing error, for obvious reasons, but the root of it seems to be the fact that parts of the data are going missing in-transit.

So far we've only seen this problem when making the call using the InDesign Sockets object, and not every response exhibits this behavior.

Any help or insights you could offer would be appreciated.

Here is the function I'm using to call for data...

function httpRequest(url, encoding) {
   try {
      var response = "";

      var hostName = getHostFromUrl(url);
      var pathAndQuery = getPathAndQueryFromUrl(url);

      var httpGet = "GET ";
         httpGet += pathAndQuery;
         httpGet += " HTTP/1.0\r\nHost: ";
         httpGet += hostName;
         httpGet += "\r\n";

      var conn = new Socket;

      conn.timeout = 30;
     //conn.encoding = encoding || "UTF-8";
     //conn.charset = "UTF-16";

      if (conn.open(hostName + ":80", encoding || "UTF-8")) {
         // send a HTTP GET request
         conn.writeln(httpGet);

         // and read the server's response
         response = conn.read(99999999);

         conn.close();
      }

      return parseHttpResponse(response);
   }
   catch (e) {
      $.writeln(e);
      $.global.alert("There was a problem making an HTTP Request: " + e);
      return null;
   }
}


问:
Processing pararelly drainded data from publisher
How to process data pararelly subscribed from Publisher?

Should I subscribe in a loop in a pool of workers? When I call subscribe in Project Reactor I got only one chunk of data. How to "drain all"?

How to ensure that every worker will take different chunk of data?

答:
Convert each chunk of data into a task and submit it to an Executor. Converter may look as follows:

```<code>class Converter implements Subscriber<T> {
    final Executor executor;
    Subscription subscription;

    Converter(Executor executor) {
        this.executor = executor;
    }

    @Override
    public void onSubscribe(Subscription s) {
        subscription = s;
        s.request(1);
    }

    @Override
    public void onNext(T data) {
        executor.execute(()->process(data));
        subscription.request(1);
    }
    ...
    void process(T o) {
        ...
    }
}
</code>```

Body:
Convert each chunk of data into a task and submit it to an Executor. Converter may look as follows:

class Converter implements Subscriber<T> {
    final Executor executor;
    Subscription subscription;

    Converter(Executor executor) {
        this.executor = executor;
    }

    @Override
    public void onSubscribe(Subscription s) {
        subscription = s;
        s.request(1);
    }

    @Override
    public void onNext(T data) {
        executor.execute(()->process(data));
        subscription.request(1);
    }
    ...
    void process(T o) {
        ...
    }
}


问:
Dotnet core 502 gateway with FileResult return
i have a controller method that return an excel file developed using dotnet core 2.2. The method work fine while testing on my local IIS. However the same method returns a 502 gateway error when deployed as a container on openshift. Can someone please help understand the issue here. Also please note that these requests are routed through an Ocelot gateway api.

```<code>[HttpGet, Route("GetCaseFeedData")]
        public async Task<FileResult> GetCaseFeedData([FromQuery] int caseId, [FromQuery] int proposalId, [FromQuery] int equipmentId)
        {
            try
            {
                var queryParams = new Dictionary<string, string> { { "caseId", caseId.ToString() }, { "proposalId", proposalId.ToString() }, { "equipmentId", equipmentId.ToString() } };
                var restObj = _restFactory.createRestRequest(Method.GET, "PsaDataFetch-api/GetCaseFeedCompositionForSimulation", queryParams);
                Console.WriteLine(restObj.Item2.BaseUrl);
                var response = await restObj.Item2.ExecuteTaskAsync(restObj.Item1);
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var outPut = JsonConvert.DeserializeObject<CaseFeedCompositionResponse>(response.Content);
                    Console.WriteLine("inside status ok");
                    Console.WriteLine(_hostingEnvironment.ContentRootPath, "App_data", "PSASim v5.1 template.xlsm");
                    var excelPackage = await _excelService.PopulatePsaSimFile(outPut, Path.Combine(_hostingEnvironment.ContentRootPath, "App_Data", "PSASim v5.1 template.xlsm"));
                    return File(_excelHelper.ConvertExcelToByteArray(excelPackage), ContentTypeEnums.excel, "template"+".xlsm");
                }
                else
                {
                    Console.WriteLine("inside else portion");
                    return null;
                }
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
        }
</code>```

UPDATE:
I can see in the logs the below error message:

[08:08:52 INF] Executed action method STSLog.PsaSIM.API.Controllers.PSASimulatorController.GetCaseFeedData (UOP.TOOLS.STSLOG.PSASIM.API.Web), returned result Microsoft.AspNetCore.Mvc.FileContentResult in 95501.3656ms.
[08:08:52 INF] Executing Microsoft.AspNetCore.Mvc.FileContentResult, sending file with download name 'template.xlsm' ...
[08:08:52 INF] Connection id "0HLTJF7INHERP", Request id "0HLTJF7INHERP:00000001": the application aborted the connection.

答:
I was finally able to overcome this issue, posting my solution here so that it helps someone else. Openshift uses ha proxy as its ingress pod, the time out was occurring since it waits for only 30 seconds for a request to complete. This setting can be overriden in the routes as below

https://access.redhat.com/documentation/en-us/red_hat_process_automation_manager/7.1/html/managing_and_monitoring_process_server/configuring-openshift-connection-timeout-proc

Body:
i have a controller method that return an excel file developed using dotnet core 2.2. The method work fine while testing on my local IIS. However the same method returns a 502 gateway error when deployed as a container on openshift. Can someone please help understand the issue here. Also please note that these requests are routed through an Ocelot gateway api.

[HttpGet, Route("GetCaseFeedData")]
        public async Task<FileResult> GetCaseFeedData([FromQuery] int caseId, [FromQuery] int proposalId, [FromQuery] int equipmentId)
        {
            try
            {
                var queryParams = new Dictionary<string, string> { { "caseId", caseId.ToString() }, { "proposalId", proposalId.ToString() }, { "equipmentId", equipmentId.ToString() } };
                var restObj = _restFactory.createRestRequest(Method.GET, "PsaDataFetch-api/GetCaseFeedCompositionForSimulation", queryParams);
                Console.WriteLine(restObj.Item2.BaseUrl);
                var response = await restObj.Item2.ExecuteTaskAsync(restObj.Item1);
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var outPut = JsonConvert.DeserializeObject<CaseFeedCompositionResponse>(response.Content);
                    Console.WriteLine("inside status ok");
                    Console.WriteLine(_hostingEnvironment.ContentRootPath, "App_data", "PSASim v5.1 template.xlsm");
                    var excelPackage = await _excelService.PopulatePsaSimFile(outPut, Path.Combine(_hostingEnvironment.ContentRootPath, "App_Data", "PSASim v5.1 template.xlsm"));
                    return File(_excelHelper.ConvertExcelToByteArray(excelPackage), ContentTypeEnums.excel, "template"+".xlsm");
                }
                else
                {
                    Console.WriteLine("inside else portion");
                    return null;
                }
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
        }

UPDATE:
I can see in the logs the below error message:

[08:08:52 INF] Executed action method STSLog.PsaSIM.API.Controllers.PSASimulatorController.GetCaseFeedData (UOP.TOOLS.STSLOG.PSASIM.API.Web), returned result Microsoft.AspNetCore.Mvc.FileContentResult in 95501.3656ms.
[08:08:52 INF] Executing Microsoft.AspNetCore.Mvc.FileContentResult, sending file with download name 'template.xlsm' ...
[08:08:52 INF] Connection id "0HLTJF7INHERP", Request id "0HLTJF7INHERP:00000001": the application aborted the connection.


问:
Amazon Cognito "A client attempted to write unauthorized attribute"
I'm using the JavaScript SDK for AWS Cognito, and there are a couple of custom attributes that I just can't seem to save to and can't see why.

The problem attributes are mutable string fields as follows:

```<code>custom: role
custom: recruitingrole
custom: title
</code>```

Other custom fields in the same request seem to update OK.  Specifically, these ones seem to work:

```<code>custom:division
custom:linkedin
custom:location
custom:bio
</code>```

When I submit via the SDK, this is returned:

{"__type":"NotAuthorizedException","message":"A client attempted to write unauthorized attribute"}

Here is the data that is sent, as show in the Chrome developer console network output:

```<code>{
    "AccessToken": "",
    "UserAttributes": [{
        "Name": "name",
        "Value": "Steve Austin"
    }, {
        "Name": "custom:company",
        "Value": "OSI"
    }, {
        "Name": "custom:division",
        "Value": "Bionics"
    }, {
        "Name": "custom:recruitingrole",
        "Value": "other"
    }, {
        "Name": "custom:linkedin",
        "Value": "http://www.linkedin.com"
    }, {
        "Name": "custom:location",
        "Value": "Mexico City, Mexico City, Mexico"
    }, {
        "Name": "custom:bio",
        "Value": "A man barely alive."
    }]
}
</code>```

Can anyone suggest why I can't save to these attributes?

thanks

答:
My case is a bit different. I am using Amplify angular component and I don't have any custom attributes (standard email login type).

It turns out that the key of the sign-up fields is case-sensitive. For the uppercase 'Email' key, I will see the error.
Below is the sign-up configurations

```<code>emailSignUpConfig = {
        header: 'Sign up header',
        hideAllDefaults: true,
        defaultCountryCode: '1',
        signUpFields: [
            {
                label: 'Email',
                key: 'email', //the email should be in lower case
                required: true,
                displayOrder: 1,
                type: 'string',
            },
            {
                label: 'Password',
                key: 'password',
                required: true,
                displayOrder: 2,
                type: 'password',
            },
        ],
    };
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I'm using the JavaScript SDK for AWS Cognito, and there are a couple of custom attributes that I just can't seem to save to and can't see why.

The problem attributes are mutable string fields as follows:

custom: role
custom: recruitingrole
custom: title

Other custom fields in the same request seem to update OK.  Specifically, these ones seem to work:

custom:division
custom:linkedin
custom:location
custom:bio

When I submit via the SDK, this is returned:

{"__type":"NotAuthorizedException","message":"A client attempted to write unauthorized attribute"}

Here is the data that is sent, as show in the Chrome developer console network output:

{
    "AccessToken": "",
    "UserAttributes": [{
        "Name": "name",
        "Value": "Steve Austin"
    }, {
        "Name": "custom:company",
        "Value": "OSI"
    }, {
        "Name": "custom:division",
        "Value": "Bionics"
    }, {
        "Name": "custom:recruitingrole",
        "Value": "other"
    }, {
        "Name": "custom:linkedin",
        "Value": "http://www.linkedin.com"
    }, {
        "Name": "custom:location",
        "Value": "Mexico City, Mexico City, Mexico"
    }, {
        "Name": "custom:bio",
        "Value": "A man barely alive."
    }]
}

Can anyone suggest why I can't save to these attributes?

thanks

Body:
My case is a bit different. I am using Amplify angular component and I don't have any custom attributes (standard email login type).

It turns out that the key of the sign-up fields is case-sensitive. For the uppercase 'Email' key, I will see the error.
Below is the sign-up configurations

emailSignUpConfig = {
        header: 'Sign up header',
        hideAllDefaults: true,
        defaultCountryCode: '1',
        signUpFields: [
            {
                label: 'Email',
                key: 'email', //the email should be in lower case
                required: true,
                displayOrder: 1,
                type: 'string',
            },
            {
                label: 'Password',
                key: 'password',
                required: true,
                displayOrder: 2,
                type: 'password',
            },
        ],
    };


问:
Rounding items within a list of lists
I'm trying to round specific items within lists to different decimal places. For example, I'm trying to round the first number to 5 decimal places and the second number to 4 decimal places. So far I have this but I can't figure out how to iterate it over each list within the list.

```<code>round_test = []
test = [['start, 0.2222195726, 0.3332746298, 2, 'end'], ['start, 0.4444393872, 0.5554983, 2, 'end'], ['start, 0.6666559246, 0.777692366, 2, 'end']]
for start, starttime, endtime, amt, end in test:
    starttime_5 = round(starttime,5)
    endtime_4 = round(endtime,4)
    round_test = [[start, starttime_5, endtime_4, amt, end]]
print(round_test)
</code>```

My current output is

```<code>[['start', 0.66666, 0.7777, 2, 'end']]
</code>```

What I'm trying to achieve is

```<code>[['start, 0.22222, 0.3333, 2, 'end'], ['start, 0.44444, 0.5555, 2, 'end'], ['start, 0.66666, 0.7777, 2, 'end']]
</code>```

Thank you for the help!

答:
Small errors.

(1) start should be in quotes i.e. 'start' rather than 'start

(2) round_test.append(...) rather than round_test = ...

```<code>round_test = []
test = [['start', 0.2222195726, 0.3332746298, 2, 'end'], ['start', 0.4444393872, 0.5554983, 2, 'end'], ['start', 0.6666559246, 0.777692366, 2, 'end']]
for start, starttime, endtime, amt, end in test:
    starttime_5 = round(starttime,5)
    endtime_4 = round(endtime,4)
    round_test.append([start, starttime_5, endtime_4, amt, end])
print(round_test)
</code>```

Output

```<code>[['start', 0.22222, 0.3333, 2, 'end'],
 ['start', 0.44444, 0.5555, 2, 'end'],
 ['start', 0.66666, 0.7777, 2, 'end']]
</code>```

Title: Rounding items within a list of lists

Body:
I'm trying to round specific items within lists to different decimal places. For example, I'm trying to round the first number to 5 decimal places and the second number to 4 decimal places. So far I have this but I can't figure out how to iterate it over each list within the list.

round_test = []
test = [['start, 0.2222195726, 0.3332746298, 2, 'end'], ['start, 0.4444393872, 0.5554983, 2, 'end'], ['start, 0.6666559246, 0.777692366, 2, 'end']]
for start, starttime, endtime, amt, end in test:
    starttime_5 = round(starttime,5)
    endtime_4 = round(endtime,4)
    round_test = [[start, starttime_5, endtime_4, amt, end]]
print(round_test)

My current output is

[['start', 0.66666, 0.7777, 2, 'end']]

What I'm trying to achieve is

[['start, 0.22222, 0.3333, 2, 'end'], ['start, 0.44444, 0.5555, 2, 'end'], ['start, 0.66666, 0.7777, 2, 'end']]

Thank you for the help!

Body:
Small errors.

(1) start should be in quotes i.e. 'start' rather than 'start

(2) round_test.append(...) rather than round_test = ...

round_test = []
test = [['start', 0.2222195726, 0.3332746298, 2, 'end'], ['start', 0.4444393872, 0.5554983, 2, 'end'], ['start', 0.6666559246, 0.777692366, 2, 'end']]
for start, starttime, endtime, amt, end in test:
    starttime_5 = round(starttime,5)
    endtime_4 = round(endtime,4)
    round_test.append([start, starttime_5, endtime_4, amt, end])
print(round_test)

Output

[['start', 0.22222, 0.3333, 2, 'end'],
 ['start', 0.44444, 0.5555, 2, 'end'],
 ['start', 0.66666, 0.7777, 2, 'end']]


问:
How to create a dataframe with 31 days in July
I want to create a df which includes every day in 2019 July that looks like this:

```<code>      datetime
0   2019-07-01 00:00:00
1   2019-07-02 00:00:00
2   2019-07-03 00:00:00
3   2019-07-04 00:00:00
...

</code>```

What is the best way to do it?

答:
IIUC</p>

```<code>m = '2019-07'
period = pd.Period(m, freq='M')
df = pd.DataFrame()
df['Date'] = pd.date_range(start=period.start_time, end=period.end_time, freq='D')
</code>```

Body:
I want to create a df which includes every day in 2019 July that looks like this:

      datetime
0   2019-07-01 00:00:00
1   2019-07-02 00:00:00
2   2019-07-03 00:00:00
3   2019-07-04 00:00:00
...

What is the best way to do it?

Body:
IIUC

m = '2019-07'
period = pd.Period(m, freq='M')
df = pd.DataFrame()
df['Date'] = pd.date_range(start=period.start_time, end=period.end_time, freq='D')


问:
Decorator Not Returning Value in Expected Units
The following code uses pint to convert a mass flow to a volumetric flow. To convert from mass to volume, the density of the gas must be calculated. The calculation returns the correct values in the desired units.

```<code>import pint
ureg = pint.UnitRegistry()
Q_ = ureg.Quantity

def density(T):
    R = 287 * ureg('J/kg/K')
    P = 101325 * ureg('Pa')
    return (P / R / T.to(ureg.kelvin)).to(ureg('kg/m^3'))

@ureg.wraps(ret='m^3/sec', args=['kg/sec', 'kg/m^3'])
def volumetric_flow_rate(mass_flow_rate, rho):
    return mass_flow_rate / rho

mfr = 1 * ureg('kg/s')
temperature = Q_(25, ureg.degC)

rho = density(temperature)
print(rho)
# 1.1841314120000166 kilogram / meter ** 3

v = volumetric_flow_rate(mfr, rho)
print(v)
# 0.8445008635578583 meter ** 3 / second
</code>```

However, when I apply to use the @ureg.wraps decorator on the density function in the same way used for volumetric_flow_rate, the value is correct, but the units are not the desired units.

```<code>@ureg.wraps(ret='kg/m^3', args=['K'])
def density(T):
    R = 287 * ureg('J/kg/K')
    P = 101325 * ureg('Pa')
    return P / R / T

rho = density(temperature)
print(rho)
# 1.1841314120000166 kelvin * kilogram * pascal / joule kilogram / meter ** 3

v = volumetric_flow_rate(mfr, rho)
print(v)
# 0.8445008635578583 joule / kelvin / kilogram / pascal meter ** 3 / second
</code>```

The following versions of the decorator all yield the same results (incorrect return units) for the density function:

```<code>@ureg.wraps(ret='kg/m^3', args='K')
@ureg.wraps(ret='kg/m^3', args=['K'])
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin)
@ureg.wraps(ret='kg/m^3', args='K', strict=True)
@ureg.wraps(ret='kg/m^3', args=['K'], strict=True)
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin, strict=True)
@ureg.wraps(ret='kg/m^3', args='K', strict=False)
@ureg.wraps(ret='kg/m^3', args=['K'], strict=False)
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin, strict=False)
</code>```

The following version of the decorator raises an error

```<code>@ureg.wraps(ret=ureg('kg/m^3'), args=ureg.kelvin)
</code>```

TypeError: wraps 'ret' argument must by of type str or Unit, not <class 'pint.quantity.build_quantity_class.<locals>.Quantity'> (1.0 kilogram / meter ** 3)

With that error message, I defined a custom unit mass_flow

```<code>ureg.define('mass_flow = 1 * kg / m^3')
print(ureg.mass_flow)
# mass_flow
print(type(ureg.mass_flow))
# <class 'pint.unit.build_unit_class.<locals>.Unit'>
print(1 * ureg.mass_flow)
# 1 mass_flow
</code>```

The following decorators don't raise an error, however they still yiled the incorrect units (though now with the mass_flow "units".

```<code>@ureg.wraps(ret=ureg.mass_flow, args='K')
@ureg.wraps(ret='mass_flow', args='K')
# 1.1841314120000166 kelvin * kilogram * pascal / joule mass_flow
</code>```

One last ditch attempt I tried was to define R and P outside of the function. Didn't expect it to change the answer, and expectations were correct.

```<code>R = 287 * ureg('J/kg/K')
P = 101325 * ureg('Pa')
@ureg.wraps(ret='kg/m^3', args='K')
def density(T):
    return P / R / T
</code>```

Question:

How can I define the decorator for the density function in a similar manner to the volumetric_flow_rate function so that the body of the function is cleaner and does not require me to do the internal unit conversions?

Furthermore, if the volumetric_flow_rate function has a complex return unit m^3/sec why would kg/m^3 not work for the density function?

Python 3.7.0, Pint 0.10.1

答:
Pint appears to strip away all units before entering the function and then applies units when the function is over. As such, either of the following works.

```<code>@ureg.wraps(ret='kg/m^3', args=['K', 'Pa', 'J/kg/K'])
def density(T, P=101325 * ureg.Pa, R=287 * ureg('J/kg/K')):
    return P / R / T

@ureg.wraps(ret='kg/m^3', args=['K', 'Pa', 'J/kg/K'], strict=False)
def density(T, P=101325, R=287):
    return P / R / T
</code>```

The key is to ensure everything in the function is dimensionless. If you call another function within a @ureg.wraps decorated function, and that function returns a dimensional quantity, convert it to the required units and then strip the units by using the .magnitude attribute.

Body:
The following code uses pint to convert a mass flow to a volumetric flow. To convert from mass to volume, the density of the gas must be calculated. The calculation returns the correct values in the desired units.

import pint
ureg = pint.UnitRegistry()
Q_ = ureg.Quantity

def density(T):
    R = 287 * ureg('J/kg/K')
    P = 101325 * ureg('Pa')
    return (P / R / T.to(ureg.kelvin)).to(ureg('kg/m^3'))

@ureg.wraps(ret='m^3/sec', args=['kg/sec', 'kg/m^3'])
def volumetric_flow_rate(mass_flow_rate, rho):
    return mass_flow_rate / rho

mfr = 1 * ureg('kg/s')
temperature = Q_(25, ureg.degC)

rho = density(temperature)
print(rho)
# 1.1841314120000166 kilogram / meter ** 3

v = volumetric_flow_rate(mfr, rho)
print(v)
# 0.8445008635578583 meter ** 3 / second

However, when I apply to use the @ureg.wraps decorator on the density function in the same way used for volumetric_flow_rate, the value is correct, but the units are not the desired units.

@ureg.wraps(ret='kg/m^3', args=['K'])
def density(T):
    R = 287 * ureg('J/kg/K')
    P = 101325 * ureg('Pa')
    return P / R / T

rho = density(temperature)
print(rho)
# 1.1841314120000166 kelvin * kilogram * pascal / joule kilogram / meter ** 3

v = volumetric_flow_rate(mfr, rho)
print(v)
# 0.8445008635578583 joule / kelvin / kilogram / pascal meter ** 3 / second

The following versions of the decorator all yield the same results (incorrect return units) for the density function:

@ureg.wraps(ret='kg/m^3', args='K')
@ureg.wraps(ret='kg/m^3', args=['K'])
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin)
@ureg.wraps(ret='kg/m^3', args='K', strict=True)
@ureg.wraps(ret='kg/m^3', args=['K'], strict=True)
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin, strict=True)
@ureg.wraps(ret='kg/m^3', args='K', strict=False)
@ureg.wraps(ret='kg/m^3', args=['K'], strict=False)
@ureg.wraps(ret='kg/m^3', args=ureg.kelvin, strict=False)

The following version of the decorator raises an error

@ureg.wraps(ret=ureg('kg/m^3'), args=ureg.kelvin)

TypeError: wraps 'ret' argument must by of type str or Unit, not <class 'pint.quantity.build_quantity_class.<locals>.Quantity'> (1.0 kilogram / meter ** 3)

With that error message, I defined a custom unit mass_flow

ureg.define('mass_flow = 1 * kg / m^3')
print(ureg.mass_flow)
# mass_flow
print(type(ureg.mass_flow))
# <class 'pint.unit.build_unit_class.<locals>.Unit'>
print(1 * ureg.mass_flow)
# 1 mass_flow

The following decorators don't raise an error, however they still yiled the incorrect units (though now with the mass_flow "units".

@ureg.wraps(ret=ureg.mass_flow, args='K')
@ureg.wraps(ret='mass_flow', args='K')
# 1.1841314120000166 kelvin * kilogram * pascal / joule mass_flow

One last ditch attempt I tried was to define R and P outside of the function. Didn't expect it to change the answer, and expectations were correct.

R = 287 * ureg('J/kg/K')
P = 101325 * ureg('Pa')
@ureg.wraps(ret='kg/m^3', args='K')
def density(T):
    return P / R / T

Question:

How can I define the decorator for the density function in a similar manner to the volumetric_flow_rate function so that the body of the function is cleaner and does not require me to do the internal unit conversions?

Furthermore, if the volumetric_flow_rate function has a complex return unit m^3/sec why would kg/m^3 not work for the density function?

Python 3.7.0, Pint 0.10.1

Body:
Pint appears to strip away all units before entering the function and then applies units when the function is over. As such, either of the following works.

@ureg.wraps(ret='kg/m^3', args=['K', 'Pa', 'J/kg/K'])
def density(T, P=101325 * ureg.Pa, R=287 * ureg('J/kg/K')):
    return P / R / T

@ureg.wraps(ret='kg/m^3', args=['K', 'Pa', 'J/kg/K'], strict=False)
def density(T, P=101325, R=287):
    return P / R / T

The key is to ensure everything in the function is dimensionless. If you call another function within a @ureg.wraps decorated function, and that function returns a dimensional quantity, convert it to the required units and then strip the units by using the .magnitude attribute.


问:
AudioPlayers on Flutter: I can't play mp3 one behind the other
I've been stuck for several days looking for a solution and I can't find it. I need to play mp3 files one behind the other using AudioPlayers and it is impossible for me. I'm using the only tool (as far as I know) that gives you the lib to do this kind of thing, but I can't find how to do it. Thanks for the help.</p>

```<code>playLocal(List list) async {

list.forEach((f) async {
  final file = new File('${(await getTemporaryDirectory()).path}/voice.mp3');
  await file.writeAsBytes((await loadAsset(f)).buffer.asUint8List());
  bool finish = false;

  if (player.state == null || player.state == AudioPlayerState.COMPLETED) {
    await player.play(file.path, isLocal:true);
  }

  if (player.state != null && player.state != AudioPlayerState.COMPLETED) {
    while(!finish){
      player.onPlayerCompletion.listen((event){
        finish = true;
      });
      if (finish) {await player.play(file.path, isLocal:true);}
    }
  }

});

}
</code>```

答:
You can use package https://pub.dev/packages/assets_audio_player

In assetsAudioPlayer.finished.listen call _next()

code snippet

```<code>void _next() {
    if (_assetsAudioPlayer.playlist != null) {
      _assetsAudioPlayer.playlistNext();
    } else {
      _currentAssetPosition++;
      _open(_currentAssetPosition);
    }
  }
@override
      void initState() {
        super.initState();
        _assetsAudioPlayer.finished.listen((finished) {
          print("paly next");
          _next();
        });
      }
</code>```

working demo after song1.mp3 finish auto play song2.mp3

full code

```<code>import 'package:assets_audio_player/assets_audio_player.dart';
import 'package:assets_audio_player_example/asset_audio_player_icons.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final assets = <String>[
    "assets/audios/song1.mp3",
    "assets/audios/song2.mp3",
    "assets/audios/song3.mp3",
  ];
  final AssetsAudioPlayer _assetsAudioPlayer = AssetsAudioPlayer();

  var _currentAssetPosition = -1;

  void _open(int assetIndex) {
    _currentAssetPosition = assetIndex % assets.length;
    _assetsAudioPlayer.open(assets[_currentAssetPosition]);
  }

  void _playPause() {
    _assetsAudioPlayer.playOrPause();
  }

  void _next() {
    if (_assetsAudioPlayer.playlist != null) {
      _assetsAudioPlayer.playlistNext();
    } else {
      _currentAssetPosition++;
      _open(_currentAssetPosition);
    }
  }

  void _prev() {
    if (_assetsAudioPlayer.playlist != null) {
      _assetsAudioPlayer.playlistPrevious();
    } else {
      _currentAssetPosition--;
      _open(_currentAssetPosition);
    }
  }

  @override
  void initState() {
    super.initState();
    _assetsAudioPlayer.finished.listen((finished) {
      print("paly next");
      _next();
    });
  }

  @override
  void dispose() {
    _assetsAudioPlayer.stop();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Padding(
          padding: const EdgeInsets.only(bottom: 48.0),
          child: Column(
            mainAxisSize: MainAxisSize.max,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              RaisedButton(
                onPressed: () {
                  _assetsAudioPlayer
                      .openPlaylist(Playlist(assetAudioPaths: this.assets));
                },
                child: Text("Playlist test"),
              ),
              Expanded(
                child: StreamBuilder(
                  stream: _assetsAudioPlayer.current,
                  initialData: const PlayingAudio(),
                  builder: (BuildContext context,
                      AsyncSnapshot<PlayingAudio> snapshot) {
                    final PlayingAudio currentAudio = snapshot.data;
                    return ListView.builder(
                      itemBuilder: (context, position) {
                        return ListTile(
                            title: Text(assets[position].split("/").last,
                                style: TextStyle(
                                    color: assets[position] ==
                                            currentAudio.assetAudioPath
                                        ? Colors.blue
                                        : Colors.black)),
                            onTap: () {
                              _open(position);
                            });
                      },
                      itemCount: assets.length,
                    );
                  },
                ),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.max,
                children: <Widget>[
                  StreamBuilder(
                    stream: _assetsAudioPlayer.isLooping,
                    initialData: false,
                    builder:
                        (BuildContext context, AsyncSnapshot<bool> snapshot) {
                      return RaisedButton(
                        child: Text(snapshot.data ? "Looping" : "Not looping"),
                        onPressed: () {
                          _assetsAudioPlayer.toggleLoop();
                        },
                      );
                    },
                  ),
                  SizedBox(width: 20),
                  RaisedButton(
                    child: Text("Seek to 2:00"),
                    onPressed: () {
                      _assetsAudioPlayer.seek(Duration(minutes: 2));
                    },
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  StreamBuilder(
                    stream: _assetsAudioPlayer.currentPosition,
                    initialData: const Duration(),
                    builder: (BuildContext context,
                        AsyncSnapshot<Duration> snapshot) {
                      Duration duration = snapshot.data;
                      return Text(durationToString(duration));
                    },
                  ),
                  Text(" - "),
                  StreamBuilder(
                    stream: _assetsAudioPlayer.current,
                    builder: (BuildContext context,
                        AsyncSnapshot<PlayingAudio> snapshot) {
                      Duration duration = Duration();
                      if (snapshot.hasData) {
                        duration = snapshot.data.duration;
                      }
                      return Text(durationToString(duration));
                    },
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.max,
                children: [
                  IconButton(
                    onPressed: _prev,
                    icon: Icon(AssetAudioPlayerIcons.to_start),
                  ),
                  StreamBuilder(
                    stream: _assetsAudioPlayer.isPlaying,
                    initialData: false,
                    builder:
                        (BuildContext context, AsyncSnapshot<bool> snapshot) {
                      return IconButton(
                        onPressed: _playPause,
                        icon: Icon(snapshot.data
                            ? AssetAudioPlayerIcons.pause
                            : AssetAudioPlayerIcons.play),
                      );
                    },
                  ),
                  IconButton(
                    icon: Icon(AssetAudioPlayerIcons.to_end),
                    onPressed: _next,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

String durationToString(Duration duration) {
  String twoDigits(int n) {
    if (n >= 10) return "$n";
    return "0$n";
  }

  String twoDigitMinutes =
      twoDigits(duration.inMinutes.remainder(Duration.minutesPerHour));
  String twoDigitSeconds =
      twoDigits(duration.inSeconds.remainder(Duration.secondsPerMinute));
  return "$twoDigitMinutes:$twoDigitSeconds";
}
</code>```

Body:
I've been stuck for several days looking for a solution and I can't find it. I need to play mp3 files one behind the other using AudioPlayers and it is impossible for me. I'm using the only tool (as far as I know) that gives you the lib to do this kind of thing, but I can't find how to do it. Thanks for the help.

playLocal(List list) async {

list.forEach((f) async {
  final file = new File('${(await getTemporaryDirectory()).path}/voice.mp3');
  await file.writeAsBytes((await loadAsset(f)).buffer.asUint8List());
  bool finish = false;

  if (player.state == null || player.state == AudioPlayerState.COMPLETED) {
    await player.play(file.path, isLocal:true);
  }

  if (player.state != null && player.state != AudioPlayerState.COMPLETED) {
    while(!finish){
      player.onPlayerCompletion.listen((event){
        finish = true;
      });
      if (finish) {await player.play(file.path, isLocal:true);}
    }
  }

});

}

Body:
You can use package https://pub.dev/packages/assets_audio_player

In assetsAudioPlayer.finished.listen call _next()

code snippet

void _next() {
    if (_assetsAudioPlayer.playlist != null) {
      _assetsAudioPlayer.playlistNext();
    } else {
      _currentAssetPosition++;
      _open(_currentAssetPosition);
    }
  }
@override
      void initState() {
        super.initState();
        _assetsAudioPlayer.finished.listen((finished) {
          print("paly next");
          _next();
        });
      }

working demo after song1.mp3 finish auto play song2.mp3

full code

import 'package:assets_audio_player/assets_audio_player.dart';
import 'package:assets_audio_player_example/asset_audio_player_icons.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final assets = <String>[
    "assets/audios/song1.mp3",
    "assets/audios/song2.mp3",
    "assets/audios/song3.mp3",
  ];
  final AssetsAudioPlayer _assetsAudioPlayer = AssetsAudioPlayer();

  var _currentAssetPosition = -1;

  void _open(int assetIndex) {
    _currentAssetPosition = assetIndex % assets.length;
    _assetsAudioPlayer.open(assets[_currentAssetPosition]);
  }

  void _playPause() {
    _assetsAudioPlayer.playOrPause();
  }

  void _next() {
    if (_assetsAudioPlayer.playlist != null) {
      _assetsAudioPlayer.playlistNext();
    } else {
      _currentAssetPosition++;
      _open(_currentAssetPosition);
    }
  }

  void _prev() {
    if (_assetsAudioPlayer.playlist != null) {
      _assetsAudioPlayer.playlistPrevious();
    } else {
      _currentAssetPosition--;
      _open(_currentAssetPosition);
    }
  }

  @override
  void initState() {
    super.initState();
    _assetsAudioPlayer.finished.listen((finished) {
      print("paly next");
      _next();
    });
  }

  @override
  void dispose() {
    _assetsAudioPlayer.stop();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Padding(
          padding: const EdgeInsets.only(bottom: 48.0),
          child: Column(
            mainAxisSize: MainAxisSize.max,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              RaisedButton(
                onPressed: () {
                  _assetsAudioPlayer
                      .openPlaylist(Playlist(assetAudioPaths: this.assets));
                },
                child: Text("Playlist test"),
              ),
              Expanded(
                child: StreamBuilder(
                  stream: _assetsAudioPlayer.current,
                  initialData: const PlayingAudio(),
                  builder: (BuildContext context,
                      AsyncSnapshot<PlayingAudio> snapshot) {
                    final PlayingAudio currentAudio = snapshot.data;
                    return ListView.builder(
                      itemBuilder: (context, position) {
                        return ListTile(
                            title: Text(assets[position].split("/").last,
                                style: TextStyle(
                                    color: assets[position] ==
                                            currentAudio.assetAudioPath
                                        ? Colors.blue
                                        : Colors.black)),
                            onTap: () {
                              _open(position);
                            });
                      },
                      itemCount: assets.length,
                    );
                  },
                ),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.max,
                children: <Widget>[
                  StreamBuilder(
                    stream: _assetsAudioPlayer.isLooping,
                    initialData: false,
                    builder:
                        (BuildContext context, AsyncSnapshot<bool> snapshot) {
                      return RaisedButton(
                        child: Text(snapshot.data ? "Looping" : "Not looping"),
                        onPressed: () {
                          _assetsAudioPlayer.toggleLoop();
                        },
                      );
                    },
                  ),
                  SizedBox(width: 20),
                  RaisedButton(
                    child: Text("Seek to 2:00"),
                    onPressed: () {
                      _assetsAudioPlayer.seek(Duration(minutes: 2));
                    },
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  StreamBuilder(
                    stream: _assetsAudioPlayer.currentPosition,
                    initialData: const Duration(),
                    builder: (BuildContext context,
                        AsyncSnapshot<Duration> snapshot) {
                      Duration duration = snapshot.data;
                      return Text(durationToString(duration));
                    },
                  ),
                  Text(" - "),
                  StreamBuilder(
                    stream: _assetsAudioPlayer.current,
                    builder: (BuildContext context,
                        AsyncSnapshot<PlayingAudio> snapshot) {
                      Duration duration = Duration();
                      if (snapshot.hasData) {
                        duration = snapshot.data.duration;
                      }
                      return Text(durationToString(duration));
                    },
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.max,
                children: [
                  IconButton(
                    onPressed: _prev,
                    icon: Icon(AssetAudioPlayerIcons.to_start),
                  ),
                  StreamBuilder(
                    stream: _assetsAudioPlayer.isPlaying,
                    initialData: false,
                    builder:
                        (BuildContext context, AsyncSnapshot<bool> snapshot) {
                      return IconButton(
                        onPressed: _playPause,
                        icon: Icon(snapshot.data
                            ? AssetAudioPlayerIcons.pause
                            : AssetAudioPlayerIcons.play),
                      );
                    },
                  ),
                  IconButton(
                    icon: Icon(AssetAudioPlayerIcons.to_end),
                    onPressed: _next,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

String durationToString(Duration duration) {
  String twoDigits(int n) {
    if (n >= 10) return "$n";
    return "0$n";
  }

  String twoDigitMinutes =
      twoDigits(duration.inMinutes.remainder(Duration.minutesPerHour));
  String twoDigitSeconds =
      twoDigits(duration.inSeconds.remainder(Duration.secondsPerMinute));
  return "$twoDigitMinutes:$twoDigitSeconds";
}


问:
How to compute nested group proportions using python pandas without losing original row count
Given the following data:

df = pd.DataFrame({
    'where': ['a','a','a','a','a','a'] +  ['b','b','b','b','b','b'],
    'what': ['x','y','z','x','y','z'] +  ['x','y','z','x','y','z'],
    'val' : [1,3,2,5,4,3] + [5,6,3,4,5,3]
})
```

<p>Which looks as:</p>

```   where what  val
0      a    x    1
1      a    y    3
2      a    z    2
3      a    x    5
4      a    y    4
5      a    z    3
6      b    x    5
7      b    y    6
8      b    z    3
9      b    x    4
10     b    y    5
11     b    z    3
```

<p>I would like to compute the proportion of <code>what</code> in <code>where</code>, and create a new
column that represented this.</p>

<p>The column will have duplicates, If I consider <code>what = x</code> in the above, and
add that column in then the data would be as follows</p>

```   where what  val   what_where_prop
0      a    x    1         6/18
1      a    y    3
2      a    z    2
3      a    x    5         6/18
4      a    y    4
5      a    z    3
6      b    x    5         9/26
7      b    y    6
8      b    z    3
9      b    x    4         9/26
10     b    y    5
11     b    z    3
```

Here 6/18 is computed by finding the total x (6 = 1 + 5) in a over the total of val in a. The same process is taken for 9/26

The full solution will be filled similarly for y and z in the final column.

答:
IIUC,

```<code>df['what_where_group'] = (df.groupby(['where', 'what'], as_index=False)['val']
                            .transform('sum')
                            .div(df.groupby('where')['val']
                                   .transform('sum'),
                                 axis=0))

df
</code>```

Output:

```<code>   where what  val  what_where_prop  what_where_group
0      a    x    1                6          0.333333
1      a    y    3                7          0.388889
2      a    z    2                5          0.277778
3      a    x    5                6          0.333333
4      a    y    4                7          0.388889
5      a    z    3                5          0.277778
6      b    x    5                9          0.346154
7      b    y    6               11          0.423077
8      b    z    3                6          0.230769
9      b    x    4                9          0.346154
10     b    y    5               11          0.423077
11     b    z    3                6          0.230769
</code>```

Details:

First groupby two levels using what and where, by using index=False, I am not setting the index as the groups, and transform sum.  Next, groupby only where and transform sum.  Lastly, divide, using div, the first groupby by the second groupby using the direction as rows with axis=0.

Another way:

```<code>g = df.set_index(['where', 'what'])['val']
num = g.sum(level=[0,1])
denom = g.sum(level=0)
ww_group = num.div(denom, level=0).rename('what_where_group')
df.merge(ww_group, left_on=['where','what'], right_index=True)
</code>```

Output:

```<code>   where what  val  what_where_prop  what_where_group
0      a    x    1                6          0.333333
3      a    x    5                6          0.333333
1      a    y    3                7          0.388889
4      a    y    4                7          0.388889
2      a    z    2                5          0.277778
5      a    z    3                5          0.277778
6      b    x    5                9          0.346154
9      b    x    4                9          0.346154
7      b    y    6               11          0.423077
10     b    y    5               11          0.423077
8      b    z    3                6          0.230769
11     b    z    3                6          0.230769
</code>```

Details:

Basically the same as before just using steps. And, merge results to apply division to each line.

Body:
Given the following data:

df = pd.DataFrame({
    'where': ['a','a','a','a','a','a'] +  ['b','b','b','b','b','b'],
    'what': ['x','y','z','x','y','z'] +  ['x','y','z','x','y','z'],
    'val' : [1,3,2,5,4,3] + [5,6,3,4,5,3]
})

Which looks as:

   where what  val
0      a    x    1
1      a    y    3
2      a    z    2
3      a    x    5
4      a    y    4
5      a    z    3
6      b    x    5
7      b    y    6
8      b    z    3
9      b    x    4
10     b    y    5
11     b    z    3

I would like to compute the proportion of what in where, and create a new
column that represented this.

The column will have duplicates, If I consider what = x in the above, and
add that column in then the data would be as follows

   where what  val   what_where_prop
0      a    x    1         6/18
1      a    y    3
2      a    z    2
3      a    x    5         6/18
4      a    y    4
5      a    z    3
6      b    x    5         9/26
7      b    y    6
8      b    z    3
9      b    x    4         9/26
10     b    y    5
11     b    z    3

Here 6/18 is computed by finding the total x (6 = 1 + 5) in a over the total of val in a. The same process is taken for 9/26

The full solution will be filled similarly for y and z in the final column.

Body:
IIUC,

df['what_where_group'] = (df.groupby(['where', 'what'], as_index=False)['val']
                            .transform('sum')
                            .div(df.groupby('where')['val']
                                   .transform('sum'),
                                 axis=0))

df

Output:

   where what  val  what_where_prop  what_where_group
0      a    x    1                6          0.333333
1      a    y    3                7          0.388889
2      a    z    2                5          0.277778
3      a    x    5                6          0.333333
4      a    y    4                7          0.388889
5      a    z    3                5          0.277778
6      b    x    5                9          0.346154
7      b    y    6               11          0.423077
8      b    z    3                6          0.230769
9      b    x    4                9          0.346154
10     b    y    5               11          0.423077
11     b    z    3                6          0.230769

Details:

First groupby two levels using what and where, by using index=False, I am not setting the index as the groups, and transform sum.  Next, groupby only where and transform sum.  Lastly, divide, using div, the first groupby by the second groupby using the direction as rows with axis=0.

Another way:

g = df.set_index(['where', 'what'])['val']
num = g.sum(level=[0,1])
denom = g.sum(level=0)
ww_group = num.div(denom, level=0).rename('what_where_group')
df.merge(ww_group, left_on=['where','what'], right_index=True)

Output:

   where what  val  what_where_prop  what_where_group
0      a    x    1                6          0.333333
3      a    x    5                6          0.333333
1      a    y    3                7          0.388889
4      a    y    4                7          0.388889
2      a    z    2                5          0.277778
5      a    z    3                5          0.277778
6      b    x    5                9          0.346154
9      b    x    4                9          0.346154
7      b    y    6               11          0.423077
10     b    y    5               11          0.423077
8      b    z    3                6          0.230769
11     b    z    3                6          0.230769

Details:

Basically the same as before just using steps. And, merge results to apply division to each line.


问:
Confusion about position: fixed
As mentioned in the picture, I want the 'menu' to be fixed on the left side (A fixed Sidebar). To achieve this I tried position: fixed; top: value; simply . And the catch is the menu gets fixed but it overlaps the footer and z-index property also doesn't seem to work here. Any explanations for this behaivour of the code? And also I'm using bootstrap v4 grid system.

答:
It can be perfectly done using CSS grid. Clean, modern, semantic and fast.

*,
*::before,
*::after {
  box-sizing: border-box;
  border: solid 1px lightgray;
}

html,
body {
  height: 100%;
  font: 400 16px/1.6 consolas;
}

#wrapper {
  height: 100%;
  display: grid;
  grid-template-rows: 50px 1fr 50px;
  grid-template-areas: "navbar navbar navbar" "menu main cart" "footer footer footer";
}

#navbar {
  grid-area: navbar;
}

#sidenav-menu {
  grid-area: menu;
  width: 100px;
}

main {
  grid-area: main;
  overflow-y: scroll;
}

#sidenav-cart {
  grid-area: cart;
  width: 100px;
}

footer#footer {
  grid-area: footer;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div id="wrapper">
  <nav id="navbar">navbar</nav>
  <nav id="sidenav-menu">menu</nav>
  <main role="main">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </main>
  <div id="sidenav-cart">cart</div>
  <footer id="footer">footer</footer>
</div></code>```

Title: Confusion about position: fixed

Body:
It can be perfectly done using CSS grid. Clean, modern, semantic and fast.

*,
*::before,
*::after {
  box-sizing: border-box;
  border: solid 1px lightgray;
}

html,
body {
  height: 100%;
  font: 400 16px/1.6 consolas;
}

#wrapper {
  height: 100%;
  display: grid;
  grid-template-rows: 50px 1fr 50px;
  grid-template-areas: "navbar navbar navbar" "menu main cart" "footer footer footer";
}

#navbar {
  grid-area: navbar;
}

#sidenav-menu {
  grid-area: menu;
  width: 100px;
}

main {
  grid-area: main;
  overflow-y: scroll;
}

#sidenav-cart {
  grid-area: cart;
  width: 100px;
}

footer#footer {
  grid-area: footer;
}

<div id="wrapper">
  <nav id="navbar">navbar</nav>
  <nav id="sidenav-menu">menu</nav>
  <main role="main">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
  </main>
  <div id="sidenav-cart">cart</div>
  <footer id="footer">footer</footer>
</div>


问:
try-catch blocks with the return type
If I have a method that returns something, like

```<code>public DataTable ReturnSomething()
{
   try
   {
      //logic here
     return ds.Tables[0];
   }
   catch (Exception e)
   {
      ErrorString=e.Message;
   }
}
</code>```

This produces compiler error, obviously because catch{} block does not return anything.

So when I have methods with return values I don't use try-catch block, which is a bad practice. If there is an error, I would like to set error string to that error. But then I need a return value as well. Advice?

答:
How about this : </p>

```<code>public DataTable ReturnSomething(out string errorString)
{
   errorString = string.Empty;
   DataTable dt = new DataTable();
   try
   {
      //logic here
     dt = ds.Tables[0];
   }
   catch (Exception e)
   {
      errorString = e.Message;
   }
   return dt;
}
</code>```

OwnerDisplayName: Julia

LastEditorDisplayName: Daniel L

ContentLicense: CC BY-SA 2.5

Title: try-catch blocks with the return type

Body:
If I have a method that returns something, like

public DataTable ReturnSomething()
{
   try
   {
      //logic here
     return ds.Tables[0];
   }
   catch (Exception e)
   {
      ErrorString=e.Message;
   }
}

This produces compiler error, obviously because catch{} block does not return anything.

So when I have methods with return values I don't use try-catch block, which is a bad practice. If there is an error, I would like to set error string to that error. But then I need a return value as well. Advice?

Body:
How about this :

public DataTable ReturnSomething(out string errorString)
{
   errorString = string.Empty;
   DataTable dt = new DataTable();
   try
   {
      //logic here
     dt = ds.Tables[0];
   }
   catch (Exception e)
   {
      errorString = e.Message;
   }
   return dt;
}

OwnerDisplayName: ScarletGarden


问:
Copying data from redshift directly to EMR cluster -- Is it a good practice?
Amazon gives a very detailed documentation for copying data from EMR to Redshift (through S3), but there doesn't seem like any docs on the other way around, which makes me wonder if it's a good practice at all to load data from redshift to EMR (directly, or through some medium)

Theoretically I don't see why not, but I don't know the consequence of it

答:
I think you can use Redshift Unload.
Export data as Parquet, then read data from EMR Hadoop(Spark, Hive)

```<code>UNLOAD ('select-statement')
TO 's3://object-path/name-prefix'
authorization
FORMAT PARQUET
</code>```

https://docs.aws.amazon.com/redshift/latest/dg/r_UNLOAD.html

Body:
I think you can use Redshift Unload.
Export data as Parquet, then read data from EMR Hadoop(Spark, Hive)

UNLOAD ('select-statement')
TO 's3://object-path/name-prefix'
authorization
FORMAT PARQUET

https://docs.aws.amazon.com/redshift/latest/dg/r_UNLOAD.html


问:
iterate through dataframe columns and determine which are numeric
I have a read data from from a csv file. I'd like to write code that does the following—

(1) starts iterating through each column (I imagine a for loop)

(2) determines if a column contains only numbers

(3) if the column is numeric, print certain statistical information about that specific column & whether that column is normally distributed (skewness & kurtosis between -1 and 1)

(4) if the column is not numeric, skip over it

This is for an Intro Python course, so it is not expected to be complex

So far this is my code:

```<code>import pandas as pd

df = pd.read_csv('file path')

columns = list(df)

for i in columns:
(if column is numeric, print: Column Title, min, max, mean, median, "Yes column normal" or "No column not normal")
(else, just skip it)
</code>```

答:
```<code>for column in df:
    if np.issubdtype(df[column], np.number):
        print(df[column]) # print(df[column].describe()) or whatever other stats
</code>```

Body:
I have a read data from from a csv file. I'd like to write code that does the following—

(1) starts iterating through each column (I imagine a for loop)

(2) determines if a column contains only numbers

(3) if the column is numeric, print certain statistical information about that specific column & whether that column is normally distributed (skewness & kurtosis between -1 and 1)

(4) if the column is not numeric, skip over it

This is for an Intro Python course, so it is not expected to be complex

So far this is my code:

import pandas as pd

df = pd.read_csv('file path')

columns = list(df)

for i in columns:
(if column is numeric, print: Column Title, min, max, mean, median, "Yes column normal" or "No column not normal")
(else, just skip it)


问:
React: how to maintain performance when updating a large parent record from a controlled child input field?
Imagine a React page that allows users to edit a bill (invoice). The bill has a fair number of editable fields, say 100. Additionally, a bill can have any number of line items. Let's imagine 100 of them, each with, say, 20 fields.

If the bill is the "parent," and is rendered by a React component, the line items are "children," each rendered by a "child" component.

I'm maintaining the state of the bill (and its line items) in the parent component, which feels right.

I want to use controlled input fields in the child (line item) component. However, this means, at least naively, that every keypress results in a state update in the parent (bill) component, and some re-renders, even if I use React.memo judiciously.

Performance has quickly gotten unacceptably slow, even with as few as 10 line items, like a 500-800ms lag on each keypress. I've done a fair bit of performance sleuthing, and have a couple of potential answers, but I'm not going to report them here, in order not to thwart any routes to the best answer.

There must be a common solution to this, no? I'd like to do it without one of the form libraries, though I'm not totally opposed to that.

The stripped-down example below, just to demonstrate the basic architecture. The example doesn't have a performance issue. :-)

Help! What's the magic that I'm missing to keep this performant?

```<code>
const INITIAL_STATE = {
  invoiceNumber: "ABC123",
  customer: "Phil's Dills",
  lineItems: [
    { index: 0, item: "Pickles", quantity: 2 },
    { index: 1, item: "Pickle Juice", quantity: 5 },
  ]
}

export function Bill() {
  const [ bill, setBill ] = useState(INITIAL_STATE);

  function updateBill(updatedLineItem) {
    const newLineItems = [...bill.lineItems];
    newLineItems[updatedLineItem.index] = updatedLineItem;
    setBill({
      ...bill,
      lineItems: newLineItems
    })
  }

  return(
    <div id="parent">
    <h1>Bill {bill.invoiceNumber} for {bill.customer}</h1>
    {bill.lineItems.map((lineItem) => (
      <LineItem key={lineItem.index} line={lineItem} updateBill={updateBill} />
    ))}
    </div>
    );
}

function LineItem({ line, updateBill }) {
  function updateField(e) {
    updateBill({
      ...line,
      [e.target.id]: e.target.value
    });
  }

  return(
    <div id="child">
      <input id="quantity" value={line.quantity} onChange={updateField} />
      <input id="item" value={line.item} onChange={updateField} />
    </div>
    );
}```
```

答:
I think your issue actually is that you're recreating updateBill every time this component re-renders, meaning every single child component will also re-render because they all receive updateBill as a prop. Consider using useCallback to memoize the updateBill function:

```<code>const updateBill = useCallback(updatedLineItem => {
  setBill(bill => {
    const newLineItems = [...bill.lineItems];
    newLineItems[updatedLineItem.index] = updatedLineItem;
    return {
      ...bill,
      lineItems: newLineItems
    }
  })
}, []);
</code>```

Body:
Imagine a React page that allows users to edit a bill (invoice). The bill has a fair number of editable fields, say 100. Additionally, a bill can have any number of line items. Let's imagine 100 of them, each with, say, 20 fields.

If the bill is the "parent," and is rendered by a React component, the line items are "children," each rendered by a "child" component.

I'm maintaining the state of the bill (and its line items) in the parent component, which feels right.

I want to use controlled input fields in the child (line item) component. However, this means, at least naively, that every keypress results in a state update in the parent (bill) component, and some re-renders, even if I use React.memo judiciously.

Performance has quickly gotten unacceptably slow, even with as few as 10 line items, like a 500-800ms lag on each keypress. I've done a fair bit of performance sleuthing, and have a couple of potential answers, but I'm not going to report them here, in order not to thwart any routes to the best answer.

There must be a common solution to this, no? I'd like to do it without one of the form libraries, though I'm not totally opposed to that.

The stripped-down example below, just to demonstrate the basic architecture. The example doesn't have a performance issue. :-)

Help! What's the magic that I'm missing to keep this performant?

const INITIAL_STATE = {
  invoiceNumber: "ABC123",
  customer: "Phil's Dills",
  lineItems: [
    { index: 0, item: "Pickles", quantity: 2 },
    { index: 1, item: "Pickle Juice", quantity: 5 },
  ]
}

export function Bill() {
  const [ bill, setBill ] = useState(INITIAL_STATE);

  function updateBill(updatedLineItem) {
    const newLineItems = [...bill.lineItems];
    newLineItems[updatedLineItem.index] = updatedLineItem;
    setBill({
      ...bill,
      lineItems: newLineItems
    })
  }

  return(

Bill {bill.invoiceNumber} for {bill.customer}

    {bill.lineItems.map((lineItem) => (
      <LineItem key={lineItem.index} line={lineItem} updateBill={updateBill} />
    ))}

    );
}

function LineItem({ line, updateBill }) {
  function updateField(e) {
    updateBill({
      ...line,
      [e.target.id]: e.target.value
    });
  }

  return(

      <input id="quantity" value={line.quantity} onChange={updateField} />
      <input id="item" value={line.item} onChange={updateField} />

    );
}```

Body:
I think your issue actually is that you're recreating updateBill every time this component re-renders, meaning every single child component will also re-render because they all receive updateBill as a prop. Consider using useCallback to memoize the updateBill function:

const updateBill = useCallback(updatedLineItem => {
  setBill(bill => {
    const newLineItems = [...bill.lineItems];
    newLineItems[updatedLineItem.index] = updatedLineItem;
    return {
      ...bill,
      lineItems: newLineItems
    }
  })
}, []);


问:
AddAutoMapper not found in .NET Core with AutoMapper
Using Visual Studio 2019 I installed AutoMapper version 8.1.0 via NuGet.  When I try to add the services.AddAutoMapper() call though in my Startup.cs file I get a compiler error that the method doesn't exist.

I've already tried to do a dotnet clean and dotnet restore from the NuGet console but that didn't help.

答:
It is an old thread, however the solution for this problem is to install Automapper.Extensions.Microsoft.DependencyInjection package along with your automapper package.
I hope it helps.


问:
Translation of this Python Line
I am relatively new to Python and having problem translating the following one line:

```<code>diffList = [key for key in set(dict1n.keys() + dict2.keys()) if dict1.get(key) != dict2t.get(key)]
</code>```

Can someone please rewrite it for me - break it down into multiple lines in a "normal" nice format?

I think - and I am not sure - what the line is trying to do is to compare two dictionaries and output the differences to a list.

Thanks.

UPDATE: I had typos in the line - there should only be dict1 and dict2:

```<code>diffList = [key for key in set(dict1.keys() + dict2.keys()) if dict1.get(key) != dict2.get(key
</code>```

答:
In English it is:

List those keys that:

are present in at least one of the dictionaries

but do not have the same values in both dictionaries

treating the cases: dictX[key] is None and: key not in dictY as having the same value (that's how dict.get()works.)

Title: Translation of this Python Line

Body:
I am relatively new to Python and having problem translating the following one line:

diffList = [key for key in set(dict1n.keys() + dict2.keys()) if dict1.get(key) != dict2t.get(key)]

Can someone please rewrite it for me - break it down into multiple lines in a "normal" nice format?

I think - and I am not sure - what the line is trying to do is to compare two dictionaries and output the differences to a list.

Thanks.

UPDATE: I had typos in the line - there should only be dict1 and dict2:

diffList = [key for key in set(dict1.keys() + dict2.keys()) if dict1.get(key) != dict2.get(key


问:
Kubernetes - How to setup parallels clusters (Prod, Dev) sharing the same repositories/pipeline
I am currently facing a situation where I need to deploy a small cluster (only 4 pods for now) which will be containing 4 different microservices. This cluster has to be duplicated so I can have one PRODUCTION cluster and one DEVELOPMENT cluster.

Even if it's not hard from my point of view (Creating a cluster and then uploading docker images to pods with parameters in order to use the right resources connection strings), I am stuck at the CD/CI part..

From a CloudBuild trigger, how to push the Docker image to the right "cluster's pod", I have absolutely no idea AT ALL how to achieve it...

There is my cloudbuild.yaml

```<code>steps:
  #step 1 - Getting the previous (current) image
  - name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args: [
      '-c',
      'docker pull gcr.io/{PROJECT_ID}/{SERVICE_NAME}:latest || exit 0'
    ]
  #step 2 - Build the image and push it to gcr.io
  - name: 'gcr.io/cloud-builders/docker'
    args: [
      'build',
      '-t',
      'gcr.io/{PROJECT_ID}/{SERVICE_NAME}',
      '-t',
      'gcr.io/{PROJECT_ID}/{SERVICE_NAME}:latest',
      '.'
    ]
  #step 3 - Deploy our container to our cluster
  - name: 'gcr.io/cloud-builders/kubectl'
    args: ['apply', '-f', 'service.yaml', '--force']
    env:
      - 'CLOUDSDK_COMPUTE_ZONE={CLUSTER_ZONE}'
      - 'CLOUDSDK_CONTAINER_CLUSTER={CLUSTER_NAME}'
  #step 4 - Set the image
  - name: 'gcr.io/cloud-builders/kubectl'
    args: [
      'set',
      'image',
      'deployment',
      '{SERVICE_NAME}',
      '{SERVICE_NAME}=gcr.io/{PROJECT_ID}/{SERVICE_NAME}'
    ]
    env:
      - 'CLOUDSDK_COMPUTE_ZONE={CLUSTER_ZONE}'
      - 'CLOUDSDK_CONTAINER_CLUSTER={CLUSTER_NAME}'
# push images to Google Container Registry with tags
images: [
  'gcr.io/{PROJECT_ID}/{SERVICE_NAME}',
  'gcr.io/{PROJECT_ID}/{SERVICE_NAME}:latest'
]
</code>```

Can anyone help me out? I don't really know in which direction to go to..

答:
Did you know helm chart? It is designed for different environment deployment.

With different values.yaml file, you can quickly deploy to different environment with same source code base.

For example, you can name the values.yaml file with environment.

```<code>values-dev.yaml
values-sit.yaml
values-prod.yaml
</code>```

the only differences are some varialbes, such as environment (dev/sit/prod), and namespaces.

so when you run the deployment, it will be:

```<code>env=${ENVIRONMENT}
helm install -f values-${env}.yaml myredis ./redis
</code>```

Body:
I am currently facing a situation where I need to deploy a small cluster (only 4 pods for now) which will be containing 4 different microservices. This cluster has to be duplicated so I can have one PRODUCTION cluster and one DEVELOPMENT cluster.

Even if it's not hard from my point of view (Creating a cluster and then uploading docker images to pods with parameters in order to use the right resources connection strings), I am stuck at the CD/CI part..

From a CloudBuild trigger, how to push the Docker image to the right "cluster's pod", I have absolutely no idea AT ALL how to achieve it...

There is my cloudbuild.yaml

steps:
  #step 1 - Getting the previous (current) image
  - name: 'gcr.io/cloud-builders/docker'
    entrypoint: 'bash'
    args: [
      '-c',
      'docker pull gcr.io/{PROJECT_ID}/{SERVICE_NAME}:latest || exit 0'
    ]
  #step 2 - Build the image and push it to gcr.io
  - name: 'gcr.io/cloud-builders/docker'
    args: [
      'build',
      '-t',
      'gcr.io/{PROJECT_ID}/{SERVICE_NAME}',
      '-t',
      'gcr.io/{PROJECT_ID}/{SERVICE_NAME}:latest',
      '.'
    ]
  #step 3 - Deploy our container to our cluster
  - name: 'gcr.io/cloud-builders/kubectl'
    args: ['apply', '-f', 'service.yaml', '--force']
    env:
      - 'CLOUDSDK_COMPUTE_ZONE={CLUSTER_ZONE}'
      - 'CLOUDSDK_CONTAINER_CLUSTER={CLUSTER_NAME}'
  #step 4 - Set the image
  - name: 'gcr.io/cloud-builders/kubectl'
    args: [
      'set',
      'image',
      'deployment',
      '{SERVICE_NAME}',
      '{SERVICE_NAME}=gcr.io/{PROJECT_ID}/{SERVICE_NAME}'
    ]
    env:
      - 'CLOUDSDK_COMPUTE_ZONE={CLUSTER_ZONE}'
      - 'CLOUDSDK_CONTAINER_CLUSTER={CLUSTER_NAME}'
# push images to Google Container Registry with tags
images: [
  'gcr.io/{PROJECT_ID}/{SERVICE_NAME}',
  'gcr.io/{PROJECT_ID}/{SERVICE_NAME}:latest'
]

Can anyone help me out? I don't really know in which direction to go to..

Body:
Did you know helm chart? It is designed for different environment deployment.

With different values.yaml file, you can quickly deploy to different environment with same source code base.

For example, you can name the values.yaml file with environment.

values-dev.yaml
values-sit.yaml
values-prod.yaml

the only differences are some varialbes, such as environment (dev/sit/prod), and namespaces.

so when you run the deployment, it will be:

env=${ENVIRONMENT}
helm install -f values-${env}.yaml myredis ./redis


问:
no local server type "database engine" were found (V 2016)
I don't know many things about SQL server, today I install the SQL Server Management Studio 2016 and want to create a local Database. after search in the internet find this link from microsoft. in step 4 of this tutorial found this error when want to regester local servers

no local server type "database engine" were found

witch part is wrong?

答:
Open command prompt as admin
-> sqllocaldb info  (which gets your local databases)
-> sqllocaldb versions (which gets your right version to be installed with your local db server)
-> sqllocaldb create "Your db Name" version name given if you find it (This creates a local db engine)
-> In SSMS Server Name : (LocalDb)\Your db Name

This should solve your sql server 2018 or other versions initial setup of local server db engine issue.