问:
How to change cloudwatch SNS emails?
Using this tutorial I created a lambda function, when it fails a cloud watch alarm causes SNS to send out emails using the lambda errors metric.  I'm using it to check if any ec2 instances have upcomming scheduled events.  Right now this is the info CloudWatch and SNS sends in its emails:

```<code>Alarm Details:
- Name:                       ec2-scheduled-events-alarm
- Description:                an ec2 instance has an upcomming scheduled event
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 1 datapoint (1.0) was greater than or equal to the threshold (1.0).
- Timestamp:                  Wednesday 12 September, 2016 00:16:54 UTC
- AWS Account:                ..........

Threshold:
- The alarm is in the ALARM state when the metric is GreaterThanOrEqualToThreshold 1.0 for 300 seconds.

Monitored Metric:
- MetricNamespace:            AWS/Lambda
- MetricName:                 Errors
- Dimensions:
- Period:                     300 seconds
- Statistic:                  Sum
- Unit:                       not specified

State Change Actions:
- OK:
- ALARM: [arn:aws:sns:us-west-2:..........:ec2-scheduled-events]
- INSUFFICIENT_DATA:
</code>```

I would like to change this message to also contain info from my lambda script (such as listing out ec2 instances I defined as failing).  How can I do this? I'm guessing it involves changing the output of the Monitored Metric: - Dimensions: somehow.

Or better yet how can I just have my emails contain the Log output of my lambda function?

答:
Yes, you may have your lambda function publish your own message, which could be the log information. You didn't mention what language you are using, so I'm just going to present it using python.

```<code>from __future__ import print_function
import json
import boto3
import logging
import time
import datetime

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def Publish():
        """
        Send a message to the topic
        """

        sns = boto3.client('sns')
        subject = ''
        message = 'Here is the message'
        # You can likely insert the debugging prints from logger into the
        # message

        # This will have TargetArn - the arn of the topic
        # Subject and message of the email. There are other parameters as
        # well. Just check out boto3 sns api

        sns.publish(
            TargetArn='arn:',
            Subject= subject,
            Message= message)#of email
  return
</code>```

I am uncertain if you would be able to access the information in your lambda log from the default SNS email you showed. The option I listed might be your solution. You will need to make a separate SNS topic and subscribe to it as well, so this might be too much overhead for what you are looking for.

I hope this helps!

( EDIT: I now realize you asked this 9 months ago, so you probably already figured it out, oops.)

Title: How to change cloudwatch SNS emails?

Body:
Using this tutorial I created a lambda function, when it fails a cloud watch alarm causes SNS to send out emails using the lambda errors metric.  I'm using it to check if any ec2 instances have upcomming scheduled events.  Right now this is the info CloudWatch and SNS sends in its emails:

Alarm Details:
- Name:                       ec2-scheduled-events-alarm
- Description:                an ec2 instance has an upcomming scheduled event
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 1 datapoint (1.0) was greater than or equal to the threshold (1.0).
- Timestamp:                  Wednesday 12 September, 2016 00:16:54 UTC
- AWS Account:                ..........

Threshold:
- The alarm is in the ALARM state when the metric is GreaterThanOrEqualToThreshold 1.0 for 300 seconds.

Monitored Metric:
- MetricNamespace:            AWS/Lambda
- MetricName:                 Errors
- Dimensions:
- Period:                     300 seconds
- Statistic:                  Sum
- Unit:                       not specified

State Change Actions:
- OK:
- ALARM: [arn:aws:sns:us-west-2:..........:ec2-scheduled-events]
- INSUFFICIENT_DATA:

I would like to change this message to also contain info from my lambda script (such as listing out ec2 instances I defined as failing).  How can I do this? I'm guessing it involves changing the output of the Monitored Metric: - Dimensions: somehow.

Or better yet how can I just have my emails contain the Log output of my lambda function?

Body:
Yes, you may have your lambda function publish your own message, which could be the log information. You didn't mention what language you are using, so I'm just going to present it using python.

from __future__ import print_function
import json
import boto3
import logging
import time
import datetime

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def Publish():
        """
        Send a message to the topic
        """

        sns = boto3.client('sns')
        subject = ''
        message = 'Here is the message'
        # You can likely insert the debugging prints from logger into the
        # message

        # This will have TargetArn - the arn of the topic
        # Subject and message of the email. There are other parameters as
        # well. Just check out boto3 sns api

        sns.publish(
            TargetArn='arn:',
            Subject= subject,
            Message= message)#of email
  return

I am uncertain if you would be able to access the information in your lambda log from the default SNS email you showed. The option I listed might be your solution. You will need to make a separate SNS topic and subscribe to it as well, so this might be too much overhead for what you are looking for.

I hope this helps!

( EDIT: I now realize you asked this 9 months ago, so you probably already figured it out, oops.)


来源: stackexchange

问:
How to format (transform) laravel database paginated results?
For example i have following code:

```<code>public function index()
{
    return
        Model::select(['id', 'some_field', ...// more some fields])
            ->with('data') // load relation
            ->paginate(20);
}
</code>```

How do i format (transform/manipulate on) obtained data from database?

CakePHP ORM have useful method for this -https://book.cakephp.org/3.0/en/orm/query-builder.html#adding-calculated-fields
&& https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#map-reduce

But i can't find any thing, that can help me to do a same things in Laravel.
I can override "toArray" method in a model, but this will affect all application parts (not only an index action in my controller).

答:
paginate() and get() will return a Collection giving you access to all the Collection methods.

You would be able to do:

```<code>public function index()
{
    return
        Model::select(['id', 'some_field', ...// more some fields])
            ->with('data') // load relation
            ->paginate(20)
            ->map(function($model) {
                $model->total_things = $model->one_thing + $model->other_thing;
                return $model;
            });
}
</code>```

ContentLicense: CC BY-SA 3.0

Body:
For example i have following code:

public function index()
{
    return
        Model::select(['id', 'some_field', ...// more some fields])
            ->with('data') // load relation
            ->paginate(20);
}

How do i format (transform/manipulate on) obtained data from database?

CakePHP ORM have useful method for this -https://book.cakephp.org/3.0/en/orm/query-builder.html#adding-calculated-fields
&& https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#map-reduce

But i can't find any thing, that can help me to do a same things in Laravel.
I can override "toArray" method in a model, but this will affect all application parts (not only an index action in my controller).

Body:
paginate() and get() will return a Collection giving you access to all the Collection methods.

You would be able to do:

public function index()
{
    return
        Model::select(['id', 'some_field', ...// more some fields])
            ->with('data') // load relation
            ->paginate(20)
            ->map(function($model) {
                $model->total_things = $model->one_thing + $model->other_thing;
                return $model;
            });
}


问:
Removing pop/hiss from WebAudio generated sound
I am using the nodeOscillator function from Web Audio API to generate a sound, however when the sound cuts it makes a pop sound (the amplitude is not zero at the cut). Does anyone know a way to check the amplitude of a nodeOscillator and wait until it is zero before I call nodeOff()?</p>

答: If you are using an Apple computer, take a look at this: https://vsee.zendesk.com/hc/en-us/articles/204973595-Mac-audio-pop-click-sound</p>


问:
remove the first html tag in a string
i have this text

```<code><?php
   $example1 = '<b class="counter">1</b> This is a computer';
   $example2 = '<b class="counter">5</b> i have a laptop';
   $example3 = '<b class="counter">1</b> i need a smartphone';
   $example4 = 'i need a car'; // does not have <b> tag
?>
</code>```

i'm looking for a php function to remove a part of the string, starting from  to , so the results should be like :

```<code>$example1_result = 'This is a computer';
$example2_result = 'i have a laptop';
$example3_result = 'i need a smartphone';
$example4_result = 'i need a car';
</code>```

答:
You'll want to use strip_tags http://php.net/manual/en/function.strip-tags.php

it essentially strips, well tags from the string:

```<code><?php
    $htmlStr = '<p>Text</p>';
    $str     = strip_tags($htmlStr);

    var_dump($str); //will echo Text
</code>```

Title: remove the first html tag in a string

Body:
i have this text

<?php
   $example1 = '1 This is a computer';
   $example2 = '5 i have a laptop';
   $example3 = '1 i need a smartphone';
   $example4 = 'i need a car'; // does not have  tag
?>

i'm looking for a php function to remove a part of the string, starting from  to , so the results should be like :

$example1_result = 'This is a computer';
$example2_result = 'i have a laptop';
$example3_result = 'i need a smartphone';
$example4_result = 'i need a car';

Body:
You'll want to use strip_tags http://php.net/manual/en/function.strip-tags.php

it essentially strips, well tags from the string:

<?php
    $htmlStr = '<p>Text</p>';
    $str     = strip_tags($htmlStr);

    var_dump($str); //will echo Text


问:
Spark - move data from tables to new table with extra column
So we have a Cassandra project and it requires us to migrate a large number of tables from 3 separate tables into one.

e.g. table_d_abc, table_m_abc, table_w_abc to table_t_abc

Essentially data needs to be moved to this new table with an extra column with a value that was in the table's name.
There are 100's of tables like this - so you could imagine the huge job it would be to 'hand-make' a migration script. And naturally I thought SPARK should be able to do the job.

e.g.:

```<code>var tables = List("table_*_abc", "table_*_def") // etc
var periods = List('d','w','m')

for (table <- tables) {
  for (period <- periods) {
    var rTable = table.replace('*', period)
    var nTable = table.replace('*', 't')
    try {
      var t = sc.cassandraTable("data", rTable)
      var fr = t.first
      var columns = fr.toMap.keys.toArray :+ "period"
      var data = t.map(_.iterator.toArray :+ period)

      // This line does not work as data is a RDD of Array[Any] and not RDD of tuple[...]
      // How to ???
      data.saveToCassandra("data", nTable, SomeColumns(columns.map(ColumnName(_)):_*))
    } //catch {}
  }
}
</code>```

versus:

```<code>var periods = List('d','w','m')

for (period <- periods) {
  sc.cassandraTable("data","table_" + period + "_abc")
    .map(v => (v.getString("a"), v.getInt("b"), v.getInt("c"), period))
    .saveToCassandra("data", "table_t_abc", SomeColumns("a","b","c","period"))

  // ... 100s of other scripts like this
}
</code>```

Is what I'm trying to do possible?

Is there a way to programatically save an extra column from an source with unknown number of columns and datatypes?

答:
The issue here is the RDD objects must be of a type which has a "RowWriter" defined. This maps the data in the object to C* insertable buffers.

RDD World

Using "CassandraRow" objects this is possible. These objects allow for generic contents and can be constructed on the file. They are also the default output so making a new one from an old one should be relatively cheap.

https://github.com/datastax/spark-cassandra-connector/blob/master/spark-cassandra-connector/src/main/scala/com/datastax/spark/connector/CassandraRow.scala

You would make a single RowMetadata (basically schema info) for each table with the additional column, then populate the row with the values of the input row + the new period variable.

Dataframe World

If you wanted to switch to Dataframes this would be easier as you could just use the DataFrame add column before saving.

```<code>cassandraDF.withColumn("period",lit("Value based on first row"))
</code>```

Body:
So we have a Cassandra project and it requires us to migrate a large number of tables from 3 separate tables into one.

e.g. table_d_abc, table_m_abc, table_w_abc to table_t_abc

Essentially data needs to be moved to this new table with an extra column with a value that was in the table's name.
There are 100's of tables like this - so you could imagine the huge job it would be to 'hand-make' a migration script. And naturally I thought SPARK should be able to do the job.

e.g.:

var tables = List("table_*_abc", "table_*_def") // etc
var periods = List('d','w','m')

for (table <- tables) {
  for (period <- periods) {
    var rTable = table.replace('*', period)
    var nTable = table.replace('*', 't')
    try {
      var t = sc.cassandraTable("data", rTable)
      var fr = t.first
      var columns = fr.toMap.keys.toArray :+ "period"
      var data = t.map(_.iterator.toArray :+ period)

      // This line does not work as data is a RDD of Array[Any] and not RDD of tuple[...]
      // How to ???
      data.saveToCassandra("data", nTable, SomeColumns(columns.map(ColumnName(_)):_*))
    } //catch {}
  }
}

versus:

var periods = List('d','w','m')

for (period <- periods) {
  sc.cassandraTable("data","table_" + period + "_abc")
    .map(v => (v.getString("a"), v.getInt("b"), v.getInt("c"), period))
    .saveToCassandra("data", "table_t_abc", SomeColumns("a","b","c","period"))

  // ... 100s of other scripts like this
}

Is what I'm trying to do possible?

Is there a way to programatically save an extra column from an source with unknown number of columns and datatypes?

Body:
The issue here is the RDD objects must be of a type which has a "RowWriter" defined. This maps the data in the object to C* insertable buffers.

RDD World

Using "CassandraRow" objects this is possible. These objects allow for generic contents and can be constructed on the file. They are also the default output so making a new one from an old one should be relatively cheap.

https://github.com/datastax/spark-cassandra-connector/blob/master/spark-cassandra-connector/src/main/scala/com/datastax/spark/connector/CassandraRow.scala

You would make a single RowMetadata (basically schema info) for each table with the additional column, then populate the row with the values of the input row + the new period variable.

Dataframe World

If you wanted to switch to Dataframes this would be easier as you could just use the DataFrame add column before saving.

cassandraDF.withColumn("period",lit("Value based on first row"))


答:
You can do same thing in Laravel, for example:

```<code>return Model::select(['id', 'some_field', ...// more some fields])
->with('data')
->paginate(20)
->map(function($item, $key) {
    // Some pseudo code
    $item->uid = uniqid();

    // Must return the $item
    return $item;
});
</code>```

There are other ways doing similar things. You can do many more in Laravel. There is a transform method as well, among many.

Title: How to format (transform) laravel database paginated results?

Body:
You can do same thing in Laravel, for example:

return Model::select(['id', 'some_field', ...// more some fields])
->with('data')
->paginate(20)
->map(function($item, $key) {
    // Some pseudo code
    $item->uid = uniqid();

    // Must return the $item
    return $item;
});

There are other ways doing similar things. You can do many more in Laravel. There is a transform method as well, among many.


问:
How to communicate between callbacks in gtk+ c
I'm working on a project right now, and I am trying to make 2 callbacks communicate with each other by passing to them the same variable (the callbacks share the same variable). Since the callbacks cannot return a value, I have passed a pointer to the value which is assigned in the main loop (main function).
However, it isn't working at all!

This is my code:

```<code>#include <gtk/gtk.h>

static void inc_val (GtkWidget *widget, gpointer data)
{
    int* value =  data;
    *value++;
    printf("value is: %d\n", *value);
}

static void inc_val_ten (GtkWidget *widget, gpointer data)
{
    int* value =  data;
    *value+=10;
    printf("value is: %d\n", *value);
}

static void activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *button;
    int value = 0;

    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window");
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);

    button = gtk_button_new_with_label ("Add 1 to value");
    g_signal_connect (button, "clicked", G_CALLBACK (inc_val), &value);
    gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);

    button = gtk_button_new_with_label ("Add 10 to value");
    g_signal_connect (button, "clicked", G_CALLBACK (inc_val_ten), &value);
    gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1);

    button = gtk_button_new_with_label ("Quit");
    g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
    gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);

    gtk_widget_show_all (window);
}

int main (int argc, char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);

    return status;
}
</code>```

The program has 3 buttons in the window:

adding 1 to value

adding 10 to value

quitting the program

value is an integer on the main loop. When one of the buttons (first or second) are pressed, the value getting bigger (by 1 or by ten) and the program prints the new value.

I have run the program and clicked the buttons and that's what I've got:

```<code>value is: 46525384
value is: 46525384
value is: 46157330
value is: -830528646
value is: 56
value is: 10
</code>```

instead of:

```<code>value is: 1
value is: 2
value is: 12
value is: 22
value is: 23
value is: 33
</code>```

Anyone knows why does it happen?

Thanks for helping!

Edit: I have tried the same thing, just instead of adding numbers to a value, I've tried to add button to the grid. Since the solution from the answer (under the question) worked at the previous code, I've made the grid global.

So here is the new code:

```<code>#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdio.h>

GtkWidget *grid;

static void add_button (GtkWidget *widget, gpointer data)
{
    static int value = 0;
    GtkWidget* grid = data;
    value++;
    printf("attach to line %d\n", value);
    gtk_grid_attach(GTK_GRID(grid), gtk_button_new_from_stock(GTK_STOCK_NEW), 0, value, 1, 1);
}

static void activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *button;

    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window");
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);

    button = gtk_button_new_with_label ("Add Button");
    g_signal_connect (button, "clicked", G_CALLBACK (add_button), grid);
    gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);

    gtk_widget_show_all (window);
}

int main (int argc, char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);

    return status;
}
</code>```

However, it didn't work from some reason. Help will be appreciated!

答:
The value is local to activate. When activate completes, its local variables are gone; the pointer you pass to the handlers is now meaningless.

The solution is to make value surviving an entire lifetime of the application. A simplest (but possibly not cleanest) way is to make it global.

Body:
I'm working on a project right now, and I am trying to make 2 callbacks communicate with each other by passing to them the same variable (the callbacks share the same variable). Since the callbacks cannot return a value, I have passed a pointer to the value which is assigned in the main loop (main function).
However, it isn't working at all!

This is my code:

#include <gtk/gtk.h>

static void inc_val (GtkWidget *widget, gpointer data)
{
    int* value =  data;
    *value++;
    printf("value is: %d\n", *value);
}

static void inc_val_ten (GtkWidget *widget, gpointer data)
{
    int* value =  data;
    *value+=10;
    printf("value is: %d\n", *value);
}

static void activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *grid;
    GtkWidget *button;
    int value = 0;

    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window");
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);

    button = gtk_button_new_with_label ("Add 1 to value");
    g_signal_connect (button, "clicked", G_CALLBACK (inc_val), &value);
    gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);

    button = gtk_button_new_with_label ("Add 10 to value");
    g_signal_connect (button, "clicked", G_CALLBACK (inc_val_ten), &value);
    gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1);

    button = gtk_button_new_with_label ("Quit");
    g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
    gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);

    gtk_widget_show_all (window);
}

int main (int argc, char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);

    return status;
}

The program has 3 buttons in the window:

adding 1 to value

adding 10 to value

quitting the program

value is an integer on the main loop. When one of the buttons (first or second) are pressed, the value getting bigger (by 1 or by ten) and the program prints the new value.

I have run the program and clicked the buttons and that's what I've got:

value is: 46525384
value is: 46525384
value is: 46157330
value is: -830528646
value is: 56
value is: 10

instead of:

value is: 1
value is: 2
value is: 12
value is: 22
value is: 23
value is: 33

Anyone knows why does it happen?

Thanks for helping!

Edit: I have tried the same thing, just instead of adding numbers to a value, I've tried to add button to the grid. Since the solution from the answer (under the question) worked at the previous code, I've made the grid global.

So here is the new code:

#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdio.h>

GtkWidget *grid;

static void add_button (GtkWidget *widget, gpointer data)
{
    static int value = 0;
    GtkWidget* grid = data;
    value++;
    printf("attach to line %d\n", value);
    gtk_grid_attach(GTK_GRID(grid), gtk_button_new_from_stock(GTK_STOCK_NEW), 0, value, 1, 1);
}

static void activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *button;

    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Window");
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    grid = gtk_grid_new ();
    gtk_container_add (GTK_CONTAINER (window), grid);

    button = gtk_button_new_with_label ("Add Button");
    g_signal_connect (button, "clicked", G_CALLBACK (add_button), grid);
    gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);

    gtk_widget_show_all (window);
}

int main (int argc, char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);

    return status;
}

However, it didn't work from some reason. Help will be appreciated!


问:
R: RMariaDB not available for 3.4.0 - How connect to MySQL from R v 3.4.0?
The RMySQL package notes recommend using RMariaDB instead. RMariaDB package says that it is not available for R3.4.0, and does not install.

What is the best way to connect to a MySQL database if I'm running R v3.4.0?

答:
It doesn't look like RMariaDB is on CRAN yet. You can install the dev version from github:

```<code># install.packages("devtools")
devtools::install_github("rstats-db/DBI")
devtools::install_github("rstats-db/RMariaDB")
</code>```

Or you can use RMySQL for now, and keep your eye on further developments from RMariaDB.

Body:
It doesn't look like RMariaDB is on CRAN yet. You can install the dev version from github:

# install.packages("devtools")
devtools::install_github("rstats-db/DBI")
devtools::install_github("rstats-db/RMariaDB")

Or you can use RMySQL for now, and keep your eye on further developments from RMariaDB.


问:
Best way in java to create a new tree which contains ordered data based on a specific criteria
A tree exists which stores earthquake information as objects (contains data such as magnitude, date of earthquake, depth of earthquake). I want to filter the objects based on a certain criteria such as depth of earthquake (ascending or descending) and add each object to a new tree which will be all of the earthquakes ordered based on the specific criteria. I don't wont to sort the same tree every time, but instead have different trees for different filters and then be able to use in order search to obtain a specific earthquake object. Also multiple filters can be used. I don't want the code, but instead the algorithmic thinking that would be used to solve such a problem, specifically how one would go through the original tree and then add the objects into the new one in an ordered way. </p>

答:
You can use a TreeMap with a custom comparator (it sorts by the keys' natural ordering by default).

To use it with a custom Comaparator you simply pass the comparator into the constructor of the TreeMap:

```<code>    TreeMap<SomeKey, Earthquake> earthquakes =
            new TreeMap<>(new YourCustomEarthquakeComparator());
</code>```

Then, in order to have separate trees that sort the earthquakes in a different order, you just define several comparators that compare different fields of the earthquakes.

Body:
You can use a TreeMap with a custom comparator (it sorts by the keys' natural ordering by default).

To use it with a custom Comaparator you simply pass the comparator into the constructor of the TreeMap:

    TreeMap<SomeKey, Earthquake> earthquakes =
            new TreeMap<>(new YourCustomEarthquakeComparator());

Then, in order to have separate trees that sort the earthquakes in a different order, you just define several comparators that compare different fields of the earthquakes.


问:
Add Non Scatter Chart Data For Use With OnClick
Have a XY chart, I would like to relate year data to the data point so I can pass the year to an onclick message alert. I'm already retrieving the chart data. The attached shows two ways that I can retrieve the chart data, using d. and using signify() in case one method is more capable than the other. JSFiddle

Not sure where to place the year data in the code?
How would I retrieve the year for clicked on point to send to onclick Alert message?

```<code>       data: {
 xs: {
        'data1': 'x1',
        'data2': 'x2',
        'data3': 'x3',
        'data4': 'x4',
    },
columns: [
        ['x1', 10, 30, 45, 50, 70, 100],
        ['x2', 30, 50, 75, 100, 120],
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 20, 180, 240, 100, 190]
    ],
   names: {
        data1: 'Oracle 1',
        data2: 'HP 2'
          },
  // Not sure where to place this data?
  // How would I retrieve year for clicked on point to send to onclick Alert message?
  //   [year1,2000, 2001, 2002, 2003, 2004, 2006]
  //   [year2,2000, 2002, 2003, 2004, 2005]
</code>```

答:
Unfortunately I can't post in the comments, but you could turn off sorting and ordering for the data. This would mean that you need to provide all data in the correct order each time you load it. This also uses an undocumented setting.

This fiddle builds on what you are discussing above, note the change to the code:

```<code>....
data: {
    xSort: null,
    xs: {
....
</code>```

Body:
Have a XY chart, I would like to relate year data to the data point so I can pass the year to an onclick message alert. I'm already retrieving the chart data. The attached shows two ways that I can retrieve the chart data, using d. and using signify() in case one method is more capable than the other. JSFiddle

Not sure where to place the year data in the code?
How would I retrieve the year for clicked on point to send to onclick Alert message?

       data: {
 xs: {
        'data1': 'x1',
        'data2': 'x2',
        'data3': 'x3',
        'data4': 'x4',
    },
columns: [
        ['x1', 10, 30, 45, 50, 70, 100],
        ['x2', 30, 50, 75, 100, 120],
        ['data1', 30, 200, 100, 400, 150, 250],
        ['data2', 20, 180, 240, 100, 190]
    ],
   names: {
        data1: 'Oracle 1',
        data2: 'HP 2'
          },
  // Not sure where to place this data?
  // How would I retrieve year for clicked on point to send to onclick Alert message?
  //   [year1,2000, 2001, 2002, 2003, 2004, 2006]
  //   [year2,2000, 2002, 2003, 2004, 2005]

Body:
Unfortunately I can't post in the comments, but you could turn off sorting and ordering for the data. This would mean that you need to provide all data in the correct order each time you load it. This also uses an undocumented setting.

This fiddle builds on what you are discussing above, note the change to the code:

....
data: {
    xSort: null,
    xs: {
....


问:
Fragment inside ViewPager returning null in getView()
In my app, I have a ViewPager, and inside that ViewPager there're about 17 Fragments. I've designed the layouts for both Portrait and Landscape.
When I Rotate my Screen, the method getView() its returning a null object, don't know why this happens, I've used setRetainInstance(true), but still the same thing, I'm using a PagerStateFragmentAdapter as my adapter implementation.

Why does this happens?

Thank you in advance.

EDIT

MainActivity

```<code>public class MainActivity extends FragmentActivity implements ViewPagerController{
    public static final String READ_TYPE = "Read_type";
    private static final String TAG = MainActivity.class.getSimpleName();
    private int mReadType;
    private ViewPager mBookPager;

    @Override
    public void goToNextPage() {
        // TODO Auto-generated method stub
        int currentPage = mBookPager.getCurrentItem();
        if(currentPage+1 < mBookPager.getAdapter().getCount()){
            FragmentPagerAdapter adapter = (FragmentPagerAdapter)mBookPager.getAdapter();
            BookPageFragment bookPage = (BookPageFragment)adapter.getItem(currentPage);
            bookPage.setCurrentPage(false);

            bookPage = (BookPageFragment)adapter.getItem(currentPage+1);
            bookPage.setCurrentPage(true);
            mBookPager.setCurrentItem(currentPage+1, true);
        }
    }

    @Override
    public void goToPreviousPage() {
        // TODO Auto-generated method stub
        int currentPage = mBookPager.getCurrentItem();
        if(currentPage >= 0){
            mBookPager.setCurrentItem(currentPage-1,true);
        }
    }

    @Override
    public void onBackPressed() {
        // TODO Auto-generated method stub
        finish();
        overridePendingTransition(R.anim.anim_move_to_right,R.anim.anim_from_left_to_right);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        Log.i(TAG,"onDestroy");
        mBookPager.removeAllViews();
        mBookPager = null;
        super.onDestroy();
    }

    @Override
    protected void onCreate(Bundle arg0) {
        // TODO Auto-generated method stub
        super.onCreate(arg0);
        setContentView(R.layout.main_layout);
        overridePendingTransition(R.anim.anim_from_right_to_left, R.anim.anim_move_to_left);
        initReadType();
        mBookPager = (ViewPager)findViewById(R.id.mainLayout_mainViewPager);
        initViewPager();

    }

    private void initReadType(){
        mReadType = getIntent().getIntExtra(READ_TYPE, -1);
    }

    private void initViewPager(){
        BookPagerAdapter mPagerAdapter = new BookPagerAdapter(getSupportFragmentManager(),mReadType);
        ((BookPageFragment)mPagerAdapter.getItem(0)).setCurrentPage(true);
        mBookPager.setAdapter(mPagerAdapter);
        mBookPager.setOnPageChangeListener(mOnPageChangeListener);
    }

    private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener(){

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageSelected(int selection) {
            // TODO Auto-generated method stub
            BookPagerAdapter bookAdapter = (BookPagerAdapter)mBookPager.getAdapter();
            BookPageFragment fragment = (BookPageFragment)bookAdapter.getItem(selection);
            if(selection > 0){
                bookAdapter.getItem(selection - 1).onPause();
//              bookAdapter.getItem(selection - 1).onDestroy();
            }
            if(selection + 1 < bookAdapter.getCount() && (bookAdapter.getItem(selection + 1) != null)){
                bookAdapter.getItem(selection + 1).onPause();
            }
            fragment.setCurrentPage(true);
            fragment.onResume();
        }

    };

    public static class BookPagerAdapter extends FragmentStatePagerAdapter{
        private List<Fragment> mBookPagesList;
        private int mReadType;

        public BookPagerAdapter(FragmentManager fm,int readType) {
            super(fm);
            // TODO Auto-generated constructor stub
            mReadType = readType;
            initPages();
        }

        @Override
        public Fragment getItem(int position) {
            // TODO Auto-generated method stub
            return mBookPagesList.get(position);
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return mBookPagesList.size();
        }

        private void initPages(){
            mBookPagesList = new ArrayList<Fragment>();
            mBookPagesList.add(FirstPageFragment.newInstance(mReadType));
            mBookPagesList.add(SecondPageFragment.newInstance(mReadType));
            mBookPagesList.add(ThirdPageFragment.newInstance(mReadType));
            mBookPagesList.add(FourthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FifthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SixthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SeventhPageFragment.newInstance(mReadType));
            mBookPagesList.add(EigthPageFragment.newInstance(mReadType));
            mBookPagesList.add(NinethPageFragment.newInstance(mReadType));
            mBookPagesList.add(TenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(EleventhPageFragment.newInstance(mReadType));
            mBookPagesList.add(TwelvethPageFragment.newInstance(mReadType));
            mBookPagesList.add(ThirteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FourteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FifteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SixteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SeventeenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(CreditsPageFragment.newInstance(mReadType));
        }
    }
}
</code>```

BookPageFragment

```<code>public abstract class BookPageFragment extends Fragment{
public static final String TAG = BookPageFragment.class.getSimpleName();

public static final int AUTO_PLAY = 1;
public static final int READ_WITH_ME = 2;
public static final int READ_TO_MYSELF = 3;

private ViewPagerController mPageController;
protected final static String READ_TYPE_KEY = "readType";

private boolean mIsCurrentPage;

private int mCurrentWordIndex;
private MediaPlayer mMediaPlayer;
private BookPage mBookPage;
private SpeechController mSpeechController;

private TextHighlightController mCurrentHighlightController;
protected List<TextHighlightController> mHighlighters;
private int mCurrentHighlightIndex;

public abstract int getJsonId();
public abstract int getAudioResourceId();
protected abstract int[] getParagraphsTextView();
protected abstract int[] getParagraphsStringRes();
protected abstract int[] getPopupButtonsId();

public BookPageFragment(){
    mIsCurrentPage = false;
    mCurrentHighlightIndex = 0;
}

public void endAudioPlayback(){
    if(getReadTypeFromArgs() == AUTO_PLAY){
        mPageController.goToNextPage();
    }
}

private void loadHighlighters(){
    int[] paragraphsTextViews = getParagraphsTextView();
    int[] stringRes = getParagraphsStringRes();
    for(int i=0;i<paragraphsTextViews.length;i++){
        int currentParagraph = paragraphsTextViews[i];
        int stringId = stringRes[i];
        TextView paragraph = (TextView)getView().findViewById(currentParagraph);
        TextHighlightController controller = TextHighlightController.newInstance(getActivity(), paragraph, stringId);
        addHighlighter(controller);
    }
}

public final void highlightNextWord(){
    if(!mCurrentHighlightController.highlightNextWord()){
        mCurrentHighlightIndex++;
        if(mCurrentHighlightIndex < mHighlighters.size()){
            mCurrentHighlightController = mHighlighters.get(mCurrentHighlightIndex);
            mCurrentHighlightController.highlightNextWord();
        }
    }
}

@Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);
    Log.i(TAG,"onAttach");
    try{
        mPageController = (ViewPagerController)activity;
    }catch(ClassCastException e){
        throw new IllegalArgumentException("Activity not implementing ViewPagerController");
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    Log.i(TAG,"onCreate");
}

@Override
public void onDetach() {
    // TODO Auto-generated method stub
    super.onDetach();
    resetAll();
    Log.i(TAG,"onDetach");
}

public void goToNextPage(){
    mPageController.goToNextPage();
}

public void goToPreviousPage(){
    mPageController.goToPreviousPage();
}

public void setCurrentPage(boolean isCurrentPage){
    mIsCurrentPage = isCurrentPage;
}

public boolean isCurrentPage(){
    return mIsCurrentPage;
}

@Override
public void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
    Log.i(TAG,"onStart");
}

@Override
public void onResume() {
    // TODO Auto-generated method stub
    Log.i(TAG,"onResume");
    super.onResume();
    resetAll();
    configureBookPage();
}

public final void startWithAutoPlay(){
    disablePopupButtons();
    initAudioPlayback();
}

public final void startWithRead(){
    initAudioPlayback();
}

private long prevWordStartTime = 0;
public final long getNextWordStart(){
    long wordStart=-1;
    if(mCurrentWordIndex < mBookPage.getWordList().size()){
        Word currentWord = mBookPage.getWordList().get(mCurrentWordIndex);
        wordStart = currentWord.getStartTime() - prevWordStartTime;
        wordStart = wordStart + currentWord.getWordLength() - 25;
        prevWordStartTime = currentWord.getEndTime();
        mCurrentWordIndex++;
    }
    return wordStart;
}

public final long getNextWordLength(){
    long wordLength;
    if(mCurrentWordIndex < mBookPage.getWordList().size()){
        Word currentWord = mBookPage.getWordList().get(mCurrentWordIndex);
        if(mCurrentWordIndex == 0){
            wordLength= currentWord.getStartTime();
        }else{
            wordLength = currentWord.getWordLength();
        }
        mCurrentWordIndex++;
    }else{
        wordLength = -1;
    }
    return wordLength;
}

public final void startPlayback(){
    mMediaPlayer = MediaPlayer.create(getActivity(), getAudioResourceId());
    mMediaPlayer.start();
}

@Override
public void onPause() {
    // TODO Auto-generated method stub
    Log.i(TAG,"onPause");
    mIsCurrentPage = false;
    if(mSpeechController != null){
        mSpeechController.stopHighlighting();
    }
    if(mMediaPlayer != null){
        try{
            mMediaPlayer.stop();
            mMediaPlayer.release();
        }catch(Exception e){

        }
    }
    resetHighlighters();
    resetAll();
    super.onPause();
}

@Override
public void onStop() {
    // TODO Auto-generated method stub
    super.onStop();
    Log.i(TAG,"onStop");
}

protected void addHighlighter(TextHighlightController controller){
    if(mHighlighters == null){
        mHighlighters = new ArrayList<TextHighlightController>();
    }
    mHighlighters.add(controller);
}

private void resetHighlighters(){
    if(mHighlighters != null){
        for(TextHighlightController controller : mHighlighters){
            controller.reset();
        }
    }
    mCurrentHighlightIndex = 0;
    mCurrentWordIndex = 0;
}

private void resetAll(){
    mCurrentWordIndex = 0;
    mCurrentHighlightIndex = 0;
    if(mMediaPlayer != null){
        try{
            mMediaPlayer.reset();
        }catch(Exception e){

        }
    }
    if(mCurrentHighlightController != null){
        mCurrentHighlightController.reset();
    }
    if(mSpeechController != null){
        Message msg = mSpeechController.obtainMessage(SpeechController.END_AUDIO);
        mSpeechController.sendMessage(msg);
    }
    if(mHighlighters != null){
        for(TextHighlightController controller : mHighlighters){
            controller.reset();
        }
    }
}

private void initAudioPlayback(){
    if(getJsonId() != 0){
        initHighlightersList();
        loadJson();
        mSpeechController = new SpeechController(this);
        Message msg = mSpeechController.obtainMessage(SpeechController.START_AUTO_PLAY);
        mSpeechController.sendMessageDelayed(msg, 1000);
    }
}

private void disablePopupButtons(){
    if(getView() != null){
        int[] buttonsId = getPopupButtonsId();
        for(int currentButtonId : buttonsId){
            getView().findViewById(currentButtonId).setVisibility(View.INVISIBLE);
        }
    }
}

private void initHighlightersList(){
    loadHighlighters();
    if(mHighlighters != null)
        mCurrentHighlightController = mHighlighters.get(mCurrentHighlightIndex);
}

private void loadJson(){
    Gson gson = new Gson();
    InputStream jsonStream = getResources().openRawResource(getJsonId());
    InputStreamReader jsonReader = new InputStreamReader(jsonStream);
    mBookPage = gson.fromJson(jsonReader, BookPage.class);
}

private void configureBookPage(){
    int currentReadType = getReadTypeFromArgs();
    Log.i(TAG,"GotReadType");
    switch(currentReadType){
    case AUTO_PLAY:
        if(mIsCurrentPage){
            startWithAutoPlay();
        }
        break;
    case READ_WITH_ME:
        if(mIsCurrentPage){
            startWithRead();
        }
        break;
    case READ_TO_MYSELF:
        //Should do Nothing
        break;
    default:
        throw new IllegalArgumentException("You must select one of the reading types of BookPageFragment");
    }
}

protected int getReadTypeFromArgs(){
    return getArguments().getInt(READ_TYPE_KEY);
}
</code>```

}

LOGCAT

```<code>    09-30 22:56:37.602: E/AndroidRuntime(7640): FATAL EXCEPTION: main
09-30 22:56:37.602: E/AndroidRuntime(7640): java.lang.NullPointerException
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.loadHighlighters(BookPageFragment.java:68)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.initHighlightersList(BookPageFragment.java:275)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.initAudioPlayback(BookPageFragment.java:257)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.startWithRead(BookPageFragment.java:149)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.configureBookPage(BookPageFragment.java:298)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.onResume(BookPageFragment.java:140)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.MainActivity$1.onPageSelected(MainActivity.java:136)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:567)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:551)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:2008)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.View.dispatchTouchEvent(View.java:7253)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2168)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1903)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2215)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1458)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.app.Activity.dispatchTouchEvent(Activity.java:2410)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2163)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.View.dispatchPointerEvent(View.java:7433)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3220)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3165)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4292)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4271)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4363)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:179)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.MessageQueue.nativePollOnce(Native Method)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.MessageQueue.next(MessageQueue.java:125)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.Looper.loop(Looper.java:124)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.app.ActivityThread.main(ActivityThread.java:5227)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at java.lang.reflect.Method.invokeNative(Native Method)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at java.lang.reflect.Method.invoke(Method.java:511)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at dalvik.system.NativeStart.main(Native Method)
</code>```

答:
setRetainInstance is ignored for android.support.v4.app.FragmentManager.

The solution that worked for me was removing the saved fragments in the onCreate of my activity BEFORE super.OnCreate is called.

```<code>if(savedInstanceState != null) {
    savedInstanceState.remove("android:support:fragments");
}
</code>```

This worked for me in the way I expected setRetainInstance(true); to work in the fragments themselves.

I found this solution here

*Note that if you are calling to a DialogFragment from any of the fragments, they will dismiss on orientation change if you use this solution.

Body:
In my app, I have a ViewPager, and inside that ViewPager there're about 17 Fragments. I've designed the layouts for both Portrait and Landscape.
When I Rotate my Screen, the method getView() its returning a null object, don't know why this happens, I've used setRetainInstance(true), but still the same thing, I'm using a PagerStateFragmentAdapter as my adapter implementation.

Why does this happens?

Thank you in advance.

EDIT

MainActivity

public class MainActivity extends FragmentActivity implements ViewPagerController{
    public static final String READ_TYPE = "Read_type";
    private static final String TAG = MainActivity.class.getSimpleName();
    private int mReadType;
    private ViewPager mBookPager;

    @Override
    public void goToNextPage() {
        // TODO Auto-generated method stub
        int currentPage = mBookPager.getCurrentItem();
        if(currentPage+1 < mBookPager.getAdapter().getCount()){
            FragmentPagerAdapter adapter = (FragmentPagerAdapter)mBookPager.getAdapter();
            BookPageFragment bookPage = (BookPageFragment)adapter.getItem(currentPage);
            bookPage.setCurrentPage(false);

            bookPage = (BookPageFragment)adapter.getItem(currentPage+1);
            bookPage.setCurrentPage(true);
            mBookPager.setCurrentItem(currentPage+1, true);
        }
    }

    @Override
    public void goToPreviousPage() {
        // TODO Auto-generated method stub
        int currentPage = mBookPager.getCurrentItem();
        if(currentPage >= 0){
            mBookPager.setCurrentItem(currentPage-1,true);
        }
    }

    @Override
    public void onBackPressed() {
        // TODO Auto-generated method stub
        finish();
        overridePendingTransition(R.anim.anim_move_to_right,R.anim.anim_from_left_to_right);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        Log.i(TAG,"onDestroy");
        mBookPager.removeAllViews();
        mBookPager = null;
        super.onDestroy();
    }

    @Override
    protected void onCreate(Bundle arg0) {
        // TODO Auto-generated method stub
        super.onCreate(arg0);
        setContentView(R.layout.main_layout);
        overridePendingTransition(R.anim.anim_from_right_to_left, R.anim.anim_move_to_left);
        initReadType();
        mBookPager = (ViewPager)findViewById(R.id.mainLayout_mainViewPager);
        initViewPager();

    }

    private void initReadType(){
        mReadType = getIntent().getIntExtra(READ_TYPE, -1);
    }

    private void initViewPager(){
        BookPagerAdapter mPagerAdapter = new BookPagerAdapter(getSupportFragmentManager(),mReadType);
        ((BookPageFragment)mPagerAdapter.getItem(0)).setCurrentPage(true);
        mBookPager.setAdapter(mPagerAdapter);
        mBookPager.setOnPageChangeListener(mOnPageChangeListener);
    }

    private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener(){

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageSelected(int selection) {
            // TODO Auto-generated method stub
            BookPagerAdapter bookAdapter = (BookPagerAdapter)mBookPager.getAdapter();
            BookPageFragment fragment = (BookPageFragment)bookAdapter.getItem(selection);
            if(selection > 0){
                bookAdapter.getItem(selection - 1).onPause();
//              bookAdapter.getItem(selection - 1).onDestroy();
            }
            if(selection + 1 < bookAdapter.getCount() && (bookAdapter.getItem(selection + 1) != null)){
                bookAdapter.getItem(selection + 1).onPause();
            }
            fragment.setCurrentPage(true);
            fragment.onResume();
        }

    };

    public static class BookPagerAdapter extends FragmentStatePagerAdapter{
        private List<Fragment> mBookPagesList;
        private int mReadType;

        public BookPagerAdapter(FragmentManager fm,int readType) {
            super(fm);
            // TODO Auto-generated constructor stub
            mReadType = readType;
            initPages();
        }

        @Override
        public Fragment getItem(int position) {
            // TODO Auto-generated method stub
            return mBookPagesList.get(position);
        }

        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return mBookPagesList.size();
        }

        private void initPages(){
            mBookPagesList = new ArrayList<Fragment>();
            mBookPagesList.add(FirstPageFragment.newInstance(mReadType));
            mBookPagesList.add(SecondPageFragment.newInstance(mReadType));
            mBookPagesList.add(ThirdPageFragment.newInstance(mReadType));
            mBookPagesList.add(FourthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FifthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SixthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SeventhPageFragment.newInstance(mReadType));
            mBookPagesList.add(EigthPageFragment.newInstance(mReadType));
            mBookPagesList.add(NinethPageFragment.newInstance(mReadType));
            mBookPagesList.add(TenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(EleventhPageFragment.newInstance(mReadType));
            mBookPagesList.add(TwelvethPageFragment.newInstance(mReadType));
            mBookPagesList.add(ThirteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FourteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(FifteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SixteenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(SeventeenthPageFragment.newInstance(mReadType));
            mBookPagesList.add(CreditsPageFragment.newInstance(mReadType));
        }
    }
}

BookPageFragment

public abstract class BookPageFragment extends Fragment{
public static final String TAG = BookPageFragment.class.getSimpleName();

public static final int AUTO_PLAY = 1;
public static final int READ_WITH_ME = 2;
public static final int READ_TO_MYSELF = 3;

private ViewPagerController mPageController;
protected final static String READ_TYPE_KEY = "readType";

private boolean mIsCurrentPage;

private int mCurrentWordIndex;
private MediaPlayer mMediaPlayer;
private BookPage mBookPage;
private SpeechController mSpeechController;

private TextHighlightController mCurrentHighlightController;
protected List<TextHighlightController> mHighlighters;
private int mCurrentHighlightIndex;

public abstract int getJsonId();
public abstract int getAudioResourceId();
protected abstract int[] getParagraphsTextView();
protected abstract int[] getParagraphsStringRes();
protected abstract int[] getPopupButtonsId();

public BookPageFragment(){
    mIsCurrentPage = false;
    mCurrentHighlightIndex = 0;
}

public void endAudioPlayback(){
    if(getReadTypeFromArgs() == AUTO_PLAY){
        mPageController.goToNextPage();
    }
}

private void loadHighlighters(){
    int[] paragraphsTextViews = getParagraphsTextView();
    int[] stringRes = getParagraphsStringRes();
    for(int i=0;i<paragraphsTextViews.length;i++){
        int currentParagraph = paragraphsTextViews[i];
        int stringId = stringRes[i];
        TextView paragraph = (TextView)getView().findViewById(currentParagraph);
        TextHighlightController controller = TextHighlightController.newInstance(getActivity(), paragraph, stringId);
        addHighlighter(controller);
    }
}

public final void highlightNextWord(){
    if(!mCurrentHighlightController.highlightNextWord()){
        mCurrentHighlightIndex++;
        if(mCurrentHighlightIndex < mHighlighters.size()){
            mCurrentHighlightController = mHighlighters.get(mCurrentHighlightIndex);
            mCurrentHighlightController.highlightNextWord();
        }
    }
}

@Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);
    Log.i(TAG,"onAttach");
    try{
        mPageController = (ViewPagerController)activity;
    }catch(ClassCastException e){
        throw new IllegalArgumentException("Activity not implementing ViewPagerController");
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    Log.i(TAG,"onCreate");
}

@Override
public void onDetach() {
    // TODO Auto-generated method stub
    super.onDetach();
    resetAll();
    Log.i(TAG,"onDetach");
}

public void goToNextPage(){
    mPageController.goToNextPage();
}

public void goToPreviousPage(){
    mPageController.goToPreviousPage();
}

public void setCurrentPage(boolean isCurrentPage){
    mIsCurrentPage = isCurrentPage;
}

public boolean isCurrentPage(){
    return mIsCurrentPage;
}

@Override
public void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
    Log.i(TAG,"onStart");
}

@Override
public void onResume() {
    // TODO Auto-generated method stub
    Log.i(TAG,"onResume");
    super.onResume();
    resetAll();
    configureBookPage();
}

public final void startWithAutoPlay(){
    disablePopupButtons();
    initAudioPlayback();
}

public final void startWithRead(){
    initAudioPlayback();
}

private long prevWordStartTime = 0;
public final long getNextWordStart(){
    long wordStart=-1;
    if(mCurrentWordIndex < mBookPage.getWordList().size()){
        Word currentWord = mBookPage.getWordList().get(mCurrentWordIndex);
        wordStart = currentWord.getStartTime() - prevWordStartTime;
        wordStart = wordStart + currentWord.getWordLength() - 25;
        prevWordStartTime = currentWord.getEndTime();
        mCurrentWordIndex++;
    }
    return wordStart;
}

public final long getNextWordLength(){
    long wordLength;
    if(mCurrentWordIndex < mBookPage.getWordList().size()){
        Word currentWord = mBookPage.getWordList().get(mCurrentWordIndex);
        if(mCurrentWordIndex == 0){
            wordLength= currentWord.getStartTime();
        }else{
            wordLength = currentWord.getWordLength();
        }
        mCurrentWordIndex++;
    }else{
        wordLength = -1;
    }
    return wordLength;
}

public final void startPlayback(){
    mMediaPlayer = MediaPlayer.create(getActivity(), getAudioResourceId());
    mMediaPlayer.start();
}

@Override
public void onPause() {
    // TODO Auto-generated method stub
    Log.i(TAG,"onPause");
    mIsCurrentPage = false;
    if(mSpeechController != null){
        mSpeechController.stopHighlighting();
    }
    if(mMediaPlayer != null){
        try{
            mMediaPlayer.stop();
            mMediaPlayer.release();
        }catch(Exception e){

        }
    }
    resetHighlighters();
    resetAll();
    super.onPause();
}

@Override
public void onStop() {
    // TODO Auto-generated method stub
    super.onStop();
    Log.i(TAG,"onStop");
}

protected void addHighlighter(TextHighlightController controller){
    if(mHighlighters == null){
        mHighlighters = new ArrayList<TextHighlightController>();
    }
    mHighlighters.add(controller);
}

private void resetHighlighters(){
    if(mHighlighters != null){
        for(TextHighlightController controller : mHighlighters){
            controller.reset();
        }
    }
    mCurrentHighlightIndex = 0;
    mCurrentWordIndex = 0;
}

private void resetAll(){
    mCurrentWordIndex = 0;
    mCurrentHighlightIndex = 0;
    if(mMediaPlayer != null){
        try{
            mMediaPlayer.reset();
        }catch(Exception e){

        }
    }
    if(mCurrentHighlightController != null){
        mCurrentHighlightController.reset();
    }
    if(mSpeechController != null){
        Message msg = mSpeechController.obtainMessage(SpeechController.END_AUDIO);
        mSpeechController.sendMessage(msg);
    }
    if(mHighlighters != null){
        for(TextHighlightController controller : mHighlighters){
            controller.reset();
        }
    }
}

private void initAudioPlayback(){
    if(getJsonId() != 0){
        initHighlightersList();
        loadJson();
        mSpeechController = new SpeechController(this);
        Message msg = mSpeechController.obtainMessage(SpeechController.START_AUTO_PLAY);
        mSpeechController.sendMessageDelayed(msg, 1000);
    }
}

private void disablePopupButtons(){
    if(getView() != null){
        int[] buttonsId = getPopupButtonsId();
        for(int currentButtonId : buttonsId){
            getView().findViewById(currentButtonId).setVisibility(View.INVISIBLE);
        }
    }
}

private void initHighlightersList(){
    loadHighlighters();
    if(mHighlighters != null)
        mCurrentHighlightController = mHighlighters.get(mCurrentHighlightIndex);
}

private void loadJson(){
    Gson gson = new Gson();
    InputStream jsonStream = getResources().openRawResource(getJsonId());
    InputStreamReader jsonReader = new InputStreamReader(jsonStream);
    mBookPage = gson.fromJson(jsonReader, BookPage.class);
}

private void configureBookPage(){
    int currentReadType = getReadTypeFromArgs();
    Log.i(TAG,"GotReadType");
    switch(currentReadType){
    case AUTO_PLAY:
        if(mIsCurrentPage){
            startWithAutoPlay();
        }
        break;
    case READ_WITH_ME:
        if(mIsCurrentPage){
            startWithRead();
        }
        break;
    case READ_TO_MYSELF:
        //Should do Nothing
        break;
    default:
        throw new IllegalArgumentException("You must select one of the reading types of BookPageFragment");
    }
}

protected int getReadTypeFromArgs(){
    return getArguments().getInt(READ_TYPE_KEY);
}

}

LOGCAT

    09-30 22:56:37.602: E/AndroidRuntime(7640): FATAL EXCEPTION: main
09-30 22:56:37.602: E/AndroidRuntime(7640): java.lang.NullPointerException
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.loadHighlighters(BookPageFragment.java:68)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.initHighlightersList(BookPageFragment.java:275)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.initAudioPlayback(BookPageFragment.java:257)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.startWithRead(BookPageFragment.java:149)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.configureBookPage(BookPageFragment.java:298)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.fragment.BookPageFragment.onResume(BookPageFragment.java:140)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.mobimanage.kagadventures.MainActivity$1.onPageSelected(MainActivity.java:136)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:567)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:551)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.support.v4.view.ViewPager.onTouchEvent(ViewPager.java:2008)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.View.dispatchTouchEvent(View.java:7253)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2168)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1903)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2174)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1917)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2215)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1458)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.app.Activity.dispatchTouchEvent(Activity.java:2410)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2163)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.View.dispatchPointerEvent(View.java:7433)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3220)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3165)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4292)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4271)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4363)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:179)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.MessageQueue.nativePollOnce(Native Method)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.MessageQueue.next(MessageQueue.java:125)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.os.Looper.loop(Looper.java:124)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at android.app.ActivityThread.main(ActivityThread.java:5227)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at java.lang.reflect.Method.invokeNative(Native Method)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at java.lang.reflect.Method.invoke(Method.java:511)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
09-30 22:56:37.602: E/AndroidRuntime(7640):     at dalvik.system.NativeStart.main(Native Method)

Body:
setRetainInstance is ignored for android.support.v4.app.FragmentManager.

The solution that worked for me was removing the saved fragments in the onCreate of my activity BEFORE super.OnCreate is called.

if(savedInstanceState != null) {
    savedInstanceState.remove("android:support:fragments");
}

This worked for me in the way I expected setRetainInstance(true); to work in the fragments themselves.

I found this solution here

*Note that if you are calling to a DialogFragment from any of the fragments, they will dismiss on orientation change if you use this solution.


问:
Find version of Chrome browser in registry
How do I get Chrome version using PowerShell? I tried the following query:

```<code>(Get-ItemProperty 'HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Google Chrome').DisplayVersion
</code>```

This didn't work.

答:
This is probably what you want (it reads the version of the executable, not a value from the registry):</p>

```<code>(Get-Item (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe').'(Default)').VersionInfo
</code>```

Body:
How do I get Chrome version using PowerShell? I tried the following query:

(Get-ItemProperty 'HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Google Chrome').DisplayVersion

This didn't work.

Body:
This is probably what you want (it reads the version of the executable, not a value from the registry):

(Get-Item (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe').'(Default)').VersionInfo


问:
How to get a short unique URL using mod_rewrite in the following case?
I'm coding for a project similar to pastebin. Each snippet should be accessible by some short unique URL that everyone can access. For example, if I make a new snippet, then that would have a associated URL like /2k3nan5. Anyone who visits yourwebsite.com/2k3nan5 should see that snippet.

I create a random string for each snippet that is being pasted e.g., 2k3nan5. I store the code of the snippet(code), username of the user who posted it (username) and the random string(url) in the snippet table of the database.

How do I alter .htaccess for doing this?

答:
```<code><IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9]{7})/?$ deltatask/snippet.php?url=$1 [NC,L]
</IfModule>
</code>```

This helped me in rewriting www.website.com/abcdefg to www.website.com/deltatask/snippet.php?url=abcdefg

Body:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([a-zA-Z0-9]{7})/?$ deltatask/snippet.php?url=$1 [NC,L]
</IfModule>

This helped me in rewriting www.website.com/abcdefg to www.website.com/deltatask/snippet.php?url=abcdefg


问:
String Anglicization?
Is anyone aware of any simple way to anglicize a string? Currently, in our system, we're doing replacements on "invalid" characters, such as shown below:

```<code>        ret = ret.Replace("ä", "ae");
        ret = ret.Replace("Ä", "Ae");
        ret = ret.Replace("ß", "ss");
        ret = ret.Replace("ç", "c");
        ret = ret.Replace("Ç", "C");
        ret = ret.Replace("Ž", "Z");
</code>```

The issue here is that as we're opening the business up in additional countries (Turkey, Russia, Hungary...), we're finding that there's a whole slew of characters that this process does not convert.

Is anyone aware of any sort of solution that would allow us to not depend on a table of "invalid" characters?

Also, if it helps, we're using C# to code. :)

Thanks!

edit:

In response to some comments, our system does support the full set of unicode characters... however, other system that we integrate to (such as card processors) do not. :(

答:
I apologize for a shameless plug, but I couldn't resist. I once wrote a Python module that does exactly what the author of the post needed:

https://github.com/revl/anglicize

Because Python is almost as readable as pseudocode and the module is only about 125 lines long, it's relatively easy to rewrite it in C#.

Here's what the module produces given the input from the original post:

```<code>$ echo 'ä Ä ß ç Ç Ž' | anglicize
a A ss s S S
</code>```

As you can see, "ß" was replaced with "ss" as requested, while "ç", "Ç", and "Ž" were replaced with "s", "S", and "S" respectively, likely because those were the phonetic equivalents in English.

As for "ä" and "Ä", the transliterations "ae" and "Ae" would probably work better than "a" and "A". I will gladly change the transliteration table if the linguists out there confirm that that's the right thing to do.

The module can transliterate the whole input text at once, or it can process input data in chunks. The documentation is in the README file that comes with the module.

ContentLicense: CC BY-SA 2.5

Title: String Anglicization?

Body:
Is anyone aware of any simple way to anglicize a string? Currently, in our system, we're doing replacements on "invalid" characters, such as shown below:

        ret = ret.Replace("ä", "ae");
        ret = ret.Replace("Ä", "Ae");
        ret = ret.Replace("ß", "ss");
        ret = ret.Replace("ç", "c");
        ret = ret.Replace("Ç", "C");
        ret = ret.Replace("Ž", "Z");

The issue here is that as we're opening the business up in additional countries (Turkey, Russia, Hungary...), we're finding that there's a whole slew of characters that this process does not convert.

Is anyone aware of any sort of solution that would allow us to not depend on a table of "invalid" characters?

Also, if it helps, we're using C# to code. :)

Thanks!

edit:

In response to some comments, our system does support the full set of unicode characters... however, other system that we integrate to (such as card processors) do not. :(

Body:
I apologize for a shameless plug, but I couldn't resist. I once wrote a Python module that does exactly what the author of the post needed:

https://github.com/revl/anglicize

Because Python is almost as readable as pseudocode and the module is only about 125 lines long, it's relatively easy to rewrite it in C#.

Here's what the module produces given the input from the original post:

$ echo 'ä Ä ß ç Ç Ž' | anglicize
a A ss s S S

As you can see, "ß" was replaced with "ss" as requested, while "ç", "Ç", and "Ž" were replaced with "s", "S", and "S" respectively, likely because those were the phonetic equivalents in English.

As for "ä" and "Ä", the transliterations "ae" and "Ae" would probably work better than "a" and "A". I will gladly change the transliteration table if the linguists out there confirm that that's the right thing to do.

The module can transliterate the whole input text at once, or it can process input data in chunks. The documentation is in the README file that comes with the module.


问:
Access 2016 VBA code to export to Excel, 'could not find installable ISAM'
I have a database in Access with multiple tables. My end goal is to create a form with a button, that when pressed, runs a macro. This macro will run custom VBA code.

When run, I want the macro to create a new Excel workbook with one worksheet, and import one specific table into that worksheet.

Currently, this is my VBA code. I have literally 0 experience with VBA, so have no idea if this code will work or not. I found this code online as an answer to a question about a similar goal, and is not mine (Export MS Access tables through VBA to an excel spreadsheet in same directory)

```<code>Option Compare Database

Public Function exportToExcel()

Dim outputFileName As String
outputFileName = CurrentProject.Path & "\Export_" & Format(Date, "yyyyMMdd") & ".xlsx"

DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel2Xml, "all_data", outputFileName, True

End Function
</code>```

I opened the VBA editor, created a new module called export module that is in the Modules folder in the navigator pane on the right side of the VBA editor window. The Option Compare Database bit was there already, and I typed the rest into this new module.

After saving the module, I created a new Macro, in which I have the RunCode command, and the Function field being =exportToExcel(). When I run the Macro, I get the error

```<code>Run-time error '3170':
Could not find installable ISAM.
</code>```

Does anyone know where this error is coming from, and how I fix it? Also would you be able to comment on my VBA code and tell me if anything is wrong and what I should change, or if I'm even going about automating an export to Excel in the correct way?

Thank you so much for your help.

答:
I suspect this was a reference to the wrong excel library and that changing the code from using

acSpreadsheetTypeExcel2Xml

to

acSpreadsheetTypeExcel9

has actually made the difference, based on whatever versionof excel is installed on the host machine.

Body:
I have a database in Access with multiple tables. My end goal is to create a form with a button, that when pressed, runs a macro. This macro will run custom VBA code.

When run, I want the macro to create a new Excel workbook with one worksheet, and import one specific table into that worksheet.

Currently, this is my VBA code. I have literally 0 experience with VBA, so have no idea if this code will work or not. I found this code online as an answer to a question about a similar goal, and is not mine (Export MS Access tables through VBA to an excel spreadsheet in same directory)

Option Compare Database

Public Function exportToExcel()

Dim outputFileName As String
outputFileName = CurrentProject.Path & "\Export_" & Format(Date, "yyyyMMdd") & ".xlsx"

DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel2Xml, "all_data", outputFileName, True

End Function

I opened the VBA editor, created a new module called export module that is in the Modules folder in the navigator pane on the right side of the VBA editor window. The Option Compare Database bit was there already, and I typed the rest into this new module.

After saving the module, I created a new Macro, in which I have the RunCode command, and the Function field being =exportToExcel(). When I run the Macro, I get the error

Run-time error '3170':
Could not find installable ISAM.

Does anyone know where this error is coming from, and how I fix it? Also would you be able to comment on my VBA code and tell me if anything is wrong and what I should change, or if I'm even going about automating an export to Excel in the correct way?

Thank you so much for your help.


问:
rtrim error when updating post
I'm getting this error when I'm trying to update a post in my WordPress site. If I add or change content then update I get a white page with the following messages. The actual change I've made gets saved and published ok but I'm not sure how to stop these error messages. Any help is greatly appreciated

Warning: rtrim() expects parameter 1 to be string, array given in /home/mysite/public_html/wp-includes/formatting.php on line 2376

Warning: rtrim() expects parameter 1 to be string, array given in /home/mysite/public_html/wp-includes/formatting.php on line 2376

Warning: Cannot modify header information - headers already sent by (output started at /home/mysite/public_html/wp-includes/formatting.php:2376) in /home/mysite/public_html/wp-admin/post.php on line 197

Warning: Cannot modify header information - headers already sent by (output started at /home/mysite/public_html/wp-includes/formatting.php:2376) in /home/mysite/public_html/wp-includes/pluggable.php on line 1174

答:
Since the trim function is expecting a string, it seems one has not been passed. Further down the error list, you're seeing header issues, so I suppose this is from a plugin changing headers.

When something like this happens to me, typically I disable all WP plugins and start enabling them one by one, and testing each time to determine which one is the issue. A process of elimination as it were. Once the warnings appear, you know which plugin is causing it.

Once, you get to this step, you can report the bug to the plugin developer or find out if anyone else is experiencing the same problem.

Title: rtrim error when updating post


问:
Cucumber - perform ActiveJob `perform_later` jobs immediately
I have many jobs that are calling other nested jobs using perform_later. However, during some tests on Cucumber, I'd like to execute those jobs immediately after to proceed with the rests of the tests.

I thought it would be enough to add

```<code># features/support/active_job.rb
World(ActiveJob::TestHelper)
</code>```

And to call jobs using this in a step definition file

```<code>perform_enqueued_jobs do
  # call step that calls MyJob.perform_later(*args)
end
</code>```

However I run into something like that

```<code>undefined method `perform_enqueued_jobs' for #<ActiveJob::QueueAdapters::AsyncAdapter:0x007f98fd03b900> (NoMethodError)
</code>```

What am I missing / doing wrong ?

答:
I switched to the :test adapter in tests and it worked out for me:</p>

```<code># initialisers/test.rb

config.active_job.queue_adapter = :test

# features/support/env.rb

World(ActiveJob::TestHelper)
</code>```

Body:
I have many jobs that are calling other nested jobs using perform_later. However, during some tests on Cucumber, I'd like to execute those jobs immediately after to proceed with the rests of the tests.

I thought it would be enough to add

# features/support/active_job.rb
World(ActiveJob::TestHelper)

And to call jobs using this in a step definition file

perform_enqueued_jobs do
  # call step that calls MyJob.perform_later(*args)
end

However I run into something like that

undefined method `perform_enqueued_jobs' for #<ActiveJob::QueueAdapters::AsyncAdapter:0x007f98fd03b900> (NoMethodError)

What am I missing / doing wrong ?

Body:
I switched to the :test adapter in tests and it worked out for me:

# initialisers/test.rb

config.active_job.queue_adapter = :test

# features/support/env.rb

World(ActiveJob::TestHelper)


问:
Determine whether one string can be made from a subset of characters in another string
I have a dictionary where letters correspond to numbers and a string, and seek to return True if each letter occurs in the string a number of times equal to or less than the number associated with that letter in the dictionary. When this problem was less complex and didn't have the limitation of counting occurrences, I used all(x in string for x in dictionary). Is there a similarly concise way to test for this based on the int value in the dictionary?

Edit: Apologies, here's what we're looking at.

```<code>def isValidWord(word, hand, wordList):
    """
    Returns True if word is in the wordList and is entirely
    composed of letters in the hand. Otherwise, returns False.

    Does not mutate hand or wordList.

    word: string
    hand: dictionary (string -> int)
    wordList: list of lowercase strings
    """
    if word.lower() in wordList and all(x in hand for x in word):
        return True
    else:
        return False
</code>```

This code returns True if any instance of the letter in the string appears as a dictionary key of Hand, when I now need it to return False unless the number of times that letter occurs is <= the int-value for that key. I've accomplished this rather messily, and was wondering if there was a way to incorporate that level of specificity into the all method or something similarly concise.

答:
If I understood you correctly, your hand dict is formed like:

```<code>hand = {"f": 1, "o": 2, "b": 1, "a": 1, "r": 1, "z": 0}
</code>```

And you want it to match foo and bar but not baz as z is set to 0 and there is at least one z. You can do that using str.count() like:

```<code>def isValidWord(word, hand, wordList):
    if word.lower() in wordList and all(hand.get(x, 0) >= word.count(x) for x in set(word)):
        return True
    else:
        return False
</code>```

Not the most efficient but should give you the idea. You can test it with:

```<code>hand = {"f": 1, "o": 2, "b": 1, "a": 1, "r": 1, "z": 0}  # letters with their allowed counts
word_list = ["foo", "bar", "baz"]  # allowed words

print(isValidWord("foo", hand, word_list))  # True
print(isValidWord("bar", hand, word_list))  # True
print(isValidWord("baz", hand, word_list))  # False
</code>```

Body:
I have a dictionary where letters correspond to numbers and a string, and seek to return True if each letter occurs in the string a number of times equal to or less than the number associated with that letter in the dictionary. When this problem was less complex and didn't have the limitation of counting occurrences, I used all(x in string for x in dictionary). Is there a similarly concise way to test for this based on the int value in the dictionary?

Edit: Apologies, here's what we're looking at.

def isValidWord(word, hand, wordList):
    """
    Returns True if word is in the wordList and is entirely
    composed of letters in the hand. Otherwise, returns False.

    Does not mutate hand or wordList.

    word: string
    hand: dictionary (string -> int)
    wordList: list of lowercase strings
    """
    if word.lower() in wordList and all(x in hand for x in word):
        return True
    else:
        return False

This code returns True if any instance of the letter in the string appears as a dictionary key of Hand, when I now need it to return False unless the number of times that letter occurs is <= the int-value for that key. I've accomplished this rather messily, and was wondering if there was a way to incorporate that level of specificity into the all method or something similarly concise.

Body:
If I understood you correctly, your hand dict is formed like:

hand = {"f": 1, "o": 2, "b": 1, "a": 1, "r": 1, "z": 0}

And you want it to match foo and bar but not baz as z is set to 0 and there is at least one z. You can do that using str.count() like:

def isValidWord(word, hand, wordList):
    if word.lower() in wordList and all(hand.get(x, 0) >= word.count(x) for x in set(word)):
        return True
    else:
        return False

Not the most efficient but should give you the idea. You can test it with:

hand = {"f": 1, "o": 2, "b": 1, "a": 1, "r": 1, "z": 0}  # letters with their allowed counts
word_list = ["foo", "bar", "baz"]  # allowed words

print(isValidWord("foo", hand, word_list))  # True
print(isValidWord("bar", hand, word_list))  # True
print(isValidWord("baz", hand, word_list))  # False


问:
Visual Studio 2013 & Windows 10 Pro - Blurry interface
For a few months, my Visual Studio interface is getting blurry for no reason, I'm just coding, using auto completion and doing some alt-tab.
I'm using 100% DPI, and I tried to update all my graphics drivers but it didn't solve the problem.

Here are some screenshots that might help to understand what i'm facing.

When i'm placing my arrow on it (like selection) it comes back clear, but not for long (about 5 min).

Any idea of what to do to solve this ?

答:
I finally solved the issue in manually installing my graphic cards' last update driver, that windows was ignoring because of the constructor's limitation set on my computer, which is a HP Pro-Book 450 G2.

My computer has a Intel(R) HD Graphics Family for the display, and a AMD Radeon Graphics Processor for the render.

This both drivers were expired and were working good with the Windows 7 Pro I had, before upgrading my computer's OS for Windows 10 Pro.

The drivers i'm using now are :
- Intel(R) HD Graphics Family : v20.19.15.4501 (from 11 aug. 2016)
- AMD Radeon Graphics Processor : v21.17.413.0 (from 25 jan. 2017)

I hope it will help some people.


问:
Java Scanner Throws InputMismatchException even when next token appears to fit data type
I'm currently working with the Java Scanner class and I'm getting a very strange InputMismatchException. I initialize the scanner like this:

```<code>Scanner in = new Scanner(new File(fileName));

in.useDelimiter("\n?.*:");</code>```

When I call System.out.println(in.next());, it prints 1500 to the command line, which is the correct value. However, if I call System.out.println(in.nextInt()); the Scanner throws an InputMismatchException. I don't think I'm printing trailing newlines or whitespace, and I'm sort of lost as to why this is happening.

EDIT: Here's the data format for what I'm reading in:

Data Description:100
Next Data Description:200

EDIT: Calling Integer.parseInt(in.next()); results in a  NumberFormatException: For input string: "1"00.

答:
That InputMismatchException isn't strange at all, because your regex isn't cross-platform compatible. You're likely a Windows user, so your text file will have \r\n as it's line endings, not just \n.

Thus the proper pattern would be:

```<code>in.useDelimiter("\r?\n?.*:");
</code>```

To accept \r\n or a single \n.

You could also try to work with System.lineSeparator() to support different line endings, but then you would need to wrap that with parenthese so the regex quantifier ? applies to both chars \r\n for Windows systems:

```<code>in.useDelimiter(String.format("(%s)?.*:", System.lineSeparator()));
</code>```

The issue with that approach is that it fails when using Windows as the operating system, but receiving the file from somewhere else, which itself just uses \n. So I recommend the first approach.

Body:
I'm currently working with the Java Scanner class and I'm getting a very strange InputMismatchException. I initialize the scanner like this:

Scanner in = new Scanner(new File(fileName));

in.useDelimiter("\n?.*:");

When I call System.out.println(in.next());, it prints 1500 to the command line, which is the correct value. However, if I call System.out.println(in.nextInt()); the Scanner throws an InputMismatchException. I don't think I'm printing trailing newlines or whitespace, and I'm sort of lost as to why this is happening.

EDIT: Here's the data format for what I'm reading in:

Data Description:100
Next Data Description:200

EDIT: Calling Integer.parseInt(in.next()); results in a  NumberFormatException: For input string: "1"00.

Body:
That InputMismatchException isn't strange at all, because your regex isn't cross-platform compatible. You're likely a Windows user, so your text file will have \r\n as it's line endings, not just \n.

Thus the proper pattern would be:

in.useDelimiter("\r?\n?.*:");

To accept \r\n or a single \n.

You could also try to work with System.lineSeparator() to support different line endings, but then you would need to wrap that with parenthese so the regex quantifier ? applies to both chars \r\n for Windows systems:

in.useDelimiter(String.format("(%s)?.*:", System.lineSeparator()));

The issue with that approach is that it fails when using Windows as the operating system, but receiving the file from somewhere else, which itself just uses \n. So I recommend the first approach.


问:
Reading floats from file with python
My input file has the form:

```<code>5.0, 1000.0, 100000000000000.0, 115.2712, 230.538, 345.796, 461.0408,
1.053E-09, 1.839E-09, 1.632E-10, 1.959E-12, 4.109, 3.683, 3.586, 3.650
</code>```

where every number is essentially in a line.

What I want to do is read all the floats, and then append only columns 7 through 10 to an array.

Here's what I've written:

```<code>T=[]
with open("test.txt", "r") as file1:
    for line in file1.readlines():
        f_list = [float(i) for i in line.split(",")]
        T.append(float(f_list[7]))
        T.append(float(f_list[8]))
        T.append(float(f_list[9]))
        T.append(float(f_list[10]))
</code>```

When I run the above I get:

```<code>ValueError: could not convert string to float:
</code>```

I think there's something wrong with the float(i) part, but I can't find a way around it.

I've seen people having similar problems here, but none of the fixes I've tried so far have helped. Any help is greatly appreciated.

答:
Your problem is that when you split line, the resulting list most likely contains whitespace. This would cause float() to fail. You need to sanitize your split list first by testing if an element is actually a valid float number. eg:

```<code>>>> def is_float(n):
    try:
        float(n)
        return True
    except:
        return False

>>>
>>> line = '5.0, 1000.0, 100000000000000.0, 115.2712, 230.538, 345.796, 461.0408,'
>>> lst = [float(n) for n in line.split(',') if is_float(n)]
>>> lst
[5.0, 1000.0, 100000000000000.0, 115.2712, 230.538, 345.796, 461.0408]
>>>
</code>```

Title: Reading floats from file with python

Body:
My input file has the form:

5.0, 1000.0, 100000000000000.0, 115.2712, 230.538, 345.796, 461.0408,
1.053E-09, 1.839E-09, 1.632E-10, 1.959E-12, 4.109, 3.683, 3.586, 3.650

where every number is essentially in a line.

What I want to do is read all the floats, and then append only columns 7 through 10 to an array.

Here's what I've written:

T=[]
with open("test.txt", "r") as file1:
    for line in file1.readlines():
        f_list = [float(i) for i in line.split(",")]
        T.append(float(f_list[7]))
        T.append(float(f_list[8]))
        T.append(float(f_list[9]))
        T.append(float(f_list[10]))

When I run the above I get:

ValueError: could not convert string to float:

I think there's something wrong with the float(i) part, but I can't find a way around it.

I've seen people having similar problems here, but none of the fixes I've tried so far have helped. Any help is greatly appreciated.

Body:
Your problem is that when you split line, the resulting list most likely contains whitespace. This would cause float() to fail. You need to sanitize your split list first by testing if an element is actually a valid float number. eg:

>>> def is_float(n):
    try:
        float(n)
        return True
    except:
        return False

>>>
>>> line = '5.0, 1000.0, 100000000000000.0, 115.2712, 230.538, 345.796, 461.0408,'
>>> lst = [float(n) for n in line.split(',') if is_float(n)]
>>> lst
[5.0, 1000.0, 100000000000000.0, 115.2712, 230.538, 345.796, 461.0408]
>>>


问:
Using mod operator in JavaScript to wrap around
I am building a Texas Hold'em Poker web application using ReactJS. In order to keep track of the dealer button, I am using the following formula...

```<code>let currentPlayers = [
    {name: "Foo", position: 1},
    {name: "Bar", position: 2},
    {name: "Baz", position: 3}
]
let dealerButtonPos = 1

dealerButtonPos = ((dealerButtonPos + currentPlayers.length ) % currentPlayers.length + 1 )
</code>```

What I am trying to do here is make sure that the dealer button starts at position 1 and is always on the correct position at the start of every round. The dealer button, in this case, should always fall on position 1, then 2, then 3, then 1 again.

The function with the formula will be called at the end of every round. This should rotate the dealer button correctly for up to 8 players.
Will I always be on the correct player position? Am I implementing this correctly? I had a hard time conceptualizing and getting to this point. Can someone explain the mod operator for clarity?

答:
I would do it this way.</p>

```<code>let currentPlayers = [
    {name: "Foo", position: 1},
    {name: "Bar", position: 2},
    {name: "Baz", position: 3}
]
let dealerButtonPos = 1
var index = dealerButtonPos % currentPlayers.length
dealerButtonPos = (index == 0) ? index + currentPlayers.length : index
</code>```

Body:
I am building a Texas Hold'em Poker web application using ReactJS. In order to keep track of the dealer button, I am using the following formula...

let currentPlayers = [
    {name: "Foo", position: 1},
    {name: "Bar", position: 2},
    {name: "Baz", position: 3}
]
let dealerButtonPos = 1

dealerButtonPos = ((dealerButtonPos + currentPlayers.length ) % currentPlayers.length + 1 )

What I am trying to do here is make sure that the dealer button starts at position 1 and is always on the correct position at the start of every round. The dealer button, in this case, should always fall on position 1, then 2, then 3, then 1 again.

The function with the formula will be called at the end of every round. This should rotate the dealer button correctly for up to 8 players.
Will I always be on the correct player position? Am I implementing this correctly? I had a hard time conceptualizing and getting to this point. Can someone explain the mod operator for clarity?

Body:
I would do it this way.

let currentPlayers = [
    {name: "Foo", position: 1},
    {name: "Bar", position: 2},
    {name: "Baz", position: 3}
]
let dealerButtonPos = 1
var index = dealerButtonPos % currentPlayers.length
dealerButtonPos = (index == 0) ? index + currentPlayers.length : index