问:
php replace specific words in a description with uppercase words and loop through it
Need to replace ALL present words within a string that tested against an array with the uppercase search words.

I am stuck with the right loop now.

My code:

```<code>   $array = [
        'weizen',
        'dinkel',
        'gerste',
        'khorasan',
        'eier',
        'haselnuss',
        'walnuss'];

   $description = "Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken."

foreach($array as $item) {
if (strpos($description, $item) !== false) {
   // $description;
 echo
 str_replace($item, mb_strtoupper($item), $description);
}
}
</code>```

Actual outcome:
"WEIZENbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und EIERn mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und Eiern mit WALNUSScreme und Haselnusspaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und HASELNUSSpaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit DINKELflocken.

Desired outcome:

WEIZENbrötchen auf HartWEIZENbasis und EIERn mit WALNUSScreme und HASELNUSSpaste sind leckerer mit DINKELflocken.

答:
Using array_map to convert your original array to uppercase and also to prepare patterns, then use preg_replace to do it:

```<code>$array = [
        'weizen',
        'dinkel',
        'gerste',
        'khorasan',
        'eier',
        'haselnuss',
        'walnuss'];

  $description = "Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken.";

  $replaces = array_map(function($v){ return strtoupper($v);}, $array);
  $patterns = array_map(function($v){ return '/'.$v.'/i';},$array);

  $str = preg_replace($patterns,$replaces,$description);

  echo $str;
</code>```

Body:
Need to replace ALL present words within a string that tested against an array with the uppercase search words.

I am stuck with the right loop now.

My code:

   $array = [
        'weizen',
        'dinkel',
        'gerste',
        'khorasan',
        'eier',
        'haselnuss',
        'walnuss'];

   $description = "Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken."

foreach($array as $item) {
if (strpos($description, $item) !== false) {
   // $description;
 echo
 str_replace($item, mb_strtoupper($item), $description);
}
}

Actual outcome:
"WEIZENbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und EIERn mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und Eiern mit WALNUSScreme und Haselnusspaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und HASELNUSSpaste sind leckerer mit Dinkelflocken.Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit DINKELflocken.

Desired outcome:

WEIZENbrötchen auf HartWEIZENbasis und EIERn mit WALNUSScreme und HASELNUSSpaste sind leckerer mit DINKELflocken.

Body:
Using array_map to convert your original array to uppercase and also to prepare patterns, then use preg_replace to do it:

$array = [
        'weizen',
        'dinkel',
        'gerste',
        'khorasan',
        'eier',
        'haselnuss',
        'walnuss'];

  $description = "Weizenbrötchen auf Hartweizenbasis und Eiern mit Walnusscreme und Haselnusspaste sind leckerer mit Dinkelflocken.";

  $replaces = array_map(function($v){ return strtoupper($v);}, $array);
  $patterns = array_map(function($v){ return '/'.$v.'/i';},$array);

  $str = preg_replace($patterns,$replaces,$description);

  echo $str;


来源: stackexchange

问:
Switching multiple bar positions javafx
I have a barchat with 5 bars, now I'm trying to move each bar from left to right based on high value (more like a bar chart race from flourish @ https://app.flourish.studio) not the same but the idea is the same.

To check small numbers against big numbers and big numbers against small numbers I'm using random integers.

For example, If barE is greater then all bars and less then barA, it should move to number 2 and replace bar B. I'm using the "if statement" to try and accomplish this. The problem is, only one transition is happening which is the first one. When random numbers change every 3 seconds the correct transition does not happen. Does anyone know how can I correct this problem?

```<code>
import java.util.Calendar;

import java.util.TimeZone;

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

import javafx.application.Application;

import javafx.application.Platform;

import javafx.beans.property.IntegerProperty;

import javafx.beans.property.SimpleIntegerProperty;

import javafx.beans.value.ChangeListener;

import javafx.geometry.Bounds;

import javafx.scene.Group;

import javafx.scene.Node;

import javafx.scene.Scene;

import javafx.scene.chart.BarChart;

import javafx.scene.chart.CategoryAxis;

import javafx.scene.chart.NumberAxis;

import javafx.scene.chart.XYChart;

import javafx.scene.chart.XYChart.Data;

import javafx.scene.text.Text;

import javafx.stage.Stage;

public class App extends Application {

    private ScheduledExecutorService scheduledExecutorService;

    final static String austria = "Austria",  brazil = "Brazil",  france = "France", england = "England", belgium = "Belgium";

    private IntegerProperty secondA,  secondB , secondC, secondD, secondE;

    private Text secondAText, secondBText , secondCText, secondDText, secondEText;

    @Override

    public void start(Stage primaryStage) throws Exception {

        primaryStage.setTitle("Realtime Bar Chart Demo");

        //defining the axes

        final CategoryAxis xAxis = new CategoryAxis();

        final NumberAxis yAxis = new NumberAxis();

        xAxis.setAnimated(false);

        yAxis.setAnimated(false);

        //creating the bar chart with two axis

        final BarChart<String,Number> bc =  new BarChart<>(xAxis,yAxis);

        bc.setAnimated(false);

        bc.setTitle("Country Summary");

        xAxis.setLabel("Country");

        yAxis.setLabel("Value");

        //defining a series to display data

        XYChart.Series<String, Number> seriesA = new XYChart.Series<>();

        Data<String, Number> dataA = new XYChart.Data<>(austria,0);

        seriesA.getData().add(dataA);

        seriesA.setName("Austra");

        secondA = new SimpleIntegerProperty(0);

        secondAText = new Text("");

        secondA.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataA.setYValue(newValue);

            secondAText.setText(String.valueOf(newValue));

        });

        XYChart.Series<String, Number> seriesB = new XYChart.Series<>();

        Data<String, Number> dataB = new XYChart.Data<>(brazil,0);

        seriesB.getData().add(dataB);

        seriesB.setName("Brazil");

        secondB =  new SimpleIntegerProperty(0);

        secondB.bind(secondA.add(0));

        secondBText = new Text("");

        secondB.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataB.setYValue(newValue);

            secondBText.setText(String.valueOf(newValue));

        });

        XYChart.Series<String, Number> seriesC = new XYChart.Series<>();

        Data<String, Number> dataC = new XYChart.Data<>(france,0);

        seriesC.getData().add(dataC);

        seriesC.setName("France");

        secondC =  new SimpleIntegerProperty(0);

        secondC.bind(secondA.add(0));

        secondCText = new Text("");

        secondC.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataC.setYValue(newValue);

            secondCText.setText(String.valueOf(newValue));

        });

XYChart.Series<String, Number> seriesD = new XYChart.Series<>();

        Data<String, Number> dataD = new XYChart.Data<>(england,0);

        seriesD.getData().add(dataD);

        seriesD.setName("England");

        secondD =  new SimpleIntegerProperty(0);

        secondD.bind(secondA.add(0));

        secondDText = new Text("");

        secondD.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataD.setYValue(newValue);

            secondDText.setText(String.valueOf(newValue));

        });

XYChart.Series<String, Number> seriesE = new XYChart.Series<>();

        Data<String, Number> dataE = new XYChart.Data<>(belgium,0);

        seriesE.getData().add(dataE);

        seriesE.setName("Belgium");

        secondE =  new SimpleIntegerProperty(0);

        secondE.bind(secondA.add(0));

        secondEText = new Text("");

        secondE.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataE.setYValue(newValue);

            secondEText.setText(String.valueOf(newValue));

        });

        // add series to chart

        bc.getData().add(seriesA);

        bc.getData().add(seriesB);

        bc.getData().add(seriesC);

        bc.getData().add(seriesD);

        bc.getData().add(seriesE);

        displayLabelForData(dataA, secondAText);

        displayLabelForData(dataB, secondBText);

        displayLabelForData(dataC, secondCText);

        displayLabelForData(dataD, secondDText);

        displayLabelForData(dataE, secondEText);

        // setup scene

        Scene scene = new Scene(bc, 800, 600);

        primaryStage.setScene(scene);

        // show the stage

        primaryStage.show();

        // setup a scheduled executor to periodically put data into the chart

        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        // input data onto graph per second        scheduledExecutorService.scheduleAtFixedRate(() -> {

            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

double posA = dataA.getNode().localToScene(dataA.getNode().getBoundsInLocal()).getMinX();

double posB = dataB.getNode().localToScene(dataB.getNode().getBoundsInLocal()).getMinX();

double posC = dataC.getNode().localToScene(dataC.getNode().getBoundsInLocal()).getMinX();

double posD = dataD.getNode().localToScene(dataD.getNode().getBoundsInLocal()).getMinX();

double posE = dataE.getNode().localToScene(dataE.getNode().getBoundsInLocal()).getMinX();

TranslateTransition ttA = new TranslateTransition(Duration.millis(2000), dataA.getNode());

TranslateTransition ttB = new TranslateTransition(Duration.millis(2000), dataB.getNode());

TranslateTransition ttC = new TranslateTransition(Duration.millis(2000), dataC.getNode());

TranslateTransition ttD = new TranslateTransition(Duration.millis(2000), dataD.getNode());

TranslateTransition ttE = new TranslateTransition(Duration.millis(2000), dataE.getNode());

//Genarate random numbers

Integer randomB = ThreadLocalRandom.current().nextInt(60);

Integer randomC = ThreadLocalRandom.current().nextInt(60);

Integer randomD = ThreadLocalRandom.current().nextInt(60);

Integer randomE = ThreadLocalRandom.current().nextInt(60);

int intSecondB = secondB.bind(secondA.add(randomB));

int intSecondC = secondC.bind(secondA.add(randomC));

int intSecondD = secondD.bind(secondA.add(randomD));

int intSecondE = secondE.bind(secondA.add(randomE));

</code>```

I'm not sure if the problem is with the below if statements or the code itself. To avoid the code for being more long, I only included if statements that compare only seriesB(barB) against other bars.

```<code>
//using if statement to swich each bar based on value

if (intSecondB >= intSecondA && intSecondB >= intSecondB && intSecondB >= intSecondC && intSecondB >= intSecondD && intSecondB >= intSecondE) {

double diffBA = posB - posA;

ttA.setByX(diffBA);

ttB.setByX(-diffBA);

ttA.setCycleCount(1);

    ttA.setAutoReverse(true);

    ttA.play();

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

}

if (intSecondB < intSecondA && intSecondB >= intSecondC && intSecondB >= intSecondD && intSecondB >= intSecondE) {

System.out.println("keep seriesB(barB) at its position");

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB >= intSecondD && intSecondB >= intSecondE) {

double diffCB = posC - posB;

ttB.setByX(diffCB);

ttC.setByX(-diffCB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttC.setCycleCount(1);

    ttC.setAutoReverse(true);

    ttC.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB >= intSecondE) {

double diffDB = posD - posB;

ttB.setByX(diffDB);

ttD.setByX(-diffDB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttD.setCycleCount(1);

    ttD.setAutoReverse(true);

    ttD.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffEB = posE - posB;

ttB.setByX(diffEB);

ttE.setByX(-diffEB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttE.setCycleCount(1);

    ttE.setAutoReverse(true);

    ttE.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffFB = posF - posB;

ttB.setByX(diffFB);

ttF.setByX(-diffFB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttF.setCycleCount(1);

    ttF.setAutoReverse(true);

    ttF.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffGB = posG - posB;

ttB.setByX(diffGB);

ttG.setByX(-diffGB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttG.setCycleCount(1);

    ttG.setAutoReverse(true);

    ttG.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffHB = posH - posB;

ttB.setByX(diffHB);

ttH.setByX(-diffHB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttH.setCycleCount(1);

    ttH.setAutoReverse(true);

    ttH.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffIB = posI - posB;

ttB.setByX(diffIB);

ttI.setByX(-diffIB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttI.setCycleCount(1);

    ttI.setAutoReverse(true);

    ttI.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffJB = posJ - posB;

ttB.setByX(diffJB);

ttJ.setByX(-diffJB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttJ.setCycleCount(1);

    ttJ.setAutoReverse(true);

    ttJ.play();

}

            // Update the chart

            Platform.runLater(() -> {

                secondA.set( cal.get(Calendar.SECOND));

            });

        }, 0, 3, TimeUnit.SECONDS);

    }

    @Override

    public void stop() throws Exception {

        super.stop();

        scheduledExecutorService.shutdownNow();

    }

    private void displayLabelForData(XYChart.Data<String, Number> data, Text text) {

        final Node node = data.getNode();

        ((Group) node.getParent()).getChildren().add(text);

      node.boundsInParentProperty().addListener((ChangeListener<Bounds>) (ov, oldBounds, bounds) -> {

            text.setLayoutX(

                    Math.round( bounds.getMinX() + bounds.getWidth() / 2 - text.prefWidth(-1) / 2));

            text.setLayoutY(Math.round( bounds.getMinY() - text.prefHeight(-1) * 0.5));

        });

    }

public static void main(String[] args) {

        launch(args);

    }

}

</code>```

Any help will be appreciated!

答:
Here is one strategy:

Create an ObservableList for the data

Create a SortedList from the underlying list

Register a listener with the SortedList, and when the data change, create an animation:

a. For each bar, find its current position and the position of the bar in the index corresponding to its new order

b. Use those positions to animate the translateX property of the bar

c. Animate the yValue property of the XYChart.Data in the same animation

d. At the end of the animation, reset the chart data to the new sorted data

There are a couple of little "gotchas" here: you need to turn off autoRanging on the CategoryAxis (else it will ignore changes to the order of the bars) and reset the categories using the new ordering when you update the data.

Here is an example. I created a class just to hold the data, without any chart API:

```<code>public static class CountryValue {
    private final String country ;
    private final double value ;
    public CountryValue(String country, double value) {
        super();
        this.country = country;
        this.value = value;
    }
    public String getCountry() {
        return country;
    }
    public double getValue() {
        return value;
    }

}
</code>```

and a simple data model to hold a list of these:

```<code>public static class Model {
    private final ObservableList<CountryValue> values ;

    public Model(CountryValue... countryValues) {
        values = FXCollections.observableArrayList(countryValues) ;
    }

    public ObservableList<CountryValue> getValues() {
        return values ;
    }

}
</code>```

Then the key parts look like:

```<code>    Model model = new Model() ;
    SortedList<CountryValue> sortedData = new SortedList<>(
            model.getValues(),
            Comparator.comparingDouble(CountryValue::getValue).reversed());

    ObservableList<XYChart.Data<String, Number>> chartData = FXCollections.observableArrayList();

    CategoryAxis countryAxis = new CategoryAxis();
    countryAxis.setAutoRanging(false);
    populateChartData(sortedData, chartData, countryAxis);

    sortedData.addListener((Change<? extends CountryValue> c) -> {

        Timeline timeline = new Timeline() ;

        for (int newIndex = 0 ; newIndex < sortedData.size() ; newIndex++) {

            CountryValue cv = sortedData.get(newIndex);
            int currentIndex = indexByCountry(cv.getCountry(), chartData);
            Data<String, Number> data = chartData.get(currentIndex);
            double currentX = data.getNode().getBoundsInParent().getCenterX();
            double targetX = chartData.get(newIndex).getNode().getBoundsInParent().getCenterX();
            DoubleProperty translateXProperty = data.getNode().translateXProperty();
            KeyValue kvx1 = new KeyValue(translateXProperty, 0);
            KeyValue kvx2 = new KeyValue(translateXProperty, targetX - currentX);
            ObjectProperty<Number> yValueProperty = data.YValueProperty();
            KeyValue kvy1 = new KeyValue(yValueProperty, data.getYValue());
            KeyValue kvy2 = new KeyValue(yValueProperty, cv.getValue());
            timeline.getKeyFrames().addAll(
                    new KeyFrame(Duration.ZERO, kvx1),
                    new KeyFrame(Duration.ZERO, kvy1),
                    new KeyFrame(animationDuration, kvx2),
                    new KeyFrame(animationDuration, kvy2)
            );
        }

        timeline.setOnFinished(e -> populateChartData(sortedData, chartData, countryAxis));

        timeline.play();
    });
</code>```

The utility populateChartData() method updates both the category axis and the data:

```<code>private void populateChartData(ObservableList<CountryValue> source,
        ObservableList<XYChart.Data<String, Number>> chartData,
        CategoryAxis countryAxis) {

    countryAxis.getCategories().setAll(
        source.stream()
            .map(CountryValue::getCountry)
            .collect(Collectors.toList())
    );

    chartData.setAll(
        source.stream()
            .map(cv -> new XYChart.Data<String, Number>(cv.getCountry(), cv.getValue()))
            .collect(Collectors.toList())
    );
}
</code>```

Here's a complete example. The animation is a little "jerky"; I think because the y-axis scale changes in an unpredictable way. You could manage this yourself by turning off autoranging on the y-axis, computing the max y value from the new data, and animating the y-axis range as well as the bars. Also note that it's important no updates to the data happen while the animation is running (else you'll end up with multiple animations running at once). Here that's simply managed by timing, but a more robust solution would check for that and either throttle updates or just end the current animation before starting a new one.

```<code>import java.util.Comparator;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 * JavaFX App
 */
public class FlourishChart extends Application {

    private final Duration animationDuration = Duration.millis(250);

    @Override
    public void start(Stage stage) {

        Model model = new Model() ;
        Simulator simulator = new Simulator(model);

        SortedList<CountryValue> sortedData = new SortedList<>(
                model.getValues(),
                Comparator.comparingDouble(CountryValue::getValue).reversed());

        ObservableList<XYChart.Data<String, Number>> chartData = FXCollections.observableArrayList();

        CategoryAxis countryAxis = new CategoryAxis();
        countryAxis.setAutoRanging(false);
        populateChartData(sortedData, chartData, countryAxis);

        BarChart<String, Number> chart = new BarChart<>(countryAxis, new NumberAxis());
        // turn off default animation:
        chart.setAnimated(false);
        Series<String, Number> series = new Series<>(chartData);
        chart.getData().add(series);

        // when sorted data change, animate bar chart nodes
        // at end of animation, update chart data with new data
        sortedData.addListener((Change<? extends CountryValue> c) -> {

            Timeline timeline = new Timeline() ;

            for (int newIndex = 0 ; newIndex < sortedData.size() ; newIndex++) {

                CountryValue cv = sortedData.get(newIndex);
                int currentIndex = indexByCountry(cv.getCountry(), chartData);
                Data<String, Number> data = chartData.get(currentIndex);
                double currentX = data.getNode().getBoundsInParent().getCenterX();
                double targetX = chartData.get(newIndex).getNode().getBoundsInParent().getCenterX();
                DoubleProperty translateXProperty = data.getNode().translateXProperty();
                KeyValue kvx1 = new KeyValue(translateXProperty, 0);
                KeyValue kvx2 = new KeyValue(translateXProperty, targetX - currentX);
                ObjectProperty<Number> yValueProperty = data.YValueProperty();
                KeyValue kvy1 = new KeyValue(yValueProperty, data.getYValue());
                KeyValue kvy2 = new KeyValue(yValueProperty, cv.getValue());
                timeline.getKeyFrames().addAll(
                        new KeyFrame(Duration.ZERO, kvx1),
                        new KeyFrame(Duration.ZERO, kvy1),
                        new KeyFrame(animationDuration, kvx2),
                        new KeyFrame(animationDuration, kvy2)
                );
            }

            timeline.setOnFinished(e -> populateChartData(sortedData, chartData, countryAxis));

            timeline.play();
        });

        BorderPane root = new BorderPane(chart);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();

        new Thread(simulator).start();
    }

    private int indexByCountry(String country, ObservableList<Data<String, Number>> chartData) {
        for (int index = 0 ; index < chartData.size(); index++) {
            if (chartData.get(index).getXValue().equals(country))
                return index ;
        }
        return -1 ;
    }

    private void populateChartData(ObservableList<CountryValue> source,
            ObservableList<XYChart.Data<String, Number>> chartData,
            CategoryAxis countryAxis) {

        countryAxis.getCategories().setAll(
            source.stream()
                .map(CountryValue::getCountry)
                .collect(Collectors.toList())
        );

        chartData.setAll(
            source.stream()
                .map(cv -> new XYChart.Data<String, Number>(cv.getCountry(), cv.getValue()))
                .collect(Collectors.toList())
        );
    }

    public static class Model {
        private final ObservableList<CountryValue> values ;

        public Model(CountryValue... countryValues) {
            values = FXCollections.observableArrayList(countryValues) ;
        }

        public ObservableList<CountryValue> getValues() {
            return values ;
        }

    }

    // replace with record when they are standard in Java:
    public static class CountryValue {
        private final String country ;
        private final double value ;
        public CountryValue(String country, double value) {
            super();
            this.country = country;
            this.value = value;
        }
        public String getCountry() {
            return country;
        }
        public double getValue() {
            return value;
        }

    }

    // Not really relevant to problem; just simulates changing data in model
    public class Simulator implements Runnable {

        private final Model model ;
        private final Random rng = new Random();

        public Simulator(Model model) {
            this.model = model ;
            createData();
        }

        @Override
        public void run() {
            for (int i = 0 ; i < 10 ; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                Platform.runLater(this::createData);
            }
        }

        private void createData() {
            model.getValues().setAll(
                Stream.of("Austria", "Brazil", "France", "England", "Belgium")
                    .map(country -> new CountryValue(country, 50 * rng.nextDouble() + 50))
                    .collect(Collectors.toList())
            );
        }
    }

    public static void main(String[] args) {
        launch();
    }

}
</code>```

ContentLicense: CC BY-SA 4.0

Title: Switching multiple bar positions javafx

Body:
I have a barchat with 5 bars, now I'm trying to move each bar from left to right based on high value (more like a bar chart race from flourish @ https://app.flourish.studio) not the same but the idea is the same.

To check small numbers against big numbers and big numbers against small numbers I'm using random integers.

For example, If barE is greater then all bars and less then barA, it should move to number 2 and replace bar B. I'm using the "if statement" to try and accomplish this. The problem is, only one transition is happening which is the first one. When random numbers change every 3 seconds the correct transition does not happen. Does anyone know how can I correct this problem?

import java.util.Calendar;

import java.util.TimeZone;

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

import javafx.application.Application;

import javafx.application.Platform;

import javafx.beans.property.IntegerProperty;

import javafx.beans.property.SimpleIntegerProperty;

import javafx.beans.value.ChangeListener;

import javafx.geometry.Bounds;

import javafx.scene.Group;

import javafx.scene.Node;

import javafx.scene.Scene;

import javafx.scene.chart.BarChart;

import javafx.scene.chart.CategoryAxis;

import javafx.scene.chart.NumberAxis;

import javafx.scene.chart.XYChart;

import javafx.scene.chart.XYChart.Data;

import javafx.scene.text.Text;

import javafx.stage.Stage;

public class App extends Application {

    private ScheduledExecutorService scheduledExecutorService;

    final static String austria = "Austria",  brazil = "Brazil",  france = "France", england = "England", belgium = "Belgium";

    private IntegerProperty secondA,  secondB , secondC, secondD, secondE;

    private Text secondAText, secondBText , secondCText, secondDText, secondEText;

    @Override

    public void start(Stage primaryStage) throws Exception {

        primaryStage.setTitle("Realtime Bar Chart Demo");

        //defining the axes

        final CategoryAxis xAxis = new CategoryAxis();

        final NumberAxis yAxis = new NumberAxis();

        xAxis.setAnimated(false);

        yAxis.setAnimated(false);

        //creating the bar chart with two axis

        final BarChart<String,Number> bc =  new BarChart<>(xAxis,yAxis);

        bc.setAnimated(false);

        bc.setTitle("Country Summary");

        xAxis.setLabel("Country");

        yAxis.setLabel("Value");

        //defining a series to display data

        XYChart.Series<String, Number> seriesA = new XYChart.Series<>();

        Data<String, Number> dataA = new XYChart.Data<>(austria,0);

        seriesA.getData().add(dataA);

        seriesA.setName("Austra");

        secondA = new SimpleIntegerProperty(0);

        secondAText = new Text("");

        secondA.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataA.setYValue(newValue);

            secondAText.setText(String.valueOf(newValue));

        });

        XYChart.Series<String, Number> seriesB = new XYChart.Series<>();

        Data<String, Number> dataB = new XYChart.Data<>(brazil,0);

        seriesB.getData().add(dataB);

        seriesB.setName("Brazil");

        secondB =  new SimpleIntegerProperty(0);

        secondB.bind(secondA.add(0));

        secondBText = new Text("");

        secondB.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataB.setYValue(newValue);

            secondBText.setText(String.valueOf(newValue));

        });

        XYChart.Series<String, Number> seriesC = new XYChart.Series<>();

        Data<String, Number> dataC = new XYChart.Data<>(france,0);

        seriesC.getData().add(dataC);

        seriesC.setName("France");

        secondC =  new SimpleIntegerProperty(0);

        secondC.bind(secondA.add(0));

        secondCText = new Text("");

        secondC.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataC.setYValue(newValue);

            secondCText.setText(String.valueOf(newValue));

        });

XYChart.Series<String, Number> seriesD = new XYChart.Series<>();

        Data<String, Number> dataD = new XYChart.Data<>(england,0);

        seriesD.getData().add(dataD);

        seriesD.setName("England");

        secondD =  new SimpleIntegerProperty(0);

        secondD.bind(secondA.add(0));

        secondDText = new Text("");

        secondD.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataD.setYValue(newValue);

            secondDText.setText(String.valueOf(newValue));

        });

XYChart.Series<String, Number> seriesE = new XYChart.Series<>();

        Data<String, Number> dataE = new XYChart.Data<>(belgium,0);

        seriesE.getData().add(dataE);

        seriesE.setName("Belgium");

        secondE =  new SimpleIntegerProperty(0);

        secondE.bind(secondA.add(0));

        secondEText = new Text("");

        secondE.addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {

            dataE.setYValue(newValue);

            secondEText.setText(String.valueOf(newValue));

        });

        // add series to chart

        bc.getData().add(seriesA);

        bc.getData().add(seriesB);

        bc.getData().add(seriesC);

        bc.getData().add(seriesD);

        bc.getData().add(seriesE);

        displayLabelForData(dataA, secondAText);

        displayLabelForData(dataB, secondBText);

        displayLabelForData(dataC, secondCText);

        displayLabelForData(dataD, secondDText);

        displayLabelForData(dataE, secondEText);

        // setup scene

        Scene scene = new Scene(bc, 800, 600);

        primaryStage.setScene(scene);

        // show the stage

        primaryStage.show();

        // setup a scheduled executor to periodically put data into the chart

        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

        // input data onto graph per second        scheduledExecutorService.scheduleAtFixedRate(() -> {

            Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

double posA = dataA.getNode().localToScene(dataA.getNode().getBoundsInLocal()).getMinX();

double posB = dataB.getNode().localToScene(dataB.getNode().getBoundsInLocal()).getMinX();

double posC = dataC.getNode().localToScene(dataC.getNode().getBoundsInLocal()).getMinX();

double posD = dataD.getNode().localToScene(dataD.getNode().getBoundsInLocal()).getMinX();

double posE = dataE.getNode().localToScene(dataE.getNode().getBoundsInLocal()).getMinX();

TranslateTransition ttA = new TranslateTransition(Duration.millis(2000), dataA.getNode());

TranslateTransition ttB = new TranslateTransition(Duration.millis(2000), dataB.getNode());

TranslateTransition ttC = new TranslateTransition(Duration.millis(2000), dataC.getNode());

TranslateTransition ttD = new TranslateTransition(Duration.millis(2000), dataD.getNode());

TranslateTransition ttE = new TranslateTransition(Duration.millis(2000), dataE.getNode());

//Genarate random numbers

Integer randomB = ThreadLocalRandom.current().nextInt(60);

Integer randomC = ThreadLocalRandom.current().nextInt(60);

Integer randomD = ThreadLocalRandom.current().nextInt(60);

Integer randomE = ThreadLocalRandom.current().nextInt(60);

int intSecondB = secondB.bind(secondA.add(randomB));

int intSecondC = secondC.bind(secondA.add(randomC));

int intSecondD = secondD.bind(secondA.add(randomD));

int intSecondE = secondE.bind(secondA.add(randomE));

I'm not sure if the problem is with the below if statements or the code itself. To avoid the code for being more long, I only included if statements that compare only seriesB(barB) against other bars.

//using if statement to swich each bar based on value

if (intSecondB >= intSecondA && intSecondB >= intSecondB && intSecondB >= intSecondC && intSecondB >= intSecondD && intSecondB >= intSecondE) {

double diffBA = posB - posA;

ttA.setByX(diffBA);

ttB.setByX(-diffBA);

ttA.setCycleCount(1);

    ttA.setAutoReverse(true);

    ttA.play();

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

}

if (intSecondB < intSecondA && intSecondB >= intSecondC && intSecondB >= intSecondD && intSecondB >= intSecondE) {

System.out.println("keep seriesB(barB) at its position");

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB >= intSecondD && intSecondB >= intSecondE) {

double diffCB = posC - posB;

ttB.setByX(diffCB);

ttC.setByX(-diffCB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttC.setCycleCount(1);

    ttC.setAutoReverse(true);

    ttC.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB >= intSecondE) {

double diffDB = posD - posB;

ttB.setByX(diffDB);

ttD.setByX(-diffDB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttD.setCycleCount(1);

    ttD.setAutoReverse(true);

    ttD.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffEB = posE - posB;

ttB.setByX(diffEB);

ttE.setByX(-diffEB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttE.setCycleCount(1);

    ttE.setAutoReverse(true);

    ttE.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffFB = posF - posB;

ttB.setByX(diffFB);

ttF.setByX(-diffFB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttF.setCycleCount(1);

    ttF.setAutoReverse(true);

    ttF.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffGB = posG - posB;

ttB.setByX(diffGB);

ttG.setByX(-diffGB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttG.setCycleCount(1);

    ttG.setAutoReverse(true);

    ttG.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffHB = posH - posB;

ttB.setByX(diffHB);

ttH.setByX(-diffHB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttH.setCycleCount(1);

    ttH.setAutoReverse(true);

    ttH.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffIB = posI - posB;

ttB.setByX(diffIB);

ttI.setByX(-diffIB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttI.setCycleCount(1);

    ttI.setAutoReverse(true);

    ttI.play();

}

if (intSecondB < intSecondA && intSecondB < intSecondC && intSecondB < intSecondD && intSecondB < intSecondE) {

double diffJB = posJ - posB;

ttB.setByX(diffJB);

ttJ.setByX(-diffJB);

ttB.setCycleCount(1);

    ttB.setAutoReverse(true);

    ttB.play();

ttJ.setCycleCount(1);

    ttJ.setAutoReverse(true);

    ttJ.play();

}

            // Update the chart

            Platform.runLater(() -> {

                secondA.set( cal.get(Calendar.SECOND));

            });

        }, 0, 3, TimeUnit.SECONDS);

    }

    @Override

    public void stop() throws Exception {

        super.stop();

        scheduledExecutorService.shutdownNow();

    }

    private void displayLabelForData(XYChart.Data<String, Number> data, Text text) {

        final Node node = data.getNode();

        ((Group) node.getParent()).getChildren().add(text);

      node.boundsInParentProperty().addListener((ChangeListener<Bounds>) (ov, oldBounds, bounds) -> {

            text.setLayoutX(

                    Math.round( bounds.getMinX() + bounds.getWidth() / 2 - text.prefWidth(-1) / 2));

            text.setLayoutY(Math.round( bounds.getMinY() - text.prefHeight(-1) * 0.5));

        });

    }

public static void main(String[] args) {

        launch(args);

    }

}

Any help will be appreciated!

Body:
Here is one strategy:

Create an ObservableList for the data

Create a SortedList from the underlying list

Register a listener with the SortedList, and when the data change, create an animation:

a. For each bar, find its current position and the position of the bar in the index corresponding to its new order

b. Use those positions to animate the translateX property of the bar

c. Animate the yValue property of the XYChart.Data in the same animation

d. At the end of the animation, reset the chart data to the new sorted data

There are a couple of little "gotchas" here: you need to turn off autoRanging on the CategoryAxis (else it will ignore changes to the order of the bars) and reset the categories using the new ordering when you update the data.

Here is an example. I created a class just to hold the data, without any chart API:

public static class CountryValue {
    private final String country ;
    private final double value ;
    public CountryValue(String country, double value) {
        super();
        this.country = country;
        this.value = value;
    }
    public String getCountry() {
        return country;
    }
    public double getValue() {
        return value;
    }

}

and a simple data model to hold a list of these:

public static class Model {
    private final ObservableList<CountryValue> values ;

    public Model(CountryValue... countryValues) {
        values = FXCollections.observableArrayList(countryValues) ;
    }

    public ObservableList<CountryValue> getValues() {
        return values ;
    }

}

Then the key parts look like:

    Model model = new Model() ;
    SortedList<CountryValue> sortedData = new SortedList<>(
            model.getValues(),
            Comparator.comparingDouble(CountryValue::getValue).reversed());

    ObservableList<XYChart.Data<String, Number>> chartData = FXCollections.observableArrayList();

    CategoryAxis countryAxis = new CategoryAxis();
    countryAxis.setAutoRanging(false);
    populateChartData(sortedData, chartData, countryAxis);

    sortedData.addListener((Change<? extends CountryValue> c) -> {

        Timeline timeline = new Timeline() ;

        for (int newIndex = 0 ; newIndex < sortedData.size() ; newIndex++) {

            CountryValue cv = sortedData.get(newIndex);
            int currentIndex = indexByCountry(cv.getCountry(), chartData);
            Data<String, Number> data = chartData.get(currentIndex);
            double currentX = data.getNode().getBoundsInParent().getCenterX();
            double targetX = chartData.get(newIndex).getNode().getBoundsInParent().getCenterX();
            DoubleProperty translateXProperty = data.getNode().translateXProperty();
            KeyValue kvx1 = new KeyValue(translateXProperty, 0);
            KeyValue kvx2 = new KeyValue(translateXProperty, targetX - currentX);
            ObjectProperty<Number> yValueProperty = data.YValueProperty();
            KeyValue kvy1 = new KeyValue(yValueProperty, data.getYValue());
            KeyValue kvy2 = new KeyValue(yValueProperty, cv.getValue());
            timeline.getKeyFrames().addAll(
                    new KeyFrame(Duration.ZERO, kvx1),
                    new KeyFrame(Duration.ZERO, kvy1),
                    new KeyFrame(animationDuration, kvx2),
                    new KeyFrame(animationDuration, kvy2)
            );
        }

        timeline.setOnFinished(e -> populateChartData(sortedData, chartData, countryAxis));

        timeline.play();
    });

The utility populateChartData() method updates both the category axis and the data:

private void populateChartData(ObservableList<CountryValue> source,
        ObservableList<XYChart.Data<String, Number>> chartData,
        CategoryAxis countryAxis) {

    countryAxis.getCategories().setAll(
        source.stream()
            .map(CountryValue::getCountry)
            .collect(Collectors.toList())
    );

    chartData.setAll(
        source.stream()
            .map(cv -> new XYChart.Data<String, Number>(cv.getCountry(), cv.getValue()))
            .collect(Collectors.toList())
    );
}

Here's a complete example. The animation is a little "jerky"; I think because the y-axis scale changes in an unpredictable way. You could manage this yourself by turning off autoranging on the y-axis, computing the max y value from the new data, and animating the y-axis range as well as the bars. Also note that it's important no updates to the data happen while the animation is running (else you'll end up with multiple animations running at once). Here that's simply managed by timing, but a more robust solution would check for that and either throttle updates or just end the current animation before starting a new one.

import java.util.Comparator;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
 * JavaFX App
 */
public class FlourishChart extends Application {

    private final Duration animationDuration = Duration.millis(250);

    @Override
    public void start(Stage stage) {

        Model model = new Model() ;
        Simulator simulator = new Simulator(model);

        SortedList<CountryValue> sortedData = new SortedList<>(
                model.getValues(),
                Comparator.comparingDouble(CountryValue::getValue).reversed());

        ObservableList<XYChart.Data<String, Number>> chartData = FXCollections.observableArrayList();

        CategoryAxis countryAxis = new CategoryAxis();
        countryAxis.setAutoRanging(false);
        populateChartData(sortedData, chartData, countryAxis);

        BarChart<String, Number> chart = new BarChart<>(countryAxis, new NumberAxis());
        // turn off default animation:
        chart.setAnimated(false);
        Series<String, Number> series = new Series<>(chartData);
        chart.getData().add(series);

        // when sorted data change, animate bar chart nodes
        // at end of animation, update chart data with new data
        sortedData.addListener((Change<? extends CountryValue> c) -> {

            Timeline timeline = new Timeline() ;

            for (int newIndex = 0 ; newIndex < sortedData.size() ; newIndex++) {

                CountryValue cv = sortedData.get(newIndex);
                int currentIndex = indexByCountry(cv.getCountry(), chartData);
                Data<String, Number> data = chartData.get(currentIndex);
                double currentX = data.getNode().getBoundsInParent().getCenterX();
                double targetX = chartData.get(newIndex).getNode().getBoundsInParent().getCenterX();
                DoubleProperty translateXProperty = data.getNode().translateXProperty();
                KeyValue kvx1 = new KeyValue(translateXProperty, 0);
                KeyValue kvx2 = new KeyValue(translateXProperty, targetX - currentX);
                ObjectProperty<Number> yValueProperty = data.YValueProperty();
                KeyValue kvy1 = new KeyValue(yValueProperty, data.getYValue());
                KeyValue kvy2 = new KeyValue(yValueProperty, cv.getValue());
                timeline.getKeyFrames().addAll(
                        new KeyFrame(Duration.ZERO, kvx1),
                        new KeyFrame(Duration.ZERO, kvy1),
                        new KeyFrame(animationDuration, kvx2),
                        new KeyFrame(animationDuration, kvy2)
                );
            }

            timeline.setOnFinished(e -> populateChartData(sortedData, chartData, countryAxis));

            timeline.play();
        });

        BorderPane root = new BorderPane(chart);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();

        new Thread(simulator).start();
    }

    private int indexByCountry(String country, ObservableList<Data<String, Number>> chartData) {
        for (int index = 0 ; index < chartData.size(); index++) {
            if (chartData.get(index).getXValue().equals(country))
                return index ;
        }
        return -1 ;
    }

    private void populateChartData(ObservableList<CountryValue> source,
            ObservableList<XYChart.Data<String, Number>> chartData,
            CategoryAxis countryAxis) {

        countryAxis.getCategories().setAll(
            source.stream()
                .map(CountryValue::getCountry)
                .collect(Collectors.toList())
        );

        chartData.setAll(
            source.stream()
                .map(cv -> new XYChart.Data<String, Number>(cv.getCountry(), cv.getValue()))
                .collect(Collectors.toList())
        );
    }

    public static class Model {
        private final ObservableList<CountryValue> values ;

        public Model(CountryValue... countryValues) {
            values = FXCollections.observableArrayList(countryValues) ;
        }

        public ObservableList<CountryValue> getValues() {
            return values ;
        }

    }

    // replace with record when they are standard in Java:
    public static class CountryValue {
        private final String country ;
        private final double value ;
        public CountryValue(String country, double value) {
            super();
            this.country = country;
            this.value = value;
        }
        public String getCountry() {
            return country;
        }
        public double getValue() {
            return value;
        }

    }

    // Not really relevant to problem; just simulates changing data in model
    public class Simulator implements Runnable {

        private final Model model ;
        private final Random rng = new Random();

        public Simulator(Model model) {
            this.model = model ;
            createData();
        }

        @Override
        public void run() {
            for (int i = 0 ; i < 10 ; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                Platform.runLater(this::createData);
            }
        }

        private void createData() {
            model.getValues().setAll(
                Stream.of("Austria", "Brazil", "France", "England", "Belgium")
                    .map(country -> new CountryValue(country, 50 * rng.nextDouble() + 50))
                    .collect(Collectors.toList())
            );
        }
    }

    public static void main(String[] args) {
        launch();
    }

}


问:
How to use a handler to loop an if statement every 20 seconds
Hi I have been having issues using the handler (I have used nearly every single example in any thread about looping stuff using handler)to loop a if statement that I need to rerun every 20 secs, I'm very new to java, and please ignore my stupid toast messages, could someone edit it so it will rerun the code every 20 seconds, Thanks in advance</p>

```<code>DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);

for (final Display display : dm.getDisplays()) {
    Toast.makeText(MainActivity.this, "for loop reached", Toast.LENGTH_LONG).show();

    int state = display.getState();
    String StateString = Integer.toString(state);
    Toast.makeText(MainActivity.this, StateString, Toast.LENGTH_LONG).show();

    if (display.getState() == 1) {
        String command = "dumpsys deviceidle force-idle deep";
        try {
            Process process = Runtime.getRuntime().exec(command);
        } catch (Exception e) {
            Toast.makeText(MainActivity.this, "failed", Toast.LENGTH_LONG).show();
        }

        //Toast.makeText(MainActivity.this, "not failed yayay", Toast.LENGTH_LONG).show();
        TextView tv9 = (TextView) findViewById(R.id.text_view_id);
        tv9.setText("The screen was turned off");
        Toast.makeText(MainActivity.this, "The screen is offfffffffff lolol", Toast.LENGTH_LONG).show();
    } else {
        Toast.makeText(MainActivity.this, "The screen is on lolol", Toast.LENGTH_LONG).show();
    }
}
</code>```

答:
Here is a second example:</p>

```<code>package samples;

public class Emitter2 {
    public static final int MS_IN_SEC = 1000;

    public static final int[] DELAYS = { 1, 3, 4, 5, 7 };

    public static void main(String[] args) {

        Emitter[] emitters = new Emitter[ DELAYS.length ];
        Thread[] emitterThreads = new Thread[ DELAYS.length ];

        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            int delay = DELAYS[emitterNo];
            System.out.println("main: Emitter [ " + emitterNo + " ] has delay [ " + delay + " s ]");
            Emitter emitter = newEmitter(MS_IN_SEC * delay);
            emitters[emitterNo] = emitter;
            emitterThreads[emitterNo] = new Thread(emitter);
        }

        System.out.println("main: Starting emitters");
        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            emitterThreads[emitterNo].start();
        }
        System.out.println("main: Started emitters");

        System.out.println("main: Running emitters for 50s");
        sleep("main", MS_IN_SEC * 50);
        System.out.println("main: Completed running emitters for 50s");

        System.out.println("main: Requesting emitters to stop");
        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            emitters[emitterNo].requestStop();
        }
        System.out.println("main: Requested emitters to stop");

        System.out.println("main: Waiting for emitters to stop");
        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            try {
                emitterThreads[emitterNo].join();
            } catch ( InterruptedException e ) {
                System.out.println("main: Interrupted waiting for emitter to stop");
            }
        }
        System.out.println("main: Waited for emitters to stop");
    }

    public static boolean sleep(String threadName, int mSec) {
        try {
            Thread.sleep(mSec);
        } catch ( InterruptedException e ) {
            System.out.println(threadName + ": Interrupted on delay of [ " + mSec + " ms ]!");
            return false;
        }
        return true;
    }

    public interface Emitter extends Runnable {
        void requestStop();
        boolean getStopped();
    }

    public static Emitter newEmitter(int delayMs) {
        return new Emitter() {
            private final String emitterName = "emitter" + delayMs;
            private boolean stopped;

            public synchronized void requestStop() {
                stopped= true;
            }

            public synchronized boolean getStopped() {
                return stopped;
            }

            public void run() {
                int counter = 0;
                while ( !getStopped() ) {
                    System.out.println(emitterName + ": Count [ " + counter + " ]");
                    counter++;

                    if ( !sleep(emitterName, delayMs) ) {
                        break;
                    }
                }

                System.out.println(emitterName + ": Stopped at count [ " + counter + " ]");
            }
        };
    }
}
</code>```

Body:
Hi I have been having issues using the handler (I have used nearly every single example in any thread about looping stuff using handler)to loop a if statement that I need to rerun every 20 secs, I'm very new to java, and please ignore my stupid toast messages, could someone edit it so it will rerun the code every 20 seconds, Thanks in advance

DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);

for (final Display display : dm.getDisplays()) {
    Toast.makeText(MainActivity.this, "for loop reached", Toast.LENGTH_LONG).show();

    int state = display.getState();
    String StateString = Integer.toString(state);
    Toast.makeText(MainActivity.this, StateString, Toast.LENGTH_LONG).show();

    if (display.getState() == 1) {
        String command = "dumpsys deviceidle force-idle deep";
        try {
            Process process = Runtime.getRuntime().exec(command);
        } catch (Exception e) {
            Toast.makeText(MainActivity.this, "failed", Toast.LENGTH_LONG).show();
        }

        //Toast.makeText(MainActivity.this, "not failed yayay", Toast.LENGTH_LONG).show();
        TextView tv9 = (TextView) findViewById(R.id.text_view_id);
        tv9.setText("The screen was turned off");
        Toast.makeText(MainActivity.this, "The screen is offfffffffff lolol", Toast.LENGTH_LONG).show();
    } else {
        Toast.makeText(MainActivity.this, "The screen is on lolol", Toast.LENGTH_LONG).show();
    }
}

Body:
Here is a second example:

package samples;

public class Emitter2 {
    public static final int MS_IN_SEC = 1000;

    public static final int[] DELAYS = { 1, 3, 4, 5, 7 };

    public static void main(String[] args) {

        Emitter[] emitters = new Emitter[ DELAYS.length ];
        Thread[] emitterThreads = new Thread[ DELAYS.length ];

        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            int delay = DELAYS[emitterNo];
            System.out.println("main: Emitter [ " + emitterNo + " ] has delay [ " + delay + " s ]");
            Emitter emitter = newEmitter(MS_IN_SEC * delay);
            emitters[emitterNo] = emitter;
            emitterThreads[emitterNo] = new Thread(emitter);
        }

        System.out.println("main: Starting emitters");
        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            emitterThreads[emitterNo].start();
        }
        System.out.println("main: Started emitters");

        System.out.println("main: Running emitters for 50s");
        sleep("main", MS_IN_SEC * 50);
        System.out.println("main: Completed running emitters for 50s");

        System.out.println("main: Requesting emitters to stop");
        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            emitters[emitterNo].requestStop();
        }
        System.out.println("main: Requested emitters to stop");

        System.out.println("main: Waiting for emitters to stop");
        for ( int emitterNo = 0; emitterNo < DELAYS.length; emitterNo++ ) {
            try {
                emitterThreads[emitterNo].join();
            } catch ( InterruptedException e ) {
                System.out.println("main: Interrupted waiting for emitter to stop");
            }
        }
        System.out.println("main: Waited for emitters to stop");
    }

    public static boolean sleep(String threadName, int mSec) {
        try {
            Thread.sleep(mSec);
        } catch ( InterruptedException e ) {
            System.out.println(threadName + ": Interrupted on delay of [ " + mSec + " ms ]!");
            return false;
        }
        return true;
    }

    public interface Emitter extends Runnable {
        void requestStop();
        boolean getStopped();
    }

    public static Emitter newEmitter(int delayMs) {
        return new Emitter() {
            private final String emitterName = "emitter" + delayMs;
            private boolean stopped;

            public synchronized void requestStop() {
                stopped= true;
            }

            public synchronized boolean getStopped() {
                return stopped;
            }

            public void run() {
                int counter = 0;
                while ( !getStopped() ) {
                    System.out.println(emitterName + ": Count [ " + counter + " ]");
                    counter++;

                    if ( !sleep(emitterName, delayMs) ) {
                        break;
                    }
                }

                System.out.println(emitterName + ": Stopped at count [ " + counter + " ]");
            }
        };
    }
}


问:
Gradle sync failed: Support for builds using Gradle versions older than 2.6 was removed [...]. You are currently using Gradle version 2.2.1
I'm trying to build an old app I made in 2015. But I keep getting above error in Android Studio.

I tried bumping the version number to 2.6 or to 3.6.3 (as Android Studio suggested) but the message keeps appearing.

答:
Android Studio tries to download the appropriate version from jcenter, specifically from this directory. As you can see it only has gradle versions up to 2.3.0. So you will need to add another repository which has newer builds.

The fix is to change your module-levels build script in all two places from

```<code>repositories {
    jcenter()
}
</code>```

to

```<code>repositories {
    google()
    jcenter()
}
</code>```

Body:
Android Studio tries to download the appropriate version from jcenter, specifically from this directory. As you can see it only has gradle versions up to 2.3.0. So you will need to add another repository which has newer builds.

The fix is to change your module-levels build script in all two places from

repositories {
    jcenter()
}

to

repositories {
    google()
    jcenter()
}


问:
Skip element in XSLT if output already contains similar element
Say I have some XML like this (everything below has been trimmed down to try to show the minimum amount needed to showcase my issue).

```<code><Person>
    <Name>Bob</Name>
    <GroupID>123</GroupID>
</Person>
<Person>
    <Name>Doug</Name>
    <GroupID>123</GroupID>
</Person>
<Person>
    <Name>Melinda</Name>
    <GroupID>123</GroupID>
</Person>
<Person>
    <Name>Kathy</Name>
    <GroupID>22</GroupID>
</Person>
<Person>
    <Name>Mark</Name>
    <GroupID>22</GroupID>
</Person>
<Person>
    <Name>Roberto</Name>
    <GroupID>33</GroupID>
</Person>
<Person>
    <Name>Carlos</Name>
</Person>
<Person>
    <Name>Sasha</Name>
</Person>
</code>```

I want to be able to group these records by their GroupIDs, so the output should be something like:

```<code><Persons>
    <Group>
        <GroupID>123</GroupID>
        <Person>
            <Name>Bob</Name>
        </Person>
        <Person>
            <Name>Doug</Name>
        </Person>
        <Person>
            <Name>Melinda</Name>
        </Person>
    </Group>
    <Group>
        <GroupID>22</GroupID>
        <Person>
            <Name>Kathy</Name>
        </Person>
        <Person>
            <Name>Mark</Name>
        </Person>
    </Group>
    <Group>
        <GroupID>33</GroupID>
        <Person>
            <Name>Roberto</Name>
        </Person>
    </Group>
    <Group>
        <Person>
            <Name>Carlos</Name>
        </Person>
    </Group>
    <Group>
        <Person>
            <Name>Sasha</Name>
        </Person>
    </Group>
</Persons>
</code>```

What I'm doing is something like this:

```<code> <Persons>
    <xsl:for-each select="Person">
        <xsl:choose>
            <xsl:when test="GroupID != ''">
                <xsl:variable name="groupId" select="GroupID"/>
                <Group>
                    <GroupID>
                        <xsl:value-of select="groupId"/>
                    </GroupID>
                    <xsl:for-each select="../Person[GroupID = groupId]">
                        <xsl:call-template name="PersonData"/>
                    </xsl:for-each>
                </Group>
            </xsl:when>
            <xsl:otherwise>
                <Group>
                    <xsl:call-template name="PersonData"/>
                </Group>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</Persons>
</code>```

The issue is that each Group gets duplicated for as many Persons as there are in the group. What I'd really like to be able to do is to either check if I've processed the "current" GroupID already or not - that way I can say "ok, this GroupID has already been processed, so skip it".

EDIT: this is using XSLT 2 with Xalan, so actually XSLT 1.

EDIT2: It is possible that the GroupID attribute can be missing for one or more records. In those instances, those records should each get an individual Group with no GroupID present.

答:
You could do it like this:

```<code><?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <Persons>
            <xsl:for-each-group select="//Person" group-by="GroupID">
                <Group>
                    <GroupID><xsl:value-of select="current-grouping-key()"/></GroupID>
                    <xsl:for-each select="current-group()">
                        <Person>
                            <Name><xsl:value-of select="Name"/></Name>
                        </Person>
                    </xsl:for-each>
                </Group>
            </xsl:for-each-group>
        </Persons>
    </xsl:template>

</xsl:stylesheet>
</code>```

See it working here: https://xsltfiddle.liberty-development.net/a9HjZd

Body:
Say I have some XML like this (everything below has been trimmed down to try to show the minimum amount needed to showcase my issue).

<Person>
    <Name>Bob</Name>
    <GroupID>123</GroupID>
</Person>
<Person>
    <Name>Doug</Name>
    <GroupID>123</GroupID>
</Person>
<Person>
    <Name>Melinda</Name>
    <GroupID>123</GroupID>
</Person>
<Person>
    <Name>Kathy</Name>
    <GroupID>22</GroupID>
</Person>
<Person>
    <Name>Mark</Name>
    <GroupID>22</GroupID>
</Person>
<Person>
    <Name>Roberto</Name>
    <GroupID>33</GroupID>
</Person>
<Person>
    <Name>Carlos</Name>
</Person>
<Person>
    <Name>Sasha</Name>
</Person>

I want to be able to group these records by their GroupIDs, so the output should be something like:

<Persons>
    <Group>
        <GroupID>123</GroupID>
        <Person>
            <Name>Bob</Name>
        </Person>
        <Person>
            <Name>Doug</Name>
        </Person>
        <Person>
            <Name>Melinda</Name>
        </Person>
    </Group>
    <Group>
        <GroupID>22</GroupID>
        <Person>
            <Name>Kathy</Name>
        </Person>
        <Person>
            <Name>Mark</Name>
        </Person>
    </Group>
    <Group>
        <GroupID>33</GroupID>
        <Person>
            <Name>Roberto</Name>
        </Person>
    </Group>
    <Group>
        <Person>
            <Name>Carlos</Name>
        </Person>
    </Group>
    <Group>
        <Person>
            <Name>Sasha</Name>
        </Person>
    </Group>
</Persons>

What I'm doing is something like this:

 <Persons>
    <xsl:for-each select="Person">
        <xsl:choose>
            <xsl:when test="GroupID != ''">
                <xsl:variable name="groupId" select="GroupID"/>
                <Group>
                    <GroupID>
                        <xsl:value-of select="groupId"/>
                    </GroupID>
                    <xsl:for-each select="../Person[GroupID = groupId]">
                        <xsl:call-template name="PersonData"/>
                    </xsl:for-each>
                </Group>
            </xsl:when>
            <xsl:otherwise>
                <Group>
                    <xsl:call-template name="PersonData"/>
                </Group>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each>
</Persons>

The issue is that each Group gets duplicated for as many Persons as there are in the group. What I'd really like to be able to do is to either check if I've processed the "current" GroupID already or not - that way I can say "ok, this GroupID has already been processed, so skip it".

EDIT: this is using XSLT 2 with Xalan, so actually XSLT 1.

EDIT2: It is possible that the GroupID attribute can be missing for one or more records. In those instances, those records should each get an individual Group with no GroupID present.

Body:
You could do it like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <Persons>
            <xsl:for-each-group select="//Person" group-by="GroupID">
                <Group>
                    <GroupID><xsl:value-of select="current-grouping-key()"/></GroupID>
                    <xsl:for-each select="current-group()">
                        <Person>
                            <Name><xsl:value-of select="Name"/></Name>
                        </Person>
                    </xsl:for-each>
                </Group>
            </xsl:for-each-group>
        </Persons>
    </xsl:template>

</xsl:stylesheet>

See it working here: https://xsltfiddle.liberty-development.net/a9HjZd


问:
ASP.NET: how to validate
I have a simple ASP.NET (VB) page with a CompareValidator. I can check to ensure the value is numeric, but I have no idea how to check for the length (business rules require a 7 digit number). Existing code is below:

```<code><asp:TextBox ID="txtPolicyNo" runat="server"
                    BorderStyle="Ridge"></asp:TextBox>

<asp:CompareValidator ID="cvCheckPolicy" runat="server"
                    ErrorMessage="Must be a valid policy number" ControlToValidate="txtPolicyNo"
                    Type="Integer" Operator="DataTypeCheck">
</asp:CompareValidator>
</code>```

How can I accomplish this?

Thanks,

Jason

答: Use a RegularExpressionValidator with a regex string like "^\d{7}$". That will ensure you get a 7 digit number. You might have to combine that with a RequiredFieldValidator to make sure they enter something.

ContentLicense: CC BY-SA 3.0

Title: ASP.NET: how to validate

Body:
I have a simple ASP.NET (VB) page with a CompareValidator. I can check to ensure the value is numeric, but I have no idea how to check for the length (business rules require a 7 digit number). Existing code is below:

<asp:TextBox ID="txtPolicyNo" runat="server"
                    BorderStyle="Ridge"></asp:TextBox>

<asp:CompareValidator ID="cvCheckPolicy" runat="server"
                    ErrorMessage="Must be a valid policy number" ControlToValidate="txtPolicyNo"
                    Type="Integer" Operator="DataTypeCheck">
</asp:CompareValidator>

How can I accomplish this?

Thanks,

Jason


Title: How do I generate a pandas dataframe consisting of the adjusted close prices of a few stocks from yahoo finance?

Body:
The df example end result I am looking for is the below, with the adjusted close prices as the data:

#               GE    JPM    MSFT     PG
#date
#2015-01-02  25.06  62.49  46.760  90.44
#2015-01-05  24.60  60.55  46.325  90.01
#2015-01-06  24.07  58.98  45.650  89.60
#2015-01-07  24.08  59.07  46.230  90.07
#2015-01-08  24.37  60.39  47.590  91.10

import yfinance as yf
import datetime
import pandas as pd
import pandas_datareader as pdr

def get(tickers, startdate, enddate):
  def data(ticker):
    return (pdr.get_data_yahoo(ticker, start=startdate, end=enddate))
  datas = map (data, tickers)
  return(pd.concat(datas, keys=tickers, names=['Ticker', 'Date']))

ticker = ['GE' ,   'JPM' ,   'MSFT' ,    'PG']
all_data = get(ticker, datetime.datetime(2018, 10, 1), datetime.datetime(2020, 1, 1))

print (all_data)

                          High          Low  ...      Volume    Adj Close
Ticker Date                                  ...
GE     2018-10-01   229.419998   226.350006  ...  23600800.0   221.988266
       2018-10-02   230.000000   226.630005  ...  24788200.0   223.961426
       2018-10-03   233.470001   229.779999  ...  28654800.0   226.686707
       2018-10-04   232.350006   226.729996  ...  32042000.0   222.701340
       2018-10-05   228.410004   220.580002  ...  33580500.0   219.087158
...                        ...          ...  ...         ...          ...
JPM    2019-12-24  1350.260010  1342.780029  ...    347500.0  1343.560059
       2019-12-26  1361.327026  1344.469971  ...    667500.0  1360.400024
       2019-12-27  1364.530029  1349.310059  ...   1038400.0  1351.890015
       2019-12-30  1353.000000  1334.020020  ...   1050900.0  1336.140015
       2019-12-31  1338.000000  1329.084961  ...    961800.0  1337.020020

The above code stores the tickers in rows instead of columns.

I only need the adjusted close column for each ticker. I know how to extract the "adjusted close" column into another pandas series, but I get stuck on how to proceed further.

Body:
You can use pivot here:

def get(tickers, startdate, enddate):
  def data(ticker):
    return (pdr.get_data_yahoo(ticker, start=startdate, end=enddate))
  datas = map (data, tickers)
  return(pd.concat(datas, keys=tickers, names=['Ticker', 'Date']))

ticker = ['GE' ,   'JPM' ,   'MSFT' ,    'PG']
all_data = get(ticker, datetime.datetime(2018, 10, 1), datetime.datetime(2020, 1, 1))

df = all_data['Adj Close'].to_frame().reset_index()
print(df.pivot(index='Date', columns='Ticker'))

            Adj Close
Ticker             GE         JPM        MSFT          PG
Date
2018-10-01  11.550495  107.484100  112.812271   79.660583
2018-10-02  11.770231  107.929184  112.363396   80.317520
2018-10-03  11.923093  108.942482  112.382904   79.051262
2018-10-04  12.095059  109.924706  110.060501   77.994453
2018-10-05  12.591855  109.304848  109.416473   78.213432
...               ...         ...         ...         ...
2019-12-24  11.178899  135.296478  156.515396  123.655876
2019-12-26  11.218859  136.732239  157.798309  123.655876
2019-12-27  11.168909  136.830582  158.086731  124.515007
2019-12-30  11.069008  136.329041  156.724243  122.915245
2019-12-31  11.148929  137.086258  156.833633  123.339874


问:
http: From python request to equivalent curl command
I want to make an upload to Amazon s3 via MS-Flow. The http post via python looks like this

```<code>    with open('../myfile.txt', 'rb') as f:
        files = {'file': (object_name, f)}
        http_response = requests.post(
            <aws-s3-url>,
            data={
                'key': 'myfile.txt',
                'x-amz-algorithm': 'AWS4-HMAC-SHA256',
                'x-amz-credential': '<creds>',
                'x-amz-date': '20200529T120357Z',
                'policy': '<policy>',
                'x-amz-signature': '<signature>'
            },
            files=files
        )
</code>```

The raw request body and headers look as follows

```<code>--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="key"

myfile.txt
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-algorithm"

AWS4-HMAC-SHA256
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-credential"

<creds>
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-date"

20200529T120357Z
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="policy"

<policy>
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-signature"

<signature>
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="file"; filename="myfile.txt"

test test test
--ed1fdd226f0d04d8691a17ceaf914a7e--
</code>```

and

```<code>{'User-Agent': 'python-requests/2.23.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '1287', 'Content-Type': 'multipart/form-data; boundary=ed1fdd226f0d04d8691a17ceaf914a7e'}
</code>```

Sending the request via python works fine.
But when I use the raw http-request-body in MS-Flow or via curl, it fails with

```<code>The body of your POST request is not well-formed multipart/form-data.
</code>```

The curl command I use is

```<code>curl \
-d "--ed1fdd226f0d04d8691a17ceaf914a7e\r\nContent-Disposition: form-data; name="key"\r\n\r\nmyfile.txt\r\n--ed1..." \
-X POST \
-H "Content-Type: multipart/form-data" \
-H "boundary: ed1fdd226f0d04d8691a17ceaf914a7e" \
-H "Accept': */*" \
-H "Connection': keep-alive" \
-H "Accept-Encoding': gzip, deflate" \
<aws-s3-url>
</code>```

I also used

```<code>-d "$(cat body)"
</code>```

instead of the raw string. This changed the line-breaks from "\r\n" to "\n" but did not help.

My question is twofold:

How do I correctly derive a working curl command from the above python request? (Possibly even the correct format of the body I would need to enter in MS-Flow)

Why does my approach not work?

Would be glad if someone could help. Thanks a lot in advance and have a nice day!

答:
--data alias -d encodes the given string with URL-encoding. Use --trace - to see the resulting mess that goes out to the server.

If you have already encoded data like this, you need to use --data-binary instead.

You can also use -F key=value to specify each field individually and send them as multipart form data, which is less error-prone because you don't have to do the encoding yourself.

Body:
I want to make an upload to Amazon s3 via MS-Flow. The http post via python looks like this

    with open('../myfile.txt', 'rb') as f:
        files = {'file': (object_name, f)}
        http_response = requests.post(
            <aws-s3-url>,
            data={
                'key': 'myfile.txt',
                'x-amz-algorithm': 'AWS4-HMAC-SHA256',
                'x-amz-credential': '<creds>',
                'x-amz-date': '20200529T120357Z',
                'policy': '<policy>',
                'x-amz-signature': '<signature>'
            },
            files=files
        )

The raw request body and headers look as follows

--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="key"

myfile.txt
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-algorithm"

AWS4-HMAC-SHA256
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-credential"

<creds>
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-date"

20200529T120357Z
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="policy"

<policy>
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="x-amz-signature"

<signature>
--ed1fdd226f0d04d8691a17ceaf914a7e
Content-Disposition: form-data; name="file"; filename="myfile.txt"

test test test
--ed1fdd226f0d04d8691a17ceaf914a7e--

and

{'User-Agent': 'python-requests/2.23.0', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '1287', 'Content-Type': 'multipart/form-data; boundary=ed1fdd226f0d04d8691a17ceaf914a7e'}

Sending the request via python works fine.
But when I use the raw http-request-body in MS-Flow or via curl, it fails with

The body of your POST request is not well-formed multipart/form-data.

The curl command I use is

curl \
-d "--ed1fdd226f0d04d8691a17ceaf914a7e\r\nContent-Disposition: form-data; name="key"\r\n\r\nmyfile.txt\r\n--ed1..." \
-X POST \
-H "Content-Type: multipart/form-data" \
-H "boundary: ed1fdd226f0d04d8691a17ceaf914a7e" \
-H "Accept': */*" \
-H "Connection': keep-alive" \
-H "Accept-Encoding': gzip, deflate" \
<aws-s3-url>

I also used

-d "$(cat body)"

instead of the raw string. This changed the line-breaks from "\r\n" to "\n" but did not help.

My question is twofold:

How do I correctly derive a working curl command from the above python request? (Possibly even the correct format of the body I would need to enter in MS-Flow)

Why does my approach not work?

Would be glad if someone could help. Thanks a lot in advance and have a nice day!


问:
URL Rewriting Error With Wordpress
I'm using Wordpress. But i have a problem with URL Rewriting. I'm using this scheme :

```<code>http://www.domain.com/post-title/
http://www.domain.com/another-post-title/
</code>```

There isn't problem with this. This is working. But, i have a directory (zencart) on root. I'm browsing to this URL :

```<code>http://www.domain.com/zencart/
</code>```

I'm forwarding to Wordpress' 404 Error page (Nothing Found For Zencart) .

(Because there isn't any post which have zencart title, zencart is name of a directory)

This is my .htaccess file :
(also you can look here for more readability)
(I'm using W3 Total Cache plugin)

```<code># BEGIN W3TC Browser Cache
<IfModule mod_deflate.c>
    <IfModule mod_setenvif.c>
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4\.0[678] no-gzip
        BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
    </IfModule>
    <IfModule mod_headers.c>
        Header append Vary User-Agent env=!dont-vary
    </IfModule>
    AddOutputFilterByType DEFLATE text/css application/x-javascript text/html text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon
</IfModule>
<FilesMatch "\.(css|js)$">
    FileETag None
    <IfModule mod_headers.c>
         Header set X-Powered-By "W3 Total Cache/0.9.1.3"
    </IfModule>
</FilesMatch>
<FilesMatch "\.(html|htm|rtf|rtx|svg|svgz|txt|xsd|xsl|xml)$">
    FileETag None
    <IfModule mod_headers.c>
         Header set X-Powered-By "W3 Total Cache/0.9.1.3"
    </IfModule>
</FilesMatch>
<FilesMatch "\.(asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|swf|tar|tif|tiff|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">
    FileETag None
    <IfModule mod_headers.c>
         Header set X-Powered-By "W3 Total Cache/0.9.1.3"
    </IfModule>
</FilesMatch>
# END W3TC Browser Cache

# BEGIN W3TC Page Cache
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{HTTP_USER_AGENT} (2\.0\ mmp|240x320|alcatel|amoi|asus|au\-mic|audiovox|avantgo|benq|bird|blackberry|blazer|cdm|cellphone|danger|ddipocket|docomo|dopod|elaine/3\.0|ericsson|eudoraweb|fly|haier|hiptop|hp\.ipaq|htc|huawei|i\-mobile|iemobile|j\-phone|kddi|konka|kwc|kyocera/wx310k|lenovo|lg|lg/u990|lge\ vx|midp|midp\-2\.0|mmef20|mmp|mobilephone|mot\-v|motorola|netfront|newgen|newt|nintendo\ ds|nintendo\ wii|nitro|nokia|novarra|o2|openweb|opera\ mobi|opera\.mobi|palm|panasonic|pantech|pdxgw|pg|philips|phone|playstation\ portable|portalmmm|ppc|proxinet|psp|pt|qtek|sagem|samsung|sanyo|sch|sec|sendo|sgh|sharp|sharp\-tq\-gx10|small|smartphone|softbank|sonyericsson|sph|symbian|symbian\ os|symbianos|toshiba|treo|ts21i\-10|up\.browser|up\.link|uts|vertu|vodafone|wap|willcome|windows\ ce|windows\.ce|winwap|xda|zte) [NC]
    RewriteRule .* - [E=W3TC_UA:_low]
    RewriteCond %{HTTP_USER_AGENT} (acer\ s100|android|archos5|blackberry9500|blackberry9530|blackberry9550|cupcake|docomo\ ht\-03a|dream|htc\ hero|htc\ magic|htc_dream|htc_magic|incognito|ipad|iphone|ipod|lg\-gw620|liquid\ build|maemo|mot\-mb200|mot\-mb300|nexus\ one|opera\ mini|samsung\-s8000|series60.*webkit|series60/5\.0|sonyericssone10|sonyericssonu20|sonyericssonx10|t\-mobile\ mytouch\ 3g|t\-mobile\ opal|tattoo|webmate|webos) [NC]
    RewriteRule .* - [E=W3TC_UA:_high]
    RewriteCond %{HTTPS} =on
    RewriteRule .* - [E=W3TC_SSL:_ssl]
    RewriteCond %{SERVER_PORT} =443
    RewriteRule .* - [E=W3TC_SSL:_ssl]
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteRule .* - [E=W3TC_ENC:.gzip]
    RewriteCond %{REQUEST_METHOD} !=POST
    RewriteCond %{QUERY_STRING} =""
    RewriteCond %{REQUEST_URI} \/$
    RewriteCond %{REQUEST_URI} !(\/wp-admin\/|\/xmlrpc.php|\/wp-(app|cron|login|register|mail)\.php|wp-.*\.php|index\.php) [NC,OR]
    RewriteCond %{REQUEST_URI} (wp-comments-popup\.php|wp-links-opml\.php|wp-locations\.php) [NC]
    RewriteCond %{HTTP_COOKIE} !(comment_author|wp-postpass|wordpress_\[a-f0-9\]\+|wordpress_logged_in) [NC]
    RewriteCond "/home/btk1sk/public_html/wp-content/w3tc/pgcache/$1/_index%{ENV:W3TC_UA}%{ENV:W3TC_SSL}.html%{ENV:W3TC_ENC}" -f
    RewriteRule (.*) "/wp-content/w3tc/pgcache/$1/_index%{ENV:W3TC_UA}%{ENV:W3TC_SSL}.html%{ENV:W3TC_ENC}" [L]
</IfModule>
# END W3TC Page Cache

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress
</code>```

答: We solved that creating a Wordpress page using the same "url". But as you said, it's not a dynamic solution. The fact is that we have not many folders at the same level of WP index :o... Greetings!</p>

ContentLicense: CC BY-SA 2.5

Title: URL Rewriting Error With Wordpress

Body:
I'm using Wordpress. But i have a problem with URL Rewriting. I'm using this scheme :

http://www.domain.com/post-title/
http://www.domain.com/another-post-title/

There isn't problem with this. This is working. But, i have a directory (zencart) on root. I'm browsing to this URL :

http://www.domain.com/zencart/

I'm forwarding to Wordpress' 404 Error page (Nothing Found For Zencart) .

(Because there isn't any post which have zencart title, zencart is name of a directory)

This is my .htaccess file :
(also you can look here for more readability)
(I'm using W3 Total Cache plugin)

# BEGIN W3TC Browser Cache
<IfModule mod_deflate.c>
    <IfModule mod_setenvif.c>
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4\.0[678] no-gzip
        BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
        BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
    </IfModule>
    <IfModule mod_headers.c>
        Header append Vary User-Agent env=!dont-vary
    </IfModule>
    AddOutputFilterByType DEFLATE text/css application/x-javascript text/html text/richtext image/svg+xml text/plain text/xsd text/xsl text/xml image/x-icon
</IfModule>
<FilesMatch "\.(css|js)$">
    FileETag None
    <IfModule mod_headers.c>
         Header set X-Powered-By "W3 Total Cache/0.9.1.3"
    </IfModule>
</FilesMatch>
<FilesMatch "\.(html|htm|rtf|rtx|svg|svgz|txt|xsd|xsl|xml)$">
    FileETag None
    <IfModule mod_headers.c>
         Header set X-Powered-By "W3 Total Cache/0.9.1.3"
    </IfModule>
</FilesMatch>
<FilesMatch "\.(asf|asx|wax|wmv|wmx|avi|bmp|class|divx|doc|docx|exe|gif|gz|gzip|ico|jpg|jpeg|jpe|mdb|mid|midi|mov|qt|mp3|m4a|mp4|m4v|mpeg|mpg|mpe|mpp|odb|odc|odf|odg|odp|ods|odt|ogg|pdf|png|pot|pps|ppt|pptx|ra|ram|swf|tar|tif|tiff|wav|wma|wri|xla|xls|xlsx|xlt|xlw|zip)$">
    FileETag None
    <IfModule mod_headers.c>
         Header set X-Powered-By "W3 Total Cache/0.9.1.3"
    </IfModule>
</FilesMatch>
# END W3TC Browser Cache

# BEGIN W3TC Page Cache
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{HTTP_USER_AGENT} (2\.0\ mmp|240x320|alcatel|amoi|asus|au\-mic|audiovox|avantgo|benq|bird|blackberry|blazer|cdm|cellphone|danger|ddipocket|docomo|dopod|elaine/3\.0|ericsson|eudoraweb|fly|haier|hiptop|hp\.ipaq|htc|huawei|i\-mobile|iemobile|j\-phone|kddi|konka|kwc|kyocera/wx310k|lenovo|lg|lg/u990|lge\ vx|midp|midp\-2\.0|mmef20|mmp|mobilephone|mot\-v|motorola|netfront|newgen|newt|nintendo\ ds|nintendo\ wii|nitro|nokia|novarra|o2|openweb|opera\ mobi|opera\.mobi|palm|panasonic|pantech|pdxgw|pg|philips|phone|playstation\ portable|portalmmm|ppc|proxinet|psp|pt|qtek|sagem|samsung|sanyo|sch|sec|sendo|sgh|sharp|sharp\-tq\-gx10|small|smartphone|softbank|sonyericsson|sph|symbian|symbian\ os|symbianos|toshiba|treo|ts21i\-10|up\.browser|up\.link|uts|vertu|vodafone|wap|willcome|windows\ ce|windows\.ce|winwap|xda|zte) [NC]
    RewriteRule .* - [E=W3TC_UA:_low]
    RewriteCond %{HTTP_USER_AGENT} (acer\ s100|android|archos5|blackberry9500|blackberry9530|blackberry9550|cupcake|docomo\ ht\-03a|dream|htc\ hero|htc\ magic|htc_dream|htc_magic|incognito|ipad|iphone|ipod|lg\-gw620|liquid\ build|maemo|mot\-mb200|mot\-mb300|nexus\ one|opera\ mini|samsung\-s8000|series60.*webkit|series60/5\.0|sonyericssone10|sonyericssonu20|sonyericssonx10|t\-mobile\ mytouch\ 3g|t\-mobile\ opal|tattoo|webmate|webos) [NC]
    RewriteRule .* - [E=W3TC_UA:_high]
    RewriteCond %{HTTPS} =on
    RewriteRule .* - [E=W3TC_SSL:_ssl]
    RewriteCond %{SERVER_PORT} =443
    RewriteRule .* - [E=W3TC_SSL:_ssl]
    RewriteCond %{HTTP:Accept-Encoding} gzip
    RewriteRule .* - [E=W3TC_ENC:.gzip]
    RewriteCond %{REQUEST_METHOD} !=POST
    RewriteCond %{QUERY_STRING} =""
    RewriteCond %{REQUEST_URI} \/$
    RewriteCond %{REQUEST_URI} !(\/wp-admin\/|\/xmlrpc.php|\/wp-(app|cron|login|register|mail)\.php|wp-.*\.php|index\.php) [NC,OR]
    RewriteCond %{REQUEST_URI} (wp-comments-popup\.php|wp-links-opml\.php|wp-locations\.php) [NC]
    RewriteCond %{HTTP_COOKIE} !(comment_author|wp-postpass|wordpress_\[a-f0-9\]\+|wordpress_logged_in) [NC]
    RewriteCond "/home/btk1sk/public_html/wp-content/w3tc/pgcache/$1/_index%{ENV:W3TC_UA}%{ENV:W3TC_SSL}.html%{ENV:W3TC_ENC}" -f
    RewriteRule (.*) "/wp-content/w3tc/pgcache/$1/_index%{ENV:W3TC_UA}%{ENV:W3TC_SSL}.html%{ENV:W3TC_ENC}" [L]
</IfModule>
# END W3TC Page Cache

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress


问:
Is it possible to create multi page apps in angular?
I am thinking of creating a clone of Food ordering applications like Zomato, and I found out that it uses Angular like routing on certain pages that are at the time of Ordering after selecting a Restaurant.
i.e. the page is not refreshed can be seen from the Reload button on the browser and it seems that the request doesn't go to the server.

While on other sections such as selecting a restaurant the request does seem to get routed by the server.

So my question is that Is it feasible to make a multi-page application in angular?

and if yes then how please provide some links of a demo or something on the Internet, and if no then what should be the architecture of such a Food ordering app?

The architecture I am thinking:

But I am stuck at the problem that how will the server be able to render or request angular to get the data, I know the way angular can request the server to fetch the data using Restful Services but I don't know how the server will be able to pass control to the angular app when user requests for a particular URL that is designed for the angular app such as the URL at the time of ordering.

答:
If I'm good understand your question - Angular is SPA (Singe Page App) framework that interacts with the web browser by dynamically rewriting the current web page. So i think you can not create multiple page in Angular.

If you want to use  multiple web pages (i.e. index.html, page1.html) use Thymeleaf which is java template engine and integrates with Spring-Boot applications, for example:
https://www.baeldung.com/spring-boot-crud-thymeleaf

If you are using REST API from Spring-Boot and want to send request to the backend server, server will not respond until you add "Access-Control-Allow-Origin" header. The quick example is:

```<code>@CrossOrigin(origins = "http://localhost:4200")
@GetMapping("/product")
public ResponseEntity<List<YourEntity>> getAllProducts() {
  //use service or repository for get data from db
  return new ResponseEntity(entities, HttpStatus.OK)
}
</code>```

In Angular, you need to subscribe data by subscribe() method, for example:

```<code>    export class HomeComponent implements OnInit {

      values: any;

      constructor(private http: HttpClient) {
        this.values = [];
      }

    ngOnInit() {
      this.getDataOnStart();
   }

   getDataOnStart() {
      this.http.get('http://localhost:8080/products').subscribe(data => {
           this.values = data;
         });
  }

 }
</code>```

Where localhost:8080 is your Spring-Boot (server) address.

After that when you reload the page ngOnInit will send request to the server.

Example app:
https://www.baeldung.com/spring-boot-angular-web

Body:
If I'm good understand your question - Angular is SPA (Singe Page App) framework that interacts with the web browser by dynamically rewriting the current web page. So i think you can not create multiple page in Angular.

If you want to use  multiple web pages (i.e. index.html, page1.html) use Thymeleaf which is java template engine and integrates with Spring-Boot applications, for example:
https://www.baeldung.com/spring-boot-crud-thymeleaf

If you are using REST API from Spring-Boot and want to send request to the backend server, server will not respond until you add "Access-Control-Allow-Origin" header. The quick example is:

@CrossOrigin(origins = "http://localhost:4200")
@GetMapping("/product")
public ResponseEntity<List<YourEntity>> getAllProducts() {
  //use service or repository for get data from db
  return new ResponseEntity(entities, HttpStatus.OK)
}

In Angular, you need to subscribe data by subscribe() method, for example:

    export class HomeComponent implements OnInit {

      values: any;

      constructor(private http: HttpClient) {
        this.values = [];
      }

    ngOnInit() {
      this.getDataOnStart();
   }

   getDataOnStart() {
      this.http.get('http://localhost:8080/products').subscribe(data => {
           this.values = data;
         });
  }

 }

Where localhost:8080 is your Spring-Boot (server) address.

After that when you reload the page ngOnInit will send request to the server.

Example app:
https://www.baeldung.com/spring-boot-angular-web