问:
Marshal Go Struct to BSON for mongoimport
I have a slice of structs that I want to write to a BSON file for doing a mongoimport.

This a rough idea of what I'm doing (using gopkg.in/mgo.v2/bson):

```<code>type Item struct {
    ID   string `bson:"_id"`
    Text string `bson:"text"`
}

items := []Item{
    {
        ID: "abc",
        Text: "def",
    },
    {
        ID: "uvw",
        Text: "xyz",
    },
}

file, err := bson.Marshal(items)
if err != nil {
    fmt.Printf("Failed to marshal BSON file: '%s'", err.Error())
}

if err := ioutil.WriteFile("test.bson", file, 0644); err != nil {
    fmt.Printf("Failed to write BSON file: '%s'", err.Error())
}
</code>```

This runs and generates the file, but it's not formatted correctly - instead it looks like this (using bsondump --pretty test.bson):

```<code>{
    "1": {
        "_id": "abc",
        "text": "def"
    },
    "2": {
        "_id": "abc",
        "text": "def"
    }
}
</code>```

When I think it should look more like:

```<code>{
    "_id": "abc",
    "text": "def"
{
}
    "_id": "abc",
    "text": "def"
}
</code>```

Is this possible to do in Go? I just want to generate a .bson file that you would expect a mongodump command to produce, so that I can run mongoimport and populate a colection.

答:
You want independent BSON documents, so marshal the items individually:

```<code>buf := &bytes.Buffer{}
for _, item := range items {
    data, err := bson.Marshal(item)
    if err != nil {
        fmt.Printf("Failed to marshal BSON item: '%v'", err)
    }
    buf.Write(data)
}

if err := ioutil.WriteFile("test.bson", buf.Bytes(), 0644); err != nil {
    fmt.Printf("Failed to write BSON file: '%v'", err)
}
</code>```

Running bsondump --pretty test.bson, the output will be:

```<code>{
        "_id": "abc",
        "text": "def"
}
{
        "_id": "uvw",
        "text": "xyz"
}
2022-02-09T10:23:44.886+0100    2 objects found
</code>```

Note that the buffer is not needed if you write directly to the file:

```<code>f, err := os.Create("test.bson")
if err != nil {
    log.Panicf("os.Create failed: %v", err)
}
defer f.Close()

for _, item := range items {
    data, err := bson.Marshal(item)
    if err != nil {
        log.Panicf("bson.Marshal failed: %v", err)
    }
    if _, err := f.Write(data); err != nil {
        log.Panicf("f.Write failed: %v", err)
    }
}
</code>```

Body:
I have a slice of structs that I want to write to a BSON file for doing a mongoimport.

This a rough idea of what I'm doing (using gopkg.in/mgo.v2/bson):

type Item struct {
    ID   string `bson:"_id"`
    Text string `bson:"text"`
}

items := []Item{
    {
        ID: "abc",
        Text: "def",
    },
    {
        ID: "uvw",
        Text: "xyz",
    },
}

file, err := bson.Marshal(items)
if err != nil {
    fmt.Printf("Failed to marshal BSON file: '%s'", err.Error())
}

if err := ioutil.WriteFile("test.bson", file, 0644); err != nil {
    fmt.Printf("Failed to write BSON file: '%s'", err.Error())
}

This runs and generates the file, but it's not formatted correctly - instead it looks like this (using bsondump --pretty test.bson):

{
    "1": {
        "_id": "abc",
        "text": "def"
    },
    "2": {
        "_id": "abc",
        "text": "def"
    }
}

When I think it should look more like:

{
    "_id": "abc",
    "text": "def"
{
}
    "_id": "abc",
    "text": "def"
}

Is this possible to do in Go? I just want to generate a .bson file that you would expect a mongodump command to produce, so that I can run mongoimport and populate a colection.

Body:
You want independent BSON documents, so marshal the items individually:

buf := &bytes.Buffer{}
for _, item := range items {
    data, err := bson.Marshal(item)
    if err != nil {
        fmt.Printf("Failed to marshal BSON item: '%v'", err)
    }
    buf.Write(data)
}

if err := ioutil.WriteFile("test.bson", buf.Bytes(), 0644); err != nil {
    fmt.Printf("Failed to write BSON file: '%v'", err)
}

Running bsondump --pretty test.bson, the output will be:

{
        "_id": "abc",
        "text": "def"
}
{
        "_id": "uvw",
        "text": "xyz"
}
2022-02-09T10:23:44.886+0100    2 objects found

Note that the buffer is not needed if you write directly to the file:

f, err := os.Create("test.bson")
if err != nil {
    log.Panicf("os.Create failed: %v", err)
}
defer f.Close()

for _, item := range items {
    data, err := bson.Marshal(item)
    if err != nil {
        log.Panicf("bson.Marshal failed: %v", err)
    }
    if _, err := f.Write(data); err != nil {
        log.Panicf("f.Write failed: %v", err)
    }
}


来源: stackexchange

问:
Java swing resize ImageIcon for different Windows Scaling settings
I am trying to create a small swing application using Zulu JDK 11. In the bottom right part of it I am having an image (logo). My problem is that the logo is displayed poorly when the user changes the scaling to a value greater than 100% (125%, 150%, 175% etc.)

Here is my source code.

Main class:

```<code>public class Main {

public static void main(String[] args) {
    FrameServer frameServer = new FrameServer();
    frameServer.setVisible(true);
}}
</code>```

FrameServer class:

public class FrameServer extends JFrame {

```<code>private JPanel contentPane;
private JPanel centerPane = new JPanel();
private JPanel southPane = new JPanel();
private JPanel rightPane = new JPanel();
private JButton btnOK = new JButton("OK");
private JTabbedPane jTabbedPane1 = new JTabbedPane();
private Tab1 tab1Page = new Tab1();
private Tab2 tab2Page = new Tab2();

public FrameServer() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    jbInit();
    pack();
    centerFrame();
    this.repaint();
}

private void jbInit() {
    setTitle("Test Scaling App");
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(new BorderLayout());
    centerPane.setLayout(new BorderLayout());
    centerPane.add(jTabbedPane1, BorderLayout.CENTER);
    southPane.setLayout(new BorderLayout());
    rightPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 5, 5));
    rightPane.add(btnOK);

    CustomStatusBar statusBar = new CustomStatusBar();
    southPane.add(statusBar, BorderLayout.CENTER);
    southPane.add(rightPane, BorderLayout.EAST);
    jTabbedPane1.addTab("Tab 1", tab1Page);
    jTabbedPane1.addTab("Tab 2", tab2Page);

    contentPane.add(centerPane, BorderLayout.CENTER);
    contentPane.add(southPane, BorderLayout.SOUTH);
}

private void centerFrame() {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = this.getSize();
    if (frameSize.height > screenSize.height) {
        frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
        frameSize.width = screenSize.width;
    }
    this.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
}

class Tab2 extends JScrollPane {
    public Tab2() {
        super(new JTextArea(10, 60));
        super.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        super.getViewport().setPreferredSize(new Dimension(500, 300));
    }

}

class Tab1 extends JPanel {
    public Tab1() {
        contentPane = this;
        JScrollPane centerScrollPane = new JScrollPane(new JTable());
        centerScrollPane.getViewport().setBackground(Color.white);
        JPanel eastPane = new JPanel();
        eastPane.setLayout(new FlowLayout());
        JPanel topPane = new JPanel();
        topPane.setLayout(new BoxLayout(topPane, BoxLayout.Y_AXIS));
        eastPane.add(topPane, FlowLayout.LEFT);
        contentPane.setLayout(new BorderLayout());
        contentPane.add(centerScrollPane, BorderLayout.CENTER);
        contentPane.add(eastPane, BorderLayout.EAST);
    }
}

class CustomStatusBar extends JPanel {
    JLabel label0 = new JLabel("", SwingConstants.CENTER);
    JLabel label1 = new JLabel();
    JLabel label2 = new JLabel();
    JLabel label3 = new JLabel("", SwingConstants.CENTER);
    JLabel labelLogo = new JLabel();
    private static final int HEIGHT = 21;

    public CustomStatusBar() {
        setCommonFeatures(label0, 40, "Stuff 0");
        setCommonFeatures(label1, 120, "Stuff 1");
        setCommonFeatures(label2, 120, "Stuff 2");
        setCommonFeatures(label3, 90, "Stuff 3");

        labelLogo.setFont(new java.awt.Font("Dialog", 3, 12));
        labelLogo.setForeground(Color.black);
        labelLogo.setBorder(BorderFactory.createLoweredBevelBorder());
        ImageIcon image = new ImageIcon("small.png");
        labelLogo.setIcon(image);

        labelLogo.setPreferredSize(new Dimension(40, HEIGHT));
        labelLogo.setHorizontalAlignment(SwingConstants.CENTER);

        setLayout(new GridBagLayout());
        setMaximumSize(new Dimension(800, 40));
        add(label0, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label1, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label2, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label3, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(labelLogo, new GridBagConstraints(4, 0, GridBagConstraints.REMAINDER, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));

    }

    private void setCommonFeatures(JLabel label, int width, String msg) {
        label.setBackground(UIManager.getColor("ScrollBar.track"));
        label.setForeground(Color.black);
        label.setBorder(BorderFactory.createLoweredBevelBorder());
        label.setPreferredSize(new Dimension(width, HEIGHT));
        label.setText(" " + msg);
    }
}}
</code>```

Small.png image file:

When opened at scaling 100%, it looks good:

But when changing the scaling to 175%:

the pixels start to show up (open link to the picture to see better)

Now, what I have done is to replace the logo with one with a higher resolution:

Now, I am struck as I do not know how to make it fit in the space available for it and display properly when scaled. If i redimension the image from the java code as seen here, it will display properly for 100%, but for 175% scaling the pixels become visible again, like using the small.png file.

Which is the correct way of solving this?
Thank you.

答:
The workaround is the following (only tested on Windows 10):

Locate the javaw.exe that the application is using (it very important to apply the following to javaw.exe, not java.exe)

Right click -> Properties -> Compatibility tab

Click button Change high DPI settings

Check Override high DPI scaling behavior. Scaling performed by: Select System in the combobox.

Press OK twice and restart the application

ContentLicense: CC BY-SA 4.0

Body:
I am trying to create a small swing application using Zulu JDK 11. In the bottom right part of it I am having an image (logo). My problem is that the logo is displayed poorly when the user changes the scaling to a value greater than 100% (125%, 150%, 175% etc.)

Here is my source code.

Main class:

public class Main {

public static void main(String[] args) {
    FrameServer frameServer = new FrameServer();
    frameServer.setVisible(true);
}}

FrameServer class:

public class FrameServer extends JFrame {

private JPanel contentPane;
private JPanel centerPane = new JPanel();
private JPanel southPane = new JPanel();
private JPanel rightPane = new JPanel();
private JButton btnOK = new JButton("OK");
private JTabbedPane jTabbedPane1 = new JTabbedPane();
private Tab1 tab1Page = new Tab1();
private Tab2 tab2Page = new Tab2();

public FrameServer() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    jbInit();
    pack();
    centerFrame();
    this.repaint();
}

private void jbInit() {
    setTitle("Test Scaling App");
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(new BorderLayout());
    centerPane.setLayout(new BorderLayout());
    centerPane.add(jTabbedPane1, BorderLayout.CENTER);
    southPane.setLayout(new BorderLayout());
    rightPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 5, 5));
    rightPane.add(btnOK);

    CustomStatusBar statusBar = new CustomStatusBar();
    southPane.add(statusBar, BorderLayout.CENTER);
    southPane.add(rightPane, BorderLayout.EAST);
    jTabbedPane1.addTab("Tab 1", tab1Page);
    jTabbedPane1.addTab("Tab 2", tab2Page);

    contentPane.add(centerPane, BorderLayout.CENTER);
    contentPane.add(southPane, BorderLayout.SOUTH);
}

private void centerFrame() {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = this.getSize();
    if (frameSize.height > screenSize.height) {
        frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
        frameSize.width = screenSize.width;
    }
    this.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
}

class Tab2 extends JScrollPane {
    public Tab2() {
        super(new JTextArea(10, 60));
        super.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        super.getViewport().setPreferredSize(new Dimension(500, 300));
    }

}

class Tab1 extends JPanel {
    public Tab1() {
        contentPane = this;
        JScrollPane centerScrollPane = new JScrollPane(new JTable());
        centerScrollPane.getViewport().setBackground(Color.white);
        JPanel eastPane = new JPanel();
        eastPane.setLayout(new FlowLayout());
        JPanel topPane = new JPanel();
        topPane.setLayout(new BoxLayout(topPane, BoxLayout.Y_AXIS));
        eastPane.add(topPane, FlowLayout.LEFT);
        contentPane.setLayout(new BorderLayout());
        contentPane.add(centerScrollPane, BorderLayout.CENTER);
        contentPane.add(eastPane, BorderLayout.EAST);
    }
}

class CustomStatusBar extends JPanel {
    JLabel label0 = new JLabel("", SwingConstants.CENTER);
    JLabel label1 = new JLabel();
    JLabel label2 = new JLabel();
    JLabel label3 = new JLabel("", SwingConstants.CENTER);
    JLabel labelLogo = new JLabel();
    private static final int HEIGHT = 21;

    public CustomStatusBar() {
        setCommonFeatures(label0, 40, "Stuff 0");
        setCommonFeatures(label1, 120, "Stuff 1");
        setCommonFeatures(label2, 120, "Stuff 2");
        setCommonFeatures(label3, 90, "Stuff 3");

        labelLogo.setFont(new java.awt.Font("Dialog", 3, 12));
        labelLogo.setForeground(Color.black);
        labelLogo.setBorder(BorderFactory.createLoweredBevelBorder());
        ImageIcon image = new ImageIcon("small.png");
        labelLogo.setIcon(image);

        labelLogo.setPreferredSize(new Dimension(40, HEIGHT));
        labelLogo.setHorizontalAlignment(SwingConstants.CENTER);

        setLayout(new GridBagLayout());
        setMaximumSize(new Dimension(800, 40));
        add(label0, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label1, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label2, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label3, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(labelLogo, new GridBagConstraints(4, 0, GridBagConstraints.REMAINDER, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));

    }

    private void setCommonFeatures(JLabel label, int width, String msg) {
        label.setBackground(UIManager.getColor("ScrollBar.track"));
        label.setForeground(Color.black);
        label.setBorder(BorderFactory.createLoweredBevelBorder());
        label.setPreferredSize(new Dimension(width, HEIGHT));
        label.setText(" " + msg);
    }
}}

Small.png image file:

When opened at scaling 100%, it looks good:

But when changing the scaling to 175%:

the pixels start to show up (open link to the picture to see better)

Now, what I have done is to replace the logo with one with a higher resolution:

Now, I am struck as I do not know how to make it fit in the space available for it and display properly when scaled. If i redimension the image from the java code as seen here, it will display properly for 100%, but for 175% scaling the pixels become visible again, like using the small.png file.

Which is the correct way of solving this?
Thank you.


问:
./node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.mjs Attempted import error: 'Picker' is not exported from 'selderee'
When I am going to import htmlToText package I am getting this error

```<code>import { htmlToText } from 'html-to-text';
</code>```

then I got this error

```<code>./node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.mjs
Attempted import error: 'Picker' is not exported from 'selderee'.
</code>```

答: In my case, my html-to-text version is 7.0.0</p>

Body:
When I am going to import htmlToText package I am getting this error

import { htmlToText } from 'html-to-text';

then I got this error

./node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.mjs
Attempted import error: 'Picker' is not exported from 'selderee'.


问:
Archiving table data into another table in Rails
I have a table in my db holding lots of data and search query takes time, so that i want to archive some old data into another table, I searched and found some gems and solutions to add column in the same table and make some sort of scopes in model but i want that old data to move another table as archived data. Is there any gem you guys know or way to deal with this issue ?

Thanks in advance :)

答:
I have a table with entries that are getting quite big. I looked at the model and realized that I only have belongs_to relationships on it. The implication is that I have no other tables with dependencies on the table I want to archive.

The entries are for calculating a user's balance over time and thus the balance is cached in the table over time. Which will be the main difficulty imo.

I'm thinking of creating a table and model ArchivedEntry with the same relationships.

Periodically, probably one time per year at my current rate of growth I will make rake task that migrates the old records.

I will create final record in the archived table and a new record in the main table that will be the balance transfer from the archived table to the existing table.

For the time being I'll be able to query the archived table but as it gets too big I am thinking of pulling the table out entirely and migrating it to a seperate service.

This will probably affect individual validations and all of the relationships will have to be looked at again. However, the data should stay relatively static and shouldn't need to change.

ContentLicense: CC BY-SA 3.0


问:
selecting second string point using js substring
i want to select a sting from the long para. it has number of dot('.')s. i want to trim the word from the second one, is it any way to do this?

example

```<code>var name = "one.two.three";
name.substring(0,name.indexOf('.'))
name.substring(0,name.lastIndexOf('.'))
</code>```

from above trimming in case if i use indexOf it gives first word (one), if i use lastIndex of it gives the word (three), but i need to select the second one, to get value as 'second'

how can i trim this using indexOf method? or to select multicombination strings like one.three or one.two, or two.three?

thanks in advance!

答:
Is that work for you ?</p>

```<code>var name = "one.two.three";
var params = name.split('.');
console.log(params[1]);
</code>```

Body:
i want to select a sting from the long para. it has number of dot('.')s. i want to trim the word from the second one, is it any way to do this?

example

var name = "one.two.three";
name.substring(0,name.indexOf('.'))
name.substring(0,name.lastIndexOf('.'))

from above trimming in case if i use indexOf it gives first word (one), if i use lastIndex of it gives the word (three), but i need to select the second one, to get value as 'second'

how can i trim this using indexOf method? or to select multicombination strings like one.three or one.two, or two.three?

thanks in advance!

Body:
Is that work for you ?

var name = "one.two.three";
var params = name.split('.');
console.log(params[1]);


问:
Updating Graph on Interval on React
I am getting data from my database to display it on the graph. Currently, I will have to refresh the page for the graph to update. I would like to refresh the graph in x interval as my data will be inserted at x interval. Am using ant design for the graph plotting. I am using a 'home' to display my graph and another class for my data fetching.

Home.js

```<code>export class Home extends Component {
  static displayName = Home.name;

  render () {
    return (
      <div>
        <h1>Dashboard</h1>
        <h2>
        <div className="site-card-wrapper">

      Graph1
      <Graph />}

  </div>
        </h2>
      </div>
    );
  }
}
</code>```

Temp.js

```<code>const TempGraph = () => {

 const [data, setData] = useState([]);

  useEffect(() => {
    asyncFetch();
  }, []);

  const asyncFetch = () => {
      fetch('link')
      .then((response) => response.json())
      .then((json) => setDatajson))
      .catch((error) => {
        console.log('fetch data failed', error);
      });
  };
    const config = {
        data,
        xField: 'time',
        yField: 'value',
        seriesField:'location',
        xAxis: {
          title: {
          text: 'Hours',
          }
        },
        yAxis:{
            title:{
            text: 'Temperature in °',
          }
        },

        meta: {
          time: {
            alias: 'hours',

          },
          value: {
            alias: 'temperature',
            max: 50,
          },
        },

      };
     return <Line {...config} />;
}
export default TempGraph;
</code>```

答:
You could just add a setInterval in your useEffect to grab the data and update them again. Don't forgot to clear the interval on return:

```<code>useEffect(() => {
   const interval = setInterval(() => asyncFetch(), 5000)
   return () => clearInterval(interval)
}, []}
</code>```

This example triggers every 5000ms, change the value according to your needs.

Title: Updating Graph on Interval on React

Body:
I am getting data from my database to display it on the graph. Currently, I will have to refresh the page for the graph to update. I would like to refresh the graph in x interval as my data will be inserted at x interval. Am using ant design for the graph plotting. I am using a 'home' to display my graph and another class for my data fetching.

Home.js

export class Home extends Component {
  static displayName = Home.name;

  render () {
    return (

Dashboard

      Graph1
      <Graph />}

    );
  }
}

Temp.js

const TempGraph = () => {

 const [data, setData] = useState([]);

  useEffect(() => {
    asyncFetch();
  }, []);

  const asyncFetch = () => {
      fetch('link')
      .then((response) => response.json())
      .then((json) => setDatajson))
      .catch((error) => {
        console.log('fetch data failed', error);
      });
  };
    const config = {
        data,
        xField: 'time',
        yField: 'value',
        seriesField:'location',
        xAxis: {
          title: {
          text: 'Hours',
          }
        },
        yAxis:{
            title:{
            text: 'Temperature in °',
          }
        },

        meta: {
          time: {
            alias: 'hours',

          },
          value: {
            alias: 'temperature',
            max: 50,
          },
        },

      };
     return <Line {...config} />;
}
export default TempGraph;

Body:
You could just add a setInterval in your useEffect to grab the data and update them again. Don't forgot to clear the interval on return:

useEffect(() => {
   const interval = setInterval(() => asyncFetch(), 5000)
   return () => clearInterval(interval)
}, []}

This example triggers every 5000ms, change the value according to your needs.


问:
Dayjs is not updating in vue v-for
In a component template I have the following code:

```<code><v-col cols="6" v-for="(value, idx) in data[workingYear].monthValues" :key="idx">
  {{ idx }}
  <v-row class="ai-center">
    <!-- Month -->
    <v-col cols="2">{{
      dayjs(idx + 1, "M").format("MMM").ucfirst()
    }}</v-col>
    <!-- Value -->
    <v-col cols="10">
      <v-text-field
        class="mt-0 pt-0"
        hide-details="auto"
        min="0"
        suffix=",00"
        type="number"
        v-model="data[workingYear].monthValues[idx]"
        :label="$t('set')"
        :prefix="getCurrency(true)"
        :ref="'monthValue' + idx"
        :rules="[rules.required, rules.invalid]"
      />
    </v-col>
  </v-row>
</v-col>
</code>```

data[workingYear].monthValues is initialized as new Array(12).fill("") so it is an array of 12 empty string elements; ucfirst() is a custom extension to String.prototype that capitalize the first char of a string.

I'm aspecting to find in the first v-col block an incremented month, but the result is the following:

So, why {{ idx }} is incremented for every cycle as aspected but the month is always January? How can I fix this?

答:
It seems that dayjs wants only strings as input date so write this is the solution:
dayjs("" + (idx + 1), "M").format("MMM").ucfirst()

By the way, at this point, the solution posted by Boussadjra Brahim is more elegant and readable, so +1 for the function.

Thanks

Title: Dayjs is not updating in vue v-for

Body:
In a component template I have the following code:

<v-col cols="6" v-for="(value, idx) in data[workingYear].monthValues" :key="idx">
  {{ idx }}
  <v-row class="ai-center">

    <v-col cols="2">{{
      dayjs(idx + 1, "M").format("MMM").ucfirst()
    }}</v-col>

    <v-col cols="10">
      <v-text-field
        class="mt-0 pt-0"
        hide-details="auto"
        min="0"
        suffix=",00"
        type="number"
        v-model="data[workingYear].monthValues[idx]"
        :label="$t('set')"
        :prefix="getCurrency(true)"
        :ref="'monthValue' + idx"
        :rules="[rules.required, rules.invalid]"
      />
    </v-col>
  </v-row>
</v-col>

data[workingYear].monthValues is initialized as new Array(12).fill("") so it is an array of 12 empty string elements; ucfirst() is a custom extension to String.prototype that capitalize the first char of a string.

I'm aspecting to find in the first v-col block an incremented month, but the result is the following:

So, why {{ idx }} is incremented for every cycle as aspected but the month is always January? How can I fix this?


问:
Add-Migration command has an error in my .NET 6 project
I have a project and created it using .NET 6.

I used the Add-Migration command before adding some DbSet in my DbContext, it worked correctly and made migration files for me.

Today add a new DbSet to my DbContext after that used the Add-Migration command but I get an error:

Unable to create an object of type 'HospitalNetDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

I get some information from this link but I can't solve my problem.

Some people suggested using contractor without parameter in DbContext class, but when I add this contractor to DbContext class and after that, I used the Add-Migration command, I get a new error:

No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.

After this error I added a new constructor same as below but my problem still persists:

```<code>public HospitalNetDbContext(DbContextOptions<HospitalNetDbContext> options) : base(options)
{
}
</code>```

More information about my project is connection string defined into the app settings file and in startup file using below code for set connection string to DbContext instead of add into overriding OnConfiguring method in the DbContext class.

```<code>services.AddDbContext<HospitalNetDbContext>(x => x.UseSqlServer(Configuration.GetConnectionString("HospitalNetDb")));
</code>```

答: In my projects I have 2 constructors in DbContext, one empty and one with DbContextOptions. Also checkout to override the OnConfiguring method in your DbContext.</p>

Body:
I have a project and created it using .NET 6.

I used the Add-Migration command before adding some DbSet in my DbContext, it worked correctly and made migration files for me.

Today add a new DbSet to my DbContext after that used the Add-Migration command but I get an error:

Unable to create an object of type 'HospitalNetDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

I get some information from this link but I can't solve my problem.

Some people suggested using contractor without parameter in DbContext class, but when I add this contractor to DbContext class and after that, I used the Add-Migration command, I get a new error:

No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.

After this error I added a new constructor same as below but my problem still persists:

public HospitalNetDbContext(DbContextOptions<HospitalNetDbContext> options) : base(options)
{
}

More information about my project is connection string defined into the app settings file and in startup file using below code for set connection string to DbContext instead of add into overriding OnConfiguring method in the DbContext class.

services.AddDbContext<HospitalNetDbContext>(x => x.UseSqlServer(Configuration.GetConnectionString("HospitalNetDb")));


问:
How to detect curves in a binary image?
I have a binary image, i want to detect/trace curves in that image. I don't know any thing (coordinates, angle etc). Can any one guide me how should i start? suppose i have this image

I want to separate out curves and other lines. I am only interested in curved lines and their parameters. I want to store information of curves (in array) to use afterward.

答:
Since you already seem to have a good binary image, it might be easiest to just separate the different connected components of the image and then calculate their parameters.

First, you can do the separation by scanning through the image, and when you encounter a black pixel you can apply a standard flood-fill algorithm to find out all the pixels in your shape. If you have matlab image toolbox, you can find use bwconncomp and bwselect procedures for this. If your shapes are not fully connected, you might apply a morphological closing operation to your image to connect the shapes.

After you have segmented out the different shapes, you can filter out the curves by testing how much they deviate from a line. You can do this simply by picking up the endpoints of the curve, and calculating how far the other points are from the line defined by the endpoints. If this value exceeds some maximum, you have a curve instead of a line.

Another approach would be to measure the ratio of the distance of the endpoints and length of the object. This ratio would be near 1 for lines and larger for curves and wiggly shapes.

If your images have angles, which you wish to separate from curves, you might inspect the directional gradient of your curves. Segment the shape, pick set of equidistant points from it and for each point, calculate the angle to the previous point and to the next point. If the difference of the angle is too high, you do not have a smooth curve, but some angled shape.

Possible difficulties in implementation include thick lines, which you can solve by skeleton transformation. For matlab implementation of skeleton and finding curve endpoints, see matlab image processing toolkit documentation

Title: How to detect curves in a binary image?


问:
React reset state after filtering with onClick
I have a basic app which simply returns a number of cards with some content inside, I have some buttons which then filter the returned cards by a value found in the dataset. The filter buttons do work indididually but if I click one after the other the filter is being applied to the now filtered data. How can I make sure the filter is being applied to the initial state of the data or how can I reset the state to everything before the filter is applied? Thanks.

parent.js

```<code>import './App.scss';
import DataThoughts from "./assets/data/DataThoughts";
import Thoughts from "./components/Thoughts";

function AppThoughts() {
    return (
        <div className="App">
            <main className={'bg-light'}>
                <div className={'container'}>
                    <Thoughts data={DataThoughts} />
                </div>
            </main>
        </div>
    );
}

export default AppThoughts;
</code>```

Thoughts.js

```<code>import React, { Component } from 'react';
import FilterButton from "./FilterButton";

class Thoughts extends Component {

    constructor(props) {
        super(props);
        this.state = {...props};
    }

    handleClick = value => () => {
        let filtered = this.state.data.filter(item => item.Emotion === value);
        this.setState({ data: filtered });
        console.log(this.state.data);
    };

    render() {

        let data = this.state.data;
        let numberOfThoughts = data.length;

        let dataList = this.state.data.map((thought, i) =>
            <div className={`col-12 col-sm-12 col-md-6 ${i % 2 === 0 ? i % 3 === 0 ? 'col-lg-3 col-xl-3' : 'col-lg-5 col-xl-5' : 'col-lg-4 col-xl-4'}`} key={'thought'+i}>
                <div className="card mb-4">
                    {thought.Photo ? <img src={thought.Photo} className="card-img-top" alt={thought.Emotion}/> : ''}
                    <div className="p-5">
                        <blockquote className="blockquote mb-0">
                            <p className={'small text-muted'}>{thought.Date}</p>
                            <p className={`${i % 2 === 0 ? i % 3 === 0 ? 'display-6' : 'display-4' : 'display-5'} mb-4`}>{thought.Thought}</p>
                            <footer className="small text-muted">{thought.Author}, <cite title="Source Title">{thought.Location}</cite></footer>
                        </blockquote>
                    </div>
                </div>
            </div>
        );

        return (
            <section className="row section-row justify-content-start thoughts">
                <div className={`col-12`} key={'filters'}>
                    <FilterButton buttonText={"Happy"} onClick={this.handleClick('Happy')} />
                    <FilterButton buttonText={"Sad"} onClick={this.handleClick('Sad')} />
                    <FilterButton buttonText={"Thinking"} onClick={this.handleClick('Thinking')} />
                    <FilterButton buttonText={"All"} onClick={this.handleClick('All')} />
                </div>
                {dataList}
                <div className={`col-12 col-sm-12 col-md-6 col-lg-2 col-xl-2 d-flex align-items-center justify-content-center`} key={'total'}>
                    <span className={'display-1'}>{numberOfThoughts}</span>
                </div>
            </section>
        );
    }
}

Thoughts.defaultProps = {
    Photo: '',
    Emotion:'Happy',
    Date:'Morning',
    Thought:'Default',
    Author:'Me',
    Location:'Somewhere'
};

export default Thoughts; // Don’t forget to use export default!
</code>```

FilterButtons.js

```<code>import React, { Component } from 'react';

class FilterButton extends Component {
    render() {
        return (
            <button className={'btn btn-primary d-inline-block mb-4'} onClick={this.props.onClick}>{this.props.buttonText}</button>
        );
    }
}

export default FilterButton; // Don’t forget to use export default!
</code>```

答:
It looks like the initial data comes from the props. You can access the props with this.props. So you can do something like this:

```<code>handleClick = value => () => {
    // filter the initial data
    let filtered = this.props.data.filter(item => item.Emotion === value);
    this.setState({ data: filtered });

    // set to initial data
    // this.setState({ ...this.props });
    console.log(this.state.data);
};
</code>```

Body:
I have a basic app which simply returns a number of cards with some content inside, I have some buttons which then filter the returned cards by a value found in the dataset. The filter buttons do work indididually but if I click one after the other the filter is being applied to the now filtered data. How can I make sure the filter is being applied to the initial state of the data or how can I reset the state to everything before the filter is applied? Thanks.

parent.js

import './App.scss';
import DataThoughts from "./assets/data/DataThoughts";
import Thoughts from "./components/Thoughts";

function AppThoughts() {
    return (

                    <Thoughts data={DataThoughts} />

    );
}

export default AppThoughts;

Thoughts.js

import React, { Component } from 'react';
import FilterButton from "./FilterButton";

class Thoughts extends Component {

    constructor(props) {
        super(props);
        this.state = {...props};
    }

    handleClick = value => () => {
        let filtered = this.state.data.filter(item => item.Emotion === value);
        this.setState({ data: filtered });
        console.log(this.state.data);
    };

    render() {

        let data = this.state.data;
        let numberOfThoughts = data.length;

        let dataList = this.state.data.map((thought, i) =>
            <div className={`col-12 col-sm-12 col-md-6 ${i % 2 === 0 ? i % 3 === 0 ? 'col-lg-3 col-xl-3' : 'col-lg-5 col-xl-5' : 'col-lg-4 col-xl-4'}`} key={'thought'+i}>

                    {thought.Photo ?  : ''}

{thought.Date}

                            <p className={`${i % 2 === 0 ? i % 3 === 0 ? 'display-6' : 'display-4' : 'display-5'} mb-4`}>{thought.Thought}

                            {thought.Author}, {thought.Location}

        );

        return (

                <div className={`col-12`} key={'filters'}>
                    <FilterButton buttonText={"Happy"} onClick={this.handleClick('Happy')} />
                    <FilterButton buttonText={"Sad"} onClick={this.handleClick('Sad')} />
                    <FilterButton buttonText={"Thinking"} onClick={this.handleClick('Thinking')} />
                    <FilterButton buttonText={"All"} onClick={this.handleClick('All')} />

                {dataList}
                <div className={`col-12 col-sm-12 col-md-6 col-lg-2 col-xl-2 d-flex align-items-center justify-content-center`} key={'total'}>
                    {numberOfThoughts}

        );
    }
}

Thoughts.defaultProps = {
    Photo: '',
    Emotion:'Happy',
    Date:'Morning',
    Thought:'Default',
    Author:'Me',
    Location:'Somewhere'
};

export default Thoughts; // Don’t forget to use export default!

FilterButtons.js

import React, { Component } from 'react';

class FilterButton extends Component {
    render() {
        return (
            <button className={'btn btn-primary d-inline-block mb-4'} onClick={this.props.onClick}>{this.props.buttonText}</button>
        );
    }
}

export default FilterButton; // Don’t forget to use export default!

Body:
It looks like the initial data comes from the props. You can access the props with this.props. So you can do something like this:

handleClick = value => () => {
    // filter the initial data
    let filtered = this.props.data.filter(item => item.Emotion === value);
    this.setState({ data: filtered });

    // set to initial data
    // this.setState({ ...this.props });
    console.log(this.state.data);
};


问:
increment of a pointer to the next array element
Recently, I found an interesting code snippet about array and pointers I didn't understand as a whole.

Here's the code:

```<code>void Function(int *B, int *A, int *C, int m)
{
   int i;
   A++;
   for(i = 0; i < m; i++, B++, A++, C++)
    *C=*B + *(A-1);
}

int main()
{
  int A[] = {3,6,2};
  int B[] = {5,7,9};
  int C[3];
  int n = 3;
  int i;

  Function(A,B,C,n);
  for(i = 0; i < n; i++)
  printf("%d ",C[i]);
  return 0;

}
</code>```

Okay, so, in the main, we have two arrays, variable n which we're forwarding to the function. *B, *A, *C are pointers to the first element of an array.
First, we have A++, which means that now, A shows on the second element of an array, which is 7. In the first for loop, i = 0, then *C(first element) = 3 + 5 = 8

Then, i = 1, B is now pointing on 6, A on 9.

Next, the second for loop looks like this:
*C(second element) = 6 + 7 = 13
Till this part, i understood. Now, i incremented to 2, B is showing on 2, but then, we have A++ again, but how A will increment when there is no other element in that array, it's blank basically? When i debugged, in third for loop, A will be 9(A-1), but again, not completely sure how that work.

答:
It's ok to increment a pointer to just past the last element in an array. With such a pointer, you can't dereference it or increment it again (it's undefined behavior).

C is very specific about what you can do with pointer arithmetic without causing undefined behavior, for example disallowing decrementing a pointer to before the first element of the array, or having the pointer increment after the array except for just after the final element. If you have a single object pointed to (rather than an array), it's treated as an array of length 1 for these rules.

Body:
Recently, I found an interesting code snippet about array and pointers I didn't understand as a whole.

Here's the code:

void Function(int *B, int *A, int *C, int m)
{
   int i;
   A++;
   for(i = 0; i < m; i++, B++, A++, C++)
    *C=*B + *(A-1);
}

int main()
{
  int A[] = {3,6,2};
  int B[] = {5,7,9};
  int C[3];
  int n = 3;
  int i;

  Function(A,B,C,n);
  for(i = 0; i < n; i++)
  printf("%d ",C[i]);
  return 0;

}

Okay, so, in the main, we have two arrays, variable n which we're forwarding to the function. *B, *A, *C are pointers to the first element of an array.
First, we have A++, which means that now, A shows on the second element of an array, which is 7. In the first for loop, i = 0, then *C(first element) = 3 + 5 = 8

Then, i = 1, B is now pointing on 6, A on 9.

Next, the second for loop looks like this:
*C(second element) = 6 + 7 = 13
Till this part, i understood. Now, i incremented to 2, B is showing on 2, but then, we have A++ again, but how A will increment when there is no other element in that array, it's blank basically? When i debugged, in third for loop, A will be 9(A-1), but again, not completely sure how that work.


问:
How to access ASP.NET Core web server from another device
I created a project using C# and ASP.NET Core empty and it worked on localhost - how can I access it from another device using the IP of the computer running the project?

答:
You need to configure kestrel to bind requests from 0.0.0.0 instead of localhost to accept requests from everywhere.

You can achieve this with different methods.

1- Run application with urls argument

dotnet app.dll --urls "http://0.0.0.0:5000;https://0.0.0.0:5001"

2- Add kestrel config to appsettings.json (Or any other way that you can inject value to IConfiguration)

```<code>{
 ...
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://0.0.0.0:5000"
      },
      "Https": {
        "Url": "https://0.0.0.0:5001"
      }
    }
  }
  ...
}
</code>```

3- Hard-code your binding in the program.cs file.

and the result should look like this

For complete details, please visit
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints

Body:
You need to configure kestrel to bind requests from 0.0.0.0 instead of localhost to accept requests from everywhere.

You can achieve this with different methods.

1- Run application with urls argument

dotnet app.dll --urls "http://0.0.0.0:5000;https://0.0.0.0:5001"

2- Add kestrel config to appsettings.json (Or any other way that you can inject value to IConfiguration)

{
 ...
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://0.0.0.0:5000"
      },
      "Https": {
        "Url": "https://0.0.0.0:5001"
      }
    }
  }
  ...
}

3- Hard-code your binding in the program.cs file.

and the result should look like this

For complete details, please visit
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints


问:
load spring application context from string
Can somebody show me how to use Spring to load application context through xml string instead of file or classpath resource?

Thanks,

答:
Use this:

```<code>String contextXML = ...;
Resource resource = new ByteArrayResource(contextXML.getBytes());
GenericXmlApplicationContext springContext = new GenericXmlApplicationContext();
springContext.load(resource);
Object myBean = springContext.getBean("myBean");
...
</code>```

Reza

ContentLicense: CC BY-SA 2.5

Body:
Use this:

String contextXML = ...;
Resource resource = new ByteArrayResource(contextXML.getBytes());
GenericXmlApplicationContext springContext = new GenericXmlApplicationContext();
springContext.load(resource);
Object myBean = springContext.getBean("myBean");
...

Reza


问:
Removing multiple headers in a single excel sheet
Similar to Remove header row in Excel using pandas

I wish to remove headers from an excel sheet.

Using the same example but edited:

```<code>Company ABC

Account Name 1
Account No.1
Description    group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
totals                               sum values

Account Name 2
Account No.2
Description    group     pair          amount    ...  result
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
totals                               sum values

Sales
00234
Description    group     pair          amount    ...  result
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
totals                               sum values

Inventory
00012345
Description    group     pair          amount    ...  result
value7         value7    value7        value7    ...  value7
value8         value8    value8        value8    ...  value8
value9         value9    value9        value9    ...  value9
totals                               sum values
</code>```

I wish to concatenate it to become like

```<code>cabinet_name   group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
value7         value7    value7        value7    ...  value7
value8         value8    value8        value8    ...  value8
value9         value9    value9        value9    ...  value9
</code>```

I've managed to remove the top header by skipping rows e.g.(skiprows = 4). However, This still leaves the other headers and totals which append like so:

```<code>cabinet_name   group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
totals                               sum values
Account Name 2
Account No.2
cabinet_name   group     pair          amount    ...  result
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
totals                               sum values
Sales
00234
Description    group     pair          amount    ...  result
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
totals                               sum values
Inventory
00012345
Description    group     pair          amount    ...  result
value7         value7    value7        value7    ...  value7
value8         value8    value8        value8    ...  value8
value9         value9    value9        value9    ...  value9
totals                               sum values
</code>```

Would be extremely grateful if someone could enlighten me on how to clean this sheet with pandas as all I've seen online are working on only 1 table in a single excel sheet.

Let me know if I've missed anything out, I would gladly edit this question.

I thought this might be useful,

My usual process for cleaning the files in excel, is to firstly delete the first 4 rows, only leaving

```<code>cabinet_name   group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
totals         *blank*   *blank*       sum values

Account Name 2
Account No.2
cabinet_name   group     pair          amount    ...  result
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
totals         *blank*   *blank*       sum values

Account Name 3
Account No.3
cabinet_name   group     pair          amount    ...  result
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
totals         *blank*   *blank*       sum values
</code>```

Then I will filter group or pair to look for blank values in said column and deleting it.

This is the result of

```<code>print(df_total.head(8).to_dict())
</code>```
```<code>import datetime
from numpy import nan
{'Date': {0: nan, 1: datetime.datetime(2021, 1, 1, 0, 0), 2: datetime.datetime(2021, 1, 1, 0, 0), 3: datetime.datetime(2021, 1, 29, 0, 0), 4: datetime.datetime(2021, 1, 31, 0, 0), 5:
'Totals', 6: 'Net difference', 7: nan},
'Journal number': {0: nan, 1: 'AX009473', 2: 'AX009473', 3: 'AX003312', 4: 'AX009641', 5: nan, 6: nan, 7: nan},
'Voucher': {0: nan, 1: 'TSPN-2021-3', 2: 'TSPN-2021-3', 3: 'GBJ-2021-1', 4: 'VIT-2021-1', 5: nan, 6: nan, 7: nan},
'Posting type': {0: nan, 1: nan, 2: nan, 3: 'Ledger journal', 4: 'Ledger journal', 5: nan, 6: nan, 7: nan},
'Ledger account': {0: nan, 1: '00388211', 2: '00388211', 3: '00388211', 4: '00388211', 5: nan, 6: nan, 7: nan},
'Description': {0: nan, 1: nan, 2: nan, 3: 'DISBERSMENT FOR PETROL', 4: 'TAXI FAIR', 5: nan, 6: nan, 7: nan},
'Unnamed: 6': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan},
'Unnamed: 7': {0: nan, 1: 'SGD', 2: 'USD', 3: 'SGD', 4: 'SGD', 5: nan, 6: nan, 7: nan},
'Amount in transaction currency': {0: 'Debit', 1: 13.55, 2: 0, 3: 0, 4: 5, 5: nan, 6: nan, 7: nan}, 'Unnamed: 9': {0: 'Credit', 1: 0, 2: 25, 3: 52, 4: 0, 5: nan, 6: nan, 7: nan},
'Amount in accounting currency': {0: 'Debit', 1: 13.55, 2: 0, 3: 0, 4: 5, 5: 18.55, 6: nan, 7: nan}, 'Unnamed: 11': {0: 'Credit', 1: 0, 2: 33.42, 3: 52, 4: 0, 5: 85.42, 6: 66.87, 7: nan},
'Amount in reporting currency': {0: 'Debit', 1: 13.55, 2: 0, 3: 0, 4: 5, 5: 18.55, 6: nan, 7: nan}, 'Unnamed: 13': {0: 'Credit', 1: 0, 2: 33.42, 3: 52, 4: 0, 5: 85.42, 6: nan, 7: nan},
'Unnamed: 14': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan}, 'Unnamed: 15': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan}, 'Unnamed: 16': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan}}
</code>```

Created a specimen excel of what I have

VS

An excel of transformed data

答:
So, we could rework the column names a bit by adding the first row to it (this corrects the wanted columns whose names start with "Unnamed"). Then filter out the column names that start with "Unnamed" (the remaining unwanted ones), then using "Date" column, create a mask and filter the DataFrame:

```<code>df = df.rename(columns={**{f'Unnamed: {i}': j for i,j in zip((9,11,13),
                                                             ('Amount in transaction currency',
                                                              'Amount in accounting currency',
                                                              'Amount in reporting currency'))},
                        **{'Unnamed: 7': 'Currency'}})

df.columns = [f'{col}_{first}' if first==first else col for col, first in zip(df.columns, df.loc[0])]
df = df[df.columns[~df.columns.str.startswith('Unnamed')]]
date_filter = df['Date'].apply(isinstance, args=(datetime.datetime,))
df = df[date_filter]
</code>```

The above code with an explicit loop to construct the list to modify column names:

```<code>cols = {'Unnamed: 7': 'Currency', 'Unnamed: 9': 'Amount in transaction currency',
        'Unnamed: 11': 'Amount in accounting currency', 'Unnamed: 13': 'Amount in reporting currency'}
df = df.rename(columns=cols)

another_cols = []
for col, first in zip(df.columns, df.loc[0]):
    if first==first:
        another_cols.append(f'{col}_{first}')
    else:
        another_cols.append(col)
df.columns = another_cols
df = df[df.columns[~df.columns.str.startswith('Unnamed')]]
date_filter = df['Date'].apply(isinstance, args=(datetime.datetime,))
df = df[date_filter]
</code>```

Output:

```<code>                  Date Journal number      Voucher    Posting type  \
1  2021-01-01 00:00:00       AX009473  TSPN-2021-3             NaN
2  2021-01-01 00:00:00       AX009473  TSPN-2021-3             NaN
3  2021-01-29 00:00:00       AX003312   GBJ-2021-1  Ledger journal
4  2021-01-31 00:00:00       AX009641   VIT-2021-1  Ledger journal

  Ledger account             Description Currency  \
1       00388211                     NaN      SGD
2       00388211                     NaN      USD
3       00388211  DISBERSMENT FOR PETROL      SGD
4       00388211               TAXI FAIR      SGD

  Amount in transaction currency_Debit Amount in transaction currency_Credit  \
1                                13.55                                     0
2                                    0                                    25
3                                    0                                    52
4                                    5                                     0

  Amount in accounting currency_Debit Amount in accounting currency_Credit  \
1                               13.55                                    0
2                                   0                                33.42
3                                   0                                   52
4                                   5                                    0

  Amount in reporting currency_Debit Amount in reporting currency_Credit
1                              13.55                                   0
2                                  0                               33.42
3                                  0                                  52
4                                  5                                   0
</code>```

Body:
Similar to Remove header row in Excel using pandas

I wish to remove headers from an excel sheet.

Using the same example but edited:

Company ABC

Account Name 1
Account No.1
Description    group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
totals                               sum values

Account Name 2
Account No.2
Description    group     pair          amount    ...  result
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
totals                               sum values

Sales
00234
Description    group     pair          amount    ...  result
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
totals                               sum values

Inventory
00012345
Description    group     pair          amount    ...  result
value7         value7    value7        value7    ...  value7
value8         value8    value8        value8    ...  value8
value9         value9    value9        value9    ...  value9
totals                               sum values

I wish to concatenate it to become like

cabinet_name   group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
value7         value7    value7        value7    ...  value7
value8         value8    value8        value8    ...  value8
value9         value9    value9        value9    ...  value9

I've managed to remove the top header by skipping rows e.g.(skiprows = 4). However, This still leaves the other headers and totals which append like so:

cabinet_name   group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
totals                               sum values
Account Name 2
Account No.2
cabinet_name   group     pair          amount    ...  result
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
totals                               sum values
Sales
00234
Description    group     pair          amount    ...  result
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
totals                               sum values
Inventory
00012345
Description    group     pair          amount    ...  result
value7         value7    value7        value7    ...  value7
value8         value8    value8        value8    ...  value8
value9         value9    value9        value9    ...  value9
totals                               sum values

Would be extremely grateful if someone could enlighten me on how to clean this sheet with pandas as all I've seen online are working on only 1 table in a single excel sheet.

Let me know if I've missed anything out, I would gladly edit this question.

I thought this might be useful,

My usual process for cleaning the files in excel, is to firstly delete the first 4 rows, only leaving

cabinet_name   group     pair          amount    ...  result
value1         value1    value1        value1    ...  value1
value2         value2    value2        value2    ...  value2
totals         *blank*   *blank*       sum values

Account Name 2
Account No.2
cabinet_name   group     pair          amount    ...  result
value3         value3    value3        value3    ...  value3
value4         value4    value4        value4    ...  value4
totals         *blank*   *blank*       sum values

Account Name 3
Account No.3
cabinet_name   group     pair          amount    ...  result
value5         value5    value5        value5    ...  value5
value6         value6    value6        value6    ...  value6
totals         *blank*   *blank*       sum values

Then I will filter group or pair to look for blank values in said column and deleting it.

This is the result of

print(df_total.head(8).to_dict())

import datetime
from numpy import nan
{'Date': {0: nan, 1: datetime.datetime(2021, 1, 1, 0, 0), 2: datetime.datetime(2021, 1, 1, 0, 0), 3: datetime.datetime(2021, 1, 29, 0, 0), 4: datetime.datetime(2021, 1, 31, 0, 0), 5:
'Totals', 6: 'Net difference', 7: nan},
'Journal number': {0: nan, 1: 'AX009473', 2: 'AX009473', 3: 'AX003312', 4: 'AX009641', 5: nan, 6: nan, 7: nan},
'Voucher': {0: nan, 1: 'TSPN-2021-3', 2: 'TSPN-2021-3', 3: 'GBJ-2021-1', 4: 'VIT-2021-1', 5: nan, 6: nan, 7: nan},
'Posting type': {0: nan, 1: nan, 2: nan, 3: 'Ledger journal', 4: 'Ledger journal', 5: nan, 6: nan, 7: nan},
'Ledger account': {0: nan, 1: '00388211', 2: '00388211', 3: '00388211', 4: '00388211', 5: nan, 6: nan, 7: nan},
'Description': {0: nan, 1: nan, 2: nan, 3: 'DISBERSMENT FOR PETROL', 4: 'TAXI FAIR', 5: nan, 6: nan, 7: nan},
'Unnamed: 6': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan},
'Unnamed: 7': {0: nan, 1: 'SGD', 2: 'USD', 3: 'SGD', 4: 'SGD', 5: nan, 6: nan, 7: nan},
'Amount in transaction currency': {0: 'Debit', 1: 13.55, 2: 0, 3: 0, 4: 5, 5: nan, 6: nan, 7: nan}, 'Unnamed: 9': {0: 'Credit', 1: 0, 2: 25, 3: 52, 4: 0, 5: nan, 6: nan, 7: nan},
'Amount in accounting currency': {0: 'Debit', 1: 13.55, 2: 0, 3: 0, 4: 5, 5: 18.55, 6: nan, 7: nan}, 'Unnamed: 11': {0: 'Credit', 1: 0, 2: 33.42, 3: 52, 4: 0, 5: 85.42, 6: 66.87, 7: nan},
'Amount in reporting currency': {0: 'Debit', 1: 13.55, 2: 0, 3: 0, 4: 5, 5: 18.55, 6: nan, 7: nan}, 'Unnamed: 13': {0: 'Credit', 1: 0, 2: 33.42, 3: 52, 4: 0, 5: 85.42, 6: nan, 7: nan},
'Unnamed: 14': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan}, 'Unnamed: 15': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan}, 'Unnamed: 16': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan, 5: nan, 6: nan, 7: nan}}

Created a specimen excel of what I have

VS

An excel of transformed data

Body:
So, we could rework the column names a bit by adding the first row to it (this corrects the wanted columns whose names start with "Unnamed"). Then filter out the column names that start with "Unnamed" (the remaining unwanted ones), then using "Date" column, create a mask and filter the DataFrame:

df = df.rename(columns={**{f'Unnamed: {i}': j for i,j in zip((9,11,13),
                                                             ('Amount in transaction currency',
                                                              'Amount in accounting currency',
                                                              'Amount in reporting currency'))},
                        **{'Unnamed: 7': 'Currency'}})

df.columns = [f'{col}_{first}' if first==first else col for col, first in zip(df.columns, df.loc[0])]
df = df[df.columns[~df.columns.str.startswith('Unnamed')]]
date_filter = df['Date'].apply(isinstance, args=(datetime.datetime,))
df = df[date_filter]

The above code with an explicit loop to construct the list to modify column names:

cols = {'Unnamed: 7': 'Currency', 'Unnamed: 9': 'Amount in transaction currency',
        'Unnamed: 11': 'Amount in accounting currency', 'Unnamed: 13': 'Amount in reporting currency'}
df = df.rename(columns=cols)

another_cols = []
for col, first in zip(df.columns, df.loc[0]):
    if first==first:
        another_cols.append(f'{col}_{first}')
    else:
        another_cols.append(col)
df.columns = another_cols
df = df[df.columns[~df.columns.str.startswith('Unnamed')]]
date_filter = df['Date'].apply(isinstance, args=(datetime.datetime,))
df = df[date_filter]

Output:

                  Date Journal number      Voucher    Posting type  \
1  2021-01-01 00:00:00       AX009473  TSPN-2021-3             NaN
2  2021-01-01 00:00:00       AX009473  TSPN-2021-3             NaN
3  2021-01-29 00:00:00       AX003312   GBJ-2021-1  Ledger journal
4  2021-01-31 00:00:00       AX009641   VIT-2021-1  Ledger journal

  Ledger account             Description Currency  \
1       00388211                     NaN      SGD
2       00388211                     NaN      USD
3       00388211  DISBERSMENT FOR PETROL      SGD
4       00388211               TAXI FAIR      SGD

  Amount in transaction currency_Debit Amount in transaction currency_Credit  \
1                                13.55                                     0
2                                    0                                    25
3                                    0                                    52
4                                    5                                     0

  Amount in accounting currency_Debit Amount in accounting currency_Credit  \
1                               13.55                                    0
2                                   0                                33.42
3                                   0                                   52
4                                   5                                    0

  Amount in reporting currency_Debit Amount in reporting currency_Credit
1                              13.55                                   0
2                                  0                               33.42
3                                  0                                  52
4                                  5                                   0


问:
NestJS stuck on File change detected. Starting incremental compilation
I'm having endpoint which is receiving file and store it in folder. However at the moment when add destination - where file to be stored and hit the endpoint server stuck and i receive this message: [17:54:47] File change detected. Starting incremental compilation...

This is how to controller looks like:

```<code>@ApiResponse({ type: CreateNFTRespDto })
  @ApiBody({ type: CreateNFTReqDto })
  @Post('upload')
  @UseInterceptors(FileInterceptor('file', {
    dest: './images'
  }))
  createNFT(
    @UploadedFile() file: Express.Multer.File,
    @Body() data: CreateNFTReqDto,
  ) {
    return this._nftService.createNFT(file, data);
  }
</code>```

Any idea why is not able to compile, I think i had similar issue with the firebase and the reason there was the package was very big or something like this, could be the same with the Multer or so?

答:
just add the file location folder in tsconfig.build.json as i did with 'media'</p>
```<code>"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "**/media"]
</code>```

Body:
I'm having endpoint which is receiving file and store it in folder. However at the moment when add destination - where file to be stored and hit the endpoint server stuck and i receive this message: [17:54:47] File change detected. Starting incremental compilation...

This is how to controller looks like:

@ApiResponse({ type: CreateNFTRespDto })
  @ApiBody({ type: CreateNFTReqDto })
  @Post('upload')
  @UseInterceptors(FileInterceptor('file', {
    dest: './images'
  }))
  createNFT(
    @UploadedFile() file: Express.Multer.File,
    @Body() data: CreateNFTReqDto,
  ) {
    return this._nftService.createNFT(file, data);
  }

Any idea why is not able to compile, I think i had similar issue with the firebase and the reason there was the package was very big or something like this, could be the same with the Multer or so?

Body:
just add the file location folder in tsconfig.build.json as i did with 'media'

"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "**/media"]


问:
Cart discount for product that cost less in WooCommerce unless that product is already on sale
I want to add a 30% discount on the cheapest item in the cart, except if it already has a discount.

Based on Cart discount for product that cost less in Woocommerce answer code, this is my code attempt:

add_action('woocommerce_cart_calculate_fees', 'discount_on_cheapest_cart_item', 20, 1 );
function discount_on_cheapest_cart_item( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // Only for 2 items or more
    if ( $cart->get_cart_contents_count() < 2 ) return;

    // Initialising
    $percentage = 50; // 10 %
    $discount = 0;
    $item_prices = array();

    // Loop though each cart items and set prices in an array
    foreach ( $cart->get_cart() as $cart_item ) {

        $product_prices_excl_tax[] = wc_get_price_excluding_tax( $cart_item['data'] );

    }

    sort($product_prices_excl_tax);

    if( ! $cart_item['data']->is_on_sale() ){
        $discount = reset($product_prices_excl_tax) * $percentage / 100;

        $cart->add_fee( "Discount on cheapest (".$percentage."%)", -$discount );
    }
}
```

Is there a way to make it work so if the product with the lowest price is not on sale, then apply a 30%, if it is on sale, don't. But this applies only to the lowest, if any other product is on sale, we skip it.

答:
The use of if( ! $cart_item['data']->is_on_sale() ) in your code attempt
will not be of any influence as this is used outside the foreach loop.

This anwer will apply a discount calculated on the basis of the product with the lowest price, this only if this product is not already on sale.

So you get:

function action_woocommerce_cart_calculate_fees( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // Only for 2 items or more
    if ( $cart->get_cart_contents_count() < 2 ) return;

    // Setting
    $percentage = 30; // 30 %

    // Initialize
    $discount = 0;
    $product_prices_on_sale = array();
    $product_prices_excl_tax = array();

    // Loop though each cart items and set prices in an array
    foreach ( $cart->get_cart() as $cart_item ) {
        // When cart contains a on sale product
        if ( $cart_item['data']->is_on_sale() ) {
            // On sale, push to on sale array
            $product_prices_on_sale[] = wc_get_price_excluding_tax( $cart_item['data'] );
        }

        // Push to excl tax array
        $product_prices_excl_tax[] = wc_get_price_excluding_tax( $cart_item['data'] );
    }

    // Sort an array in ascending order
    sort( $product_prices_on_sale );
    sort( $product_prices_excl_tax );

    // Set the internal pointer of an array to its first element
    $p_o_s = reset( $product_prices_on_sale );
    $p_e_t = reset( $product_prices_excl_tax );

    // NOT equal
    if ( $p_o_s != $p_e_t ) {
        // Calculate discount
        $discount = $p_e_t * $percentage / 100;

        // Apply discount (negative fee)
        $cart->add_fee( 'Discount on cheapest (' . $percentage . '%)', -$discount );
    }
}
add_action( 'woocommerce_cart_calculate_fees', 'action_woocommerce_cart_calculate_fees', 10, 1 );
```

Body:
I want to add a 30% discount on the cheapest item in the cart, except if it already has a discount.

Based on Cart discount for product that cost less in Woocommerce answer code, this is my code attempt:

add_action('woocommerce_cart_calculate_fees', 'discount_on_cheapest_cart_item', 20, 1 );
function discount_on_cheapest_cart_item( $cart ) {
    if ( is_admin() && ! defined( 'DOING_AJAX' ) )
        return;

    // Only for 2 items or more
    if ( $cart->get_cart_contents_count() < 2 ) return;

    // Initialising
    $percentage = 50; // 10 %
    $discount = 0;
    $item_prices = array();

    // Loop though each cart items and set prices in an array
    foreach ( $cart->get_cart() as $cart_item ) {

        $product_prices_excl_tax[] = wc_get_price_excluding_tax( $cart_item['data'] );

    }

    sort($product_prices_excl_tax);

    if( ! $cart_item['data']->is_on_sale() ){
        $discount = reset($product_prices_excl_tax) * $percentage / 100;

        $cart->add_fee( "Discount on cheapest (".$percentage."%)", -$discount );
    }
}

Is there a way to make it work so if the product with the lowest price is not on sale, then apply a 30%, if it is on sale, don't. But this applies only to the lowest, if any other product is on sale, we skip it.


问:
Lenses, the State monad, and Maps with known keys
here is a puzzle that I keep on bumping into and that, I believe, no previous SO question has been addressing: How can I best use the lens library to set or get values within a State monad managing a nested data structure that involves Maps when I know for a fact that certain keys are present in the maps involved?

Here is the puzzle

{-# LANGUAGE TemplateHaskell, DerivingVia #-}

import Control.Monad.State
import Control.Monad.Except
import Control.Lens
import Data.Maybe
import Control.Monad
import Data.Map

type M = StateT World (ExceptT String Identity)

data World = World
  { _users      :: Map UserId User
  , _otherStuff :: Int
  }

type UserId = Int

data User = User
  { _balance     :: Balance
  , _moreStuff   :: Int
  }

newtype Balance = Balance Int
  deriving (Eq, Ord, Num) via Int

makeLenses 'World
makeLenses 'User

deleteUser :: UserId -> M ()
deleteUser uid = do
   user <- use $ users . at uid
   unless (isJust user) (throwError "unknown user")

   -- from here on we know the users exists.

   -- Question: how should the following lens look like?
   balance <- use $ users . ix uid . balance
   when (balance < 0) (throwError "you first have to settle your debt")
   when (balance > 0) (throwError "you first have to withdraw the remaining balance")

   users . at uid .= Nothing
```
<h1>Attempt 1: using <code>ix</code></h1>
<p>The snippet above is using <code>ix</code>.</p>
<pre class="lang-hs prettyprint-override"><code>   balance <- use $ users . ix uid . balance
</code>```

This yields a Traversal, so it may focus on multiple elements or none at all. In the context of use this means we need a Monoid and a Semigroup instance. In fact, this is what GHC has to say:

```<code>    • No instance for (Monoid Balance) arising from a use of ‘ix’
    • In the first argument of ‘(.)’, namely ‘ix uid’
      In the second argument of ‘(.)’, namely ‘ix uid . balance’
      In the second argument of ‘($)’, namely ‘users . ix uid . balance’
   |
45 |    balance <- use $ users . ix uid . balance
</code>```

There is no good way to implement <> for Balance. I could just implement addition, or use error, because, in fact, this function will never be called. But is this the cleanest way to do this?

Attempt 2: using at

Another option seems to be using at.

   balance <- use $ users . at uid . balance
```
<p>This yields a <code>Lens</code> that focuses on a <code>Maybe User</code>. This means, the follow-up lens <code>balance</code> has the wrong type.</p>
```    • Couldn't match type ‘User’
                     with ‘Maybe (IxValue (Map UserId User))’
      Expected type: (User -> Const Balance User)
                     -> Map UserId User -> Const Balance (Map UserId User)
        Actual type: (Maybe (IxValue (Map UserId User))
                      -> Const Balance (Maybe (IxValue (Map UserId User))))
                     -> Map UserId User -> Const Balance (Map UserId User)
    • In the first argument of ‘(.)’, namely ‘at uid’
      In the second argument of ‘(.)’, namely ‘at uid . balance’
      In the second argument of ‘($)’, namely ‘users . at uid . balance’
```
<h1>Attempt 3: working with <code>at</code>'s <code>Maybe</code></h1>
<p>Let's try to work with that <code>Maybe</code></p>
<pre class="lang-hs prettyprint-override"><code>   balance <- use $ users . at uid . _Just . balance
</code>```

This time, we have a Prism, which needs to deal with the situation when it has to work with Nothing. So we are back at requiring a Monoid.

```<code>    • No instance for (Monoid Balance) arising from a use of ‘_Just’
    • In the first argument of ‘(.)’, namely ‘_Just’
      In the second argument of ‘(.)’, namely ‘_Just . balance’
      In the second argument of ‘(.)’, namely ‘at uid . _Just . balance’
</code>```

Attempt 3b: working with at's Maybe

Let's try another way to work with that Maybe

   balance <- use $ users . at uid . non undefined . balance
```
<p>From the documentation:</p>
<blockquote>
<p>If v is an element of a type a, and a' is a sans the element v, then non v is an isomorphism from Maybe a' to a.</p>
</blockquote>
<p>We can use <code>undefined</code>, <code>error</code> or any "empty" <code>User</code> we want, it does not matter, since this case is never triggered, given the user id is present in the map.</p>
<p>For this to work we need <code>Eq</code> for <code>User</code>, which is fair enough. And it compiles and seems to work; that is, for reading. For writing, there is an, initially, unexpected twist:</p>
<pre class="lang-hs prettyprint-override"><code>topUp :: UserId -> Balance -> M ()
topUp uid b = do
   user <- use $ users . at uid
   unless (isJust user) (throwError "unknown user")

   users . at uid . non undefined . balance += b
</code>```

Running this blows up

```<code>experiment-exe: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
  undefined, called at app/Main.hs:55:25 in main:Main
</code>```

The explanation is that when writing, we use the optics "right-to-left", and in this direction non is injecting the User we provide as its parameter. Replacing undefined with a "empty" User obscures this mistake. It always replaces the existing user with the empty user, effectively loosing the user's initial balance when trying to top-up.

Conclusion

So, I have found options to make this work for reading, but none seems to be convincing. And I could not figure this out for writing.

What is your recommendation? How should that lens be constructed?

Edit: moved solution to self answer.

答:
If you are sure that the key is present then you can use fromJust to turn the Maybe User into a User:

```<code>balance <- use $ users . at uid . to fromJust . balance
</code>```

Although as a design issue I'd suggest replacing use $ users . at uid ... with functions that throw a meaningful error:

```<code>getUser :: UserId -> M User
</code>```

And for handy lens accessing:

```<code>getsUser :: UserId -> Getter User a -> M a
</code>```

Then just call one of those every time you want to look up a user. That way you don't have to have a separate check at the head of your function.

Body:
here is a puzzle that I keep on bumping into and that, I believe, no previous SO question has been addressing: How can I best use the lens library to set or get values within a State monad managing a nested data structure that involves Maps when I know for a fact that certain keys are present in the maps involved?

Here is the puzzle

{-# LANGUAGE TemplateHaskell, DerivingVia #-}

import Control.Monad.State
import Control.Monad.Except
import Control.Lens
import Data.Maybe
import Control.Monad
import Data.Map

type M = StateT World (ExceptT String Identity)

data World = World
  { _users      :: Map UserId User
  , _otherStuff :: Int
  }

type UserId = Int

data User = User
  { _balance     :: Balance
  , _moreStuff   :: Int
  }

newtype Balance = Balance Int
  deriving (Eq, Ord, Num) via Int

makeLenses 'World
makeLenses 'User

deleteUser :: UserId -> M ()
deleteUser uid = do
   user <- use $ users . at uid
   unless (isJust user) (throwError "unknown user")

   -- from here on we know the users exists.

   -- Question: how should the following lens look like?
   balance <- use $ users . ix uid . balance
   when (balance < 0) (throwError "you first have to settle your debt")
   when (balance > 0) (throwError "you first have to withdraw the remaining balance")

   users . at uid .= Nothing

Attempt 1: using ix

The snippet above is using ix.

   balance <- use $ users . ix uid . balance

This yields a Traversal, so it may focus on multiple elements or none at all. In the context of use this means we need a Monoid and a Semigroup instance. In fact, this is what GHC has to say:

    • No instance for (Monoid Balance) arising from a use of ‘ix’
    • In the first argument of ‘(.)’, namely ‘ix uid’
      In the second argument of ‘(.)’, namely ‘ix uid . balance’
      In the second argument of ‘($)’, namely ‘users . ix uid . balance’
   |
45 |    balance <- use $ users . ix uid . balance

There is no good way to implement <> for Balance. I could just implement addition, or use error, because, in fact, this function will never be called. But is this the cleanest way to do this?

Attempt 2: using at

Another option seems to be using at.

   balance <- use $ users . at uid . balance

This yields a Lens that focuses on a Maybe User. This means, the follow-up lens balance has the wrong type.

    • Couldn't match type ‘User’
                     with ‘Maybe (IxValue (Map UserId User))’
      Expected type: (User -> Const Balance User)
                     -> Map UserId User -> Const Balance (Map UserId User)
        Actual type: (Maybe (IxValue (Map UserId User))
                      -> Const Balance (Maybe (IxValue (Map UserId User))))
                     -> Map UserId User -> Const Balance (Map UserId User)
    • In the first argument of ‘(.)’, namely ‘at uid’
      In the second argument of ‘(.)’, namely ‘at uid . balance’
      In the second argument of ‘($)’, namely ‘users . at uid . balance’

Attempt 3: working with at's Maybe

Let's try to work with that Maybe

   balance <- use $ users . at uid . _Just . balance

This time, we have a Prism, which needs to deal with the situation when it has to work with Nothing. So we are back at requiring a Monoid.

    • No instance for (Monoid Balance) arising from a use of ‘_Just’
    • In the first argument of ‘(.)’, namely ‘_Just’
      In the second argument of ‘(.)’, namely ‘_Just . balance’
      In the second argument of ‘(.)’, namely ‘at uid . _Just . balance’

Attempt 3b: working with at's Maybe

Let's try another way to work with that Maybe

   balance <- use $ users . at uid . non undefined . balance

From the documentation:

If v is an element of a type a, and a' is a sans the element v, then non v is an isomorphism from Maybe a' to a.

We can use undefined, error or any "empty" User we want, it does not matter, since this case is never triggered, given the user id is present in the map.

For this to work we need Eq for User, which is fair enough. And it compiles and seems to work; that is, for reading. For writing, there is an, initially, unexpected twist:

topUp :: UserId -> Balance -> M ()
topUp uid b = do
   user <- use $ users . at uid
   unless (isJust user) (throwError "unknown user")

   users . at uid . non undefined . balance += b

Running this blows up

experiment-exe: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:79:14 in base:GHC.Err
  undefined, called at app/Main.hs:55:25 in main:Main

The explanation is that when writing, we use the optics "right-to-left", and in this direction non is injecting the User we provide as its parameter. Replacing undefined with a "empty" User obscures this mistake. It always replaces the existing user with the empty user, effectively loosing the user's initial balance when trying to top-up.

Conclusion

So, I have found options to make this work for reading, but none seems to be convincing. And I could not figure this out for writing.

What is your recommendation? How should that lens be constructed?

Edit: moved solution to self answer.

Body:
If you are sure that the key is present then you can use fromJust to turn the Maybe User into a User:

balance <- use $ users . at uid . to fromJust . balance

Although as a design issue I'd suggest replacing use $ users . at uid ... with functions that throw a meaningful error:

getUser :: UserId -> M User

And for handy lens accessing:

getsUser :: UserId -> Getter User a -> M a

Then just call one of those every time you want to look up a user. That way you don't have to have a separate check at the head of your function.


问:
Why is the console coming out differently in useEffect?
I wanted to make sure that the scroll was located in the middle of the area in case of scrolling.

```<code>
const scrollRef = useScroll(null);

useEffect(() => {
    const wrapper = scrollRef.current;
    console.dir(wrapper, 'wrapper');
    if (wrapper) {
      const hasScroll = wrapper.scrollHeight > wrapper.clientHeight;
      console.log(wrapper.scrollHeight, 'scrollheight');
      console.log(wrapper.clientHeight, 'clientHeight');
      if (hasScroll) {
        const scrollTop = (wrapper.scrollHeight - wrapper.clientHeight) / 2;
        wrapper.scrollTop = scrollTop;
      }
    }
  }, [isLoading]);

if (isLoading) {
    return (
      <TradeSection>
        <Loader />
      </TradeSection>
    );
  }

<Section>
  <TableHeader>
  <TableList ref={scrollRef}>
    <List />
    <CurrentPrice />
    <List />
  </TableList>
<Section>
</code>```

This code works well in general.
but sometime it doesnt't work
According to my guess, if you refresh after the screen size changes,
so i add console in useEffect

why console.dir > scrollHeight is different result ?
Why do you show different values in the same area?

答:
Your useEffect is not updating when the current ref value changes. This means that your console log fires whenever isLoading updates, but does not capture the final value of scrollRef.current.

Putting something inside a useEffect is only helpful if the useEffect can actually keep track of changes to that value. Unfortunately, that is not possible with useRef because an object ref does not notify your component about changes to the current ref value. For this use case, the correct hook is actually useCallback; see this React FAQ answer for an explanation and a somewhat similar example.

Body:
I wanted to make sure that the scroll was located in the middle of the area in case of scrolling.

const scrollRef = useScroll(null);

useEffect(() => {
    const wrapper = scrollRef.current;
    console.dir(wrapper, 'wrapper');
    if (wrapper) {
      const hasScroll = wrapper.scrollHeight > wrapper.clientHeight;
      console.log(wrapper.scrollHeight, 'scrollheight');
      console.log(wrapper.clientHeight, 'clientHeight');
      if (hasScroll) {
        const scrollTop = (wrapper.scrollHeight - wrapper.clientHeight) / 2;
        wrapper.scrollTop = scrollTop;
      }
    }
  }, [isLoading]);

if (isLoading) {
    return (
      <TradeSection>
        <Loader />
      </TradeSection>
    );
  }

  <TableHeader>
  <TableList ref={scrollRef}>
    <List />
    <CurrentPrice />
    <List />
  </TableList>

This code works well in general.
but sometime it doesnt't work
According to my guess, if you refresh after the screen size changes,
so i add console in useEffect

why console.dir > scrollHeight is different result ?
Why do you show different values in the same area?


问:
Navbar disappears after scrollIntoView() use on mobile view
Problem: NavBar disappears after scrollIntoView() used on mobile view.

Related JS

```<code>function disableScroll() {
  window.addEventListener('DOMMouseScroll', preventDefault, false); // older FF
  window.addEventListener(wheelEvent, preventDefault, wheelOpt); // modern desktop
  window.addEventListener('touchmove', preventDefault, wheelOpt); // mobile
  window.addEventListener('keydown', preventDefaultForScrollKeys, false);
}

function enableScroll() {
  window.removeEventListener('DOMMouseScroll', preventDefault, false);
  window.removeEventListener(wheelEvent, preventDefault, wheelOpt);
  window.removeEventListener('touchmove', preventDefault, wheelOpt);
  window.removeEventListener('keydown', preventDefaultForScrollKeys, false);
}

function scroll_to_chapters() {
    const chapters = document.getElementsByClassName("chapter_list")[0];
    if (nav.classList.contains("nav-active")) {
        navLinks.forEach((link) => {
            if (link.style.animation) {
                link.style.animation = '';
            }
        });
        enableScroll();
        burger.classList.toggle('toggle');
        nav.classList.toggle('nav-active');
    }
    chapters.scrollIntoView({ block: 'start',  behavior: 'smooth' })
}

const navSlide = ()=> {
    burger.addEventListener('click', ()=> {
        //Toggle NavBar
        nav.classList.toggle('nav-active');
        //Animate Links
        navLinks.forEach((link, index)=> {
            if (link.style.animation) {
                enableScroll();
                link.style.animation = '';
            }
            else {
                disableScroll();
                link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 + 0.5}s`;
            }
        });
        burger.classList.toggle('toggle');
    });
}
</code>```

I'm not quite sure but there might be a problem with the disabling and enabling scrolling. I didn't want mobile users to be able to scroll while the navbar menus are opened.

Navbar HTML

```<code><div class="wrapper">
    <div class="fix">
        <header>
            <div class="container">
                <nav>
                <a href="/" data-attr="img"><img src="{% static 'img/northernlogo.png' %}" class="logo" alt="logo"></a>
                <ul class="nav-links">
                    <li><a href="/">Home</a></li>
                    <li><a href="/" onclick="scroll_to_chapters();return false;">Chapters</a></li>
                    <li><a href="/about">About</a></li>
                    <li><a href="/links">Links</a></li>
                </ul>
                <div class="burger">
                    <div class="line1"></div>
                    <div class="line2"></div>
                    <div class="line3"></div>
                </div>
                </nav>
            </div>
        </header>
    </div>
</div>
</code>```

Related CSS

```<code>.container {
    width: 100%;
    margin: 0 0;
}

.container::after {
    content: '';
    display: grid;
    clear: both;
}

.burger {
    display: none;
    margin-top: 20px;
    cursor: pointer;
}

.burger div {
    width: 25px;
    height: 3px;
    background: #EEEEEE;
    margin: 5px;
    transition: all 0.3s ease;
}

@media only screen and (max-width: 800px) {
    .wrapper {
        overflow: hidden;
        position: relative;
    }
    .nav-links {
        -webkit-box-shadow: inset 0 0.5em 1.5em -0.5em black;
        position: absolute;
        right: 0;
        height: 100%;
        top: 70px;
        background-color: #3a345c;
        z-index: 99;
        display: flex;
        flex-direction: column;
        align-items: center;
        width: 100%;
        transform: translateX(100%);
        transition: transform 0.5s ease-in;
    }
    .nav-links li {
        opacity: 0;
        padding-bottom: 50px;
        padding-top: 50px;
    }

    .nav-links li a {
        font-size: 20px;
        font-weight: bold;
    }

    .burger {
        display: block;
    }
}
</code>```

Picture of the Error

Before
After

How to Reproduce

Open the website on mobile view. Open the navbar from the home menu and click chapters. It'll take you to the chapters but now the navbar is gone.

Editor's note:

The accepted answer features a self-contained reproducible example.

答:
So you are using the body as overscroll and there is also a wrapper with the same height (and it's basically the same as the body) with an overscroll hidden.

Your menu you let slide in has a 100% height, so the bottom is at nav:height + 100%. I assume the scroll into view first scrolls the wrapper (as it overflows the nav:height) and then it scrolls the body. Making the nav-bar disappear, as the overflow is hidden.

You can fix this by adjusting the menu height to make it actually 100% in height: e.g. CSS: calc(100% - 70px) or using flex-box and let the menu flex:1.

Body:
Problem: NavBar disappears after scrollIntoView() used on mobile view.

Related JS

function disableScroll() {
  window.addEventListener('DOMMouseScroll', preventDefault, false); // older FF
  window.addEventListener(wheelEvent, preventDefault, wheelOpt); // modern desktop
  window.addEventListener('touchmove', preventDefault, wheelOpt); // mobile
  window.addEventListener('keydown', preventDefaultForScrollKeys, false);
}

function enableScroll() {
  window.removeEventListener('DOMMouseScroll', preventDefault, false);
  window.removeEventListener(wheelEvent, preventDefault, wheelOpt);
  window.removeEventListener('touchmove', preventDefault, wheelOpt);
  window.removeEventListener('keydown', preventDefaultForScrollKeys, false);
}

function scroll_to_chapters() {
    const chapters = document.getElementsByClassName("chapter_list")[0];
    if (nav.classList.contains("nav-active")) {
        navLinks.forEach((link) => {
            if (link.style.animation) {
                link.style.animation = '';
            }
        });
        enableScroll();
        burger.classList.toggle('toggle');
        nav.classList.toggle('nav-active');
    }
    chapters.scrollIntoView({ block: 'start',  behavior: 'smooth' })
}

const navSlide = ()=> {
    burger.addEventListener('click', ()=> {
        //Toggle NavBar
        nav.classList.toggle('nav-active');
        //Animate Links
        navLinks.forEach((link, index)=> {
            if (link.style.animation) {
                enableScroll();
                link.style.animation = '';
            }
            else {
                disableScroll();
                link.style.animation = `navLinkFade 0.5s ease forwards ${index / 7 + 0.5}s`;
            }
        });
        burger.classList.toggle('toggle');
    });
}

I'm not quite sure but there might be a problem with the disabling and enabling scrolling. I didn't want mobile users to be able to scroll while the navbar menus are opened.

Navbar HTML

Home

Chapters

About

Links

Related CSS

.container {
    width: 100%;
    margin: 0 0;
}

.container::after {
    content: '';
    display: grid;
    clear: both;
}

.burger {
    display: none;
    margin-top: 20px;
    cursor: pointer;
}

.burger div {
    width: 25px;
    height: 3px;
    background: #EEEEEE;
    margin: 5px;
    transition: all 0.3s ease;
}

@media only screen and (max-width: 800px) {
    .wrapper {
        overflow: hidden;
        position: relative;
    }
    .nav-links {
        -webkit-box-shadow: inset 0 0.5em 1.5em -0.5em black;
        position: absolute;
        right: 0;
        height: 100%;
        top: 70px;
        background-color: #3a345c;
        z-index: 99;
        display: flex;
        flex-direction: column;
        align-items: center;
        width: 100%;
        transform: translateX(100%);
        transition: transform 0.5s ease-in;
    }
    .nav-links li {
        opacity: 0;
        padding-bottom: 50px;
        padding-top: 50px;
    }

    .nav-links li a {
        font-size: 20px;
        font-weight: bold;
    }

    .burger {
        display: block;
    }
}

Picture of the Error

Before
After

How to Reproduce

Open the website on mobile view. Open the navbar from the home menu and click chapters. It'll take you to the chapters but now the navbar is gone.

Editor's note:

The accepted answer features a self-contained reproducible example.