问:
Equal spacing for collectionview items in ios
I using collection view controller to display images like in gallery. Now I struck with spacing. I cant set equal spacing in collection view..

```<code>- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 0;
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(0, 0, 0, 0);
}
- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(106.0f, 106.0f);
}
</code>```

This is my code.. cell width 106 but the imageview width is 104.0f I gave 2 points spacing left side of the image view now I got solution as below image.

Pls help me to fix this problem...

答:
Swift 5

Set up some section insets (How far your cells will be from the frame of the CollectionView), number of cells you want in a row, and the spacing you want between your cells

```<code>let sectionInsets = UIEdgeInsets(top: 20.0, left: 20.0, bottom: 20.0, right: 20.0)
let numberOfItemsPerRow: CGFloat = 4
let spacingBetweenCells: CGFloat = 10
</code>```

Use all the values above in the UICollectionViewDelegateFlowLayout:

```<code>   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let totalSpacing = (2 * sectionInsets.left) + ((numberOfItemsPerRow - 1) * spacingBetweenCells) //Amount of total spacing in a row

        if let collection = self.collectionView{
            let width = (collection.bounds.width - totalSpacing)/numberOfItemsPerRow
            return CGSize(width: width, height: width)
        } else {
            return CGSize(width: 0, height: 0)
        }
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return spacingBetweenCells
    }
</code>```

Body:
I using collection view controller to display images like in gallery. Now I struck with spacing. I cant set equal spacing in collection view..

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 0;
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(0, 0, 0, 0);
}
- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(106.0f, 106.0f);
}

This is my code.. cell width 106 but the imageview width is 104.0f I gave 2 points spacing left side of the image view now I got solution as below image.

Pls help me to fix this problem...

Body:
Swift 5

Set up some section insets (How far your cells will be from the frame of the CollectionView), number of cells you want in a row, and the spacing you want between your cells

let sectionInsets = UIEdgeInsets(top: 20.0, left: 20.0, bottom: 20.0, right: 20.0)
let numberOfItemsPerRow: CGFloat = 4
let spacingBetweenCells: CGFloat = 10

Use all the values above in the UICollectionViewDelegateFlowLayout:

   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let totalSpacing = (2 * sectionInsets.left) + ((numberOfItemsPerRow - 1) * spacingBetweenCells) //Amount of total spacing in a row

        if let collection = self.collectionView{
            let width = (collection.bounds.width - totalSpacing)/numberOfItemsPerRow
            return CGSize(width: width, height: width)
        } else {
            return CGSize(width: 0, height: 0)
        }
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return spacingBetweenCells
    }


来源: stackexchange

答:
From your sample data and expected results it seems like you need to left join A to the UNION of the other tables:

```<code>select A.name, count(t.a) count
from A
left join (
  select id, a from B
  union all
  select id, a from C
) t
on A.id = t.a
group by A.id, A.name
</code>```

See the demo.

Results:

```<code>| name | count |
| ---- | ----- |
| foo  | 4     |
| bar  | 2     |
</code>```

ContentLicense: CC BY-SA 4.0

Title: Count total amount of references from multiple foreign tables in MySQL

Body:
I have 3 tables:

A

B which has a foreign key to A

C same

How can I count the total number of relations that references a row in A?

ex.

A

+----+------+
| id | name |
+----+------+
|  1 |  foo |
|  2 |  bar |
+----+------+

B

+----+----+
| id |  a |
+----+----+
|  1 |  1 |
|  2 |  1 |
|  3 |  2 |
|  4 |  2 |
+----+----+

C

+----+----+
| id |  a |
+----+----+
|  1 |  1 |
|  2 |  1 |
+----+----+

I want to get this result:

+------+----+
| name |  a |
+------+----+
| foo  |  4 |
| bar  |  2 |
+------+----+

Thanks

Body:
From your sample data and expected results it seems like you need to left join A to the UNION of the other tables:

select A.name, count(t.a) count
from A
left join (
  select id, a from B
  union all
  select id, a from C
) t
on A.id = t.a
group by A.id, A.name

See the demo.

Results:

| name | count |
| ---- | ----- |
| foo  | 4     |
| bar  | 2     |


问:
add class to object 1, wait, add class to object 2 within for loop
I want to get a collection of elements with a class. I then wish to loop through each element in the collection in order to add a class.

However, I want it to add a class to the first in the collection, then wait 5 seconds before adding to the 2nd in the collection. And so on...

```<code><script type="text/javascript">
    window.onload = function(){
        var boxs = document.getElementsByClassName("paragraph");

        for(let i = 0; i < boxs.length; i++){
            setTimeout(function () {
                boxs[i].classList.add("type");
            },5000);
        }
    }
</script>
</code>```

答:
You can use your i variable to calculate a suitable delay to setTimeout (first execution after 5s, second after 10s, etc.):

```<code>for(let i = 0; i < boxs.length; i++){
  setTimeout(function () {
    boxs[i].classList.add("type");
  }, (i + 1) * 5000);
}
</code>```

When you call setTimeout, you are just setting a timer for the execution of your callback. That's why you need to compute appropriate delays for each call.

Body:
You can use your i variable to calculate a suitable delay to setTimeout (first execution after 5s, second after 10s, etc.):

for(let i = 0; i < boxs.length; i++){
  setTimeout(function () {
    boxs[i].classList.add("type");
  }, (i + 1) * 5000);
}

When you call setTimeout, you are just setting a timer for the execution of your callback. That's why you need to compute appropriate delays for each call.


问:
layer two ggplot maps on top of each other
I've got two ggplot maps which both use the same shapefile. One is the data and the other is the names of each country. Currently they are in seperate ggplots but how do I add the names over the top of my existing one (plot1)?</p>

```<code>cnames <- aggregate(cbind(long, lat) ~ region, data=map,
                    FUN=function(x)mean(range(x)))
names <-ggplot(map, aes(long, lat)) +
    geom_polygon(aes(x = long, y = lat, group=group), colour='black', fill=NA) +
    geom_text(data=cnames, aes(long, lat, label = region), size=2) +
    coord_map()

plot1 <- ggplot(map, aes(x=long,y = lat, group = group, fill = map$`data`)) + geom_polygon(colour="black") + coord_map("polyconic") + labs(fill = "data") + theme(axis.title.x=element_blank(),axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),axis.title.y=element_blank(),axis.text.y=element_blank(),axis.ticks.y=element_blank())
  plot1 <- plot1 + ggtitle("data")
  plot1 <- plot1 + scale_fill_gradient2(low = muted("grey"), high = muted("deepskyblue4"))
</code>```

答:
I suppose you can just add the layers together, like this:

invisible(lapply(c("ggplot2", "scales", "mapproj"), require, character.only = TRUE))
#> Loading required package: ggplot2
#> Loading required package: scales
#> Loading required package: mapproj
#> Loading required package: maps
map <- map_data("state")

cnames <- aggregate(cbind(long, lat) ~ region, data=map,
    FUN=function(x)mean(range(x)))

    ggplot(map, aes(
        x = long,
        y = lat,
        group = group,
        fill = as.numeric(factor(map$region))
    )) +
    scale_fill_gradient2(low = muted("grey"), high = muted("deepskyblue4"))+
    geom_polygon(colour = "black") +
    geom_text(data=cnames, aes(long, lat, label = region), size=2, inherit.aes = FALSE) +
    coord_map("polyconic") +
    labs(fill = "region") +
    theme(
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()
    ) +
    ggtitle("data")
```

Body:
I've got two ggplot maps which both use the same shapefile. One is the data and the other is the names of each country. Currently they are in seperate ggplots but how do I add the names over the top of my existing one (plot1)?

cnames <- aggregate(cbind(long, lat) ~ region, data=map,
                    FUN=function(x)mean(range(x)))
names <-ggplot(map, aes(long, lat)) +
    geom_polygon(aes(x = long, y = lat, group=group), colour='black', fill=NA) +
    geom_text(data=cnames, aes(long, lat, label = region), size=2) +
    coord_map()

plot1 <- ggplot(map, aes(x=long,y = lat, group = group, fill = map$`data`)) + geom_polygon(colour="black") + coord_map("polyconic") + labs(fill = "data") + theme(axis.title.x=element_blank(),axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),axis.title.y=element_blank(),axis.text.y=element_blank(),axis.ticks.y=element_blank())
  plot1 <- plot1 + ggtitle("data")
  plot1 <- plot1 + scale_fill_gradient2(low = muted("grey"), high = muted("deepskyblue4"))


问:
How do I get all the values from one table
I am using Microsoft SQL Server. I have two tables

Cost Center - A list of all our production processes.

Scheduled Process - A list of jobs that are scheduled to go through each Cost Center

My table Cost Center looks as below

```<code>CostCenterCode  CostCenterDesc
------------------------------
123             Print
456             Stich
789             Fold
999             Ship
</code>```

My table Process Schedule looks as below

```<code>JobNumber   StartDate   ScheduledHours  CostCenterCode
------------------------------------------------------
12345   2020-01-01      33               123
12345   2020-01-01      33               456
12345   2020-01-01      33               999
</code>```

Now based on my above dataset, cost center 789 does not have anything scheduled. I want to write a query that will show what is scheduled for each cost center each day. Cost Center 789 does not have anything scheduled but it should still show that cost center with 0 hours.

答:
Use a left join:

```<code>select cc.*, ss.*
from costcenter cc left join
     schedule s
     on cc.costcentercode = s.costcentercode
</code>```

Body:
I am using Microsoft SQL Server. I have two tables

Cost Center - A list of all our production processes.

Scheduled Process - A list of jobs that are scheduled to go through each Cost Center

My table Cost Center looks as below

CostCenterCode  CostCenterDesc
------------------------------
123             Print
456             Stich
789             Fold
999             Ship

My table Process Schedule looks as below

JobNumber   StartDate   ScheduledHours  CostCenterCode
------------------------------------------------------
12345   2020-01-01      33               123
12345   2020-01-01      33               456
12345   2020-01-01      33               999

Now based on my above dataset, cost center 789 does not have anything scheduled. I want to write a query that will show what is scheduled for each cost center each day. Cost Center 789 does not have anything scheduled but it should still show that cost center with 0 hours.

Body:
Use a left join:

select cc.*, ss.*
from costcenter cc left join
     schedule s
     on cc.costcentercode = s.costcentercode


问:
UK Districts Not Mapping Power BI
Folks, my issue should be simple.

I am trying to map UK districts in Kent. But when I try to map the district of Medway I get the following;

This is obviously a polygon for all of Kent. My question is what alias do I need for Medway to get it to map correctly. When you turn on the rest of the districts there is no issue at all. but as you can see Medway is missing.

I have tried the following iterations;

Medway Towns

Medway UA

Medway Unitary Authority

答: Ideally I would have expected it to work fine. In this particular visualization, Power BI integrates with Bing, so that seems to be messing it up. You can try typing "Medway Kent", the results seem to be better. Hope this helps.</p>

Title: UK Districts Not Mapping Power BI


问:
Semantic UI segments floated property use
I'm trying to have a segment float to the left and to the right in this situation. I may have a fundamental misunderstanding of how floats work. I have no idea why the right segment is behaving this way.

Left highlighted in blue and right highlighted in red for clarification.

Perhaps Segments aren't the solution here?

This is my layout component:

```<code>return (
    <Container fluid>
      <Navbar />
      <Segment floated={"left"} style={{
          height: "65vh",
          marginLeft: "1rem",
        }}
      >Left Floating Segment</Segment>

      <Segment style={{
          height: "80vh",
          margin: `0 auto`,
          width: "60vw",
          padding: `0 1.45rem`,
        }}>{children}</Segment>

      <Segment floated={"right"} style={{
          height: "65vh",
          marginRight: "1rem",
        }}>Right Floating Segment</Segment>

      <Footer />
    </Container>
  )
</code>```

答:
I found that putting the segments in a container with display: flex was enough to get them to behave.

<Container style={{display: 'flex'}}> </Container>

Body:
I'm trying to have a segment float to the left and to the right in this situation. I may have a fundamental misunderstanding of how floats work. I have no idea why the right segment is behaving this way.

Left highlighted in blue and right highlighted in red for clarification.

Perhaps Segments aren't the solution here?

This is my layout component:

return (
    <Container fluid>
      <Navbar />
      <Segment floated={"left"} style={{
          height: "65vh",
          marginLeft: "1rem",
        }}
      >Left Floating Segment</Segment>

      <Segment style={{
          height: "80vh",
          margin: `0 auto`,
          width: "60vw",
          padding: `0 1.45rem`,
        }}>{children}</Segment>

      <Segment floated={"right"} style={{
          height: "65vh",
          marginRight: "1rem",
        }}>Right Floating Segment</Segment>

    </Container>
  )


问:
How to pass a lambda as an extra of an Intent?
I'm new to kotlin and Android, and i was looking into recyclerView but ran into a few hiccups.

Basically i have,

+ 2 Activities, MainActivity containig a recyclerView and fullDetails activity that opens with onClick on each ticket of the recyclerView,
Activity A & Activity B

The Fab show show a function unique to each item, like a Toast as in this example.

+An ArrayList of objects,tempMenuList of options class,

+The class contains a few strings an a lambda variable actionOfItem as i want to have individual functions for each object,

+I'm trying to pass the lambda through an intent as serializable throught the OnClick Listener like this:

```<code>val intent=Intent(context,fullDetails::class.java)
intent.putExtra("action",Runnable{tempMenuList[position].actionOfItem} as java.io.Serializable)
</code>```

+On Activity B, I get the lambda like this and try to call the function, as this was crashing my app, I made a seperate actions class for the lambda's so that i can write getSerializable() as an object of actions class.

```<code>val action=bundle.getSerializable("function") as actions?
fabShow.setOnClickListener{
          action?.action
    }
</code>```

Now the app loads the MainActivity,but Crashes when The OnClickListner of the RecyclerView is pressed.

I know my naming is super bad and confusing and i don't use comments,

but is there any way to pass a unique function for each object through an intent?
Edit 1: I read that i can do this using SharedPreferences, but it isn't reccommended.

Here's the Logcat:

```<code>java.lang.ClassCastException: com.example.androidreferenceapp.MainActivity$menuAdapter$onBindViewHolder$1$1 cannot be cast to java.io.Serializable
    at com.example.androidreferenceapp.MainActivity$menuAdapter$onBindViewHolder$1.onClick(MainActivity.kt:58)
    at android.view.View.performClick(View.java:6605)
    at android.view.View.performClickInternal(View.java:6582)
    at android.view.View.access$3100(View.java:778)
    at android.view.View$PerformClick.run(View.java:25897)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6762)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
</code>```

Here's the full Source Code if that helps

答:
What you are trying to do is an anti-pattern. You should instead pass the lambda as an argument to the recyclerview's adapter if possible.
for example

```<code>//adapter class
class MyAdapter(
private val items: List<MyModel>,
private val clickListener: (item: MyModel) -> Unit
) :
RecyclerView.Adapter<MyAdapter.MyModelViewHolder>() {
   //adapter boilerplate
....
//viewholder class
inner class MyViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView)
 fun bind(item: MyModel){
   itemView.setOnClickListener{
      clickListener(item)
    }
  }
}
</code>```

This way you can handle click events on the Activity which created the RecyclerView.

```<code>val myList = listOf(item1, item2...)
val adapter = MyAdapter(myList,  {item->
 //do whatever you want with item
})
</code>```

This gives you more flexibility and is fairly easier to implement as well.

Note that, serialization is a very expensive thing to do in android, which was why Parcelables were made. But in your use case, you can avoid both.

Body:
I'm new to kotlin and Android, and i was looking into recyclerView but ran into a few hiccups.

Basically i have,

+ 2 Activities, MainActivity containig a recyclerView and fullDetails activity that opens with onClick on each ticket of the recyclerView,
Activity A & Activity B

The Fab show show a function unique to each item, like a Toast as in this example.

+An ArrayList of objects,tempMenuList of options class,

+The class contains a few strings an a lambda variable actionOfItem as i want to have individual functions for each object,

+I'm trying to pass the lambda through an intent as serializable throught the OnClick Listener like this:

val intent=Intent(context,fullDetails::class.java)
intent.putExtra("action",Runnable{tempMenuList[position].actionOfItem} as java.io.Serializable)

+On Activity B, I get the lambda like this and try to call the function, as this was crashing my app, I made a seperate actions class for the lambda's so that i can write getSerializable() as an object of actions class.

val action=bundle.getSerializable("function") as actions?
fabShow.setOnClickListener{
          action?.action
    }

Now the app loads the MainActivity,but Crashes when The OnClickListner of the RecyclerView is pressed.

I know my naming is super bad and confusing and i don't use comments,

but is there any way to pass a unique function for each object through an intent?
Edit 1: I read that i can do this using SharedPreferences, but it isn't reccommended.

Here's the Logcat:

java.lang.ClassCastException: com.example.androidreferenceapp.MainActivity$menuAdapter$onBindViewHolder$1$1 cannot be cast to java.io.Serializable
    at com.example.androidreferenceapp.MainActivity$menuAdapter$onBindViewHolder$1.onClick(MainActivity.kt:58)
    at android.view.View.performClick(View.java:6605)
    at android.view.View.performClickInternal(View.java:6582)
    at android.view.View.access$3100(View.java:778)
    at android.view.View$PerformClick.run(View.java:25897)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6762)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Here's the full Source Code if that helps

Body:
What you are trying to do is an anti-pattern. You should instead pass the lambda as an argument to the recyclerview's adapter if possible.
for example

//adapter class
class MyAdapter(
private val items: List<MyModel>,
private val clickListener: (item: MyModel) -> Unit
) :
RecyclerView.Adapter<MyAdapter.MyModelViewHolder>() {
   //adapter boilerplate
....
//viewholder class
inner class MyViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView)
 fun bind(item: MyModel){
   itemView.setOnClickListener{
      clickListener(item)
    }
  }
}

This way you can handle click events on the Activity which created the RecyclerView.

val myList = listOf(item1, item2...)
val adapter = MyAdapter(myList,  {item->
 //do whatever you want with item
})

This gives you more flexibility and is fairly easier to implement as well.

Note that, serialization is a very expensive thing to do in android, which was why Parcelables were made. But in your use case, you can avoid both.


答:
All the set timeouts run at the same time. The loop runs and sets each thing to run at 5 seconds. You need to add a delay by offsetting each iteration.

```<code>for(let i = 0; i < boxs.length; i++){
  setTimeout(function () {
    boxs[i].classList.add("type");
  },5000 * (i + 1));
}
</code>```

Most people would use a queue

// grab all the elements and put it into an array
const paras = Array.from(document.querySelectorAll("p"))

function runNext() {
  // wait 5 seconds
  window.setTimeout( () => {
    // remove the first item from array and set the class
    paras.shift().classList.add("type")
    // if items are remaining, set up the next timeout
    if (paras.length) runNext()
  }, 5000)
}

runNext()```
<pre class="snippet-code-css lang-css prettyprint-override"><code>p { color: #CCC; }
p.type { color: #000; }</code>```

One

Two

Three

Four

Five
```

Title: add class to object 1, wait, add class to object 2 within for loop

Body:
I want to get a collection of elements with a class. I then wish to loop through each element in the collection in order to add a class.

However, I want it to add a class to the first in the collection, then wait 5 seconds before adding to the 2nd in the collection. And so on...

Body:
All the set timeouts run at the same time. The loop runs and sets each thing to run at 5 seconds. You need to add a delay by offsetting each iteration.

for(let i = 0; i < boxs.length; i++){
  setTimeout(function () {
    boxs[i].classList.add("type");
  },5000 * (i + 1));
}

Most people would use a queue

// grab all the elements and put it into an array
const paras = Array.from(document.querySelectorAll("p"))

function runNext() {
  // wait 5 seconds
  window.setTimeout( () => {
    // remove the first item from array and set the class
    paras.shift().classList.add("type")
    // if items are remaining, set up the next timeout
    if (paras.length) runNext()
  }, 5000)
}

runNext()

p { color: #CCC; }
p.type { color: #000; }

<p>One</p>
<p>Two</p>
<p>Three</p>
<p>Four</p>
<p>Five</p>


问:
How to get book metadata?
My application needs to retrieve information about any published book based on a provided ISBN, title, or author. This is hardly a unique requirement---sites like Amazon.com, Chegg.com, and even software like Book Collector seem to be able to do this easily. But I have not been able to replicate it.

To clarify, I do not need to search the entire database of books---only a limited subset which have been inputted, as in a book collection. The database would simply allow me to tag the inputted books with the necessary metadata to enable search on that subset of books. So scale is not the issue here---getting the metadata is.

The options I have tried are:

Scrape Amazon. Scraping the regular Amazon pages was not very robust to things like missing authors, and while scraping the smaller mobile pages was faster, they shared the same issues with robustness of extraction. Plus, building this into an application is a clear violation of Amazon's Terms of Service.

Scrape the Library of Congress. While this seems to have fewer legal ramifications, ease and robustness were again issues.

ISBNdb.com API. While the service is free up to a point, and does a good job of returning the necessary metadata, I need to do this for over 500 books on a daily basis, at which point this service costs money proportional to use. I'd prefer a free or one-time payment solution that allows me to do the same.

Google Book Data API. While this seems to provide the information I need, I cannot display the book preview as their terms of service requires.

Buy a license to a database of books. For example, companies like Ingram or Baker & Taylor provide these catalogs to retailers and libraries. This solution is obviously expensive, so I'm hoping that there's a more elegant solution I've missed. But if not, and someone on SO has had a good experience with a particular database, I'm willing to go with that.

I've tried to describe my approach in detail so others with fewer books can take advantage of the above solutions. But given my requirements, I'm at my wits' end for retrieving book metadata.

答:
Instead of scraping Amazon, you can use the API they expose for their affiliate program: https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html

It allows about 3k requests per hour and returns well-formed XML. It requires you to set a link to the book that you show the information about, and you must state that you are an affiliate partner.

Title: How to get book metadata?

ContentLicense: CC BY-SA 3.0


答:
You need a closure for this, otherwise all the functions will execute when i===boxs.length.

```<code>for (let i = 0; i < boxs.length; i++) {
    ( num => setTimeout(function () {
        boxs[num].classList.add("type");
    }, 5000*num))(i)
}
</code>```

EDIT

I just noticed that you used let, so actually you don't need a closure. Every loop will have its own scope. You can just use 5000*i

Body:
You need a closure for this, otherwise all the functions will execute when i===boxs.length.

for (let i = 0; i < boxs.length; i++) {
    ( num => setTimeout(function () {
        boxs[num].classList.add("type");
    }, 5000*num))(i)
}

EDIT

I just noticed that you used let, so actually you don't need a closure. Every loop will have its own scope. You can just use 5000*i


问:
Laravel - Eloquent Relationship not working One to Many relationship
I have two models with One-to-Many relationship. I want to display data with relationship in blade.

Products Table

```<code>Table name = Products
PrimaryKey = pro_id
ForeignKey = cat_id
</code>```

Categories Table

```<code>Table name = categories
PrimaryKey = cat_id
</code>```

Products Model Code

```<code>namespace App;

use Illuminate\Database\Eloquent\Model;

class productsModel extends Model
{
    //code...
    protected $table      = 'products';
    protected $primaryKey = 'pro_id';

    // Every Products Belongs To One Category

    public function category()
    {
        # code...
        return $this->belongsTo('APP\abcModel','cat_id');
    }
}
</code>```

Categories Model Code

```<code>namespace App;

use Illuminate\Database\Eloquent\Model;

class categoryModel extends Model
{
    //code...
    protected $table      = 'categories';
    protected $primaryKey = 'cat_id';

    // One Category Has Many Products

    public function products()
    {
        # code...
        return $this->hasMany('App\productsModel','cat_id','pro_id');
    }
}
</code>```

Controller Code

namespace App\Http\Controllers;

```<code>use Illuminate\Http\Request;
use App\productsModel;
class productsController extends Controller
{
    //code...
    public function products($category_id='')
    {
        # code...
        $data["products"] = productsModel::where
                            ('cat_id',$category_id)
                            ->get();
        $data["categories"] = productsModel::where
                            ('cat_id',$category_id)->first()->category;
        echo "```";
        print_r($data);
        echo "```";
    }
}
</code>```

ERROR:
Symfony\Component\Debug\Exception\FatalThrowableError
Class 'APP\categoryModel' not found

答:
Seems that sometimes you have App, sometimes APP, while PHP is not case sensitive on class names, you might use an operating system (Linux?) that is case sensitive in terms of file names.

I would recommend to have only App everywhere, your error message clearly indicates: APP.

Body:
I have two models with One-to-Many relationship. I want to display data with relationship in blade.

Products Table

Table name = Products
PrimaryKey = pro_id
ForeignKey = cat_id

Categories Table

Table name = categories
PrimaryKey = cat_id

Products Model Code

namespace App;

use Illuminate\Database\Eloquent\Model;

class productsModel extends Model
{
    //code...
    protected $table      = 'products';
    protected $primaryKey = 'pro_id';

    // Every Products Belongs To One Category

    public function category()
    {
        # code...
        return $this->belongsTo('APP\abcModel','cat_id');
    }
}

Categories Model Code

namespace App;

use Illuminate\Database\Eloquent\Model;

class categoryModel extends Model
{
    //code...
    protected $table      = 'categories';
    protected $primaryKey = 'cat_id';

    // One Category Has Many Products

    public function products()
    {
        # code...
        return $this->hasMany('App\productsModel','cat_id','pro_id');
    }
}

Controller Code

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\productsModel;
class productsController extends Controller
{
    //code...
    public function products($category_id='')
    {
        # code...
        $data["products"] = productsModel::where
                            ('cat_id',$category_id)
                            ->get();
        $data["categories"] = productsModel::where
                            ('cat_id',$category_id)->first()->category;
        echo "
";
        print_r($data);
        echo "
";
    }
}

ERROR:
Symfony\Component\Debug\Exception\FatalThrowableError
Class 'APP\categoryModel' not found


问:
How exactly implicitWait is handled dynamically in selenium?
I have a doubt related to the implicit wait of selenium? As we know that Implicit Wait is dynamic wait that means if we mention that wait for 10 seconds for any element to be loaded but if the element is loaded within 4 seconds then driver comes out of the wait.

So, the question is that how driver came to know that element is loaded in 4 seconds and lets come out from the wait? We have not mentioned any condition in Implicit Wait like look for the visibility of any element and then come out then how exactly implicit wait takes a call to to come out of the wait?

答:
Implicit Wait can't be handled dynamically using Selenium. In his epic comment Jim Evans [Maintainer - DotNet client / IEDriverServer] mentioned that, implicitlyWaits are often (always may not be) implemented on the remote side of the WebDriver system. That means ImplicitWait are baked in to the WebDriver variants i.e. GeckoDriver, IEDriverServer, ChromeDriver, the WebDriver Firefox extension that gets installed into the anonymous Firefox profile (Selenium RC), and the Java remote WebDriver server (selenium-server-standalone.jar).

Once you set the implicitly_wait, the WebDriver instance would be able to carry this configuration till its lifetime. To set the timespan of the waiting time, you can:

Python:

```<code>driver.implicitly_wait(5)
</code>```

Java:

```<code>driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
</code>```

DotNet:

```<code>driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
</code>```

If at any point of time you want to remove the ImplicitWait you can achieve it as follows:

Python:

```<code>driver.implicitly_wait(0)
</code>```

Java:

```<code>driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
</code>```

DotNet:

```<code>driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0);
</code>```

Body:
Implicit Wait can't be handled dynamically using Selenium. In his epic comment Jim Evans [Maintainer - DotNet client / IEDriverServer] mentioned that, implicitlyWaits are often (always may not be) implemented on the remote side of the WebDriver system. That means ImplicitWait are baked in to the WebDriver variants i.e. GeckoDriver, IEDriverServer, ChromeDriver, the WebDriver Firefox extension that gets installed into the anonymous Firefox profile (Selenium RC), and the Java remote WebDriver server (selenium-server-standalone.jar).

Once you set the implicitly_wait, the WebDriver instance would be able to carry this configuration till its lifetime. To set the timespan of the waiting time, you can:

Python:

driver.implicitly_wait(5)

Java:

driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);

DotNet:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);

If at any point of time you want to remove the ImplicitWait you can achieve it as follows:

Python:

driver.implicitly_wait(0)

Java:

driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);

DotNet:

driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0);


问:
Scraping data from charts or tables created using Google Visualization tools using Python and Selenium
I am trying to scrape data from the tables and charts from this website:
https://www.portfoliovisualizer.com/fund-performance?s=y&symbol=MUB&symbols=VTEB&benchmark=VWITX&startDate=1%2F1%2F2015&endDate=1%2F31%2F2020

The site contains both static tables, which I can parse w/o any problem using requests and BeautifulSoup, and some dynamically generated tables and charts that are created through the use of Google Vizualization tools.
For the dynamically generated parts, I used the Selenium webdriver, and was able to get the page source, after the dynamic charts and tables are being generated, so I see the values I am looking to pull. However, I do not know how to pull them, as they show in the page source in segments like the one below:

Blockquote

```<code>    <div id="chartDiv2" style="width: 900px; height: 500px;"></div>
    <script>
    function getChartData2() {
    var data2 = google.visualization.arrayToDataTable([['Year', 'Vanguard Tax-Exempt Bond ETF', 'iShares
    National Muni Bond ETF', 'Vanguard Interm-Term Tx-Ex Inv'],['2015', 0.02622989191078684,
    0.027694140180976934, 0.020218079771240793],['2016', 0.0017793103198122662, -0.0016512224730700353,
    8.245768963E-4],['2017', 0.04691417159814648, 0.04723004573804612, 0.04534581696422735],['2018',
    0.010468419206658197, 0.0092958557816043, 0.01252249494095059],['2019', 0.07344514685363279,
    0.07055205700158873, 0.06781218369439523],['2020', 0.017556966753828895, 0.01659204635238365,
    0.0158935038009671]]);
    var formatter2 = new google.visualization.NumberFormat({ pattern: '0.00%' });
    formatter2.format(data2, 1);
    formatter2.format(data2, 2);
    formatter2.format(data2, 3);
    var chart2 = new google.visualization.ColumnChart(document.getElementById('chartDiv2'));
    var options2 = { title: 'Annual Returns', legend: { textStyle: { fontSize: 13 } }, hAxis: { title:
    'Year'}, vAxis: { dummy: false, title: 'Annual Return', format:'0.0%', minValue: 0}, focusTarget:
    'category'};
    return [chart2, data2, options2];
    }
    </script>
</code>```

Blockquote

Any search of the soup with find or find_all stumbles at the outermost table (which seems to encompass the entire webpage). I am quite new at Python, so any help would be really appreciated. Right now, the only way I can think of doing this is saving the entire page source as a text file (which I have done) then parsing it myself by searching for each instance of google vizualization tools being used and proceeding from there). That would be quite tedious, and probably not very robust when trying to use it to another link.

Many thanks in advance for any suggestion.

答:
The getChartData2() function renders the chart visualization as an SVG on the page. That is how the chart supports the interactive capabilities that you see as you mouse over the chart. You could try grabbing that SVG from the DOM and saving it as SVG to see if it will keep the chart without the interactivity. Or you may try saving it as a PNG. Not sure of the best approach.

May I ask what you are trying to accomplish? It may be easier to scrape the data from the tables and then use the data to generate your own charts and tables on your platform. You could even use the same Google Visualization tools.

And as another option, Tiingo is a stock market data platform that has an API that has really good free access levels. Rather than scraping from PV, you could integrate directly with Tiingo API to pull the data that you want.

Hope that helps!

Updated based on Cimerra's comment above:

Yes, pulling the data from the getChartData2() text would be challenging. Do you have access to executing any of the JavaScript on the page through your framework? When I open Chrome Developer tools for that page, I can call getChartData2() and three objects are returned. The 2nd object is the data2 object that you could in theory manipulate to get what you want out of it.

```<code>Tf: Array(6)
  0:
    c: Array(4)
      0: {v: "2015"}
      1: {v: 0.02622989191078684, f: "2.62%"}
      2: {v: 0.027694140180976934, f: "2.77%"}
      3: {v: 0.020218079771240793, f: "2.02%"}
</code>```

If you still can't do that, I would suggest finding a source for the data (like Tiingo (free) or CSI Data (paid but is what PV uses)) and then performing your own calculations for what you need. The side benefit is that you then actually get immersed into the financial world and learn how all of these things are calculated.

Granted, that becomes pretty challenging and then you end up rebuilding a lot of what PV provides for you. I rebuilt a small part of PV in Google Sheets + Tiingo but in the end it was a brittle mess. PV just recently implemented a subscription model and I subscribed because it is an awesome site with awesome data and I don't want to spend all my time trying to recreate it.

Body:
I am trying to scrape data from the tables and charts from this website:
https://www.portfoliovisualizer.com/fund-performance?s=y&symbol=MUB&symbols=VTEB&benchmark=VWITX&startDate=1%2F1%2F2015&endDate=1%2F31%2F2020

The site contains both static tables, which I can parse w/o any problem using requests and BeautifulSoup, and some dynamically generated tables and charts that are created through the use of Google Vizualization tools.
For the dynamically generated parts, I used the Selenium webdriver, and was able to get the page source, after the dynamic charts and tables are being generated, so I see the values I am looking to pull. However, I do not know how to pull them, as they show in the page source in segments like the one below:

Blockquote

Blockquote

Any search of the soup with find or find_all stumbles at the outermost table (which seems to encompass the entire webpage). I am quite new at Python, so any help would be really appreciated. Right now, the only way I can think of doing this is saving the entire page source as a text file (which I have done) then parsing it myself by searching for each instance of google vizualization tools being used and proceeding from there). That would be quite tedious, and probably not very robust when trying to use it to another link.

Many thanks in advance for any suggestion.

Body:
The getChartData2() function renders the chart visualization as an SVG on the page. That is how the chart supports the interactive capabilities that you see as you mouse over the chart. You could try grabbing that SVG from the DOM and saving it as SVG to see if it will keep the chart without the interactivity. Or you may try saving it as a PNG. Not sure of the best approach.

May I ask what you are trying to accomplish? It may be easier to scrape the data from the tables and then use the data to generate your own charts and tables on your platform. You could even use the same Google Visualization tools.

And as another option, Tiingo is a stock market data platform that has an API that has really good free access levels. Rather than scraping from PV, you could integrate directly with Tiingo API to pull the data that you want.

Hope that helps!

Updated based on Cimerra's comment above:

Yes, pulling the data from the getChartData2() text would be challenging. Do you have access to executing any of the JavaScript on the page through your framework? When I open Chrome Developer tools for that page, I can call getChartData2() and three objects are returned. The 2nd object is the data2 object that you could in theory manipulate to get what you want out of it.

Tf: Array(6)
  0:
    c: Array(4)
      0: {v: "2015"}
      1: {v: 0.02622989191078684, f: "2.62%"}
      2: {v: 0.027694140180976934, f: "2.77%"}
      3: {v: 0.020218079771240793, f: "2.02%"}

If you still can't do that, I would suggest finding a source for the data (like Tiingo (free) or CSI Data (paid but is what PV uses)) and then performing your own calculations for what you need. The side benefit is that you then actually get immersed into the financial world and learn how all of these things are calculated.

Granted, that becomes pretty challenging and then you end up rebuilding a lot of what PV provides for you. I rebuilt a small part of PV in Google Sheets + Tiingo but in the end it was a brittle mess. PV just recently implemented a subscription model and I subscribed because it is an awesome site with awesome data and I don't want to spend all my time trying to recreate it.


问:
Issues after installing tidymodel and dependent packages in R
I was trying to use tidymodels and while installing this package it also installed certain dependent packages I would assume. Post that I have been getting this error whenever I run some dplyr based standalone code or my shiny app which was working fine till then. How can I fix this issue:

```<code>library(readr)
library(dplyr)
uscities <- read_csv("https://gist.githubusercontent.com/senthilthyagarajan/f2e7839a08a377c698d9235bb1bcc0bb/raw/3d4e40b422e5535389804d6e2390b674241ca045/uscities.csv")
#View(uscities)

uscities <- uscities %>% select(city,city_ascii,state_id,state_name,population,lat,lng)
</code>```

```<code>Error: `...` is not empty.

We detected these problematic arguments:
* `logical`

These dots only exist to allow future extensions and should be empty.
Did you misspecify an argument?
Run `rlang::last_error()` to see where the error occurred.
</code>```

So I did sessionInfo() and this is what I got :

```<code>> rm(list=ls())
> sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.5

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

loaded via a namespace (and not attached):
[1] compiler_3.6.1 tools_3.6.1    packrat_0.5.0
> library(readr)
> library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

> uscities <- read_csv("https://gist.githubusercontent.com/senthilthyagarajan/f2e7839a08a377c698d9235bb1bcc0bb/raw/3d4e40b422e5535389804d6e2390b674241ca045/uscities.csv")
Parsed with column specification:
cols(
  city = col_character(),
  city_ascii = col_character(),
  state_id = col_character(),
  state_name = col_character(),
  county_fips = col_double(),
  county_name = col_character(),
  county_fips_all = col_character(),
  county_name_all = col_character(),
  lat = col_double(),
  lng = col_double(),
  population = col_double(),
  density = col_double(),
  source = col_character(),
  military = col_logical(),
  incorporated = col_logical(),
  timezone = col_character(),
  ranking = col_double(),
  zips = col_character(),
  id = col_double()
)
> #View(uscities)
>
> uscities <- uscities %>% dplyr::select(city)
Error: `...` is not empty.

We detected these problematic arguments:
* `logical`

These dots only exist to allow future extensions and should be empty.
Did you misspecify an argument?
</code>```

So I did try the rlang::last_trace() and got this

```<code>> rlang::last_trace()
<error/rlib_error_dots_nonempty>
`...` is not empty.

We detected these problematic arguments:
* `logical`

These dots only exist to allow future extensions and should be empty.
Did you misspecify an argument?
Backtrace:
     █
  1. └─uscities %>% dplyr::select(city)
  2.   ├─base::withVisible(eval(quote(`_fseq`(`_lhs`)), env, env))
  3.   └─base::eval(quote(`_fseq`(`_lhs`)), env, env)
  4.     └─base::eval(quote(`_fseq`(`_lhs`)), env, env)
  5.       └─`_fseq`(`_lhs`)
  6.         └─magrittr::freduce(value, `_function_list`)
  7.           ├─base::withVisible(function_list[[k]](value))
  8.           └─function_list[[k]](value)
  9.             ├─dplyr::select(., city)
 10.             └─dplyr:::select.data.frame(., city)
 11.               └─tidyselect::vars_select(tbl_vars(.data), !!!enquos(...))
 12.                 └─tidyselect:::eval_select_impl(...)
 13.                   ├─tidyselect:::with_subscript_errors(...)
 14.                   │ ├─base::tryCatch(...)
 15.                   │ │ └─base:::tryCatchList(expr, classes, parentenv, handlers)
 16.                   │ │   └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]])
 17.                   │ │     └─base:::doTryCatch(return(expr), name, parentenv, handler)
 18.                   │ └─tidyselect:::instrument_base_errors(expr)
 19.                   │   └─base::withCallingHandlers(...)
 20.                   └─tidyselect:::vars_select_eval(...)
 21.                     └─tidyselect:::walk_data_tree(expr, data_mask, context_mask)
 22.                       └─tidyselect:::eval_c(expr, data_mask, context_mask)
 23.                         └─tidyselect:::reduce_sels(node, data_mask, context_mask, init = init)
 24.                           └─tidyselect:::walk_data_tree(init, data_mask, context_mask)
 25.                             └─tidyselect:::as_indices_sel_impl(...)
 26.                               └─tidyselect:::as_indices_impl(x, vars, strict = strict)
 27.                                 └─vctrs::vec_as_subscript(x, logical = "error")
 28.                                   └─ellipsis::check_dots_empty()
 29.                                     └─ellipsis:::action_dots(...)
</code>```

答: It was an issue with vctrs package . I could see it from rlang trace error logs </p>

Body:
I was trying to use tidymodels and while installing this package it also installed certain dependent packages I would assume. Post that I have been getting this error whenever I run some dplyr based standalone code or my shiny app which was working fine till then. How can I fix this issue:

library(readr)
library(dplyr)
uscities <- read_csv("https://gist.githubusercontent.com/senthilthyagarajan/f2e7839a08a377c698d9235bb1bcc0bb/raw/3d4e40b422e5535389804d6e2390b674241ca045/uscities.csv")
#View(uscities)

uscities <- uscities %>% select(city,city_ascii,state_id,state_name,population,lat,lng)

Error: `...` is not empty.

We detected these problematic arguments:
* `logical`

These dots only exist to allow future extensions and should be empty.
Did you misspecify an argument?
Run `rlang::last_error()` to see where the error occurred.

So I did sessionInfo() and this is what I got :

> rm(list=ls())
> sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.5

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

loaded via a namespace (and not attached):
[1] compiler_3.6.1 tools_3.6.1    packrat_0.5.0
> library(readr)
> library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

> uscities <- read_csv("https://gist.githubusercontent.com/senthilthyagarajan/f2e7839a08a377c698d9235bb1bcc0bb/raw/3d4e40b422e5535389804d6e2390b674241ca045/uscities.csv")
Parsed with column specification:
cols(
  city = col_character(),
  city_ascii = col_character(),
  state_id = col_character(),
  state_name = col_character(),
  county_fips = col_double(),
  county_name = col_character(),
  county_fips_all = col_character(),
  county_name_all = col_character(),
  lat = col_double(),
  lng = col_double(),
  population = col_double(),
  density = col_double(),
  source = col_character(),
  military = col_logical(),
  incorporated = col_logical(),
  timezone = col_character(),
  ranking = col_double(),
  zips = col_character(),
  id = col_double()
)
> #View(uscities)
>
> uscities <- uscities %>% dplyr::select(city)
Error: `...` is not empty.

We detected these problematic arguments:
* `logical`

These dots only exist to allow future extensions and should be empty.
Did you misspecify an argument?

So I did try the rlang::last_trace() and got this

> rlang::last_trace()
<error/rlib_error_dots_nonempty>
`...` is not empty.

We detected these problematic arguments:
* `logical`

These dots only exist to allow future extensions and should be empty.
Did you misspecify an argument?
Backtrace:
     █
  1. └─uscities %>% dplyr::select(city)
  2.   ├─base::withVisible(eval(quote(`_fseq`(`_lhs`)), env, env))
  3.   └─base::eval(quote(`_fseq`(`_lhs`)), env, env)
  4.     └─base::eval(quote(`_fseq`(`_lhs`)), env, env)
  5.       └─`_fseq`(`_lhs`)
  6.         └─magrittr::freduce(value, `_function_list`)
  7.           ├─base::withVisible(function_list[[k]](value))
  8.           └─function_list[[k]](value)
  9.             ├─dplyr::select(., city)
 10.             └─dplyr:::select.data.frame(., city)
 11.               └─tidyselect::vars_select(tbl_vars(.data), !!!enquos(...))
 12.                 └─tidyselect:::eval_select_impl(...)
 13.                   ├─tidyselect:::with_subscript_errors(...)
 14.                   │ ├─base::tryCatch(...)
 15.                   │ │ └─base:::tryCatchList(expr, classes, parentenv, handlers)
 16.                   │ │   └─base:::tryCatchOne(expr, names, parentenv, handlers[[1L]])
 17.                   │ │     └─base:::doTryCatch(return(expr), name, parentenv, handler)
 18.                   │ └─tidyselect:::instrument_base_errors(expr)
 19.                   │   └─base::withCallingHandlers(...)
 20.                   └─tidyselect:::vars_select_eval(...)
 21.                     └─tidyselect:::walk_data_tree(expr, data_mask, context_mask)
 22.                       └─tidyselect:::eval_c(expr, data_mask, context_mask)
 23.                         └─tidyselect:::reduce_sels(node, data_mask, context_mask, init = init)
 24.                           └─tidyselect:::walk_data_tree(init, data_mask, context_mask)
 25.                             └─tidyselect:::as_indices_sel_impl(...)
 26.                               └─tidyselect:::as_indices_impl(x, vars, strict = strict)
 27.                                 └─vctrs::vec_as_subscript(x, logical = "error")
 28.                                   └─ellipsis::check_dots_empty()
 29.                                     └─ellipsis:::action_dots(...)


问:
How do I make words of certain length flip?
So I'm trying to create a program that takes sentences and makes words of length 5 or longer reverse itself. At the moment it is only flipping the last word that meets the condition and I don't know why.

```<code>userInput = "Hello this is a test sentence"
wordList = userInput.split()

for i in wordList:
    if len(i) >= 5:
        reversedWord = i[::-1]
        print(reversedWord)
        reversedSentence = userInput.replace(i, reversedWord)

print(reversedSentence)
</code>```

Instead of outputing "olleH this is a test ecnetnes" it outputs "Hello this is a test ecnetnes"

答:
The actual bug in your code has already been stated, I just want to add some feedback regarding the style:

You are performing the following steps:

split the input into words

find words that meet your requirement (len(word) > 5)

change the original string for each of those

This is rather unconventional and a bit unintuitive (it also has bad performance, since it manipulates your original string multiple times). I recommend the following algorithm instead:

split the input into words

reverse the words meeting your requirement inside that list

join the list into a sentence again to get your string

Example implementation:

```<code>user_input = "Hello this is a test sentence"
processed_words = []

for word in user_input.split():
    if len(word) >= 5:
        word = word[::-1]
    processed_words.append(word)

reversed_sentence = ' '.join(processed_words)
print(reversed_sentence)
</code>```

Taking this idea a bit further by using a generator expression, it might look like this:

```<code>user_input = "Hello this is a test sentence"

reversed_sentence = ' '.join(
    word[::-1] if len(word) >= 5 else word
    for word in user_input.split())

print(reversed_sentence)
</code>```

Body:
So I'm trying to create a program that takes sentences and makes words of length 5 or longer reverse itself. At the moment it is only flipping the last word that meets the condition and I don't know why.

userInput = "Hello this is a test sentence"
wordList = userInput.split()

for i in wordList:
    if len(i) >= 5:
        reversedWord = i[::-1]
        print(reversedWord)
        reversedSentence = userInput.replace(i, reversedWord)

print(reversedSentence)

Instead of outputing "olleH this is a test ecnetnes" it outputs "Hello this is a test ecnetnes"

Body:
The actual bug in your code has already been stated, I just want to add some feedback regarding the style:

You are performing the following steps:

split the input into words

find words that meet your requirement (len(word) > 5)

change the original string for each of those

This is rather unconventional and a bit unintuitive (it also has bad performance, since it manipulates your original string multiple times). I recommend the following algorithm instead:

split the input into words

reverse the words meeting your requirement inside that list

join the list into a sentence again to get your string

Example implementation:

user_input = "Hello this is a test sentence"
processed_words = []

for word in user_input.split():
    if len(word) >= 5:
        word = word[::-1]
    processed_words.append(word)

reversed_sentence = ' '.join(processed_words)
print(reversed_sentence)

Taking this idea a bit further by using a generator expression, it might look like this:

user_input = "Hello this is a test sentence"

reversed_sentence = ' '.join(
    word[::-1] if len(word) >= 5 else word
    for word in user_input.split())

print(reversed_sentence)


答:
There are a couple methods attempted in the code below attempting to capture the changes: by percent change and by using a rolling median method.

First import a couple useful libraries.  Also changing your data into a tibble called 'lizard_data'

```<code>library(tidyverse)
library(RcppRoll)
lizard_data <- tibble(your_data)
</code>```

Then using ggplot2, we can visualize all the time series.

```<code>lizard_data %>%
  pivot_longer(names_to = 'key', values_to = 'value', cols = c(LIZ, COP, BLK)) %>%
  arrange(TIME) %>%
  ggplot(aes(x = TIME, y = value, color = key))+
    geom_line()+
  facet_wrap(~ID, nrow = 2)
</code>```

Then we remove the adjustments by finding the delta, and we can use two different methods to smooth the time series.  First, with a percentile method (changing the top 5% and bottom 5% of values to the median) and second, with the rolling median (if the max change is ten percent higher or lower than the median, replacing the value with the median).

```<code>ld_w_change <- lizard_data %>%
  pivot_longer(names_to = 'key', values_to = 'value', cols = c(LIZ, COP, BLK)) %>%
  group_by(ID, key) %>%
  arrange(TIME) %>%
  mutate(lag = lag(value),
    raw_change = (value-lag),
    #using the percentile change method
    med_raw_change = median(raw_change, na.rm = T),
    q_05 = quantile(raw_change,.05, na.rm = T),
    q_95 = quantile(raw_change,.95, na.rm = T),
    adj_raw_change = if_else(raw_change > q_95 | raw_change < q_05, med_raw_change, raw_change),
    normalized_change = if_else(is.na(adj_raw_change), 0,adj_raw_change),
    initial_value = first(value),
    roll_raw_change = cumsum(normalized_change),
    new_value_pct = initial_value + roll_raw_change,
    # using the rolling median method
    rolling_median_change = roll_median(raw_change, n = 5, align = "right", na.rm = T, fill = NA),
    adj_median_change = case_when(raw_change > rolling_median_change*1.1 | raw_change < rolling_median_change*.9 ~ rolling_median_change,
                                  is.na(rolling_median_change) & is.na(raw_change) ~ 0,
                                  T ~ raw_change),
    normalized_med_change = cumsum(adj_median_change),
    new_value_roll = initial_value + normalized_med_change
    )
</code>```

I personally prefer the median adjustment, it seems to preserve the shape of the data better than the percentile method.  To compare these methods visually, we can plot them side-by-side:

```<code>ld_w_change %>%
  pivot_longer(names_to = 'method', values_to = 'adjusted_temp', cols = c(new_value_pct, new_value_roll)) %>%
  ggplot(aes(x = TIME, y =adjusted_temp, color = key))+
  geom_line()+
  facet_wrap(ID ~ method, nrow = 2)
</code>```

Title: Remove steps in time series

Body:
I am analyzing lizards increase of temperature. Problem is that the animals sometime move moving the thermometer we are using for the measurements. This results in spikes (few measurements extremely high or low) and steps (sudden offsets of the curve). I wanted to clean my curves from this noise, removing the spikes and aligning the two parts of the curve separated by each step. I guess the spikes can be easily smoothed but what about the steps?
Examples of time series with steps marked in yellow and spikes in red

This is a sample from my dataframe

structure(list(ID = structure(c(183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L, 183L,
183L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L, 194L,
194L, 194L, 194L), .Label = c("101", "102", "104", "106", "107",
"109", "110", "111", "112", "113", "114", "115", "116", "118",
"119", "121", "122", "123", "124", "125", "126", "128", "129",
"130", "132", "133", "134", "157", "158", "161", "163", "164",
"165", "166", "167", "168", "169", "170", "171", "172", "173",
"174", "175", "177", "178", "179", "180", "181", "182", "183",
"186", "187", "188", "189", "191", "192", "193", "194", "195",
"196", "198", "199", "201", "202", "203", "204", "205", "207",
"208", "209", "210", "211", "213", "214", "215", "218", "219",
"220", "221", "222", "223", "224", "225", "226", "227", "228",
"229", "230", "233", "235", "307", "308", "310", "311", "312",
"313", "314", "315", "316", "317", "318", "319", "320", "321",
"322", "323", "324", "325", "326", "327", "328", "329", "330",
"331", "332", "333", "334", "335", "336", "339", "340", "341",
"343", "344", "346", "347", "348", "349", "350", "351", "352",
"353", "354", "355", "356", "357", "358", "58", "59", "60", "61",
"62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72",
"73", "74", "75", "76", "78", "79", "80", "81", "82", "83", "84",
"85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95",
"96", "97", "98", "99", "F04000017", "F04001300", "F04060000",
"F04070000", "F04080000", "F05000017", "F05000020", "F05060000",
"F05070000", "FSUM", "M03100000", "M04000016", "M04090000", "M04100000",
"M05000016", "M05000018", "M05080000", "M05090000", "M05100000",
"MSUM"), class = "factor"), TIME = c(1600, 0, 180, 280, 1270,
190, 1570, 100, 630, 110, 1530, 790, 90, 650, 910, 1520, 460,
270, 710, 1240, 1610, 550, 470, 1320, 360, 1220, 860, 540, 290,
1330, 1180, 170, 1700, 990, 1060, 420, 10, 330, 1110, 1160, 890,
260, 620, 1140, 1420, 380, 300, 1650, 1430, 200, 490, 1590, 150,
430, 720, 950, 730, 1660, 1260, 740, 810, 780, 1370, 960, 1130,
1210, 1670, 1010, 760, 1280, 1450, 770, 1070, 1000, 1030, 690,
80, 1040, 1050, 160, 1350, 1230, 1630, 640, 1390, 1460, 1100,
850, 1120, 390, 1170, 980, 320, 590, 520, 1090, 560, 870, 1020,
750, 140, 700, 70, 1500, 340, 1290, 530, 840, 230, 370, 1440,
1200, 1480, 30, 1400, 210, 1300, 480, 450, 1580, 1560, 410, 1360,
900, 670, 1540, 50, 500, 400, 1380, 930, 580, 1680, 600, 1340,
240, 1190, 570, 1640, 940, 350, 1550, 830, 310, 880, 1080, 920,
1490, 610, 220, 1470, 800, 820, 40, 1250, 130, 60, 680, 20, 970,
1620, 440, 1690, 120, 510, 1410, 660, 250, 1310, 1150, 1510,
1230, 1540, 320, 1380, 680, 410, 480, 580, 130, 670, 1200, 1900,
1410, 1470, 1950, 400, 870, 970, 1740, 500, 1300, 1220, 240,
660, 1100, 20, 490, 590, 900, 820, 1910, 920, 690, 1290, 1710,
750, 1860, 1840, 880, 1250, 2070, 640, 1580, 1310, 800, 1000,
2090, 1760, 330, 760, 40, 600, 1800, 200, 1730, 2080, 470, 30,
1490, 2030, 860, 1620, 250, 1880, 790, 90, 360, 1520, 460, 180,
1770, 1450, 1940, 1370, 1180, 290, 2060, 1240, 1500, 1480, 510,
980, 1610, 1630, 950, 1980, 990, 140, 60, 110, 1680, 10, 550,
1700, 1750, 1270, 1690, 230, 2010, 1070, 910, 300, 1850, 1140,
1350, 930, 170, 1650, 1170, 1820, 1040, 1420, 120, 1150, 50,
960, 1560, 1790, 630, 280, 740, 1890, 2020, 370, 2040, 2050,
310, 380, 1920, 340, 1030, 430, 1330, 1670, 1960, 830, 1590,
420, 1400, 560, 1360, 1460, 1440, 1120, 1870, 1720, 1130, 730,
390, 850, 520, 1090, 1550, 100, 1930, 1010, 440, 210, 1390, 720,
1190, 450, 770, 1320, 220, 1640, 570, 2100, 1210, 650, 2000,
840, 1340, 1830, 530, 1110, 1260, 890, 700, 80, 810, 1060, 260,
1510, 1600, 70, 1430, 1280, 1530, 1020, 540, 940, 1050, 710,
1660, 1570, 270, 610, 620, 780, 1780, 350, 1970, 0, 1160, 1990,
190, 150, 1080, 160, 1810), LIZ = c(33.88628, 16.01848, 19.07537,
20.7521, 31.20864, 19.28933, 33.81645, 17.74926, 25.17476, 17.96775,
35.05947, 27.00651, 17.59508, 25.4069, 28.208, 34.99299, 22.88728,
20.59275, 26.18355, 31.03587, 33.947, 24.10997, 23.02703, 33.7095,
22.17608, 30.91595, 27.75973, 23.97134, 20.93754, 33.80886, 30.68742,
18.91375, 33.92175, 29.09865, 29.63962, 22.70535, 16.21696, 21.63548,
30.08059, 30.53127, 27.98175, 20.43409, 25.05877, 30.36036, 34.46184,
22.44901, 21.10243, 33.94136, 34.52333, 19.46398, 23.28305, 33.80731,
18.61317, 22.47734, 26.25653, 28.72091, 26.38854, 33.93099, 31.15667,
26.51461, 27.30298, 26.90585, 34.10386, 28.83213, 30.1994, 30.83049,
33.89071, 29.26265, 26.67329, 32.40561, 34.64661, 26.80018, 29.67405,
29.16813, 29.42029, 25.87777, 17.42933, 29.50874, 29.60253, 18.75925,
33.97794, 30.99272, 33.94607, 25.2893, 34.24567, 34.68945, 30.0688,
27.65221, 30.13411, 22.59461, 30.63778, 28.96221, 21.41397, 24.58403,
23.68083, 29.85481, 24.22983, 27.8342, 29.36583, 26.60143, 18.46704,
26.03891, 17.26645, 34.9014, 21.84469, 33.39574, 23.82, 27.57049,
19.93821, 22.30472, 34.60674, 30.77051, 34.79948, 16.55761, 34.33158,
19.62092, 33.46234, 23.15645, 22.68871, 33.79304, 33.88377, 22.99619,
34.04042, 28.1129, 25.6251, 34.21122, 16.89074, 23.43516, 22.78885,
34.17764, 28.47507, 24.45472, 33.8742, 24.72735, 33.90453, 20.10577,
30.73417, 24.35771, 33.93048, 28.62741, 21.99781, 33.97049, 27.48719,
21.25535, 27.92438, 29.80396, 28.35731, 34.8615, 24.93956, 19.783,
34.76926, 27.19699, 27.40897, 16.72252, 31.08047, 18.32881, 17.0416,
25.72955, 16.38935, 28.8926, 33.97636, 22.53829, 33.86432, 18.22302,
23.55972, 34.38583, 25.50873, 20.27311, 33.6045, 30.43855, 34.93784,
35.288345, 36.257075, 25.391195, 36.09727, 30.813695, 27.044815,
28.04567, 29.548165, 20.606055, 30.69551, 35.129335, 37.32639,
36.37374, 36.308585, 37.41784, 26.86707, 32.548155, 33.36402,
37.37834, 28.385865, 35.88449, 35.231535, 23.53661, 30.580155,
34.58997, 16.9712, 28.21824, 29.69837, 32.803, 32.16565, 37.3345,
32.96087, 30.917135, 35.835545, 37.40881, 31.57274, 37.28267,
37.3545, 32.635805, 35.639945, 37.55586, 30.322245, 36.361875,
35.93363, 32.083515, 33.9122, 37.57389, 37.38447, 25.60093, 31.70867,
17.74926, 29.83628, 37.32308, 22.486975, 37.37677, 37.54575,
27.8517, 17.37036, 36.13542, 37.58466, 32.4728, 36.84912, 23.79395,
37.2999, 32.03574, 19.402135, 27.835535, 36.185425, 27.68629,
21.91643, 37.37574, 36.612895, 37.38406, 36.11211, 35.03594,
24.74032, 37.55308, 35.4775, 36.152685, 36.125095, 28.51215,
33.614975, 36.71473, 36.859965, 33.190425, 37.57786, 33.82105,
20.911715, 18.444165, 19.9942, 36.89602, 16.551, 29.161815, 37.4295,
37.38779, 35.75298, 36.91141, 23.29514, 37.59916, 34.393665,
32.88079, 24.885135, 37.30579, 34.812115, 36.05718, 33.03272,
21.730805, 36.877595, 34.980885, 37.34123, 34.19463, 36.436875,
20.27451, 34.880975, 18.10635, 33.268755, 36.24434, 37.33012,
30.18474, 24.530635, 31.445215, 37.32058, 37.6003, 36.417575,
37.57818, 37.56227, 25.15269, 26.548085, 37.34238, 25.799625,
34.12894, 27.14156, 36.0024, 36.89349, 37.48383, 32.23698, 36.386895,
27.013425, 36.295295, 29.29934, 36.091595, 36.642735, 36.5601,
34.706135, 37.27491, 37.38146, 34.758915, 31.35675, 26.709435,
32.374665, 28.69313, 34.52595, 36.22561, 19.717425, 37.35049,
33.991875, 27.288855, 22.76699, 36.179625, 31.25419, 35.08752,
27.507965, 31.821405, 35.97357, 23.037415, 36.86924, 29.408195,
37.60048, 35.18184, 30.45653, 37.58567, 32.27861, 36.04241, 37.34733,
28.86293, 34.64831, 35.684655, 32.71743, 31.01652, 19.07221,
32.1161, 34.32663, 24.059185, 36.16283, 36.413085, 18.77961,
36.49902, 35.7932, 36.214135, 34.05778, 29.01832, 33.111965,
34.2606, 31.14351, 36.88914, 36.326515, 24.30303, 29.97399, 30.103995,
31.92968, 37.36615, 26.01068, 37.52906, 16.12443, 34.929045,
37.59149, 22.175545, 21.19651, 34.4613, 21.473975, 37.33004),
    COP = c(22.39478, 22.68049, 22.27224, 22.19685, 22.16573,
    22.26254, 22.34891, 22.41931, 22.15782, 22.39973, 22.31492,
    22.13082, 22.44822, 22.16036, 22.13963, 22.3111, 22.15529,
    22.20868, 22.14849, 22.16546, 22.40751, 22.15873, 22.15807,
    22.15667, 22.17006, 22.16576, 22.13619, 22.15633, 22.18792,
    22.15968, 22.15784, 22.28282, 22.39207, 22.15544, 22.15307,
    22.15378, 22.65061, 22.18484, 22.14693, 22.1517, 22.14945,
    22.22223, 22.15782, 22.15069, 22.18498, 22.17095, 22.18882,
    22.44182, 22.18867, 22.25752, 22.16363, 22.37156, 22.33576,
    22.14907, 22.15658, 22.15133, 22.1547, 22.43926, 22.16738,
    22.15422, 22.13264, 22.14114, 22.17317, 22.15817, 22.14417,
    22.16643, 22.43323, 22.14401, 22.14921, 22.15957, 22.22265,
    22.14089, 22.14463, 22.14593, 22.14691, 22.14661, 22.47322,
    22.15314, 22.15694, 22.3083, 22.16482, 22.16823, 22.42285,
    22.16284, 22.17225, 22.2391, 22.1465, 22.12234, 22.14539,
    22.15492, 22.14823, 22.15392, 22.18663, 22.14773, 22.16047,
    22.14056, 22.15791, 22.14152, 22.14251, 22.1509, 22.35001,
    22.14744, 22.49713, 22.28185, 22.18089, 22.15846, 22.15929,
    22.12327, 22.23335, 22.16951, 22.20456, 22.16193, 22.25876,
    22.60373, 22.17513, 22.25065, 22.15608, 22.16255, 22.14552,
    22.36192, 22.3395, 22.15159, 22.16513, 22.14421, 22.15804,
    22.31474, 22.5485, 22.16658, 22.15816, 22.16993, 22.14259,
    22.14321, 22.4235, 22.16097, 22.16565, 22.22893, 22.16082,
    22.14911, 22.43463, 22.14959, 22.16988, 22.32926, 22.12439,
    22.18906, 22.14787, 22.143, 22.14448, 22.26607, 22.16002,
    22.24653, 22.25201, 22.13589, 22.13117, 22.578, 22.16947,
    22.36273, 22.51722, 22.15239, 22.62479, 22.15932, 22.41646,
    22.14778, 22.41367, 22.38414, 22.16356, 22.18521, 22.16367,
    22.22729, 22.16007, 22.15065, 22.29892, 21.72296, 21.62249,
    22.017515, 21.693785, 21.70153, 21.87866, 21.81236, 21.732425,
    22.36322, 21.70375, 21.72846, 21.91553, 21.68792, 21.660505,
    22.00908, 21.89052, 21.763825, 21.760305, 21.83179, 21.79684,
    21.71059, 21.726415, 22.149185, 21.70785, 21.75106, 22.571055,
    21.804205, 21.7291, 21.761135, 21.747215, 21.92869, 21.76272,
    21.705115, 21.712995, 21.83027, 21.708885, 21.83844, 21.84054,
    21.768415, 21.71803, 22.11175, 21.70465, 21.60251, 21.70955,
    21.742635, 21.753505, 22.13507, 21.82251, 21.999255, 21.717505,
    22.53302, 21.72247, 21.82229, 22.22044, 21.829, 22.12267,
    21.82473, 22.55087, 21.6558, 22.09163, 21.76516, 21.593285,
    22.13412, 21.86871, 21.73596, 22.43231, 21.943965, 21.636055,
    21.836155, 22.26584, 21.82428, 21.672995, 21.98196, 21.694165,
    21.73181, 22.066775, 22.10273, 21.71976, 21.64993, 21.65895,
    21.788935, 21.759365, 21.59079, 21.59272, 21.762905, 22.04811,
    21.755645, 22.34494, 22.4932, 22.397445, 21.59399, 22.582895,
    21.750065, 21.84207, 21.82297, 21.712635, 21.593685, 22.164485,
    22.07698, 21.7517, 21.760385, 22.04753, 21.8382, 21.741645,
    21.69029, 21.759415, 22.28582, 21.590015, 21.73355, 21.83193,
    21.75102, 21.68036, 22.378585, 21.73784, 22.51333, 21.75792,
    21.609515, 21.82392, 21.70592, 22.084645, 21.708, 21.89372,
    22.08329, 21.93241, 22.10217, 22.10085, 22.030495, 21.91551,
    21.94469, 21.979055, 21.75095, 21.858405, 21.698245, 21.59609,
    22.02914, 21.755635, 21.593795, 21.86841, 21.689295, 21.739825,
    21.691495, 21.66596, 21.674615, 21.74691, 21.84458, 21.82984,
    21.741525, 21.710355, 21.90157, 21.762305, 21.77891, 21.750345,
    21.61608, 22.41471, 21.95989, 21.7551, 21.84604, 22.198325,
    21.691115, 21.709805, 21.732425, 21.84097, 21.723055, 21.70937,
    22.179165, 21.58997, 21.732705, 22.13691, 21.725925, 21.70574,
    22.06154, 21.755495, 21.692555, 21.83686, 21.77328, 21.74777,
    21.716135, 21.761175, 21.709325, 22.451175, 21.749225, 21.750545,
    22.117925, 21.636325, 21.59097, 22.47463, 21.67836, 21.715015,
    21.63479, 21.75122, 21.762415, 21.764115, 21.751305, 21.70731,
    21.591635, 21.606505, 22.09898, 21.71826, 21.71403, 21.727555,
    21.81842, 21.963065, 22.03673, 22.597065, 21.73344, 22.05635,
    22.243885, 22.325185, 21.75266, 22.3091, 21.82619), BLK = c(28.64989,
    15.80412, 20.22131, 22.01231, 28.0591, 20.41488, 28.57393,
    18.42224, 25.81396, 18.66597, 28.51571, 26.66224, 18.17439,
    25.95201, 27.20529, 28.51703, 24.38048, 21.85311, 26.30937,
    28.02257, 28.6773, 25.22704, 24.48749, 28.1236, 23.18583,
    27.98485, 27.00689, 25.14024, 22.16927, 28.1335, 27.89662,
    20.00687, 28.67155, 27.44175, 27.62627, 23.92489, 16.09932,
    22.78544, 27.75227, 27.83675, 27.13084, 21.69284, 25.74085,
    27.80579, 28.28594, 23.44893, 22.33534, 28.7166, 28.29154,
    20.61311, 24.68904, 28.60215, 19.59335, 24.03528, 26.36296,
    27.34839, 26.40381, 28.7205, 28.04637, 26.45016, 26.76595,
    26.62852, 28.18898, 27.38003, 27.79384, 27.96629, 28.71652,
    27.47686, 26.54292, 28.06953, 28.37088, 26.5854, 27.64778,
    27.45691, 27.54817, 26.17697, 17.91728, 27.57453, 27.59667,
    19.79719, 28.15391, 28.01052, 28.70145, 25.8918, 28.19863,
    28.40318, 27.73245, 26.95575, 27.77656, 23.56018, 27.86381,
    27.42115, 22.64232, 25.52273, 24.96468, 27.69186, 25.29434,
    27.05567, 27.51177, 26.4991, 19.37665, 26.24547, 17.66023,
    28.45211, 22.92771, 28.08868, 25.05819, 26.9147, 21.16986,
    23.31623, 28.31888, 27.94109, 28.41742, 16.63277, 28.21869,
    20.81001, 28.10906, 24.58388, 24.26295, 28.59208, 28.56833,
    23.80437, 28.16685, 27.16407, 26.06582, 28.53314, 17.15336,
    24.78023, 23.69012, 28.19161, 27.27431, 25.4426, 28.70709,
    25.60821, 28.15239, 21.35028, 27.92147, 25.36057, 28.71294,
    27.31714, 23.05455, 28.55633, 26.8609, 22.49237, 27.09901,
    27.67287, 27.23569, 28.43207, 25.6761, 20.99499, 28.41302,
    26.72662, 26.81219, 16.89905, 28.04126, 19.14027, 17.39888,
    26.11992, 16.37336, 27.39998, 28.69902, 24.15099, 28.69344,
    18.90929, 24.86793, 28.25387, 26.01419, 21.52158, 28.12068,
    27.81882, 28.48342, 27.96163, 28.197645, 22.70333, 28.117945,
    26.073955, 23.85303, 24.593665, 25.413525, 19.11083, 26.00622,
    27.90615, 27.98023, 28.14475, 28.161525, 28.08333, 23.7368,
    27.01432, 27.341995, 27.83233, 24.77127, 28.08601, 27.96112,
    21.39113, 25.949465, 27.68429, 15.858655, 24.68182, 25.48676,
    27.12372, 26.823595, 27.98649, 27.17823, 26.13994, 28.074105,
    27.80747, 26.44518, 27.88772, 27.88865, 27.054655, 27.983055,
    28.14709, 25.80761, 28.22729, 28.087765, 26.741425, 27.415515,
    28.16615, 27.82628, 22.852945, 26.515965, 16.55507, 25.558165,
    27.86497, 20.59904, 27.82338, 28.15537, 24.503635, 16.208215,
    28.18434, 28.12301, 26.98152, 28.238175, 21.57631, 27.93972,
    26.69019, 18.11697, 23.249475, 28.194915, 24.400325, 20.18436,
    27.83363, 28.152575, 28.05914, 28.1046, 27.87944, 22.246695,
    28.13895, 27.97113, 28.17759, 28.17134, 24.852555, 27.36403,
    28.231645, 28.240475, 27.28467, 28.09842, 27.38207, 19.33762,
    17.208895, 18.63795, 28.32022, 15.478795, 25.178505, 27.81531,
    27.83335, 28.025865, 28.32901, 21.198015, 28.12642, 27.594495,
    27.149095, 22.40141, 27.87721, 27.77537, 28.07577, 27.214415,
    19.976595, 28.24768, 27.87019, 27.87417, 27.512335, 28.1487,
    18.87582, 27.808485, 16.88221, 27.304755, 28.22269, 27.85485,
    25.751105, 22.085525, 26.402235, 27.96385, 28.12362, 23.3511,
    28.13134, 28.13854, 22.55042, 23.483435, 27.99603, 22.988955,
    27.479825, 24.074565, 28.06897, 28.300515, 28.08899, 26.850145,
    28.21175, 23.961985, 28.148655, 25.25804, 28.084975, 28.15017,
    28.142015, 27.74106, 27.89856, 27.81585, 27.762185, 26.34704,
    23.61241, 26.9402, 24.945815, 27.660965, 28.20952, 18.388425,
    28.03487, 27.44823, 24.182, 20.80328, 28.138395, 26.294595,
    27.8952, 24.294155, 26.569235, 28.076645, 21.003065, 28.221055,
    25.336215, 28.17753, 27.934355, 25.886285, 28.10892, 26.890965,
    28.06394, 27.89246, 25.030615, 27.71521, 27.994955, 27.091235,
    26.189505, 17.829845, 26.78325, 27.566845, 21.749355, 28.181235,
    28.216485, 17.523135, 28.145175, 28.05206, 28.198345, 27.46945,
    25.099975, 27.266245, 27.54595, 26.236675, 28.27499, 28.230255,
    21.91532, 25.631615, 25.69132, 26.62857, 27.83423, 23.119855,
    28.08352, 15.10413, 27.84174, 28.10417, 20.39175, 19.55529,
    27.62871, 19.76947, 27.87254)), row.names = c(39410L, 39411L,
39412L, 39413L, 39414L, 39415L, 39416L, 39417L, 39418L, 39419L,
39420L, 39421L, 39422L, 39423L, 39424L, 39425L, 39426L, 39427L,
39428L, 39429L, 39430L, 39431L, 39432L, 39433L, 39434L, 39435L,
39436L, 39437L, 39438L, 39439L, 39440L, 39441L, 39442L, 39443L,
39444L, 39445L, 39446L, 39447L, 39448L, 39449L, 39450L, 39451L,
39452L, 39453L, 39454L, 39455L, 39456L, 39457L, 39458L, 39459L,
39460L, 39461L, 39462L, 39463L, 39464L, 39465L, 39466L, 39467L,
39468L, 39469L, 39470L, 39471L, 39472L, 39473L, 39474L, 39475L,
39476L, 39477L, 39478L, 39479L, 39480L, 39481L, 39482L, 39483L,
39484L, 39485L, 39486L, 39487L, 39488L, 39489L, 39490L, 39491L,
39492L, 39493L, 39494L, 39495L, 39496L, 39497L, 39498L, 39499L,
39500L, 39501L, 39502L, 39503L, 39504L, 39505L, 39506L, 39507L,
39508L, 39509L, 39510L, 39511L, 39512L, 39513L, 39514L, 39515L,
39516L, 39517L, 39518L, 39519L, 39520L, 39521L, 39522L, 39523L,
39524L, 39525L, 39526L, 39527L, 39528L, 39529L, 39530L, 39531L,
39532L, 39533L, 39534L, 39535L, 39536L, 39537L, 39538L, 39539L,
39540L, 39541L, 39542L, 39543L, 39544L, 39545L, 39546L, 39547L,
39548L, 39549L, 39550L, 39551L, 39552L, 39553L, 39554L, 39555L,
39556L, 39557L, 39558L, 39559L, 39560L, 39561L, 39562L, 39563L,
39564L, 39565L, 39566L, 39567L, 39568L, 39569L, 39570L, 39571L,
39572L, 39573L, 39574L, 39575L, 39576L, 39577L, 39578L, 39579L,
39580L, 41926L, 41927L, 41928L, 41929L, 41930L, 41931L, 41932L,
41933L, 41934L, 41935L, 41936L, 41937L, 41938L, 41939L, 41940L,
41941L, 41942L, 41943L, 41944L, 41945L, 41946L, 41947L, 41948L,
41949L, 41950L, 41951L, 41952L, 41953L, 41954L, 41955L, 41956L,
41957L, 41958L, 41959L, 41960L, 41961L, 41962L, 41963L, 41964L,
41965L, 41966L, 41967L, 41968L, 41969L, 41970L, 41971L, 41972L,
41973L, 41974L, 41975L, 41976L, 41977L, 41978L, 41979L, 41980L,
41981L, 41982L, 41983L, 41984L, 41985L, 41986L, 41987L, 41988L,
41989L, 41990L, 41991L, 41992L, 41993L, 41994L, 41995L, 41996L,
41997L, 41998L, 41999L, 42000L, 42001L, 42002L, 42003L, 42004L,
42005L, 42006L, 42007L, 42008L, 42009L, 42010L, 42011L, 42012L,
42013L, 42014L, 42015L, 42016L, 42017L, 42018L, 42019L, 42020L,
42021L, 42022L, 42023L, 42024L, 42025L, 42026L, 42027L, 42028L,
42029L, 42030L, 42031L, 42032L, 42033L, 42034L, 42035L, 42036L,
42037L, 42038L, 42039L, 42040L, 42041L, 42042L, 42043L, 42044L,
42045L, 42046L, 42047L, 42048L, 42049L, 42050L, 42051L, 42052L,
42053L, 42054L, 42055L, 42056L, 42057L, 42058L, 42059L, 42060L,
42061L, 42062L, 42063L, 42064L, 42065L, 42066L, 42067L, 42068L,
42069L, 42070L, 42071L, 42072L, 42073L, 42074L, 42075L, 42076L,
42077L, 42078L, 42079L, 42080L, 42081L, 42082L, 42083L, 42084L,
42085L, 42086L, 42087L, 42088L, 42089L, 42090L, 42091L, 42092L,
42093L, 42094L, 42095L, 42096L, 42097L, 42098L, 42099L, 42100L,
42101L, 42102L, 42103L, 42104L, 42105L, 42106L, 42107L, 42108L,
42109L, 42110L, 42111L, 42112L, 42113L, 42114L, 42115L, 42116L,
42117L, 42118L, 42119L, 42120L, 42121L, 42122L, 42123L, 42124L,
42125L, 42126L, 42127L, 42128L, 42129L, 42130L, 42131L, 42132L,
42133L, 42134L, 42135L, 42136L), class = "data.frame")

My problem is actually very similar to the one that this person had in python
Remove jumps like peaks and steps in timeseries but I haven't been able to find something similar for R

EDIT: I actually found something similar R-related in this question https://stats.stackexchange.com/questions/139660/detecting-changes-in-time-series-r-example?newreg=f119230044de4802a9f0f6f4e4637d8f
The solution using tsoutliers looks applicable to my problem but so far it didn't work very well. I am not sure about what I am doing wrong.

tso(dat.ts, types = c("LS","TC"))

flattens completely my curve

tso(dat.ts, types = c("LS","TC"), discard.method = "bottom-up")

Moves my curve in the right direction but not enough to fix the problem.

Any approach using the bottom-up method to discard outliers gives this result, any approac using the en-masse approach flattens the curve.

Body:
There are a couple methods attempted in the code below attempting to capture the changes: by percent change and by using a rolling median method.

First import a couple useful libraries.  Also changing your data into a tibble called 'lizard_data'

library(tidyverse)
library(RcppRoll)
lizard_data <- tibble(your_data)

Then using ggplot2, we can visualize all the time series.

lizard_data %>%
  pivot_longer(names_to = 'key', values_to = 'value', cols = c(LIZ, COP, BLK)) %>%
  arrange(TIME) %>%
  ggplot(aes(x = TIME, y = value, color = key))+
    geom_line()+
  facet_wrap(~ID, nrow = 2)

Then we remove the adjustments by finding the delta, and we can use two different methods to smooth the time series.  First, with a percentile method (changing the top 5% and bottom 5% of values to the median) and second, with the rolling median (if the max change is ten percent higher or lower than the median, replacing the value with the median).

ld_w_change <- lizard_data %>%
  pivot_longer(names_to = 'key', values_to = 'value', cols = c(LIZ, COP, BLK)) %>%
  group_by(ID, key) %>%
  arrange(TIME) %>%
  mutate(lag = lag(value),
    raw_change = (value-lag),
    #using the percentile change method
    med_raw_change = median(raw_change, na.rm = T),
    q_05 = quantile(raw_change,.05, na.rm = T),
    q_95 = quantile(raw_change,.95, na.rm = T),
    adj_raw_change = if_else(raw_change > q_95 | raw_change < q_05, med_raw_change, raw_change),
    normalized_change = if_else(is.na(adj_raw_change), 0,adj_raw_change),
    initial_value = first(value),
    roll_raw_change = cumsum(normalized_change),
    new_value_pct = initial_value + roll_raw_change,
    # using the rolling median method
    rolling_median_change = roll_median(raw_change, n = 5, align = "right", na.rm = T, fill = NA),
    adj_median_change = case_when(raw_change > rolling_median_change*1.1 | raw_change < rolling_median_change*.9 ~ rolling_median_change,
                                  is.na(rolling_median_change) & is.na(raw_change) ~ 0,
                                  T ~ raw_change),
    normalized_med_change = cumsum(adj_median_change),
    new_value_roll = initial_value + normalized_med_change
    )

I personally prefer the median adjustment, it seems to preserve the shape of the data better than the percentile method.  To compare these methods visually, we can plot them side-by-side:

ld_w_change %>%
  pivot_longer(names_to = 'method', values_to = 'adjusted_temp', cols = c(new_value_pct, new_value_roll)) %>%
  ggplot(aes(x = TIME, y =adjusted_temp, color = key))+
  geom_line()+
  facet_wrap(ID ~ method, nrow = 2)


问:
Spring: how to get rootUri from RestTempalte
I'm using this configuration class to initialize RestTemplate:

```<code>@Configuration
public class RestTemplateConfig {

  @Value("${endpoint-url}")
  private String endpointUrl;

  @Bean
  public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
        .rootUri(endpointUrl)
        .messageConverters(new MappingJackson2HttpMessageConverter())
        .build();
  }
}
</code>```

And in one of my service's method I use the code:

```<code>RootUriTemplateHandler handler = (RootUriTemplateHandler) restTemplate.getUriTemplateHandler();
String uri = handler.getRootUri();
restTemplate.postForLocation(uri, request);
</code>```

To get this URI. Is there an easier method to get this rootUri (without casting)? Or to execute the post request directly to rootUri?

Body:
I'm using this configuration class to initialize RestTemplate:

@Configuration
public class RestTemplateConfig {

  @Value("${endpoint-url}")
  private String endpointUrl;

  @Bean
  public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
        .rootUri(endpointUrl)
        .messageConverters(new MappingJackson2HttpMessageConverter())
        .build();
  }
}

And in one of my service's method I use the code:

RootUriTemplateHandler handler = (RootUriTemplateHandler) restTemplate.getUriTemplateHandler();
String uri = handler.getRootUri();
restTemplate.postForLocation(uri, request);

To get this URI. Is there an easier method to get this rootUri (without casting)? Or to execute the post request directly to rootUri?

Body: restTemplate.getUriTemplateHandler().expand("/")


问:
SolrHealthIndicator without deprecated CompositeHealthIndicator
I've tried to upgrade Spring Boot to 2.2.4.RELEASE version. Everzthing if fine exept problem with CompositeHealthIndicator which is deprecated.

I have this bean method

```<code>@Autowired
private HealthAggregator healthAggregator;

    @Bean
public HealthIndicator solrHealthIndicator() {
    CompositeHealthIndicator composite = new CompositeHealthIndicator(
            this.healthAggregator);
    composite.addHealthIndicator("solr1", createHealthIndicator(firstHttpSolrClient()));
    composite.addHealthIndicator("solr2", createHealthIndicator(secondHttpSolrClient()));
    composite.addHealthIndicator("querySolr", createHealthIndicator(queryHttpSolrClient()));
    return composite;
}

private CustomSolrHealthIndicator createHealthIndicator(SolrClient source) {

    try {
        return new CustomSolrHealthIndicator(source);
    } catch (Exception ex) {
        throw new IllegalStateException("Unable to create helthCheckIndicator for solr client instance.", ex);
    }
}
</code>```

That registers HealthIndicator for 3 instances of SOLR (2 indexing, 1 for query). Everything worked fine until Spring Boot update. After update the method CompositeHealthIndicator.addHealthIndicator is not present, the whole class is marked as Deprecated.

The class which is created in createHealthIndicator is like this:

```<code>    public class CustomSolrHealthIndicator extends SolrHealthIndicator {

    private final SolrClient solrClient;

    public CustomSolrHealthIndicator(SolrClient solrClient) {
        super(solrClient);
        this.solrClient = solrClient;
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {

        if (!this.solrClient.getClass().isAssignableFrom(HttpSolrClient.class)) {

            super.doHealthCheck(builder);
        }

        HttpSolrClient httpSolrClient = (HttpSolrClient) this.solrClient;
        if (StringUtils.isBlank(httpSolrClient.getBaseURL())) {
            return;
        }

        super.doHealthCheck(builder);
    }
}
</code>```

Is there any easy way to transform the old way how to register the instances of SOLR i want to check if they are up or down at Spring Boot version 2.2.X?

EDIT:
 I have tried this:

```<code>@Bean
public CompositeHealthContributor solrHealthIndicator() {

    Map<String, HealthIndicator> solrIndicators = Maps.newLinkedHashMap();
    solrIndicators.put("solr1", createHealthIndicator(firstHttpSolrClient()));
    solrIndicators.put("solr2", createHealthIndicator(secondHttpSolrClient()));
    solrIndicators.put("querySolr", createHealthIndicator(queryHttpSolrClient()));

    return CompositeHealthContributor.fromMap(solrIndicators);
}

private CustomSolrHealthIndicator createHealthIndicator(SolrClient source) {

    try {
        return new CustomSolrHealthIndicator(source);
    } catch (Exception ex) {
        throw new IllegalStateException("Unable to create healthCheckIndicator for solr client instance.", ex);
    }
}
</code>```

The CustomSolrHealthIndicator has no changes against start state.

But I cannot create that bean. When calling createHealthIndicator I am getting NoClassDefFoundError

Does anyone know where the problem is?

答:
Instead of deprecated CompositeHealthIndicator#addHealthIndicator use constructor with map:</p>

```<code>@Bean
public HealthIndicator solrHealthIndicator() {

    Map<String, HealthIndicator> healthIndicators = new HashMap<>();
    healthIndicators.put("solr1", createHealthIndicator(firstHttpSolrClient()));
    healthIndicators.put("solr2", createHealthIndicator(secondHttpSolrClient()));
    healthIndicators.put("querySolr", createHealthIndicator(queryHttpSolrClient()));

    return new CompositeHealthIndicator(this.healthAggregator, healthIndicators);
}
</code>```

Body:
I've tried to upgrade Spring Boot to 2.2.4.RELEASE version. Everzthing if fine exept problem with CompositeHealthIndicator which is deprecated.

I have this bean method

@Autowired
private HealthAggregator healthAggregator;

    @Bean
public HealthIndicator solrHealthIndicator() {
    CompositeHealthIndicator composite = new CompositeHealthIndicator(
            this.healthAggregator);
    composite.addHealthIndicator("solr1", createHealthIndicator(firstHttpSolrClient()));
    composite.addHealthIndicator("solr2", createHealthIndicator(secondHttpSolrClient()));
    composite.addHealthIndicator("querySolr", createHealthIndicator(queryHttpSolrClient()));
    return composite;
}

private CustomSolrHealthIndicator createHealthIndicator(SolrClient source) {

    try {
        return new CustomSolrHealthIndicator(source);
    } catch (Exception ex) {
        throw new IllegalStateException("Unable to create helthCheckIndicator for solr client instance.", ex);
    }
}

That registers HealthIndicator for 3 instances of SOLR (2 indexing, 1 for query). Everything worked fine until Spring Boot update. After update the method CompositeHealthIndicator.addHealthIndicator is not present, the whole class is marked as Deprecated.

The class which is created in createHealthIndicator is like this:

    public class CustomSolrHealthIndicator extends SolrHealthIndicator {

    private final SolrClient solrClient;

    public CustomSolrHealthIndicator(SolrClient solrClient) {
        super(solrClient);
        this.solrClient = solrClient;
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {

        if (!this.solrClient.getClass().isAssignableFrom(HttpSolrClient.class)) {

            super.doHealthCheck(builder);
        }

        HttpSolrClient httpSolrClient = (HttpSolrClient) this.solrClient;
        if (StringUtils.isBlank(httpSolrClient.getBaseURL())) {
            return;
        }

        super.doHealthCheck(builder);
    }
}

Is there any easy way to transform the old way how to register the instances of SOLR i want to check if they are up or down at Spring Boot version 2.2.X?

EDIT:
 I have tried this:

@Bean
public CompositeHealthContributor solrHealthIndicator() {

    Map<String, HealthIndicator> solrIndicators = Maps.newLinkedHashMap();
    solrIndicators.put("solr1", createHealthIndicator(firstHttpSolrClient()));
    solrIndicators.put("solr2", createHealthIndicator(secondHttpSolrClient()));
    solrIndicators.put("querySolr", createHealthIndicator(queryHttpSolrClient()));

    return CompositeHealthContributor.fromMap(solrIndicators);
}

private CustomSolrHealthIndicator createHealthIndicator(SolrClient source) {

    try {
        return new CustomSolrHealthIndicator(source);
    } catch (Exception ex) {
        throw new IllegalStateException("Unable to create healthCheckIndicator for solr client instance.", ex);
    }
}

The CustomSolrHealthIndicator has no changes against start state.

But I cannot create that bean. When calling createHealthIndicator I am getting NoClassDefFoundError

Does anyone know where the problem is?

Body:
Instead of deprecated CompositeHealthIndicator#addHealthIndicator use constructor with map:

@Bean
public HealthIndicator solrHealthIndicator() {

    Map<String, HealthIndicator> healthIndicators = new HashMap<>();
    healthIndicators.put("solr1", createHealthIndicator(firstHttpSolrClient()));
    healthIndicators.put("solr2", createHealthIndicator(secondHttpSolrClient()));
    healthIndicators.put("querySolr", createHealthIndicator(queryHttpSolrClient()));

    return new CompositeHealthIndicator(this.healthAggregator, healthIndicators);
}