问:
How to transform a log4j message to fit an avro schema and post to kafka
I am working on a system that sends all logs for all microservices to a single topic apache kafka. Most services are in python but we are now forwarding logs from a Streams app. All other services use the same Schema defined in avro and managed by confluent's Schema Registry. I can get data posting to kafka fine as a string but cannot figure out how to upload a valid avro object linked to a schema registry schema. I am currently attempting to do this via a custom log4j plugin. For testing purposes I am writing these logs to their own topic and reading them out using kcat -b localhost:9092 -s value=avro -r localhost:8081 -t new_logs -f 'key: %k value: %s Partition: %p\n\n', but I get

ERROR: Failed to format message in new_logs [0] at offset 0: Avro/Schema-registry message deserialization: Invalid CP1 magic byte 115, expected 0: message not produced with Schema-Registry Avro framing: terminating

when doing this (that kcat command does work for my actual service logs topic and all other topics that use valid avro). Originally I tried using the org.apache.avro.generic.GenericData.Record class but could not figure out how to make it work in the methods toSerializable and toByteArray required by the AbstractLayout Interface since that class does not implement the serializable class. Below is the Plugin, class definition, log4j config

ServiceLogLayout.java

```<code>@Plugin(name="ServiceLogLayout", category= Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
public class ServiceLogLayout extends AbstractLayout<byte[]> {
    Schema record;
    DatumWriter<GenericData.Record> serviceLogDatumWriter;

    public ServiceLogLayout() {
        // maybe set these for avro
        super(null, null, null);
        Schema timestampMilliType = LogicalTypes.timestampMillis().addToSchema(Schema.create(Schema.Type.LONG));

        // CREATE SCHEMA
        Schema.Field service = new Schema.Field("service", SchemaBuilder.builder().stringType(), "Name of service sending this message");
        Schema.Field environment = new Schema.Field("environment", SchemaBuilder.builder().enumeration("environment_type").symbols("local", "dev", "staging", "prod", "shared_services", "testing", "security"));
        Schema.Field level = new Schema.Field("level", SchemaBuilder.builder().enumeration("level_type").symbols("debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"), "logging level");
        Schema.Field msg = new Schema.Field("msg", SchemaBuilder.builder().stringType(), "Required log message");

        List<Schema.Field> fields = new ArrayList<>();
        fields.add(service);
        fields.add(environment);
        fields.add(level);
        fields.add(msg);
        this.record = Schema.createRecord("service_logs", "", "com.test.avro", false, fields);
        this.serviceLogDatumWriter = new GenericDatumWriter<>(this.record);
    }

    @Override
    public byte[] toByteArray(LogEvent event) {
        LOGGER.warn("toByteArray");

        String env = System.getenv("ENVIRONMENT") != null ? System.getenv("ENVIRONMENT").toLowerCase() : "local";
        // FILL IN RECORD
        GenericRecordBuilder schemaBuilder = new GenericRecordBuilder(this.record);
        schemaBuilder.set("service", "testService");
        schemaBuilder.set("environment", new GenericData.EnumSymbol(this.record.getField("environment").schema(), env));
        schemaBuilder.set("level", new GenericData.EnumSymbol(this.record.getField("level").schema(), event.getLevel().name().toLowerCase()));
        schemaBuilder.set("msg", event.getMessage().getFormattedMessage());

        // SERIALIZE
        byte[] data = new byte[0];
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        Encoder jsonEncoder = null;
        try {
            jsonEncoder = EncoderFactory.get().jsonEncoder(
                    this.record, stream);
            this.serviceLogDatumWriter.write(schemaBuilder.build(), jsonEncoder);
            jsonEncoder.flush();
            data = stream.toByteArray();
        } catch (IOException e) {
            LOGGER.error("Serialization error:" + e.getMessage());
        }
        return data;
    }

    @Override
    public byte[] toSerializable(LogEvent event) {
        return toByteArray(event);
    }

    @Override
    public String getContentType() {
        return null;
    }

    @PluginFactory
    public static Layout<?> createLayout() {
        return new ServiceLogLayout();
    }

    private static class PrivateObjectOutputStream extends ObjectOutputStream {

        public PrivateObjectOutputStream(final OutputStream os) throws IOException {
            super(os);
        }

        @Override
        protected void writeStreamHeader() {
            // do nothing
        }
    }

}
</code>```

log4j2.xml

```<code><?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="logging.log4j.custom.plugins">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <ServiceLogLayout />

        </Console>
        <Kafka name="Kafka" topic="new_logs">
            <ServiceLogLayout />
            <Property name="bootstrap.servers">${env:BOOTSTRAP_SERVERS}</Property>
        </Kafka>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="Kafka"/>
        </Root>
        <Logger name="org.apache.kafka" level="WARN"/>
    </Loggers>
</Configuration>
</code>```

答:
OneCricketeer had the right idea, here is the implementation:

```<code>public class ServiceLogLayout extends AbstractLayout<byte[]> {
    Schema record;
    SchemaRegistryClient client;
    Schema.Parser parser;

    public ServiceLogLayout() {
        // maybe set these for avro
        super(null, null, null);
        Schema timestampMilliType = LogicalTypes.timestampMillis().addToSchema(Schema.create(Schema.Type.LONG));

        // CREATE SCHEMA
        Schema.Field service = new Schema.Field("service", SchemaBuilder.builder().stringType(), "Name of service sending this message");
        Schema.Field environment = new Schema.Field("environment", SchemaBuilder.builder().enumeration("environment_type").symbols("local", "dev", "staging", "prod", "shared_services", "testing", "security"));
        Schema.Field level = new Schema.Field("level", SchemaBuilder.builder().enumeration("level_type").symbols("debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"), "logging level");
        Schema.Field msg = new Schema.Field("msg", SchemaBuilder.builder().stringType(), "Required log message");
        Schema.Field data = new Schema.Field("data", SchemaBuilder.builder().nullable().stringType(), "Optional extra data, such as stack frames");
        Schema.Field timestamp = new Schema.Field("timestamp", SchemaBuilder.builder().type(timestampMilliType));

        List<Schema.Field> fields = new ArrayList<>();
        fields.add(service);
        fields.add(environment);
        fields.add(level);
        fields.add(msg);
        fields.add(data);
        fields.add(timestamp);
        this.record = Schema.createRecord("service_logs", "", "com.test.avro", false, fields);

        client = new CachedSchemaRegistryClient("http://schema-registry:8081", 10000);
        parser = new Schema.Parser();
    }

    @Override
    public byte[] toByteArray(LogEvent event) {

        String env = System.getenv("ENVIRONMENT") != null ? System.getenv("ENVIRONMENT").toLowerCase() : "local";
        // FILL IN RECORD
        GenericRecordBuilder schemaBuilder = new GenericRecordBuilder(this.record);
        schemaBuilder.set("service", "testService");
        schemaBuilder.set("environment", new GenericData.EnumSymbol(this.record.getField("environment").schema(), env));
        schemaBuilder.set("level", new GenericData.EnumSymbol(this.record.getField("level").schema(), event.getLevel().name()));
        schemaBuilder.set("msg", event.getMessage().getFormattedMessage());
        schemaBuilder.set("data", null);
        schemaBuilder.set("timestamp", event.getTimeMillis());

        // SERIALIZE
        byte[] data;
        KafkaAvroSerializer kafkaAvroSerializer = new KafkaAvroSerializer(client);
        data = kafkaAvroSerializer.serialize("service_logs", schemaBuilder.build());

        return data;
    }

    @Override
    public byte[] toSerializable(LogEvent event) {
        return toByteArray(event);
    }

    @Override
    public String getContentType() {
        return null;
    }

    @PluginFactory
    public static Layout<?> createLayout() {
        return new ServiceLogLayout();
    }

    private static class PrivateObjectOutputStream extends ObjectOutputStream {

        public PrivateObjectOutputStream(final OutputStream os) throws IOException {
            super(os);
        }

        @Override
        protected void writeStreamHeader() {
            // do nothing
        }
    }

}
</code>```

It is worth noting that using logstash might be a good solution to this as well

Body:
I am working on a system that sends all logs for all microservices to a single topic apache kafka. Most services are in python but we are now forwarding logs from a Streams app. All other services use the same Schema defined in avro and managed by confluent's Schema Registry. I can get data posting to kafka fine as a string but cannot figure out how to upload a valid avro object linked to a schema registry schema. I am currently attempting to do this via a custom log4j plugin. For testing purposes I am writing these logs to their own topic and reading them out using kcat -b localhost:9092 -s value=avro -r localhost:8081 -t new_logs -f 'key: %k value: %s Partition: %p\n\n', but I get

ERROR: Failed to format message in new_logs [0] at offset 0: Avro/Schema-registry message deserialization: Invalid CP1 magic byte 115, expected 0: message not produced with Schema-Registry Avro framing: terminating

when doing this (that kcat command does work for my actual service logs topic and all other topics that use valid avro). Originally I tried using the org.apache.avro.generic.GenericData.Record class but could not figure out how to make it work in the methods toSerializable and toByteArray required by the AbstractLayout Interface since that class does not implement the serializable class. Below is the Plugin, class definition, log4j config

ServiceLogLayout.java

@Plugin(name="ServiceLogLayout", category= Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
public class ServiceLogLayout extends AbstractLayout<byte[]> {
    Schema record;
    DatumWriter<GenericData.Record> serviceLogDatumWriter;

    public ServiceLogLayout() {
        // maybe set these for avro
        super(null, null, null);
        Schema timestampMilliType = LogicalTypes.timestampMillis().addToSchema(Schema.create(Schema.Type.LONG));

        // CREATE SCHEMA
        Schema.Field service = new Schema.Field("service", SchemaBuilder.builder().stringType(), "Name of service sending this message");
        Schema.Field environment = new Schema.Field("environment", SchemaBuilder.builder().enumeration("environment_type").symbols("local", "dev", "staging", "prod", "shared_services", "testing", "security"));
        Schema.Field level = new Schema.Field("level", SchemaBuilder.builder().enumeration("level_type").symbols("debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"), "logging level");
        Schema.Field msg = new Schema.Field("msg", SchemaBuilder.builder().stringType(), "Required log message");

        List<Schema.Field> fields = new ArrayList<>();
        fields.add(service);
        fields.add(environment);
        fields.add(level);
        fields.add(msg);
        this.record = Schema.createRecord("service_logs", "", "com.test.avro", false, fields);
        this.serviceLogDatumWriter = new GenericDatumWriter<>(this.record);
    }

    @Override
    public byte[] toByteArray(LogEvent event) {
        LOGGER.warn("toByteArray");

        String env = System.getenv("ENVIRONMENT") != null ? System.getenv("ENVIRONMENT").toLowerCase() : "local";
        // FILL IN RECORD
        GenericRecordBuilder schemaBuilder = new GenericRecordBuilder(this.record);
        schemaBuilder.set("service", "testService");
        schemaBuilder.set("environment", new GenericData.EnumSymbol(this.record.getField("environment").schema(), env));
        schemaBuilder.set("level", new GenericData.EnumSymbol(this.record.getField("level").schema(), event.getLevel().name().toLowerCase()));
        schemaBuilder.set("msg", event.getMessage().getFormattedMessage());

        // SERIALIZE
        byte[] data = new byte[0];
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        Encoder jsonEncoder = null;
        try {
            jsonEncoder = EncoderFactory.get().jsonEncoder(
                    this.record, stream);
            this.serviceLogDatumWriter.write(schemaBuilder.build(), jsonEncoder);
            jsonEncoder.flush();
            data = stream.toByteArray();
        } catch (IOException e) {
            LOGGER.error("Serialization error:" + e.getMessage());
        }
        return data;
    }

    @Override
    public byte[] toSerializable(LogEvent event) {
        return toByteArray(event);
    }

    @Override
    public String getContentType() {
        return null;
    }

    @PluginFactory
    public static Layout<?> createLayout() {
        return new ServiceLogLayout();
    }

    private static class PrivateObjectOutputStream extends ObjectOutputStream {

        public PrivateObjectOutputStream(final OutputStream os) throws IOException {
            super(os);
        }

        @Override
        protected void writeStreamHeader() {
            // do nothing
        }
    }

}

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="logging.log4j.custom.plugins">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <ServiceLogLayout />

        </Console>
        <Kafka name="Kafka" topic="new_logs">
            <ServiceLogLayout />
            <Property name="bootstrap.servers">${env:BOOTSTRAP_SERVERS}</Property>
        </Kafka>
    </Appenders>
    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="Kafka"/>
        </Root>
        <Logger name="org.apache.kafka" level="WARN"/>
    </Loggers>
</Configuration>

Body:
OneCricketeer had the right idea, here is the implementation:

public class ServiceLogLayout extends AbstractLayout<byte[]> {
    Schema record;
    SchemaRegistryClient client;
    Schema.Parser parser;

    public ServiceLogLayout() {
        // maybe set these for avro
        super(null, null, null);
        Schema timestampMilliType = LogicalTypes.timestampMillis().addToSchema(Schema.create(Schema.Type.LONG));

        // CREATE SCHEMA
        Schema.Field service = new Schema.Field("service", SchemaBuilder.builder().stringType(), "Name of service sending this message");
        Schema.Field environment = new Schema.Field("environment", SchemaBuilder.builder().enumeration("environment_type").symbols("local", "dev", "staging", "prod", "shared_services", "testing", "security"));
        Schema.Field level = new Schema.Field("level", SchemaBuilder.builder().enumeration("level_type").symbols("debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"), "logging level");
        Schema.Field msg = new Schema.Field("msg", SchemaBuilder.builder().stringType(), "Required log message");
        Schema.Field data = new Schema.Field("data", SchemaBuilder.builder().nullable().stringType(), "Optional extra data, such as stack frames");
        Schema.Field timestamp = new Schema.Field("timestamp", SchemaBuilder.builder().type(timestampMilliType));

        List<Schema.Field> fields = new ArrayList<>();
        fields.add(service);
        fields.add(environment);
        fields.add(level);
        fields.add(msg);
        fields.add(data);
        fields.add(timestamp);
        this.record = Schema.createRecord("service_logs", "", "com.test.avro", false, fields);

        client = new CachedSchemaRegistryClient("http://schema-registry:8081", 10000);
        parser = new Schema.Parser();
    }

    @Override
    public byte[] toByteArray(LogEvent event) {

        String env = System.getenv("ENVIRONMENT") != null ? System.getenv("ENVIRONMENT").toLowerCase() : "local";
        // FILL IN RECORD
        GenericRecordBuilder schemaBuilder = new GenericRecordBuilder(this.record);
        schemaBuilder.set("service", "testService");
        schemaBuilder.set("environment", new GenericData.EnumSymbol(this.record.getField("environment").schema(), env));
        schemaBuilder.set("level", new GenericData.EnumSymbol(this.record.getField("level").schema(), event.getLevel().name()));
        schemaBuilder.set("msg", event.getMessage().getFormattedMessage());
        schemaBuilder.set("data", null);
        schemaBuilder.set("timestamp", event.getTimeMillis());

        // SERIALIZE
        byte[] data;
        KafkaAvroSerializer kafkaAvroSerializer = new KafkaAvroSerializer(client);
        data = kafkaAvroSerializer.serialize("service_logs", schemaBuilder.build());

        return data;
    }

    @Override
    public byte[] toSerializable(LogEvent event) {
        return toByteArray(event);
    }

    @Override
    public String getContentType() {
        return null;
    }

    @PluginFactory
    public static Layout<?> createLayout() {
        return new ServiceLogLayout();
    }

    private static class PrivateObjectOutputStream extends ObjectOutputStream {

        public PrivateObjectOutputStream(final OutputStream os) throws IOException {
            super(os);
        }

        @Override
        protected void writeStreamHeader() {
            // do nothing
        }
    }

}

It is worth noting that using logstash might be a good solution to this as well


来源: stackexchange

问:
Fortran fpm Run Tests on Module in Parent Directory
I have written a module in fortran that I want to test using fortran-fpm and vegetables.

My directory structure looks like this:

```<code>my_repo/
├─ foo/
│  ├─ bar/
│  │  ├─ my_module.f90
│  │  ├─ test/
│  │  │  ├─ main.f90
│  │  │  ├─ my_module_test.f90
├─ fpm.toml
</code>```

When I run fpm test, I get this error:

```<code><ERROR>*cmd_run*:targets error:Unable to find source for module dependency: "my_module" used by "foo/bar/test/my_module_test.f90"
STOP 1
</code>```

If I instead move my_module.f90 into the test directory, all the tests run fine. How do I point my_module_test.f90 to my_module.f90 without having my source code in the test directory?

I have tried:

Including:

```<code>[test-dependencies]
my_module = { path = "foo/bar/my_module.f90" }
</code>```

in my fpm.toml file at the top of my repo as suggested in the documentation. It then prompts me to put another fpm.toml file at foo/bar/. When I do that, it still gives me the same error.

Using putting file: "foo/bar/my_module.f90 at the top of my_module_test.f90. As suggested here.

EDIT:
Note that my fpm.toml file looks like this:

```<code>name = "My_Project"
author = "NolantheNerd"

[install]
library = true

[library]
source-dir = "foo/bar"
include-dir = "foo/bar"

[build]
external-modules = "foo/bar"
link = "foo/bar/my_module.f90"

[dev-dependencies]
vegetables = { git = "https://gitlab.com/everythingfunctional/vegetables.git", tag = "v7.2.2" }

[[test]]
name = "TestsForMyModule"
source-dir = "foo/bar/test"
main = "main.f90"
link = "foo/bar/my_module.f90"
</code>```

答:
Many thanks to everythingfunctional, the creator of vegetables for his solution:

Your build section is incorrect, and actually unnecessary in your case. Try removing it and let us know how it goes.

Edit: just noticed as well that the link entry in your test section is incorrect and unnecessary as well.

See the thread here.

ContentLicense: CC BY-SA 4.0

Body:
I have written a module in fortran that I want to test using fortran-fpm and vegetables.

My directory structure looks like this:

my_repo/
├─ foo/
│  ├─ bar/
│  │  ├─ my_module.f90
│  │  ├─ test/
│  │  │  ├─ main.f90
│  │  │  ├─ my_module_test.f90
├─ fpm.toml

When I run fpm test, I get this error:

<ERROR>*cmd_run*:targets error:Unable to find source for module dependency: "my_module" used by "foo/bar/test/my_module_test.f90"
STOP 1

If I instead move my_module.f90 into the test directory, all the tests run fine. How do I point my_module_test.f90 to my_module.f90 without having my source code in the test directory?

I have tried:

Including:

[test-dependencies]
my_module = { path = "foo/bar/my_module.f90" }

in my fpm.toml file at the top of my repo as suggested in the documentation. It then prompts me to put another fpm.toml file at foo/bar/. When I do that, it still gives me the same error.

Using putting file: "foo/bar/my_module.f90 at the top of my_module_test.f90. As suggested here.

EDIT:
Note that my fpm.toml file looks like this:

name = "My_Project"
author = "NolantheNerd"

[install]
library = true

[library]
source-dir = "foo/bar"
include-dir = "foo/bar"

[build]
external-modules = "foo/bar"
link = "foo/bar/my_module.f90"

[dev-dependencies]
vegetables = { git = "https://gitlab.com/everythingfunctional/vegetables.git", tag = "v7.2.2" }

[[test]]
name = "TestsForMyModule"
source-dir = "foo/bar/test"
main = "main.f90"
link = "foo/bar/my_module.f90"


问:
How do I get a users input and set it as a variable?
I am very new to Discord.js so please forgive me for any basic errors.

I am trying to create a command that will ask for a name, and then store the users input into a variable, however this is proving itself quite difficult.

After the program sends the message "What would you like to name your event?", I type "TEST", and then it sends another message saying "createevent", the command word.

client.on('message', async message => {
    if (message.author.bot) return;
    if (message.content.startsWith('createevent')) {
        const filter = m => m.author.id === message.author.id;

        message.channel.startTyping()
        await sleep(500);
        message.channel.stopTyping()

        message.lineReply('What would you like to name your event?')

        message.channel.awaitMessages(filter, {max: 1, time: 50000}).then(collected => {
            const eventname = message.content;
            message.channel.send(eventname);
        })
    }
});
```

答: First of all, you should stop the collector and, as you said you want to know the content that the user replies, the content in your case would be collected.content not message.content.


问:
Control ESP32 via Flutter BLE
I am using this library (https://pub.dev/packages/flutter_blue/example) to control my ESP32 (Arduino). I have two buttons that work perfectly, one to turn off the led and one to turn on the led. My problem is that I want to receive data that the arduino sends (notify). I don’t know how to do it.

main.dart

```<code>// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert' show utf8;

import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:minertti/widgets.dart';

void main() {
  runApp(FlutterBlueApp());
}

class FlutterBlueApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      color: Colors.lightBlue,
      home: StreamBuilder<BluetoothState>(
          stream: FlutterBlue.instance.state,
          initialData: BluetoothState.unknown,
          builder: (c, snapshot) {
            final state = snapshot.data;
            if (state == BluetoothState.on) {
              return FindDevicesScreen();
            }
            return BluetoothOffScreen(state: state);
          }),
    );
  }
}

class BluetoothOffScreen extends StatelessWidget {
  const BluetoothOffScreen({Key? key, this.state}) : super(key: key);

  final BluetoothState? state;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.lightBlue,
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Icon(
              Icons.bluetooth_disabled,
              size: 200.0,
              color: Colors.white54,
            ),
            Text(
              'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.',
              style: Theme.of(context)
                  .primaryTextTheme
                  .subtitle1
                  ?.copyWith(color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

class FindDevicesScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Find Devices'),
      ),
      body: RefreshIndicator(
        onRefresh: () =>
            FlutterBlue.instance.startScan(timeout: Duration(seconds: 4)),
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              StreamBuilder<List<BluetoothDevice>>(
                stream: Stream.periodic(Duration(seconds: 2))
                    .asyncMap((_) => FlutterBlue.instance.connectedDevices),
                initialData: [],
                builder: (c, snapshot) => Column(
                  children: snapshot.data!
                      .map((d) => ListTile(
                            title: Text(d.name),
                            subtitle: Text(d.id.toString()),
                            trailing: StreamBuilder<BluetoothDeviceState>(
                              stream: d.state,
                              initialData: BluetoothDeviceState.disconnected,
                              builder: (c, snapshot) {
                                if (snapshot.data ==
                                    BluetoothDeviceState.connected) {
                                  return RaisedButton(
                                    child: Text('OPEN'),
                                    onPressed: () => Navigator.of(context).push(
                                        MaterialPageRoute(
                                            builder: (context) =>
                                                DeviceScreen(device: d))),
                                  );
                                }
                                return Text(snapshot.data.toString());
                              },
                            ),
                          ))
                      .toList(),
                ),
              ),
              StreamBuilder<List<ScanResult>>(
                stream: FlutterBlue.instance.scanResults,
                initialData: [],
                builder: (c, snapshot) => Column(
                  children: snapshot.data!
                      .map(
                        (r) => ScanResultTile(
                          result: r,
                          onTap: () => Navigator.of(context)
                              .push(MaterialPageRoute(builder: (context) {
                            r.device.connect();
                            return DeviceScreen(device: r.device);
                          })),
                        ),
                      )
                      .toList(),
                ),
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: StreamBuilder<bool>(
        stream: FlutterBlue.instance.isScanning,
        initialData: false,
        builder: (c, snapshot) {
          if (snapshot.data!) {
            return FloatingActionButton(
              child: Icon(Icons.stop),
              onPressed: () => FlutterBlue.instance.stopScan(),
              backgroundColor: Colors.red,
            );
          } else {
            return FloatingActionButton(
                child: Icon(Icons.search),
                onPressed: () => FlutterBlue.instance
                    .startScan(timeout: Duration(seconds: 4)));
          }
        },
      ),
    );
  }
}

class DeviceScreen extends StatelessWidget {
  const DeviceScreen({Key? key, required this.device}) : super(key: key);

  final BluetoothDevice device;

  List<Widget> _buildServiceTiles(List<BluetoothService> services) {
    return services
        //just show the last service
        .sublist(services.length - 1)
        .map(
          (s) => ServiceTile(
            service: s,
            characteristicTiles: s.characteristics
                .map(
                  (c) => CharacteristicTile(
                    characteristic: c,
                    //turnOff: () => c.read(),
                    turnOff: () => c.write(utf8.encode("0")),
                    turnOn: () => c.write(utf8.encode("1")),
                    extraButton: () => c.write(utf8.encode("2")),

                    onNotificationPressed: () async {
                      await c.setNotifyValue(!c.isNotifying);
                      await c.read();
                    },
                    descriptorTiles: c.descriptors
                        .map(
                          (d) => DescriptorTile(
                            descriptor: d,
                            //turnOff: () => d.read(),
                            //turnOn: () => d.read(),
                          ),
                        )
                        .toList(),
                  ),
                )
                .toList(),
          ),
        )
        .toList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(device.name),
        actions: <Widget>[
          StreamBuilder<BluetoothDeviceState>(
            stream: device.state,
            initialData: BluetoothDeviceState.connecting,
            builder: (c, snapshot) {
              VoidCallback? onPressed;
              String text;
              switch (snapshot.data) {
                case BluetoothDeviceState.connected:
                  onPressed = () => device.disconnect();
                  text = 'DISCONNECT';
                  break;
                case BluetoothDeviceState.disconnected:
                  onPressed = () => device.connect();
                  text = 'CONNECT';
                  break;
                default:
                  onPressed = null;
                  text = snapshot.data.toString().substring(21).toUpperCase();
                  break;
              }
              return FlatButton(
                  onPressed: onPressed,
                  child: Text(
                    text,
                    style: Theme.of(context)
                        .primaryTextTheme
                        .button
                        ?.copyWith(color: Colors.white),
                  ));
            },
          )
        ],
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            StreamBuilder<BluetoothDeviceState>(
              stream: device.state,
              initialData: BluetoothDeviceState.connecting,
              builder: (c, snapshot) => ListTile(
                leading: (snapshot.data == BluetoothDeviceState.connected)
                    ? Icon(Icons.bluetooth_connected)
                    : Icon(Icons.bluetooth_disabled),
                title: Text(
                    'Device is ${snapshot.data.toString().split('.')[1]}.'),
                subtitle: Text('${device.id}'),
                trailing: StreamBuilder<bool>(
                  stream: device.isDiscoveringServices,
                  initialData: false,
                  builder: (c, snapshot) => IndexedStack(
                    index: snapshot.data! ? 1 : 0,
                    children: <Widget>[
                      IconButton(
                        icon: Icon(Icons.refresh),
                        onPressed: () => device.discoverServices(),
                      ),
                      IconButton(
                        icon: SizedBox(
                          child: CircularProgressIndicator(
                            valueColor: AlwaysStoppedAnimation(Colors.grey),
                          ),
                          width: 18.0,
                          height: 18.0,
                        ),
                        onPressed: null,
                      )
                    ],
                  ),
                ),
              ),
            ),
            StreamBuilder<int>(
              stream: device.mtu,
              initialData: 0,
              builder: (c, snapshot) => ListTile(
                title: Text('MTU Size'),
                subtitle: Text('${snapshot.data} bytes'),
                trailing: IconButton(
                  icon: Icon(Icons.edit),
                  onPressed: () => device.requestMtu(223),
                ),
              ),
            ),
            StreamBuilder<List<BluetoothService>>(
              stream: device.services,
              initialData: [],
              builder: (c, snapshot) {
                return Column(
                  children: _buildServiceTiles(snapshot.data!),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}
</code>```

device.dart

```<code>// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';

class ScanResultTile extends StatelessWidget {
  const ScanResultTile({Key? key, required this.result, this.onTap})
      : super(key: key);

  final ScanResult result;
  final VoidCallback? onTap;

  Widget _buildTitle(BuildContext context) {
    if (result.device.name.length > 0) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(
            result.device.name,
            overflow: TextOverflow.ellipsis,
          ),
          Text(
            result.device.id.toString(),
            style: Theme.of(context).textTheme.caption,
          )
        ],
      );
    } else {
      return Text(result.device.id.toString());
    }
  }

  Widget _buildAdvRow(BuildContext context, String title, String value) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(title, style: Theme.of(context).textTheme.caption),
          SizedBox(
            width: 12.0,
          ),
          Expanded(
            child: Text(
              value,
              style: Theme.of(context)
                  .textTheme
                  .caption
                  ?.apply(color: Colors.black),
              softWrap: true,
            ),
          ),
        ],
      ),
    );
  }

  String getNiceHexArray(List<int> bytes) {
    return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
        .toUpperCase();
  }

  String getNiceManufacturerData(Map<int, List<int>> data) {
    if (data.isEmpty) {
      return 'N/A';
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add(
          '${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }

  String getNiceServiceData(Map<String, List<int>> data) {
    if (data.isEmpty) {
      return 'N/A';
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add('${id.toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }

  @override
  Widget build(BuildContext context) {
    return ExpansionTile(
      title: _buildTitle(context),
      leading: Text(result.rssi.toString()),
      trailing: RaisedButton(
        child: Text('CONNECT'),
        color: Colors.black,
        textColor: Colors.white,
        onPressed: (result.advertisementData.connectable) ? onTap : null,
      ),
      children: <Widget>[
        _buildAdvRow(
            context, 'Complete Local Name', result.advertisementData.localName),
        _buildAdvRow(context, 'Tx Power Level',
            '${result.advertisementData.txPowerLevel ?? 'N/A'}'),
        _buildAdvRow(context, 'Manufacturer Data',
            getNiceManufacturerData(result.advertisementData.manufacturerData)),
        _buildAdvRow(
            context,
            'Service UUIDs',
            (result.advertisementData.serviceUuids.isNotEmpty)
                ? result.advertisementData.serviceUuids.join(', ').toUpperCase()
                : 'N/A'),
        _buildAdvRow(context, 'Service Data',
            getNiceServiceData(result.advertisementData.serviceData)),
      ],
    );
  }
}

class ServiceTile extends StatelessWidget {
  final BluetoothService service;
  final List<CharacteristicTile> characteristicTiles;

  const ServiceTile(
      {Key? key, required this.service, required this.characteristicTiles})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (characteristicTiles.length > 0) {
      return ExpansionTile(
        title: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text('Service'),
            Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
                style: Theme.of(context).textTheme.bodyText1?.copyWith(
                    color: Theme.of(context).textTheme.caption?.color))
          ],
        ),
        children: characteristicTiles,
      );
    } else {
      return ListTile(
        title: Text('Service'),
        subtitle:
            Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
      );
    }
  }
}

class CharacteristicTile extends StatelessWidget {
  final BluetoothCharacteristic characteristic;
  final List<DescriptorTile> descriptorTiles;
  final VoidCallback? turnOff;
  final VoidCallback? extraButton;
  final VoidCallback? turnOn;
  final VoidCallback? onNotificationPressed;

  const CharacteristicTile(
      {Key? key,
      required this.characteristic,
      required this.descriptorTiles,
      this.turnOff,
      this.extraButton,
      this.turnOn,
      this.onNotificationPressed})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<int>>(
      stream: characteristic.value,
      initialData: characteristic.lastValue,
      builder: (c, snapshot) {
        final value = snapshot.data;
        return ExpansionTile(
          title: ListTile(
            title: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text('Characteristic'),
                Text(
                    '0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
                    style: Theme.of(context).textTheme.bodyText1?.copyWith(
                        color: Theme.of(context).textTheme.caption?.color))
              ],
            ),
            subtitle: Text(value.toString()),
            contentPadding: EdgeInsets.all(0.0),
          ),
          trailing: Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              IconButton(
                icon: Icon(
                  Icons.lightbulb_outline,
                  color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
                ),
                onPressed: turnOff,
              ),
              IconButton(
                icon: Icon(Icons.lightbulb,
                    color: Theme.of(context).iconTheme.color?.withOpacity(0.5)),
                onPressed: turnOn,
              ),
              //iconButton for add
              IconButton(
                icon: Icon(
                  Icons.add_circle,
                  color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
                ),
                onPressed: extraButton,
              ),
              IconButton(
                icon: Icon(
                    characteristic.isNotifying
                        ? Icons.sync_disabled
                        : Icons.sync,
                    color: Theme.of(context).iconTheme.color?.withOpacity(0.5)),
                onPressed: onNotificationPressed,
              )
            ],
          ),
          children: descriptorTiles,
        );
      },
    );
  }
}

class DescriptorTile extends StatelessWidget {
  final BluetoothDescriptor descriptor;
  final VoidCallback? turnOff;
  final VoidCallback? turnOn;
  final VoidCallback? extraButton;

  const DescriptorTile(
      {Key? key,
      required this.descriptor,
      this.turnOff,
      this.extraButton,
      this.turnOn})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text('Descriptor'),
          Text('0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
              style: Theme.of(context)
                  .textTheme
                  .bodyText1
                  ?.copyWith(color: Theme.of(context).textTheme.caption?.color))
        ],
      ),
      subtitle: StreamBuilder<List<int>>(
        stream: descriptor.value,
        initialData: descriptor.lastValue,
        builder: (c, snapshot) => Text(snapshot.data.toString()),
      ),
      trailing: Row(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          IconButton(
            icon: Icon(
              Icons.lightbulb_outline,
              color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
            ),
            onPressed: turnOff,
          ),
          IconButton(
            icon: Icon(
              Icons.lightbulb,
              color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
            ),
            onPressed: turnOn,
          ),
          IconButton(
            icon: Icon(
              Icons.add_circle,
              color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
            ),
            onPressed: extraButton,
          )
        ],
      ),
    );
  }
}

class AdapterStateTile extends StatelessWidget {
  const AdapterStateTile({Key? key, required this.state}) : super(key: key);

  final BluetoothState state;

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.redAccent,
      child: ListTile(
        title: Text(
          'Bluetooth adapter is ${state.toString().substring(15)}',
          style: Theme.of(context).primaryTextTheme.subtitle1,
        ),
        trailing: Icon(
          Icons.error,
          color: Theme.of(context).primaryTextTheme.subtitle1?.color,
        ),
      ),
    );
  }
}
</code>```

ESP32 Code:

```<code>#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
float txValue = 0;
const int readPin = 32; // Use GPIO number. See ESP32 board pinouts
const int LED = 2; // Could be different depending on the dev board. I used the DOIT ESP32 dev board.

//std::string rxValue; // Could also make this a global var to access it in loop()

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");

        for (int i = 0; i < rxValue.length(); i++) {
          Serial.print(rxValue[i]);
        }

        Serial.println();

        // Do stuff based on the command received from the app
        if (rxValue.find("1") != -1) {
          Serial.println("Turning ON!");
          digitalWrite(LED, HIGH);
        }
        else if (rxValue.find("0") != -1) {
          Serial.println("Turning OFF!");
          digitalWrite(LED, LOW);
        }

        Serial.println();
        Serial.println("*********");
      }
    }
};

void setup() {
  Serial.begin(115200);

  pinMode(LED, OUTPUT);

  // Create the BLE Device
  BLEDevice::init("ESP32"); // Give it a name

  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );

  pCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID_RX,
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  if (deviceConnected) {
    // Fabricate some arbitrary junk for now...
    txValue = analogRead(readPin) / 3.456; // This could be an actual sensor reading!

    // Let's convert the value to a char array:
    char txString[8]; // make sure this is big enuffz
    dtostrf(txValue, 1, 2, txString); // float_val, min_width, digits_after_decimal, char_buffer

//    pCharacteristic->setValue(&txValue, 1); // To send the integer value
//    pCharacteristic->setValue("Hello!"); // Sending a test message
    pCharacteristic->setValue(txString);

    pCharacteristic->notify(); // Send the value to the app!
    Serial.print("*** Sent Value: ");
    Serial.print(txString);
    Serial.println(" ***");

    // You can add the rxValue checks down here instead
    // if you set "rxValue" as a global var at the top!
    // Note you will have to delete "std::string" declaration
    // of "rxValue" in the callback function.
//    if (rxValue.find("A") != -1) {
//      Serial.println("Turning ON!");
//      digitalWrite(LED, HIGH);
//    }
//    else if (rxValue.find("B") != -1) {
//      Serial.println("Turning OFF!");
//      digitalWrite(LED, LOW);
//    }
  }
  delay(1000);
}
</code>```

The app correctly receives the information, but in a strange code that I don't understand. How do I convert it to letters and numbers?

In device.dart you can see that there is a part that says: "subtitle: Text(value.toString())"

That is the one that sends the data, but I don't understand it.

```<code>...
builder: (c, snapshot) {
        final value = snapshot.data;
        return ExpansionTile(
          title: ListTile(
            title: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text('Characteristic'),
                Text(
                    '0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
                    style: Theme.of(context).textTheme.bodyText1?.copyWith(
                        color: Theme.of(context).textTheme.caption?.color))
              ],
            ),
            subtitle: Text(value.toString()),

...
</code>```

Arduino sends: 98.96 and I receive this data from value.toString(): [57, 56, 46, 57, 54]

答: Try using String.fromCharCodes to convert the received data ([57, 56, 46, 57, 54]) to 98.96.</p>

Title: Control ESP32 via Flutter BLE

Body:
I am using this library (https://pub.dev/packages/flutter_blue/example) to control my ESP32 (Arduino). I have two buttons that work perfectly, one to turn off the led and one to turn on the led. My problem is that I want to receive data that the arduino sends (notify). I don’t know how to do it.

main.dart

// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert' show utf8;

import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:minertti/widgets.dart';

void main() {
  runApp(FlutterBlueApp());
}

class FlutterBlueApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      color: Colors.lightBlue,
      home: StreamBuilder<BluetoothState>(
          stream: FlutterBlue.instance.state,
          initialData: BluetoothState.unknown,
          builder: (c, snapshot) {
            final state = snapshot.data;
            if (state == BluetoothState.on) {
              return FindDevicesScreen();
            }
            return BluetoothOffScreen(state: state);
          }),
    );
  }
}

class BluetoothOffScreen extends StatelessWidget {
  const BluetoothOffScreen({Key? key, this.state}) : super(key: key);

  final BluetoothState? state;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.lightBlue,
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Icon(
              Icons.bluetooth_disabled,
              size: 200.0,
              color: Colors.white54,
            ),
            Text(
              'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.',
              style: Theme.of(context)
                  .primaryTextTheme
                  .subtitle1
                  ?.copyWith(color: Colors.white),
            ),
          ],
        ),
      ),
    );
  }
}

class FindDevicesScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Find Devices'),
      ),
      body: RefreshIndicator(
        onRefresh: () =>
            FlutterBlue.instance.startScan(timeout: Duration(seconds: 4)),
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              StreamBuilder<List<BluetoothDevice>>(
                stream: Stream.periodic(Duration(seconds: 2))
                    .asyncMap((_) => FlutterBlue.instance.connectedDevices),
                initialData: [],
                builder: (c, snapshot) => Column(
                  children: snapshot.data!
                      .map((d) => ListTile(
                            title: Text(d.name),
                            subtitle: Text(d.id.toString()),
                            trailing: StreamBuilder<BluetoothDeviceState>(
                              stream: d.state,
                              initialData: BluetoothDeviceState.disconnected,
                              builder: (c, snapshot) {
                                if (snapshot.data ==
                                    BluetoothDeviceState.connected) {
                                  return RaisedButton(
                                    child: Text('OPEN'),
                                    onPressed: () => Navigator.of(context).push(
                                        MaterialPageRoute(
                                            builder: (context) =>
                                                DeviceScreen(device: d))),
                                  );
                                }
                                return Text(snapshot.data.toString());
                              },
                            ),
                          ))
                      .toList(),
                ),
              ),
              StreamBuilder<List<ScanResult>>(
                stream: FlutterBlue.instance.scanResults,
                initialData: [],
                builder: (c, snapshot) => Column(
                  children: snapshot.data!
                      .map(
                        (r) => ScanResultTile(
                          result: r,
                          onTap: () => Navigator.of(context)
                              .push(MaterialPageRoute(builder: (context) {
                            r.device.connect();
                            return DeviceScreen(device: r.device);
                          })),
                        ),
                      )
                      .toList(),
                ),
              ),
            ],
          ),
        ),
      ),
      floatingActionButton: StreamBuilder<bool>(
        stream: FlutterBlue.instance.isScanning,
        initialData: false,
        builder: (c, snapshot) {
          if (snapshot.data!) {
            return FloatingActionButton(
              child: Icon(Icons.stop),
              onPressed: () => FlutterBlue.instance.stopScan(),
              backgroundColor: Colors.red,
            );
          } else {
            return FloatingActionButton(
                child: Icon(Icons.search),
                onPressed: () => FlutterBlue.instance
                    .startScan(timeout: Duration(seconds: 4)));
          }
        },
      ),
    );
  }
}

class DeviceScreen extends StatelessWidget {
  const DeviceScreen({Key? key, required this.device}) : super(key: key);

  final BluetoothDevice device;

  List<Widget> _buildServiceTiles(List<BluetoothService> services) {
    return services
        //just show the last service
        .sublist(services.length - 1)
        .map(
          (s) => ServiceTile(
            service: s,
            characteristicTiles: s.characteristics
                .map(
                  (c) => CharacteristicTile(
                    characteristic: c,
                    //turnOff: () => c.read(),
                    turnOff: () => c.write(utf8.encode("0")),
                    turnOn: () => c.write(utf8.encode("1")),
                    extraButton: () => c.write(utf8.encode("2")),

                    onNotificationPressed: () async {
                      await c.setNotifyValue(!c.isNotifying);
                      await c.read();
                    },
                    descriptorTiles: c.descriptors
                        .map(
                          (d) => DescriptorTile(
                            descriptor: d,
                            //turnOff: () => d.read(),
                            //turnOn: () => d.read(),
                          ),
                        )
                        .toList(),
                  ),
                )
                .toList(),
          ),
        )
        .toList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(device.name),
        actions: <Widget>[
          StreamBuilder<BluetoothDeviceState>(
            stream: device.state,
            initialData: BluetoothDeviceState.connecting,
            builder: (c, snapshot) {
              VoidCallback? onPressed;
              String text;
              switch (snapshot.data) {
                case BluetoothDeviceState.connected:
                  onPressed = () => device.disconnect();
                  text = 'DISCONNECT';
                  break;
                case BluetoothDeviceState.disconnected:
                  onPressed = () => device.connect();
                  text = 'CONNECT';
                  break;
                default:
                  onPressed = null;
                  text = snapshot.data.toString().substring(21).toUpperCase();
                  break;
              }
              return FlatButton(
                  onPressed: onPressed,
                  child: Text(
                    text,
                    style: Theme.of(context)
                        .primaryTextTheme
                        .button
                        ?.copyWith(color: Colors.white),
                  ));
            },
          )
        ],
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            StreamBuilder<BluetoothDeviceState>(
              stream: device.state,
              initialData: BluetoothDeviceState.connecting,
              builder: (c, snapshot) => ListTile(
                leading: (snapshot.data == BluetoothDeviceState.connected)
                    ? Icon(Icons.bluetooth_connected)
                    : Icon(Icons.bluetooth_disabled),
                title: Text(
                    'Device is ${snapshot.data.toString().split('.')[1]}.'),
                subtitle: Text('${device.id}'),
                trailing: StreamBuilder<bool>(
                  stream: device.isDiscoveringServices,
                  initialData: false,
                  builder: (c, snapshot) => IndexedStack(
                    index: snapshot.data! ? 1 : 0,
                    children: <Widget>[
                      IconButton(
                        icon: Icon(Icons.refresh),
                        onPressed: () => device.discoverServices(),
                      ),
                      IconButton(
                        icon: SizedBox(
                          child: CircularProgressIndicator(
                            valueColor: AlwaysStoppedAnimation(Colors.grey),
                          ),
                          width: 18.0,
                          height: 18.0,
                        ),
                        onPressed: null,
                      )
                    ],
                  ),
                ),
              ),
            ),
            StreamBuilder<int>(
              stream: device.mtu,
              initialData: 0,
              builder: (c, snapshot) => ListTile(
                title: Text('MTU Size'),
                subtitle: Text('${snapshot.data} bytes'),
                trailing: IconButton(
                  icon: Icon(Icons.edit),
                  onPressed: () => device.requestMtu(223),
                ),
              ),
            ),
            StreamBuilder<List<BluetoothService>>(
              stream: device.services,
              initialData: [],
              builder: (c, snapshot) {
                return Column(
                  children: _buildServiceTiles(snapshot.data!),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

device.dart

// Copyright 2017, Paul DeMarco.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';

class ScanResultTile extends StatelessWidget {
  const ScanResultTile({Key? key, required this.result, this.onTap})
      : super(key: key);

  final ScanResult result;
  final VoidCallback? onTap;

  Widget _buildTitle(BuildContext context) {
    if (result.device.name.length > 0) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(
            result.device.name,
            overflow: TextOverflow.ellipsis,
          ),
          Text(
            result.device.id.toString(),
            style: Theme.of(context).textTheme.caption,
          )
        ],
      );
    } else {
      return Text(result.device.id.toString());
    }
  }

  Widget _buildAdvRow(BuildContext context, String title, String value) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(title, style: Theme.of(context).textTheme.caption),
          SizedBox(
            width: 12.0,
          ),
          Expanded(
            child: Text(
              value,
              style: Theme.of(context)
                  .textTheme
                  .caption
                  ?.apply(color: Colors.black),
              softWrap: true,
            ),
          ),
        ],
      ),
    );
  }

  String getNiceHexArray(List<int> bytes) {
    return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
        .toUpperCase();
  }

  String getNiceManufacturerData(Map<int, List<int>> data) {
    if (data.isEmpty) {
      return 'N/A';
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add(
          '${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }

  String getNiceServiceData(Map<String, List<int>> data) {
    if (data.isEmpty) {
      return 'N/A';
    }
    List<String> res = [];
    data.forEach((id, bytes) {
      res.add('${id.toUpperCase()}: ${getNiceHexArray(bytes)}');
    });
    return res.join(', ');
  }

  @override
  Widget build(BuildContext context) {
    return ExpansionTile(
      title: _buildTitle(context),
      leading: Text(result.rssi.toString()),
      trailing: RaisedButton(
        child: Text('CONNECT'),
        color: Colors.black,
        textColor: Colors.white,
        onPressed: (result.advertisementData.connectable) ? onTap : null,
      ),
      children: <Widget>[
        _buildAdvRow(
            context, 'Complete Local Name', result.advertisementData.localName),
        _buildAdvRow(context, 'Tx Power Level',
            '${result.advertisementData.txPowerLevel ?? 'N/A'}'),
        _buildAdvRow(context, 'Manufacturer Data',
            getNiceManufacturerData(result.advertisementData.manufacturerData)),
        _buildAdvRow(
            context,
            'Service UUIDs',
            (result.advertisementData.serviceUuids.isNotEmpty)
                ? result.advertisementData.serviceUuids.join(', ').toUpperCase()
                : 'N/A'),
        _buildAdvRow(context, 'Service Data',
            getNiceServiceData(result.advertisementData.serviceData)),
      ],
    );
  }
}

class ServiceTile extends StatelessWidget {
  final BluetoothService service;
  final List<CharacteristicTile> characteristicTiles;

  const ServiceTile(
      {Key? key, required this.service, required this.characteristicTiles})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    if (characteristicTiles.length > 0) {
      return ExpansionTile(
        title: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text('Service'),
            Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
                style: Theme.of(context).textTheme.bodyText1?.copyWith(
                    color: Theme.of(context).textTheme.caption?.color))
          ],
        ),
        children: characteristicTiles,
      );
    } else {
      return ListTile(
        title: Text('Service'),
        subtitle:
            Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
      );
    }
  }
}

class CharacteristicTile extends StatelessWidget {
  final BluetoothCharacteristic characteristic;
  final List<DescriptorTile> descriptorTiles;
  final VoidCallback? turnOff;
  final VoidCallback? extraButton;
  final VoidCallback? turnOn;
  final VoidCallback? onNotificationPressed;

  const CharacteristicTile(
      {Key? key,
      required this.characteristic,
      required this.descriptorTiles,
      this.turnOff,
      this.extraButton,
      this.turnOn,
      this.onNotificationPressed})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<int>>(
      stream: characteristic.value,
      initialData: characteristic.lastValue,
      builder: (c, snapshot) {
        final value = snapshot.data;
        return ExpansionTile(
          title: ListTile(
            title: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text('Characteristic'),
                Text(
                    '0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
                    style: Theme.of(context).textTheme.bodyText1?.copyWith(
                        color: Theme.of(context).textTheme.caption?.color))
              ],
            ),
            subtitle: Text(value.toString()),
            contentPadding: EdgeInsets.all(0.0),
          ),
          trailing: Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              IconButton(
                icon: Icon(
                  Icons.lightbulb_outline,
                  color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
                ),
                onPressed: turnOff,
              ),
              IconButton(
                icon: Icon(Icons.lightbulb,
                    color: Theme.of(context).iconTheme.color?.withOpacity(0.5)),
                onPressed: turnOn,
              ),
              //iconButton for add
              IconButton(
                icon: Icon(
                  Icons.add_circle,
                  color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
                ),
                onPressed: extraButton,
              ),
              IconButton(
                icon: Icon(
                    characteristic.isNotifying
                        ? Icons.sync_disabled
                        : Icons.sync,
                    color: Theme.of(context).iconTheme.color?.withOpacity(0.5)),
                onPressed: onNotificationPressed,
              )
            ],
          ),
          children: descriptorTiles,
        );
      },
    );
  }
}

class DescriptorTile extends StatelessWidget {
  final BluetoothDescriptor descriptor;
  final VoidCallback? turnOff;
  final VoidCallback? turnOn;
  final VoidCallback? extraButton;

  const DescriptorTile(
      {Key? key,
      required this.descriptor,
      this.turnOff,
      this.extraButton,
      this.turnOn})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text('Descriptor'),
          Text('0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
              style: Theme.of(context)
                  .textTheme
                  .bodyText1
                  ?.copyWith(color: Theme.of(context).textTheme.caption?.color))
        ],
      ),
      subtitle: StreamBuilder<List<int>>(
        stream: descriptor.value,
        initialData: descriptor.lastValue,
        builder: (c, snapshot) => Text(snapshot.data.toString()),
      ),
      trailing: Row(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          IconButton(
            icon: Icon(
              Icons.lightbulb_outline,
              color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
            ),
            onPressed: turnOff,
          ),
          IconButton(
            icon: Icon(
              Icons.lightbulb,
              color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
            ),
            onPressed: turnOn,
          ),
          IconButton(
            icon: Icon(
              Icons.add_circle,
              color: Theme.of(context).iconTheme.color?.withOpacity(0.5),
            ),
            onPressed: extraButton,
          )
        ],
      ),
    );
  }
}

class AdapterStateTile extends StatelessWidget {
  const AdapterStateTile({Key? key, required this.state}) : super(key: key);

  final BluetoothState state;

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.redAccent,
      child: ListTile(
        title: Text(
          'Bluetooth adapter is ${state.toString().substring(15)}',
          style: Theme.of(context).primaryTextTheme.subtitle1,
        ),
        trailing: Icon(
          Icons.error,
          color: Theme.of(context).primaryTextTheme.subtitle1?.color,
        ),
      ),
    );
  }
}

ESP32 Code:

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
float txValue = 0;
const int readPin = 32; // Use GPIO number. See ESP32 board pinouts
const int LED = 2; // Could be different depending on the dev board. I used the DOIT ESP32 dev board.

//std::string rxValue; // Could also make this a global var to access it in loop()

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");

        for (int i = 0; i < rxValue.length(); i++) {
          Serial.print(rxValue[i]);
        }

        Serial.println();

        // Do stuff based on the command received from the app
        if (rxValue.find("1") != -1) {
          Serial.println("Turning ON!");
          digitalWrite(LED, HIGH);
        }
        else if (rxValue.find("0") != -1) {
          Serial.println("Turning OFF!");
          digitalWrite(LED, LOW);
        }

        Serial.println();
        Serial.println("*********");
      }
    }
};

void setup() {
  Serial.begin(115200);

  pinMode(LED, OUTPUT);

  // Create the BLE Device
  BLEDevice::init("ESP32"); // Give it a name

  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );

  pCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID_RX,
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  if (deviceConnected) {
    // Fabricate some arbitrary junk for now...
    txValue = analogRead(readPin) / 3.456; // This could be an actual sensor reading!

    // Let's convert the value to a char array:
    char txString[8]; // make sure this is big enuffz
    dtostrf(txValue, 1, 2, txString); // float_val, min_width, digits_after_decimal, char_buffer

//    pCharacteristic->setValue(&txValue, 1); // To send the integer value
//    pCharacteristic->setValue("Hello!"); // Sending a test message
    pCharacteristic->setValue(txString);

    pCharacteristic->notify(); // Send the value to the app!
    Serial.print("*** Sent Value: ");
    Serial.print(txString);
    Serial.println(" ***");

    // You can add the rxValue checks down here instead
    // if you set "rxValue" as a global var at the top!
    // Note you will have to delete "std::string" declaration
    // of "rxValue" in the callback function.
//    if (rxValue.find("A") != -1) {
//      Serial.println("Turning ON!");
//      digitalWrite(LED, HIGH);
//    }
//    else if (rxValue.find("B") != -1) {
//      Serial.println("Turning OFF!");
//      digitalWrite(LED, LOW);
//    }
  }
  delay(1000);
}

The app correctly receives the information, but in a strange code that I don't understand. How do I convert it to letters and numbers?

In device.dart you can see that there is a part that says: "subtitle: Text(value.toString())"

That is the one that sends the data, but I don't understand it.

...
builder: (c, snapshot) {
        final value = snapshot.data;
        return ExpansionTile(
          title: ListTile(
            title: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text('Characteristic'),
                Text(
                    '0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
                    style: Theme.of(context).textTheme.bodyText1?.copyWith(
                        color: Theme.of(context).textTheme.caption?.color))
              ],
            ),
            subtitle: Text(value.toString()),

...

Arduino sends: 98.96 and I receive this data from value.toString(): [57, 56, 46, 57, 54]


问:
How to filter out all records that have duplicates in SQL?
Trying to get this result from a table with duplicates

red
red
red
blue
green
```
<p>to</p>
<pre class="lang-none prettyprint-override"><code>blue
green
</code>```

Totally omitting all the records that has duplicates and only bringing in the unique records

答:
Use GROUP BY and HAVING clause...</p>
```<code>    select color
    from table1
    group by color
    having count(color) = 1
</code>```

Body:
Trying to get this result from a table with duplicates

red
red
red
blue
green

to

blue
green

Totally omitting all the records that has duplicates and only bringing in the unique records

Body:
Use GROUP BY and HAVING clause...

    select color
    from table1
    group by color
    having count(color) = 1


问:
How to do unit testing of functions writing files using Python's 'unittest'
I have a Python function that writes an output file to disk.

I want to write a unit test for it using Python's unittest module.

How should I assert equality of files? I would like to get an error if the file content differs from the expected one + list of differences. As in the output of the Unix diff command.

Is there an official or recommended way of doing that?

答:
If you can use it, I'd strongly recommend using the following library:  http://pyfakefs.org

pyfakefs creates an in-memory fake filesystem, and patches all filesystem accesses with accesses to the fake filesystem.  This means you can write your code as you normally would, and in your unit tests, just make sure to initialize the fake filesystem in your setup.

```<code>from pyfakefs.fake_filesystem_unittest import TestCase

class ExampleTestCase(TestCase):
    def setUp(self):
        self.setUpPyfakefs()

    def test_create_file(self):
        file_path = '/test/file.txt'
        self.assertFalse(os.path.exists(file_path))
        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))
</code>```

There is also a pytest plugin if you prefer to run your tests with pytest.

There are some caveats to this approach - you can't use it if you're accessing the filesystem via C libraries, because pyfakefs can't use patch those calls.  However, if you're working in pure Python, I've found it to be a tremendously useful library.

Body:
If you can use it, I'd strongly recommend using the following library:  http://pyfakefs.org

pyfakefs creates an in-memory fake filesystem, and patches all filesystem accesses with accesses to the fake filesystem.  This means you can write your code as you normally would, and in your unit tests, just make sure to initialize the fake filesystem in your setup.

from pyfakefs.fake_filesystem_unittest import TestCase

class ExampleTestCase(TestCase):
    def setUp(self):
        self.setUpPyfakefs()

    def test_create_file(self):
        file_path = '/test/file.txt'
        self.assertFalse(os.path.exists(file_path))
        self.fs.create_file(file_path)
        self.assertTrue(os.path.exists(file_path))

There is also a pytest plugin if you prefer to run your tests with pytest.

There are some caveats to this approach - you can't use it if you're accessing the filesystem via C libraries, because pyfakefs can't use patch those calls.  However, if you're working in pure Python, I've found it to be a tremendously useful library.


问:
Why loss is NaN
I am learning about DNN and transformers and I have the following problem. Running the model on IMDB dataset this transformer NN works just fine. But when I try and run it on another dataset which instead of 2 classes has 4, the loss goes to NaN and the accuracy quickly goes to 0. Please if you are kind to help me. I am struggling for 2 days with the same problem.

I've tried clipping gradients, increasing batch size, increasing dropout, reducing lr.
If you are kind to help me I will be forever grateful.

```<code>embed_dim = 32  # Embedding size for each token
num_heads = 2  # Number of attention heads
ff_dim = 32  # Hidden layer size in feed forward network inside transformer

inputs = layers.Input(shape=(maxlen,))
embedding_layer = TokenAndPositionEmbedding(maxlen, vocab_size, embed_dim)
x = embedding_layer(inputs)
transformer_block = TransformerBlock(embed_dim, num_heads, ff_dim)
x = transformer_block(x)
# x = transformer_block(x)
x = layers.GlobalAveragePooling1D()(x)

x = layers.Dropout(0.5)(x)
x = layers.Dense(20, activation="relu")(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(4, activation="softmax")(x)

model = keras.Model(inputs=inputs, outputs=outputs)

opt = tf.keras.optimizers.Adam(learning_rate=3e-04,clipvalue=0.5)
model.compile(optimizer = opt, loss="sparse_categorical_crossentropy", metrics=["accuracy"])
history = model.fit(
    x_train, y_train, batch_size=128, epochs=10, validation_data=(x_val, y_val)
)
</code>```

答: I was running on GPU and the error did not appeared. It was because I was having labels [1,2,4,5] and I should have labels between 0 and 4.</p>

Title: Why loss is NaN

Body:
I am learning about DNN and transformers and I have the following problem. Running the model on IMDB dataset this transformer NN works just fine. But when I try and run it on another dataset which instead of 2 classes has 4, the loss goes to NaN and the accuracy quickly goes to 0. Please if you are kind to help me. I am struggling for 2 days with the same problem.

I've tried clipping gradients, increasing batch size, increasing dropout, reducing lr.
If you are kind to help me I will be forever grateful.

embed_dim = 32  # Embedding size for each token
num_heads = 2  # Number of attention heads
ff_dim = 32  # Hidden layer size in feed forward network inside transformer

inputs = layers.Input(shape=(maxlen,))
embedding_layer = TokenAndPositionEmbedding(maxlen, vocab_size, embed_dim)
x = embedding_layer(inputs)
transformer_block = TransformerBlock(embed_dim, num_heads, ff_dim)
x = transformer_block(x)
# x = transformer_block(x)
x = layers.GlobalAveragePooling1D()(x)

x = layers.Dropout(0.5)(x)
x = layers.Dense(20, activation="relu")(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(4, activation="softmax")(x)

model = keras.Model(inputs=inputs, outputs=outputs)

opt = tf.keras.optimizers.Adam(learning_rate=3e-04,clipvalue=0.5)
model.compile(optimizer = opt, loss="sparse_categorical_crossentropy", metrics=["accuracy"])
history = model.fit(
    x_train, y_train, batch_size=128, epochs=10, validation_data=(x_val, y_val)
)


问:
Why does Ubuntu WSL shows error when checking heroku version?
I have heroku installed in C: drive. I also installed heroku in my Ubuntu WSL. When I try to check the heroku version it shows:

```<code>/mnt/c/Program Files/heroku/bin/../client/bin/heroku.cmd: 1: @echo: not found
/mnt/c/Program Files/heroku/bin/../client/bin/heroku.cmd: 2: setlocal: not found
/mnt/c/Program Files/heroku/bin/../client/bin/heroku.cmd: 4: Syntax error: "(" unexpected (expecting "then")
</code>```

I tried to push inside my code folder in command prompt.

```<code>git push heroku main
fatal: 'heroku' does not appear to be a git repository
fatal: Could not read from remote repository.
</code>```

答:
It looks like you're trying to run a batch script (for cmd.exe) in your Linux shell (likely bash unless you've changed it). That's not going to work.

It's possible to run Windows .exe files in WSL, but I don't think there's a heroku.exe in the Windows version. I suggest you install the Linux version right in WSL and use that instead.

Body:
I have heroku installed in C: drive. I also installed heroku in my Ubuntu WSL. When I try to check the heroku version it shows:

/mnt/c/Program Files/heroku/bin/../client/bin/heroku.cmd: 1: @echo: not found
/mnt/c/Program Files/heroku/bin/../client/bin/heroku.cmd: 2: setlocal: not found
/mnt/c/Program Files/heroku/bin/../client/bin/heroku.cmd: 4: Syntax error: "(" unexpected (expecting "then")

I tried to push inside my code folder in command prompt.

git push heroku main
fatal: 'heroku' does not appear to be a git repository
fatal: Could not read from remote repository.


问:
People Counting System
I want to develop a "People Counting System" using OpenCV (or Emgu CV).

Please guide me on how to implement or lead me to some examples or open source projects.

(I have done some work: extracting diff then threshold to delete background, using motion history and like that; still no good results.)

Edit 1: I am counting a high people flow (a dozen of them may come through simultaneously).

Edit 2: It must be at least 80% accurate. People are walking through a door that is almost 5 meters wide. The problem is I have no control on the position or angle of the camera. Camera is shouting the place from a 10m distance at a 2.5m height.

Thank you

答: Are people the only kind of "entities" in the scene? If this is not the case, do you care about considering a person some other kind of thing that moves through the scene? Because if that is the case, you could just count blobs that come in or come out from the scene. It may sound a bit naive but I will take some kind of motion image, group motion pixels by distance in clusters. Your distance metric could take into account some restrictions, such as that people will "often" stand so pixels in a cluster should group around some kind of regression line (an straight-up line if the camera is aligned with de floor). It shouldn't be necessary to track them in the scene, just noticing when they enter or they leave, though you'd get some issues with, for example, people entering on their own in the scene and leaving in pairs or in groups... Good luck :)</p>

ContentLicense: CC BY-SA 3.0

Title: People Counting System


问:
Extract json key/value pairs with postgresql/snowflake, where value is not null/blank
I have a field called "filter" with json array like:

[
   {
      "after":"2021-10-14T00:00:00",
      "column":"createddate",
      "from":null,
      "gt":null,
      "gte":null,
      "id":"928d57b0",
      "lt":null,
      "lte":null,
      "not":null,
      "prior":null,
      "to":null,
      "value":null
   },
   {
      "after":null,
      "column":"last_coach_date",
      "from":"",
      "gt":null,
      "gte":null,
      "id":"01704cdd",
      "lt":null,
      "lte":null,
      "not":null,
      "prior":null,
      "to":"",
      "value":null
   }
]
```

I'm trying to extract key/value pairs where value is not null/blank and create another field for it.

Maybe to something like this or one long string:

 { "after": "2021-10-14T00:00:00", "column": "createddate", "id": "928d57b0"}, {"column": "last_coach_date","id": "01704cdd"} AS filter_value

答:
For Postgres:</p>
```<code>select (select jsonb_object_agg(key, value)
        from jsonb_array_elements(t.filter) as x(item)
          cross join jsonb_each_text(x.item) as e(key,value)
        where e.value <> '')
from the_table t;
</code>```

Body:
I have a field called "filter" with json array like:

[
   {
      "after":"2021-10-14T00:00:00",
      "column":"createddate",
      "from":null,
      "gt":null,
      "gte":null,
      "id":"928d57b0",
      "lt":null,
      "lte":null,
      "not":null,
      "prior":null,
      "to":null,
      "value":null
   },
   {
      "after":null,
      "column":"last_coach_date",
      "from":"",
      "gt":null,
      "gte":null,
      "id":"01704cdd",
      "lt":null,
      "lte":null,
      "not":null,
      "prior":null,
      "to":"",
      "value":null
   }
]

I'm trying to extract key/value pairs where value is not null/blank and create another field for it.

Maybe to something like this or one long string:

 { "after": "2021-10-14T00:00:00", "column": "createddate", "id": "928d57b0"}, {"column": "last_coach_date","id": "01704cdd"} AS filter_value

Body:
For Postgres:

select (select jsonb_object_agg(key, value)
        from jsonb_array_elements(t.filter) as x(item)
          cross join jsonb_each_text(x.item) as e(key,value)
        where e.value <> '')
from the_table t;


问:
overflow-y or word-break nothing is working for HTML options tag
In my angular app dynamically I was creating options tag inside of select.

The HTML is somehow similar to this one.

<!DOCTYPE html>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>

<select size="10" name="ChangeProcessGroups"style="width: 200px; word-wrap: break-word">
  <option value="0: -1">Something long string. But it goes outside of the box</option>
</select>

```

Now browsing from chrome shows no problem as overflow-y is working properly. But the problem occurs while browsing it from firefox. Overflow, and word-break, none of the CSS properly working properly, and if options value is long enough then disappeared and can't see the full string value. What could be the possible solution for it?

答:
If you are willing to use the js library select2, then here is a working fiddle by Kyle Mitofsky.

var $select2 = $('.select2').select2({
  containerCssClass: "wrap"
})```
<pre class="snippet-code-css lang-css prettyprint-override"><code>.select2.narrow {
  width: 200px;
}

.wrap.select2-selection--single {
  height: 100%!important; /* Does not work without !important?? */
}

.select2-container .wrap.select2-selection--single .select2-selection__rendered {
  word-wrap: break-word;
  text-overflow: inherit;
  white-space: normal;
}</code>```

<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" rel="stylesheet" />

<select class="select2 narrow wrap">
  <option value="AL">Really long name that normally</option>
  <option value="AK">Alaska</option>
  <option value="AZ">Arizona</option>
</select>```

This works in webkit and moz browsers.

Body:
In my angular app dynamically I was creating options tag inside of select.

The HTML is somehow similar to this one.

<!DOCTYPE html>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>

<select size="10" name="ChangeProcessGroups"style="width: 200px; word-wrap: break-word">
  <option value="0: -1">Something long string. But it goes outside of the box</option>
</select>

Now browsing from chrome shows no problem as overflow-y is working properly. But the problem occurs while browsing it from firefox. Overflow, and word-break, none of the CSS properly working properly, and if options value is long enough then disappeared and can't see the full string value. What could be the possible solution for it?

Body:
If you are willing to use the js library select2, then here is a working fiddle by Kyle Mitofsky.

var $select2 = $('.select2').select2({
  containerCssClass: "wrap"
})

.select2.narrow {
  width: 200px;
}

.wrap.select2-selection--single {
  height: 100%!important; /* Does not work without !important?? */
}

.select2-container .wrap.select2-selection--single .select2-selection__rendered {
  word-wrap: break-word;
  text-overflow: inherit;
  white-space: normal;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.full.js"></script>

<select class="select2 narrow wrap">
  <option value="AL">Really long name that normally</option>
  <option value="AK">Alaska</option>
  <option value="AZ">Arizona</option>
</select>

This works in webkit and moz browsers.


问:
Can't use Selenium to find elements. Try to avoid deprecated commands warning, got result only one element. (on Colab)
As my title said. To avoid deprecated warning of Selenium.I try to use the new format as I found.
and somehow result return only 1 element. How can I fix it to return elements?
FYI I scraping website. I'm working on Colab so I can share with my workmates easier.

Here my code

```<code>#!pip install selenium
#!pip install IPython
#!pip install pandas
#!apt-get update
#!apt install chromium-chromedriver

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver',chrome_options=chrome_options)

import pandas as pd
from IPython.display import display
from selenium.webdriver.common.by import By
website = 'https://www.bitkub.com/fee/cryptocurrency'
driver.get(website)

#pull_data
coins = driver.find_elements(By.TAG_NAME,'tr')
</code>```

checking what element it contains (which somehow got only 1)

```<code>print(coins)
[<selenium.webdriver.remote.webelement.WebElement (session="091bac0ea46529043f4d84786ebc705f", element="76396e66-6516-4dd0-9d85-bc66bfad4676")>]

</code>```

答:
What is occuring is that you need webdriver waits and wait for visibility for all elements.

```<code>wait = WebDriverWait(driver, 10)
trs = wait.until(ec.visibility_of_all_elements_located((By.TAG_NAME, "tr")))
</code>```

Import:

```<code>from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
</code>```

Body:
As my title said. To avoid deprecated warning of Selenium.I try to use the new format as I found.
and somehow result return only 1 element. How can I fix it to return elements?
FYI I scraping website. I'm working on Colab so I can share with my workmates easier.

Here my code

#!pip install selenium
#!pip install IPython
#!pip install pandas
#!apt-get update
#!apt install chromium-chromedriver

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome('chromedriver',chrome_options=chrome_options)

import pandas as pd
from IPython.display import display
from selenium.webdriver.common.by import By
website = 'https://www.bitkub.com/fee/cryptocurrency'
driver.get(website)

#pull_data
coins = driver.find_elements(By.TAG_NAME,'tr')

checking what element it contains (which somehow got only 1)

print(coins)
[<selenium.webdriver.remote.webelement.WebElement (session="091bac0ea46529043f4d84786ebc705f", element="76396e66-6516-4dd0-9d85-bc66bfad4676")>]

Body:
What is occuring is that you need webdriver waits and wait for visibility for all elements.

wait = WebDriverWait(driver, 10)
trs = wait.until(ec.visibility_of_all_elements_located((By.TAG_NAME, "tr")))

Import:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec


问:
StreamWriter writes all data into obe Column in CSV
```<code>using (var stream = new MemoryStream())
            using (var writer = new StreamWriter(stream))
            using (var mailClient = client)

            using (var messagesd = msg)
            {

                foreach (DataColumn column in objDT.Columns)
                {
                    writer.WriteLine(column.ColumnName);
                }

                writer.WriteLine();

                for (int i = 0; i < objDT.Rows.Count; i++)
                {
                    DataRow row = objDT.Rows[i];

                    for (int j = 0; j < row.ItemArray.Length; j++)
                    {
                        if (row.ItemArray[j] != null && !Convert.IsDBNull(row.ItemArray[j]))
                        {
                            writer.Write(row.ItemArray[j].ToString());
                        }
                        else
                        {
                            writer.Write("");
                        }

                        if (j < row.ItemArray.Length - 1)
                        {
                            writer.Write(",");
                        }
                        else if (i < objDT.Rows.Count - 1)
                        {
                            writer.WriteLine();
                        }
                    }
                }
                writer.Flush();
                stream.Position = 0;

                messagesd.Attachments.Add(new Attachment(stream, "test.csv"));
                mailClient.Send(messagesd);
</code>```

I have 3 columns, but result I`m getting:

testATestBTestC

under single column
Result i want is TestA column 1, TestB column 2 and TestC column 3

Any help would be appreciated. Thank you.

答:
You should write a delimeter(,) after every value (header name or value) except last one. Use Writemethod to put values into a row and WriteLine to start a new row.

It is better to use existing libraries from Nuget. CSVHelperas example.

Body:
using (var stream = new MemoryStream())
            using (var writer = new StreamWriter(stream))
            using (var mailClient = client)

            using (var messagesd = msg)
            {

                foreach (DataColumn column in objDT.Columns)
                {
                    writer.WriteLine(column.ColumnName);
                }

                writer.WriteLine();

                for (int i = 0; i < objDT.Rows.Count; i++)
                {
                    DataRow row = objDT.Rows[i];

                    for (int j = 0; j < row.ItemArray.Length; j++)
                    {
                        if (row.ItemArray[j] != null && !Convert.IsDBNull(row.ItemArray[j]))
                        {
                            writer.Write(row.ItemArray[j].ToString());
                        }
                        else
                        {
                            writer.Write("");
                        }

                        if (j < row.ItemArray.Length - 1)
                        {
                            writer.Write(",");
                        }
                        else if (i < objDT.Rows.Count - 1)
                        {
                            writer.WriteLine();
                        }
                    }
                }
                writer.Flush();
                stream.Position = 0;

                messagesd.Attachments.Add(new Attachment(stream, "test.csv"));
                mailClient.Send(messagesd);

I have 3 columns, but result I`m getting:

testATestBTestC

under single column
Result i want is TestA column 1, TestB column 2 and TestC column 3

Any help would be appreciated. Thank you.