问:
PHP, Printf,Sprintf Functions
I am studying about printf,sprintf and i didnt understand few points, if can some one please help me understand thos points,

At This Link at PHP Manual:

There are explanations are numbered from one to six:

What i didnt understand is: The First and The Second(1(sign specifier), 2(padding specifier)), if can some one please help me with example for thos i will be very thankful.

答:
1.Sign specifier:

By default browsers only display - sign in front of negative numbers. + sign in front of positive numbers are omitted. But it is possible to instruct the browser to display + sign in front of positive numbers by using sign specifier. For example:

```<code>$num1=10;
$num2=-10;
$output=sprintf("%d",$num1);
echo "$output<br>";
$output=sprintf("%d",$num2);
echo "$output";
</code>```

Output:

```<code>10
-10
</code>```

Here the + sign before the positive number is omitted. However, if we put a + sign after % character of %d then the omission no longer takes place.

```<code>$num1=10;
$num2=-10;
$output=sprintf("%+d",$num1);
echo "$output<br>";
$output=sprintf("%+d",$num2);
echo "$output";
</code>```

Output:

```<code>+10
-10
</code>```

2.Padding specifier:

The padding specifier adds certain number of characters to the left or right of the output. The characters may be empty spaces, zeroes or any other ASCII character.

For example,

```<code>$str="hello";
$output=sprintf("[%10s]",$str);
echo $output;
</code>```

Source code output:

```<code>[     hello]             //Total length of 10 positions,first five being empty spaces and remaining five being "hello"
</code>```

HTML output:

```<code> [ hello]                 //HTML displays only one empty space and collapses the rest, you have to use the ```...``` tag in the code for HTML to preserve the empty spaces.
</code>```

Putting a negative sign left justifies the output:

```<code>$output=["%-10s",$string];
echo $output;
</code>```

Source code output:

```<code>[hello     ]
</code>```

HTML output:

```<code>[hello ]
</code>```

Putting 0 after % sign replaces empty spaces with zeroes.

```<code>$str="hello";
$output=sprintf("[%010s]",$str);
echo $output;
</code>```

Output:

```<code>[00000hello]
</code>```

Left justification

```<code>$output=sprintf("[%-010s]",$str);
</code>```

Output:

```<code>[hello00000]
</code>```

Putting ' followed by any ASCII character like * after % results in the display of that ASCII character instead of empty spaces

```<code>$str="hello";
$output=sprintf("[%'*10s]",$str);
echo $output;
</code>```

Output:

```<code>*****hello
</code>```

Left justification:

```<code>$output=sprintf("[%-'*10s]",$str);
echo $output;
</code>```

Output:

```<code>hello*****
</code>```

Title: PHP, Printf,Sprintf Functions

Body:
1.Sign specifier:

By default browsers only display - sign in front of negative numbers. + sign in front of positive numbers are omitted. But it is possible to instruct the browser to display + sign in front of positive numbers by using sign specifier. For example:

$num1=10;
$num2=-10;
$output=sprintf("%d",$num1);
echo "$output<br>";
$output=sprintf("%d",$num2);
echo "$output";

Output:

10
-10

Here the + sign before the positive number is omitted. However, if we put a + sign after % character of %d then the omission no longer takes place.

$num1=10;
$num2=-10;
$output=sprintf("%+d",$num1);
echo "$output<br>";
$output=sprintf("%+d",$num2);
echo "$output";

Output:

+10
-10

2.Padding specifier:

The padding specifier adds certain number of characters to the left or right of the output. The characters may be empty spaces, zeroes or any other ASCII character.

For example,

$str="hello";
$output=sprintf("[%10s]",$str);
echo $output;

Source code output:

[     hello]             //Total length of 10 positions,first five being empty spaces and remaining five being "hello"

HTML output:

 [ hello]                 //HTML displays only one empty space and collapses the rest, you have to use the <pre>...</pre> tag in the code for HTML to preserve the empty spaces.

Putting a negative sign left justifies the output:

$output=["%-10s",$string];
echo $output;

Source code output:

[hello     ]

HTML output:

[hello ]

Putting 0 after % sign replaces empty spaces with zeroes.

$str="hello";
$output=sprintf("[%010s]",$str);
echo $output;

Output:

[00000hello]

Left justification

$output=sprintf("[%-010s]",$str);

Output:

[hello00000]

Putting ' followed by any ASCII character like * after % results in the display of that ASCII character instead of empty spaces

$str="hello";
$output=sprintf("[%'*10s]",$str);
echo $output;

Output:

*****hello

Left justification:

$output=sprintf("[%-'*10s]",$str);
echo $output;

Output:

hello*****


来源: stackexchange

问:
Why can't I ref return a static readonly field?
The following code doesn't compile with C# 7.0 / Visual Studio 2017.2:

```<code>class C {
    private static readonly int s = 5;
    public static ref int Data => ref s;
}
</code>```

Is there an technical reason for disallowing references on static readonly fields or is this just a missing feature?

The error message says:

CS8162: A static readonly field cannot returned by reference.

答:
Because it's readonly.

The point of ref is to allow the referenced variable to be changed, which would violate readonly.

ContentLicense: CC BY-SA 3.0

Body:
The following code doesn't compile with C# 7.0 / Visual Studio 2017.2:

class C {
    private static readonly int s = 5;
    public static ref int Data => ref s;
}

Is there an technical reason for disallowing references on static readonly fields or is this just a missing feature?

The error message says:

CS8162: A static readonly field cannot returned by reference.


问:
Print n choose k combination algorithm using recursion
This must be a classic interview question, however, I'm having a problem understanding it.

Below is my implementation in Python and if you run it, it's only printing ab, ac, ad. It doesn't go to the 'b' (bc, bd) level.

```<code>def Print_nCk (the_list, k, str_builder, used):
    if len(str_builder) == k:
        print str_builder
        return
    else:
        for i in xrange(len(the_list)):
            if used[i] !=True:
                str_builder+=the_list[i]
                used[i] = True
                Print_nCk(the_list, k, str_builder, used)
                str_builder = str_builder[:-1]

Print_nCk(['a','b','c','d'], 2, "",[False,False,False,False])
</code>```

The right answer is ab,ac,ad,bc,bd,cd when above line is passed.

I know the right implementation from here without using used param (http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/) but
my question is what is wrong is my implementation?

Can you shed some light on it?

To debug, I printed out "used" every time. The used param becomes (True, True, True, True) after printing "ad" then it doesn't go deeper than that. What's the smart way to fix the used, if I insist on using used?

答:
Bit late to the party, but I think you should take more advantage of recursion. There's no need to pass any superfluous arguments.

Here's a simpler approach:

```<code>def Print_nCk(the_list, size):
    combs = []
    if size == 1: # the base case
        return the_list

    for i, c in enumerate(the_list[:-size + 1]):
        for sub_comb in Print_nCk(the_list[i + 1:], size  - 1): # generate and return all sub-combos of size - 1
            combs.append(c + sub_comb) # for each sub-combo, add the sizeth (or n - sizeth) character

    return combs
</code>```

This approach generates combinations of size - 1 and combines them with the sizeth character.

For size-2 combinations:

```<code>>>> Print_nCk(['a','b','c','d'], 2)
['ab', 'ac', 'ad', 'bc', 'bd', 'cd']
</code>```

For size-3 combinations:

```<code>>>> Print_nCk(['a','b','c','d'], 3)
['abc', 'abd', 'acd', 'bcd']
</code>```

Body:
This must be a classic interview question, however, I'm having a problem understanding it.

Below is my implementation in Python and if you run it, it's only printing ab, ac, ad. It doesn't go to the 'b' (bc, bd) level.

def Print_nCk (the_list, k, str_builder, used):
    if len(str_builder) == k:
        print str_builder
        return
    else:
        for i in xrange(len(the_list)):
            if used[i] !=True:
                str_builder+=the_list[i]
                used[i] = True
                Print_nCk(the_list, k, str_builder, used)
                str_builder = str_builder[:-1]

Print_nCk(['a','b','c','d'], 2, "",[False,False,False,False])

The right answer is ab,ac,ad,bc,bd,cd when above line is passed.

I know the right implementation from here without using used param (http://www.geeksforgeeks.org/print-all-possible-combinations-of-r-elements-in-a-given-array-of-size-n/) but
my question is what is wrong is my implementation?

Can you shed some light on it?

To debug, I printed out "used" every time. The used param becomes (True, True, True, True) after printing "ad" then it doesn't go deeper than that. What's the smart way to fix the used, if I insist on using used?

Body:
Bit late to the party, but I think you should take more advantage of recursion. There's no need to pass any superfluous arguments.

Here's a simpler approach:

def Print_nCk(the_list, size):
    combs = []
    if size == 1: # the base case
        return the_list

    for i, c in enumerate(the_list[:-size + 1]):
        for sub_comb in Print_nCk(the_list[i + 1:], size  - 1): # generate and return all sub-combos of size - 1
            combs.append(c + sub_comb) # for each sub-combo, add the sizeth (or n - sizeth) character

    return combs

This approach generates combinations of size - 1 and combines them with the sizeth character.

For size-2 combinations:

>>> Print_nCk(['a','b','c','d'], 2)
['ab', 'ac', 'ad', 'bc', 'bd', 'cd']

For size-3 combinations:

>>> Print_nCk(['a','b','c','d'], 3)
['abc', 'abd', 'acd', 'bcd']


问:
Why is my Laravel Morphmap returning empty
I have a table like so:

```<code>    Schema::create('comments', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id');
        $table->integer('comment_id');
        $table->string('comment_type');
        $table->text('comment');
        $table->timestamps();
    });
</code>```

Which is populated like so:

```<code>INSERT INTO `job`.`comments` (`id`, `user_id`, `comment_id`, `comment_type`, `comment`, `created_at`, `updated_at`) VALUES ('1', '1', '8', 'courses', 'Hello', NULL, NULL);
</code>```

I have a course model like so:

```<code><?php

namespace App\Modules\Courses\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Laravelista\Comments\Comments\Traits\Comments;

class Courses extends Model
{
    use Comments;

    protected $table = 'courses';

    public function comments()
    {
        return $this->morphMany('App\Modules\Comments\Models\Comments', 'comment');
    }
</code>```

which morphs my Comment model with my Morph map:

```<code><?php

namespace App\Modules\Comments\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
    'courses' => App\Modules\Courses\Models\Courses,
]);

class Comments extends Model
{
    public function commentable()
    {
      return $this->morphTo();
    }
}
</code>```

If I reference my map in my row and use courses at the type it returns empty as you can see from Tinker:

But if I use the full namespace in the comment_type in the database it works:

```<code>INSERT INTO `job`.`comments` (`id`, `user_id`, `comment_id`, `comment_type`, `comment`, `created_at`, `updated_at`) VALUES ('1', '1', '8', 'App\\Modules\\Courses\\Models\\Courses', 'Hello', NULL, NULL);
</code>```

What am I doing wrong, and how can I fix this?

edit: I have also tried the suggestions of placing it inside my app service provider too, but that didn't work neither:

答:
Try to register the Relation::morphMap() in a Service Provider

AppServiceProvider

```<code>use Illuminate\Database\Eloquent\Relations\Relation;
...
public function boot()
{
    Relation::morphMap([
         'courses' => 'App\Modules\Courses\Models\Courses',
    ]);
}
</code>```

https://laravel.com/docs/5.4/eloquent-relationships#polymorphic-relations

Body:
I have a table like so:

    Schema::create('comments', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('user_id');
        $table->integer('comment_id');
        $table->string('comment_type');
        $table->text('comment');
        $table->timestamps();
    });

Which is populated like so:

INSERT INTO `job`.`comments` (`id`, `user_id`, `comment_id`, `comment_type`, `comment`, `created_at`, `updated_at`) VALUES ('1', '1', '8', 'courses', 'Hello', NULL, NULL);

I have a course model like so:

<?php

namespace App\Modules\Courses\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Laravelista\Comments\Comments\Traits\Comments;

class Courses extends Model
{
    use Comments;

    protected $table = 'courses';

    public function comments()
    {
        return $this->morphMany('App\Modules\Comments\Models\Comments', 'comment');
    }

which morphs my Comment model with my Morph map:

<?php

namespace App\Modules\Comments\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
    'courses' => App\Modules\Courses\Models\Courses,
]);

class Comments extends Model
{
    public function commentable()
    {
      return $this->morphTo();
    }
}

If I reference my map in my row and use courses at the type it returns empty as you can see from Tinker:

But if I use the full namespace in the comment_type in the database it works:

INSERT INTO `job`.`comments` (`id`, `user_id`, `comment_id`, `comment_type`, `comment`, `created_at`, `updated_at`) VALUES ('1', '1', '8', 'App\\Modules\\Courses\\Models\\Courses', 'Hello', NULL, NULL);

What am I doing wrong, and how can I fix this?

edit: I have also tried the suggestions of placing it inside my app service provider too, but that didn't work neither:

Body:
Try to register the Relation::morphMap() in a Service Provider

AppServiceProvider

use Illuminate\Database\Eloquent\Relations\Relation;
...
public function boot()
{
    Relation::morphMap([
         'courses' => 'App\Modules\Courses\Models\Courses',
    ]);
}

https://laravel.com/docs/5.4/eloquent-relationships#polymorphic-relations


问:
How can I restore parcelable list in android
I have this app that in an activity creates a list of players and displays them in a listview. When I create a player I use the populatePlayerList method and it works fine. But when I save the list in a parcel and try to restore it, it doesn't populate the listview. Can't figure out why this happens. Below is some code:

```<code>public class PlayerManager extends AppCompatActivity {

            EditText playerName, playerNumber, playerPosition;
            ArrayList<Player> players = new ArrayList<Player>();
            ListView playerListView;

            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);

                setContentView(R.layout.activity_player_manager);

                playerName = (EditText) findViewById(R.id.etPlayerName);
                playerNumber = (EditText) findViewById(R.id.etPlayerNumber);
                playerPosition = (EditText) findViewById(R.id.etPlayerPosition);
                playerListView = (ListView) findViewById(R.id.playerList);

                if(savedInstanceState!=null){
                    players = savedInstanceState.getParcelableArrayList("savedList");
                    populatePlayerList();
                }

                final Button addPlayerBtn = (Button) findViewById(R.id.bAddPlayer);

                addPlayerBtn.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        addPlayer(playerName.getText().toString(), playerNumber.getText().toString(), playerPosition.getText().toString());
                        populatePlayerList();
                        Toast.makeText(getApplicationContext(), playerName.getText().toString() + " added!", Toast.LENGTH_SHORT).show();
                    }
                });

            private void populatePlayerList(){
                ArrayAdapter<Player> adapter = new PlayerListAdapter();
                playerListView.setAdapter(adapter);
            }

            private void addPlayer(String name, String number, String position){
                players.add(new Player(name, number, position));
        }

        private class PlayerListAdapter extends ArrayAdapter<Player> {
                public PlayerListAdapter(){
                    super(PlayerManager.this, R.layout.player_list, players);
                }

                @Override
                public View getView(int position, View view, ViewGroup parent){
                    if (view == null)
                        view = getLayoutInflater().inflate(R.layout.player_list, parent, false);

                    Player currentPlayer = players.get(position);

                    TextView name = (TextView) view.findViewById(R.id.playerName);
                    name.setText(currentPlayer.get_name());
                    TextView number = (TextView) view.findViewById(R.id.playerNumber);
                    number.setText(currentPlayer.get_number());
                    TextView playerPosition = (TextView) view.findViewById(R.id.playerPosition);
                    playerPosition.setText(currentPlayer.get_position());

                    return view;
                }
            }

    @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putParcelableArrayList("savedList", players);
        }
</code>```

Here is my Player Class:

```<code>public class Player implements Parcelable{

    private String name, position,number;

    public Player (String name, String number, String position) {
        this.name = name;
        this.number = number;
        this.position = position;
    }

    protected Player(Parcel in) {
        name = in.readString();
        position = in.readString();
        number = in.readString();
    }

    public static final Parcelable.Creator<Player> CREATOR = new Parcelable.Creator<Player>() {
        @Override
        public Player createFromParcel(Parcel in) {
            return new Player(in);
        }

        @Override
        public Player[] newArray(int size) {
            return new Player[size];
        }
    };

    public String get_name() {
        return name;
    }

    public String get_position() {
        return position;
    }

    public String get_number(){
        return number;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(position);
        dest.writeString(number);
    }
}
</code>```

I checked the players list when i try to restore it and its empty. So i guess its never saved in outState. Any ideas why?

答: I fixed my problem by adding android:launchMode="singleInstance" in the PlayerManager activity in Android Manifest.xml file. And I override the onBackPressed to sent me back to a previous activity so the onDestroy method isn't called. That way I get to keep the same instance in the PlayerManager activity.  </p>

Body:
I have this app that in an activity creates a list of players and displays them in a listview. When I create a player I use the populatePlayerList method and it works fine. But when I save the list in a parcel and try to restore it, it doesn't populate the listview. Can't figure out why this happens. Below is some code:

public class PlayerManager extends AppCompatActivity {

            EditText playerName, playerNumber, playerPosition;
            ArrayList<Player> players = new ArrayList<Player>();
            ListView playerListView;

            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);

                setContentView(R.layout.activity_player_manager);

                playerName = (EditText) findViewById(R.id.etPlayerName);
                playerNumber = (EditText) findViewById(R.id.etPlayerNumber);
                playerPosition = (EditText) findViewById(R.id.etPlayerPosition);
                playerListView = (ListView) findViewById(R.id.playerList);

                if(savedInstanceState!=null){
                    players = savedInstanceState.getParcelableArrayList("savedList");
                    populatePlayerList();
                }

                final Button addPlayerBtn = (Button) findViewById(R.id.bAddPlayer);

                addPlayerBtn.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        addPlayer(playerName.getText().toString(), playerNumber.getText().toString(), playerPosition.getText().toString());
                        populatePlayerList();
                        Toast.makeText(getApplicationContext(), playerName.getText().toString() + " added!", Toast.LENGTH_SHORT).show();
                    }
                });

            private void populatePlayerList(){
                ArrayAdapter<Player> adapter = new PlayerListAdapter();
                playerListView.setAdapter(adapter);
            }

            private void addPlayer(String name, String number, String position){
                players.add(new Player(name, number, position));
        }

        private class PlayerListAdapter extends ArrayAdapter<Player> {
                public PlayerListAdapter(){
                    super(PlayerManager.this, R.layout.player_list, players);
                }

                @Override
                public View getView(int position, View view, ViewGroup parent){
                    if (view == null)
                        view = getLayoutInflater().inflate(R.layout.player_list, parent, false);

                    Player currentPlayer = players.get(position);

                    TextView name = (TextView) view.findViewById(R.id.playerName);
                    name.setText(currentPlayer.get_name());
                    TextView number = (TextView) view.findViewById(R.id.playerNumber);
                    number.setText(currentPlayer.get_number());
                    TextView playerPosition = (TextView) view.findViewById(R.id.playerPosition);
                    playerPosition.setText(currentPlayer.get_position());

                    return view;
                }
            }

    @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putParcelableArrayList("savedList", players);
        }

Here is my Player Class:

public class Player implements Parcelable{

    private String name, position,number;

    public Player (String name, String number, String position) {
        this.name = name;
        this.number = number;
        this.position = position;
    }

    protected Player(Parcel in) {
        name = in.readString();
        position = in.readString();
        number = in.readString();
    }

    public static final Parcelable.Creator<Player> CREATOR = new Parcelable.Creator<Player>() {
        @Override
        public Player createFromParcel(Parcel in) {
            return new Player(in);
        }

        @Override
        public Player[] newArray(int size) {
            return new Player[size];
        }
    };

    public String get_name() {
        return name;
    }

    public String get_position() {
        return position;
    }

    public String get_number(){
        return number;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeString(position);
        dest.writeString(number);
    }
}

I checked the players list when i try to restore it and its empty. So i guess its never saved in outState. Any ideas why?


问:
Python kernel ridge regression: how to know the feature importance for feature selection?
I am using several regressors to train and test my data in python.

While most regressors in sklearn library have the function feature_importances_ for feature selection, there is no feature_importances_ function in kernel ridge regressor.

How do people see the importance of each feature when using kernel ridge regressor?
I have read the documentation but there is no related information.

Just in case
my code:

```<code>from sklearn.kernel_ridge import KernelRidge

kr1 = KernelRidge(kernel='rbf', alpha=1.0, gamma=0.01)
kr1.fit(X_train, y_train)
y_kr1 = kr1.predict(X_test)
print("Mean squared error: %.2f" % np.mean((y_kr1 - y_test) ** 2))

# Explained variance score: 1 is perfect prediction
print('Variance score: %.5f' % kr1.score(X_test, y_test))
</code>```

When I tried

```<code>kr1.feature_importances_
</code>```

The error:

```<code>'KernelRidge' object has no attribute 'feature_importances_'
</code>```

Your help will be much appreciated.

答: Feature importance is a concept from ensemble learning methods such as sklearn.ensemble.RandomForestClassifier; it's not an attribute of a ridge regression model.  The closest counterpart would be a t-statistic, which unfortunately you'll need to compute manually.</p>

Body:
I am using several regressors to train and test my data in python.

While most regressors in sklearn library have the function feature_importances_ for feature selection, there is no feature_importances_ function in kernel ridge regressor.

How do people see the importance of each feature when using kernel ridge regressor?
I have read the documentation but there is no related information.

Just in case
my code:

from sklearn.kernel_ridge import KernelRidge

kr1 = KernelRidge(kernel='rbf', alpha=1.0, gamma=0.01)
kr1.fit(X_train, y_train)
y_kr1 = kr1.predict(X_test)
print("Mean squared error: %.2f" % np.mean((y_kr1 - y_test) ** 2))

# Explained variance score: 1 is perfect prediction
print('Variance score: %.5f' % kr1.score(X_test, y_test))

When I tried

kr1.feature_importances_

The error:

'KernelRidge' object has no attribute 'feature_importances_'

Your help will be much appreciated.


问:
Making movement smoother - JS Canvas Game development
Im experimenting with ES6 & Canvas for game development. In this example I have an image of a spaceship and I rotate it with right and left arrow keys, and move it forward with upper key.
If you look at the rotation and the moving forward you see that it's laggy. Is there a way to make it smoother?

Plunker

The code for 'animation' and movement: (found in plunker as well)

from engine.js:

```<code>let mainLoop = function() {
        clrscr();
        draw();
        requestAnimationFrame(mainLoop);
    }

let draw = function() {
        spaceship.draw(ctx);
    }

    let keyDownListener = function(e) {

    if(e.keyCode == 37)
        spaceship.rotateLeft();

        if(e.keyCode == 38)
        spaceship.moveForward(ctx);

    if(e.keyCode == 39)
        spaceship.rotateRight();

    if(e.keyCode == 32)
        createExplosion();
    };

    let clrscr = function() {
        ctx.fillStyle="#415575";
        ctx.fillRect(0,0,w,h);
    }
</code>```

from spaceship.js:

```<code>let width = image.width * resizeMultiplier;
  let height = image.height * resizeMultiplier;

  const rotateDelta = 0.37;
  const forwardDelta = 0.77;

  let draw = function(context) {
    //Save context
    context.save();
    //Translate before rotate
    context.translate(x,y);
    //Rotate on translated 0,0
    context.rotate((angle) * Math.PI/180);
    //Draw rotated image
    context.drawImage(image, -(width/2), -(height/2), width, height);
    //Restore the translated & rotated coords to where we began
    context.restore();
  }

  let rotateRight = function() {
    console.log(angle);
    angle = (angle === 360) ? 0 : angle + (rotateDelta *(1000/60));
  }

  let rotateLeft = function() {
    console.log(angle);
    angle = (angle === -360) ? 0 : angle - (rotateDelta *(1000/60));
  }

  let moveForward = function() {
    let dx = Math.sin((angle) * Math.PI/180);
    let dy = - Math.cos((angle) * Math.PI/180);
    x += dx * forwardDelta * (1000/60);
    y += dy * forwardDelta * (1000/60);
    console.log('dx: ',dx,' dy: ',dy);
    //x += forwardDelta * (1000/20);
  }
</code>```

Thank you for your time.

答:
The main reason for that is that you use dedicated functions for each input:

spaceship.rotateLeft() , spaceship.moveForward() , spaceship.rotateRight()

While this looks very good OOP wise, the result is that every time the window.onkeydown handler is invoked, it will interrupt/reset the current execution because the key-handler is not in sync with the frame-function.

The frame-function runs (in theory) at a fixed interval. But the key-handler doesn't follow the same pattern, because that get fired when you press a key. So the two kinda work against each other.

(Anyone please correct me if I'm wrong, not 100% sure about this.)

In any case, you can resolve it by moving the key-handler to spaceship.js, and in the key-handler set a boolean for every key to true when you press it, and also add a onkeyup handler to set them back to false again.

And in your draw() function you call the function that calculates all the movement, right before you draw the new values:

```<code>  //move
  const rotateDelta = 7; //degrees
  const forwardDelta = 10;
  let key = {up:false, left:false, right:false, fire:false};

//DRAW--------------------
  let draw = function(ctx) {
    move();
    ctx.save();
    ...
  };

//MOVE--------------------
  let move = function() {
    if (key.left) {angle = (angle <= -360)?0: angle-rotateDelta;}
    if (key.right) {angle = (angle >= 360)?0: angle+rotateDelta;}
    if (key.up) {
      x += Math.sin(angle*Math.PI/180)*forwardDelta;
      y += -Math.cos(angle*Math.PI/180)*forwardDelta;
    }
    if (key.fire) {}
  };

//KEY-HANDLER--------------------
  window.onkeydown = function(e) {
    if (e.keyCode == 37) {key.left=true;} //LEFT
    if (e.keyCode == 38) {key.up=true;} //UP
    if (e.keyCode == 39) {key.right=true;} //RIGHT
    if (e.keyCode == 32) {key.fire=true;} //SPACEBAR
  };
  window.onkeyup = function(e) {
    if (e.keyCode == 37) {key.left=false;} //LEFT
    if (e.keyCode == 38) {key.up=false;} //UP
    if (e.keyCode == 39) {key.right=false;} //RIGHT
    if (e.keyCode == 32) {key.fire=false;} //SPACEBAR
  };
</code>```

As you can see, I also removed what I thought were unnecessary complications for both distance and rotation (*(1000/60) and unnecessary brackets etc). If you do need them you can use them of course, but I wanted to keep the calculations as light as possible to remove any cause for stutter. And rotateDelta and forwardDelta now have nice round values.

In Plunker they are 7 and 10, in the SO Code Snippet I had to lower them a bit because the ship had to be smaller due to the available space.

In the left- and right-key calculations I changed angle === -360 and angle === 360 to respectively angle <= -360 and angle >= 360, because your angle could skip over 360 and then the value wouldn't be reset. This way is more secure.

And the last major thing I changed is adding width:100%; and height:100% to the , so the <canvas> properly covers the whole page.

I made some other changes, mainly for myself to get a good overview of your code. If you like the style, use it, otherwise ignore it.

And the result is a smooth-sailing space machine:

Engine = window.Engine || {};

Engine = function() {
  let canvas,ctx, w,h;

  //player
  let ssImgPath = "http://i68.tinypic.com/2q87s0i.png";
  let ssSizeRatio = 0.1; //multiplier for original image dimensions
  let spaceship; //player object

  let ssImage = new Image();
  ssImage.src = ssImgPath;

//INIT--------------------
  let initModule = function() {
    canvas = document.getElementById("canvas");
    canvas.width = document.body.clientWidth;
    canvas.height = document.body.clientHeight;
    ctx = canvas.getContext("2d");
    w=canvas.width, h=canvas.height;

    spaceship = new Spaceship({x:w/2, y:h*0.7, angle:0, canvasW:w, canvasH:h, resizeMultiplier:ssSizeRatio, image:ssImage});
    mainLoop();
  };

//FRAME-LOOP--------------------
  let mainLoop = function() {
    clrscr();
    draw();
    requestAnimationFrame(mainLoop);
  };
  let clrscr = function() {
    ctx.fillStyle = "rgb(65,85,117)";
    ctx.fillRect(0,0,w,h);
  };
  let draw = function() {
    spaceship.draw(ctx);
  };

//RETURN--------------------
  return {initModule};
}(); window.onload=Engine.initModule;

/*==============================================================*/
/****************************************************************/
/*==============================================================*/

Spaceship = window.Spaceship || {};

Spaceship = function(options) {
  let {x,y,angle, canvasW,canvasH, resizeMultiplier, image} = options;
  let width = image.width*resizeMultiplier;
  let height = image.height*resizeMultiplier;

  //move
  const rotateDelta = 7; //degrees
  const forwardDelta = 5;
  let key = {up:false, left:false, right:false, fire:false};

//DRAW--------------------
  let draw = function(ctx) {
    move();

    ctx.save();
    ctx.translate(x,y);
    ctx.rotate((angle) * Math.PI / 180); //player rotation
    ctx.drawImage(image, -width/2, -height/2, width,height);
    ctx.restore();
  };

//MOVE--------------------
  let move = function() {
    if (key.left) {angle = (angle <= -360)?0: angle-rotateDelta;}
    if (key.right) {angle = (angle >= 360)?0: angle+rotateDelta;}
    if (key.up) {
      x += Math.sin(angle*Math.PI/180)*forwardDelta;
      y += -Math.cos(angle*Math.PI/180)*forwardDelta;
    }
    if (key.fire) {console.log("pew");}
  };

//KEY-HANDLER--------------------
  window.onkeydown = function(e) {
    if (e.keyCode == 37) {key.left=true;} //LEFT
    if (e.keyCode == 38) {key.up=true;} //UP
    if (e.keyCode == 39) {key.right=true;} //RIGHT
    if (e.keyCode == 32) {key.fire=true;} //SPACEBAR
  };
  window.onkeyup = function(e) {
    if (e.keyCode == 37) {key.left=false;} //LEFT
    if (e.keyCode == 38) {key.up=false;} //UP
    if (e.keyCode == 39) {key.right=false;} //RIGHT
    if (e.keyCode == 32) {key.fire=false;} //SPACEBAR
  };

//RETURN--------------------
  return {draw};
};```
<pre class="snippet-code-css lang-css prettyprint-override"><code>html, body {width:100%; height:99%; margin:0; padding:0;}</code>```

<!DOCTYPE html>

    <title>Asteroids</title>
    <link rel=stylesheet href="asteroids.css">

    <canvas id="canvas"></canvas>

```

plunker: https://plnkr.co/edit/nKAyweLV4d0hmmIRzxG4?p=preview

Body:
Im experimenting with ES6 & Canvas for game development. In this example I have an image of a spaceship and I rotate it with right and left arrow keys, and move it forward with upper key.
If you look at the rotation and the moving forward you see that it's laggy. Is there a way to make it smoother?

Plunker

The code for 'animation' and movement: (found in plunker as well)

from engine.js:

let mainLoop = function() {
        clrscr();
        draw();
        requestAnimationFrame(mainLoop);
    }

let draw = function() {
        spaceship.draw(ctx);
    }

    let keyDownListener = function(e) {

    if(e.keyCode == 37)
        spaceship.rotateLeft();

        if(e.keyCode == 38)
        spaceship.moveForward(ctx);

    if(e.keyCode == 39)
        spaceship.rotateRight();

    if(e.keyCode == 32)
        createExplosion();
    };

    let clrscr = function() {
        ctx.fillStyle="#415575";
        ctx.fillRect(0,0,w,h);
    }

from spaceship.js:

let width = image.width * resizeMultiplier;
  let height = image.height * resizeMultiplier;

  const rotateDelta = 0.37;
  const forwardDelta = 0.77;

  let draw = function(context) {
    //Save context
    context.save();
    //Translate before rotate
    context.translate(x,y);
    //Rotate on translated 0,0
    context.rotate((angle) * Math.PI/180);
    //Draw rotated image
    context.drawImage(image, -(width/2), -(height/2), width, height);
    //Restore the translated & rotated coords to where we began
    context.restore();
  }

  let rotateRight = function() {
    console.log(angle);
    angle = (angle === 360) ? 0 : angle + (rotateDelta *(1000/60));
  }

  let rotateLeft = function() {
    console.log(angle);
    angle = (angle === -360) ? 0 : angle - (rotateDelta *(1000/60));
  }

  let moveForward = function() {
    let dx = Math.sin((angle) * Math.PI/180);
    let dy = - Math.cos((angle) * Math.PI/180);
    x += dx * forwardDelta * (1000/60);
    y += dy * forwardDelta * (1000/60);
    console.log('dx: ',dx,' dy: ',dy);
    //x += forwardDelta * (1000/20);
  }

Thank you for your time.

Body:
The main reason for that is that you use dedicated functions for each input:

spaceship.rotateLeft() , spaceship.moveForward() , spaceship.rotateRight()

While this looks very good OOP wise, the result is that every time the window.onkeydown handler is invoked, it will interrupt/reset the current execution because the key-handler is not in sync with the frame-function.

The frame-function runs (in theory) at a fixed interval. But the key-handler doesn't follow the same pattern, because that get fired when you press a key. So the two kinda work against each other.

(Anyone please correct me if I'm wrong, not 100% sure about this.)

In any case, you can resolve it by moving the key-handler to spaceship.js, and in the key-handler set a boolean for every key to true when you press it, and also add a onkeyup handler to set them back to false again.

And in your draw() function you call the function that calculates all the movement, right before you draw the new values:

  //move
  const rotateDelta = 7; //degrees
  const forwardDelta = 10;
  let key = {up:false, left:false, right:false, fire:false};

//DRAW--------------------
  let draw = function(ctx) {
    move();
    ctx.save();
    ...
  };

//MOVE--------------------
  let move = function() {
    if (key.left) {angle = (angle <= -360)?0: angle-rotateDelta;}
    if (key.right) {angle = (angle >= 360)?0: angle+rotateDelta;}
    if (key.up) {
      x += Math.sin(angle*Math.PI/180)*forwardDelta;
      y += -Math.cos(angle*Math.PI/180)*forwardDelta;
    }
    if (key.fire) {}
  };

//KEY-HANDLER--------------------
  window.onkeydown = function(e) {
    if (e.keyCode == 37) {key.left=true;} //LEFT
    if (e.keyCode == 38) {key.up=true;} //UP
    if (e.keyCode == 39) {key.right=true;} //RIGHT
    if (e.keyCode == 32) {key.fire=true;} //SPACEBAR
  };
  window.onkeyup = function(e) {
    if (e.keyCode == 37) {key.left=false;} //LEFT
    if (e.keyCode == 38) {key.up=false;} //UP
    if (e.keyCode == 39) {key.right=false;} //RIGHT
    if (e.keyCode == 32) {key.fire=false;} //SPACEBAR
  };

As you can see, I also removed what I thought were unnecessary complications for both distance and rotation (*(1000/60) and unnecessary brackets etc). If you do need them you can use them of course, but I wanted to keep the calculations as light as possible to remove any cause for stutter. And rotateDelta and forwardDelta now have nice round values.

In Plunker they are 7 and 10, in the SO Code Snippet I had to lower them a bit because the ship had to be smaller due to the available space.

In the left- and right-key calculations I changed angle === -360 and angle === 360 to respectively angle <= -360 and angle >= 360, because your angle could skip over 360 and then the value wouldn't be reset. This way is more secure.

And the last major thing I changed is adding width:100%; and height:100% to the <html>, so the <canvas> properly covers the whole page.

I made some other changes, mainly for myself to get a good overview of your code. If you like the style, use it, otherwise ignore it.

And the result is a smooth-sailing space machine:

Engine = window.Engine || {};

Engine = function() {
  let canvas,ctx, w,h;

  //player
  let ssImgPath = "http://i68.tinypic.com/2q87s0i.png";
  let ssSizeRatio = 0.1; //multiplier for original image dimensions
  let spaceship; //player object

  let ssImage = new Image();
  ssImage.src = ssImgPath;

//INIT--------------------
  let initModule = function() {
    canvas = document.getElementById("canvas");
    canvas.width = document.body.clientWidth;
    canvas.height = document.body.clientHeight;
    ctx = canvas.getContext("2d");
    w=canvas.width, h=canvas.height;

    spaceship = new Spaceship({x:w/2, y:h*0.7, angle:0, canvasW:w, canvasH:h, resizeMultiplier:ssSizeRatio, image:ssImage});
    mainLoop();
  };

//FRAME-LOOP--------------------
  let mainLoop = function() {
    clrscr();
    draw();
    requestAnimationFrame(mainLoop);
  };
  let clrscr = function() {
    ctx.fillStyle = "rgb(65,85,117)";
    ctx.fillRect(0,0,w,h);
  };
  let draw = function() {
    spaceship.draw(ctx);
  };

//RETURN--------------------
  return {initModule};
}(); window.onload=Engine.initModule;

/*==============================================================*/
/****************************************************************/
/*==============================================================*/

Spaceship = window.Spaceship || {};

Spaceship = function(options) {
  let {x,y,angle, canvasW,canvasH, resizeMultiplier, image} = options;
  let width = image.width*resizeMultiplier;
  let height = image.height*resizeMultiplier;

  //move
  const rotateDelta = 7; //degrees
  const forwardDelta = 5;
  let key = {up:false, left:false, right:false, fire:false};

//DRAW--------------------
  let draw = function(ctx) {
    move();

    ctx.save();
    ctx.translate(x,y);
    ctx.rotate((angle) * Math.PI / 180); //player rotation
    ctx.drawImage(image, -width/2, -height/2, width,height);
    ctx.restore();
  };

//MOVE--------------------
  let move = function() {
    if (key.left) {angle = (angle <= -360)?0: angle-rotateDelta;}
    if (key.right) {angle = (angle >= 360)?0: angle+rotateDelta;}
    if (key.up) {
      x += Math.sin(angle*Math.PI/180)*forwardDelta;
      y += -Math.cos(angle*Math.PI/180)*forwardDelta;
    }
    if (key.fire) {console.log("pew");}
  };

//KEY-HANDLER--------------------
  window.onkeydown = function(e) {
    if (e.keyCode == 37) {key.left=true;} //LEFT
    if (e.keyCode == 38) {key.up=true;} //UP
    if (e.keyCode == 39) {key.right=true;} //RIGHT
    if (e.keyCode == 32) {key.fire=true;} //SPACEBAR
  };
  window.onkeyup = function(e) {
    if (e.keyCode == 37) {key.left=false;} //LEFT
    if (e.keyCode == 38) {key.up=false;} //UP
    if (e.keyCode == 39) {key.right=false;} //RIGHT
    if (e.keyCode == 32) {key.fire=false;} //SPACEBAR
  };

//RETURN--------------------
  return {draw};
};

html, body {width:100%; height:99%; margin:0; padding:0;}

<!DOCTYPE html>
<html>
  <head>
    <title>Asteroids</title>
    <link rel=stylesheet href="asteroids.css">
    <script src="engine.js"></script>
    <script src="spaceship.js"></script>
  </head>

  <body>
    <canvas id="canvas"></canvas>
  </body>
</html>

plunker: https://plnkr.co/edit/nKAyweLV4d0hmmIRzxG4?p=preview


问:
DOMContentLoaded event firing twice for a single page load
I authored a Firefox add-on several months ago that recently failed. The add-on basically looks for a particular URL and then modifies the DOM for the page.  I traced the failure to the (accidental) installation of the "AVG Safe Search" add-on.  I found that, with the AVG add-on disabled, the DOMContentLoaded event fires once for the document (behavior I originally expected), but with it enabled, the DOMContentLoaded event fires twice for the document.  My add-on inserts a column into an HTML table, so because the event fires twice, two duplicate columns are inserted rather than one.

Here's the distilled initialization code of my add-on:

```<code>var hLoadListener = function(event) { myAddon.initialize(event); }
var hContentLoadedListener = function(event) { myAddon.onContentLoaded(event); }

myAddon.initialize = function(aEvent)
{
    gBrowser.addEventListener("DOMContentLoaded", hContentLoadedListener, false);
};

myAddon.onContentLoaded = function(aEvent)
{
    if (!(aEvent.originalTarget.nodeName === "#document")) { return; }

    var doc = aEvent.target; // document that triggered "onload" event

    if (!(doc instanceof HTMLDocument)) { return; }
    if (!doc.location) { return; }

    var href = doc.location.href; // URL of current page

    if (URLRegExp.test(href))
    {
      // Modify the page's DOM
    }
};

window.addEventListener("load", hLoadListener, false);
</code>```

This issue seems easy to fix by inserting a unique DOM element and then testing for it's existence at the start. My question is whether add-on developers should expect this event behavior as normal or whether this issue is primarily a bug/side-effect in the AVG add-on?

答:
I don't know if I would consider this "normal" however the possibilities for outside applications to affect the operation of your plugin are endless.

That said, I think regardless of AVG causing this anomoly, the smart thing to do, like you said, is to check if the column exists prior to insertion, as AVG may not be the only outside application that influences firefox event triggers.

I am very weary of the DOM driven events because in my own plugin, and the testing of it throughout development has shown PLENTY of anomolies based on so many variables (different OS, different version of FF, different applications on host computer, different plugins within any given users FF, etc..)

To summarize:

Bug in AVG? Maybe.

Is the potential there for your plugin performance to be affected by MANY other sources? Absolutely!

Solution: IMHO- Always check to see if your change has been made
prior to making the actual change for all DOM items just to be safe.

ContentLicense: CC BY-SA 2.5

Body:
I authored a Firefox add-on several months ago that recently failed. The add-on basically looks for a particular URL and then modifies the DOM for the page.  I traced the failure to the (accidental) installation of the "AVG Safe Search" add-on.  I found that, with the AVG add-on disabled, the DOMContentLoaded event fires once for the document (behavior I originally expected), but with it enabled, the DOMContentLoaded event fires twice for the document.  My add-on inserts a column into an HTML table, so because the event fires twice, two duplicate columns are inserted rather than one.

Here's the distilled initialization code of my add-on:

var hLoadListener = function(event) { myAddon.initialize(event); }
var hContentLoadedListener = function(event) { myAddon.onContentLoaded(event); }

myAddon.initialize = function(aEvent)
{
    gBrowser.addEventListener("DOMContentLoaded", hContentLoadedListener, false);
};

myAddon.onContentLoaded = function(aEvent)
{
    if (!(aEvent.originalTarget.nodeName === "#document")) { return; }

    var doc = aEvent.target; // document that triggered "onload" event

    if (!(doc instanceof HTMLDocument)) { return; }
    if (!doc.location) { return; }

    var href = doc.location.href; // URL of current page

    if (URLRegExp.test(href))
    {
      // Modify the page's DOM
    }
};

window.addEventListener("load", hLoadListener, false);

This issue seems easy to fix by inserting a unique DOM element and then testing for it's existence at the start. My question is whether add-on developers should expect this event behavior as normal or whether this issue is primarily a bug/side-effect in the AVG add-on?


问:
How to find the user current path?
I'm on linux, I wrote a python script that is located in lets say /home/python/main.py. Every time I run it, it asks for a path using raw_input. I run it from a different place every time.

say I run it from /home/test like this python /home/python/main.py from terminal.

How can I give it the path I'm currently in, if possible. I don't want to hardcode paths. So I want to give it the path from which I'm using the terminal. I don't want to do pwd and copy paths,

I'm wondering if there's something like ~ which always points to home directory. Something similar which points to the users current directory.

答:
Use os.getcwd - returns current working directory. Requires import os.

Also its slightly unclear, what exactly do you want. You dont really need current working directory in python - every relative path in python will be interpreter as if starting in current directory. So simply use relative paths (in linux those are ones NOT starting with /) - this will work as long as you dont change current directory (which is a bad habbit anyway).

Title: How to find the user current path?


问:
Handle dynamic parameters in URL in Golang
currently am working on an API Rest in Golang. I have the process to CRUD all the tables. Now someone is asking me to develop an endpoint to search in one of that tables based on the parameters send in the URL. Let's say that this is my struct for that table:

```<code>type Media struct {
    ID                         uint
    Key                   string
    RecordKey           string
    RecordID            string
    SystemMediaKey      string
    MediaObjectID       string
    ChangedByID         string
    ChangedByKey        string
    MediaCategory              string
    MimeType                   string
    ShortDescription           string
    LongDescription            string
    EntryTimestamp             time.Time
    ModificationTimestamp      time.Time
    DeletedAtTimestamp         *time.Time
    MediaModificationTimestamp time.Time
    MediaURL                   string
    MediaHTML                  string
    Order                      int
    Group                      string
    Width                      int
    Height                     int
    ImageSize                  string
    ResourceName               string
    ClassName                  string
    Permission                 *string
    MediaStatus                string
}
</code>```

Now, he can send me all or some of that fields in the URL, the I need to assign that values to my struct to be able to search in the database based on the data assigned to the object.

I am using Gorm to handle everything with the database, gorilla/schema to assign the values on the POST requests and the Julien Schmidt Router. Now,my questions are:

What should I configure in the route to accept dynamic parameters?

How can I assign the values that comes in the URL to the a type Media object?
Thank you!

答: I finally managed to use this library that converts a map to a struct. The only thing, is that I had to pre-process the map that is returned by URL.Query() Values because it returns an array for each value and I needed only the value and not inside an array.

Body:
currently am working on an API Rest in Golang. I have the process to CRUD all the tables. Now someone is asking me to develop an endpoint to search in one of that tables based on the parameters send in the URL. Let's say that this is my struct for that table:

type Media struct {
    ID                         uint
    Key                   string
    RecordKey           string
    RecordID            string
    SystemMediaKey      string
    MediaObjectID       string
    ChangedByID         string
    ChangedByKey        string
    MediaCategory              string
    MimeType                   string
    ShortDescription           string
    LongDescription            string
    EntryTimestamp             time.Time
    ModificationTimestamp      time.Time
    DeletedAtTimestamp         *time.Time
    MediaModificationTimestamp time.Time
    MediaURL                   string
    MediaHTML                  string
    Order                      int
    Group                      string
    Width                      int
    Height                     int
    ImageSize                  string
    ResourceName               string
    ClassName                  string
    Permission                 *string
    MediaStatus                string
}

Now, he can send me all or some of that fields in the URL, the I need to assign that values to my struct to be able to search in the database based on the data assigned to the object.

I am using Gorm to handle everything with the database, gorilla/schema to assign the values on the POST requests and the Julien Schmidt Router. Now,my questions are:

What should I configure in the route to accept dynamic parameters?

How can I assign the values that comes in the URL to the a type Media object?
Thank you!


问:
Is there an optimized method for finding the farthest corner of a cube in 3D
If a have a cube C with 8 corners ( not axis aligned ) and a random point P can I do better than just checking all the corners and picking the corner with the greatest distance from P or is it possible to reduce the number of checks by taking into account the symmetrical nature of the cube?

答:
Convert the coordinates of the random point to a local coordinate system aligned with the cube. This takes 9 multiplies and 9 adds.

If the local system is centered on the cube, three sign tests will tell you the furthest corner.

A good understanding of the problem is obtained by the locus approach.

If you consider all positions of the random point that lead to the same answer (i.e. same corner index; this is the furthest Voronoi diagram of the vertices), you partition space in the eight octants defined by three bisecting planes of the cube. Telling a point among eight regions requires three binary tests (Lg(8)). The tests in question tell on which side of the planes the point lies, and this requires the evaluation of affine expressions aX+bY+cZ+d.

In the "algebraic decision tree" model, this is probably optimal.

Update:

As only the signs matter, you can normalize the coefficients so that one of them is unit, and spare a multiply (aX+bY+cZ+d>0 -> X+b'Y+c'Z+d>0'). You can also trade an addition for a comparison (X+bY+cZ+d>0 -> X+bY+cZ>d'). Hence, 6 multiplies, 6 adds and 3 comparisons in total.

[For numerical stability, one should divide by the largest coefficient. This unfortunately causes the expressions to depend on which it is. This can be circumvented by writing twenty seven (!) index computation functions - see below - and invoking the right one by pointer.]

Assuming that the coefficients have been precomputed, the following expression gives the corner index, in range [0,7]:

```<code>(X + b*Y + c*Z > d) + ((X + b'*Y + c'*Z > d') << 1) + ((X + b"*Y + c"*Z > d") << 2)
</code>```

With some luck, the compiler can compute it in a branchless way by means of conditional assignments, requiring like 15 flops and 5 ops.

Body:
Convert the coordinates of the random point to a local coordinate system aligned with the cube. This takes 9 multiplies and 9 adds.

If the local system is centered on the cube, three sign tests will tell you the furthest corner.

A good understanding of the problem is obtained by the locus approach.

If you consider all positions of the random point that lead to the same answer (i.e. same corner index; this is the furthest Voronoi diagram of the vertices), you partition space in the eight octants defined by three bisecting planes of the cube. Telling a point among eight regions requires three binary tests (Lg(8)). The tests in question tell on which side of the planes the point lies, and this requires the evaluation of affine expressions aX+bY+cZ+d.

In the "algebraic decision tree" model, this is probably optimal.

Update:

As only the signs matter, you can normalize the coefficients so that one of them is unit, and spare a multiply (aX+bY+cZ+d>0 -> X+b'Y+c'Z+d>0'). You can also trade an addition for a comparison (X+bY+cZ+d>0 -> X+bY+cZ>d'). Hence, 6 multiplies, 6 adds and 3 comparisons in total.

[For numerical stability, one should divide by the largest coefficient. This unfortunately causes the expressions to depend on which it is. This can be circumvented by writing twenty seven (!) index computation functions - see below - and invoking the right one by pointer.]

Assuming that the coefficients have been precomputed, the following expression gives the corner index, in range [0,7]:

(X + b*Y + c*Z > d) + ((X + b'*Y + c'*Z > d') << 1) + ((X + b"*Y + c"*Z > d") << 2)

With some luck, the compiler can compute it in a branchless way by means of conditional assignments, requiring like 15 flops and 5 ops.


问:
Android database accessible for ALL activities to read from
UPDATE: I needed to override the onDestroy method to close the Database Helper class object.  Works fine now. Just add this in any activity where you create an object of your SQLiteOpenHelper class.

```<code>Database dbHelper; //in class
dbHelper = new Database(this, "pulling data",null,1); //in onCreate

@Override
protected void onDestroy()
{
    super.onDestroy();
    dbHelper.close();
}
</code>```

I create and update a database from a fragment with data that comes in about every 2 seconds from sensors that are connected over Bluetooth to my Android app.

I go to different activities in my app and those activities should be able to read from the database to display the data in a list/textview, but the issue is that the context in which the database was created and is getting updated is from a fragment.  Is there a way to make it so that all activities can read from the database?

I created a class that extends SQLiteOpenHelper, where you can access functions to do CRUD operations, but once I go into another activity and I query the database the cursor pulls nothing up although I inserted and am updating the database in the background from a fragment.

Heads up, I'm pretty new to Android dev and have looked at other questions/solutions but nothing works for me. Appreciate any tutorials or advice to get going, thanks!

Below is my SQLiteOpenHelper class:

```<code>import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class Database extends SQLiteOpenHelper
{

    public Context DBcontext = null;
    //DatabaseContract version
    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "Sensors";

    public static final String SENSOR_DATA_TABLE_NAME ="SensorData";
    public static final String SENSOR_DATA_COLUMN_ID = "SensorDataID";
    public static final String NODE_COLUMN_NAME = "Nodes";
    public static final String TEMP_COLUMN_NAME = "TemperatureData";
    public static final String MOTION_COLUMN_NAME = "MotionData";
    public static final String GAS_COLUMN_NAME = "GasData";
    public static final String LIGHT_COLUMN_NAME = "LightData";

    //Constructor for the Database activity
    public DatabaseContract( Context context , String name, SQLiteDatabase.CursorFactory factory, int version) {
        super( context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        db.execSQL("CREATE TABLE "+SENSOR_DATA_TABLE_NAME+" ("+SENSOR_DATA_COLUMN_ID+" INTEGER PRIMARY KEY, "+NODE_COLUMN_NAME+ " STRING, "+TEMP_COLUMN_NAME+" STRING,     "+MOTION_COLUMN_NAME+" STRING, "+GAS_COLUMN_NAME+" STRING, "+ LIGHT_COLUMN_NAME+" STRING)");

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {

        db.execSQL("DROP TABLE IF EXISTS " + SENSOR_DATA_TABLE_NAME);
        onCreate(db);
    }

    public boolean checkExist()
    {

        SQLiteDatabase db = getReadableDatabase();

        String query = "SELECT * FROM "+ SENSOR_DATA_TABLE_NAME;

        Cursor res = db.rawQuery(query, null);

        if(res.getCount() > 0){
            res.close();
            return true;
        }else {
            res.close();
            return false;
        }

    }

    public void updateSensorData(String node_number, String temp_data, String motion_data, String light_data, String gas_data)
    {

        SQLiteDatabase db = getWritableDatabase();
        String query = "SELECT * FROM " + SENSOR_DATA_TABLE_NAME + " WHERE " + NODE_COLUMN_NAME + " ='" + node_number + "'";
        Cursor res = db.rawQuery(query, null);

       if (res.getCount() == 0){
           res.close();
           ContentValues content = new ContentValues();
           content.put(NODE_COLUMN_NAME, node_number);
           content.put(TEMP_COLUMN_NAME, temp_data);
           content.put(MOTION_COLUMN_NAME, motion_data);
           content.put(GAS_COLUMN_NAME, gas_data);
           content.put(LIGHT_COLUMN_NAME, light_data);
           db.insert(SENSOR_DATA_TABLE_NAME, null, content);

       }else{

           /**try to get ID from cursor, not working so hardcoded 1 for now to test**/
           //String ID = Long.toString(res.getLong(res.getColumnIndex(SENSOR_DATA_COLUMN_ID)));
           ContentValues contentValues = new ContentValues();
           contentValues.put(NODE_COLUMN_NAME, node_number);
           contentValues.put(TEMP_COLUMN_NAME, temp_data);
           contentValues.put(MOTION_COLUMN_NAME, motion_data);
           contentValues.put(GAS_COLUMN_NAME, gas_data);
           contentValues.put(LIGHT_COLUMN_NAME, light_data);

           //hardcoded ID = 1 just for testing
           db.update(SENSOR_DATA_TABLE_NAME, contentValues, SENSOR_DATA_COLUMN_ID + " = ? ", new String[] { "1" } );

       }

    }

}
</code>```

Below is the fragment that interacts with the class from above to insert/update data in the database.  I took the Google BluetoothChat app and modified it to work for my intended purpose. This fragment interacts with the Database class in the handler for MESSAGE_READ. I parse the data sent to me, then pass it as parameters to the Database function updateSensorData where it takes care of inserting then thereafter updating the data.

```<code>import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

public class Bluetooth extends Fragment
{
    private static final String TAG = "Bluetooth";

    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE_INSECURE = 1;
    private static final int REQUEST_ENABLE_BT = 2;

    // Layout Views
    private Button scan_button;
    private Button move;
    private DatabaseContract dbHelper;

    /**
     * Name of the connected device
     */
    private String mConnectedDeviceName = null;

    /**
     * Local Bluetooth adapter
     */
    private BluetoothAdapter BAdapter = null;

    /**
     * Member object for the chat services
     */
    private BluetoothChatService mChatService = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setHasOptionsMenu(true);
        // Get local Bluetooth adapter
        BAdapter = BluetoothAdapter.getDefaultAdapter();

        if (BAdapter == null)
        {
            FragmentActivity activity = getActivity();
            new AlertDialog.Builder(activity)
                    .setTitle("Error: Not compatible")
                    .setMessage("Your phone does not support Bluetooth")
                    .setPositiveButton("Exit", new DialogInterface.OnClickListener()
                    {
                        public void onClick(DialogInterface dialog, int which)
                        {
                            System.exit(0);
                        }
                    })
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .show();

        }
    }

    @Override
    public void onStart()
    {
        super.onStart();

        if (!BAdapter.isEnabled())
        {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
            // Otherwise, setup the chat session
        }
        else if (mChatService == null)
        {
            setupChat();
        }
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        if (mChatService != null)
        {
            mChatService.stop();
        }
    }

    @Override
    public void onResume()
    {
        super.onResume();

        // Performing this check in onResume() covers the case in which BT was
        // not enabled during onStart(), so we were paused to enable it...
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
        if (mChatService != null)
        {
            // Only if the state is STATE_NONE, do we know that we haven't started already
            if (mChatService.getState() == BluetoothChatService.STATE_NONE)
            {
                // Start the Bluetooth chat services
                mChatService.start();
            }
        }
        scan_button.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View v)
            {

                Intent serverIntent = new Intent(getActivity(), DeviceList.class);
                startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);

            }
        });
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState)
    {
        View v = inflater.inflate(R.layout.bluetooth, container, false);

        Button move = (Button)v.findViewById(R.id.move);
        move.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), Network.class);
                startActivity(intent);
            }
        });
        return v;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
    {
        scan_button = (Button) view.findViewById(R.id.scan_button);
        move = (Button) view.findViewById(R.id.move);
    }

    /**
     * Set up the UI and background operations for chat.
     */
    private void setupChat()
    {

        scan_button.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View v)
            {

                Intent serverIntent = new Intent(getActivity(), DeviceList.class);
                startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);

            }
        });

        // Initialize the BluetoothChatService to perform bluetooth connections
        mChatService = new BluetoothChatService(getActivity(), mHandler);

    }

    private final Handler mHandler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            FragmentActivity activity = getActivity();
            switch (msg.what)
            {
                case Constants.MESSAGE_STATE_CHANGE:
                    switch (msg.arg1)
                    {
                        case BluetoothChatService.STATE_CONNECTED:
                            Toast.makeText(getActivity(), "Connected to "+mConnectedDeviceName+" setting up network. . .", Toast.LENGTH_SHORT).show();
                            final Handler handler = new Handler();
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    move.setVisibility(View.VISIBLE);
                                    scan_button.setVisibility(View.INVISIBLE);
                                }
                            }, 4000);

                            break;
                        case BluetoothChatService.STATE_CONNECTING:
                            Toast.makeText(getActivity(), "Connecting. . .", Toast.LENGTH_SHORT).show();
                            break;
                        case BluetoothChatService.STATE_LISTEN:

                        case BluetoothChatService.STATE_NONE:

                            scan_button.setVisibility(View.VISIBLE);
                            move.setVisibility(View.INVISIBLE);
                    }
                    break;

                /******************************** where this fragment interacts with SQLiteOpenHelper class for database******************************/

                case Constants.MESSAGE_READ:
                    byte[] readBuf = (byte[]) msg.obj;
                    // construct a string from the valid bytes in the buffer
                    String readMessage = new String(readBuf, 0, msg.arg1);

                    dbHelper = new DatabaseContract(getActivity(), "data transfer for sensors", null, 1);

                    int node = readMessage.indexOf("node");
                    int temp_number = readMessage.indexOf("t");
                    int motion_number = readMessage.indexOf("m");
                    int light_number = readMessage.indexOf("l");
                    int gas_number = readMessage.indexOf("g");

                    String node_number = readMessage.substring(node + 5, node + 6);
                    String temp_data = readMessage.substring(temp_number, motion_number);
                    String motion_data = readMessage.substring(motion_number, light_number);
                    String light_data = readMessage.substring(light_number, gas_number);
                    String gas_data = readMessage.substring(gas_number);

                    dbHelper.updateSensorData(node_number, temp_data, motion_data, light_data, gas_data);

                    break;
                case Constants.MESSAGE_DEVICE_NAME:
                    // save the connected device's name
                    mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);

                    break;
                case Constants.MESSAGE_TOAST:
                    if (null != activity) {
                        Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
                                Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    };

    //automatically invoked when app starts up
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        switch (requestCode)
        {
            case REQUEST_CONNECT_DEVICE_INSECURE:
                // When DeviceList returns with a device to connect
                if (resultCode == Activity.RESULT_OK)
                {
                    connectDevice(data, false);
                }
                break;
            case REQUEST_ENABLE_BT:
                // When the request to enable Bluetooth returns
                if (resultCode == Activity.RESULT_OK)
                {
                    // Bluetooth is now enabled, so set up a chat session
                    setupChat();
                }
                else
                {
                    FragmentActivity activity = getActivity();
                    new AlertDialog.Builder(activity)
                            .setTitle("Error")
                            .setMessage("Bluetooth is disabled")
                            .setPositiveButton("ENABLE", new DialogInterface.OnClickListener()
                            {
                                public void onClick(DialogInterface dialog, int which)
                                {

                                    Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                                    startActivityForResult(enableIntent, 8);
                                    onDestroy();
                                    onResume();
                                }
                            })
                            .setIcon(android.R.drawable.ic_dialog_alert)
                            .show();
                }
        }
    }

    private void connectDevice(Intent data, boolean insecure)
    {
        // Get the device MAC address
        String address = data.getExtras()
                .getString(DeviceList.EXTRA_DEVICE_ADDRESS);
        // Get the BluetoothDevice object
        BluetoothDevice device = BAdapter.getRemoteDevice(address);
        // Attempt to connect to the device
        mChatService.connect(device, insecure);
    }

}
</code>```

Below is an example of one of the different classes that needs to access the information in the database. I test it with the checkExist() function and it returns false although in the fragment I do successfully insert then update the sensor data. This is where my problem lies, not sure why it isn't pulling anything from the database

```<code>import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.TextView;

/**Here is an example of one of the activities that needs to pull readings from the database to display**/

public class NodeData extends AppCompatActivity
{

    private DatabaseContract dbHelper;
    private TextView tempDisplay;
    private TextView motionDisplay;
    private TextView gasDisplay;
    private TextView lightDisplay;
    private ListView dataDisplay;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.nodedata);
        String node_number = getIntent().getExtras().getString("node_number");
        String label = "Node "+node_number+" Data";
        TextView textViewToChange = (TextView) findViewById(R.id.node_data_label);
        textViewToChange.setText(label);

        dbHelper = new DatabaseContract(getApplicationContext(), "data transfer for sensors", null, 1);

        boolean test = dbHelper.checkExist();

        Toast.makeText(getApplicationContext(), "testing: "+test, Toast.LENGTH_SHORT).show();

    }

}
</code>```

答:
See this:
http://guides.codepath.com/android/local-databases-with-sqliteopenhelper

I would recommend you to use the singleton pattern to avoid leak and to re-allocate the db each time.

It's highly recommended to use startTransaction and endTransaction as described in the link above.

If it still doesn't work, i also recommend to you to use Loaders as @Bruno suggested.

Regardless your question, just a small potential bug fix -  In Database class in function updateSensorData you forgot to close the Cursor in the else flow.

Body:
UPDATE: I needed to override the onDestroy method to close the Database Helper class object.  Works fine now. Just add this in any activity where you create an object of your SQLiteOpenHelper class.

Database dbHelper; //in class
dbHelper = new Database(this, "pulling data",null,1); //in onCreate

@Override
protected void onDestroy()
{
    super.onDestroy();
    dbHelper.close();
}

I create and update a database from a fragment with data that comes in about every 2 seconds from sensors that are connected over Bluetooth to my Android app.

I go to different activities in my app and those activities should be able to read from the database to display the data in a list/textview, but the issue is that the context in which the database was created and is getting updated is from a fragment.  Is there a way to make it so that all activities can read from the database?

I created a class that extends SQLiteOpenHelper, where you can access functions to do CRUD operations, but once I go into another activity and I query the database the cursor pulls nothing up although I inserted and am updating the database in the background from a fragment.

Heads up, I'm pretty new to Android dev and have looked at other questions/solutions but nothing works for me. Appreciate any tutorials or advice to get going, thanks!

Below is my SQLiteOpenHelper class:

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class Database extends SQLiteOpenHelper
{

    public Context DBcontext = null;
    //DatabaseContract version
    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "Sensors";

    public static final String SENSOR_DATA_TABLE_NAME ="SensorData";
    public static final String SENSOR_DATA_COLUMN_ID = "SensorDataID";
    public static final String NODE_COLUMN_NAME = "Nodes";
    public static final String TEMP_COLUMN_NAME = "TemperatureData";
    public static final String MOTION_COLUMN_NAME = "MotionData";
    public static final String GAS_COLUMN_NAME = "GasData";
    public static final String LIGHT_COLUMN_NAME = "LightData";

    //Constructor for the Database activity
    public DatabaseContract( Context context , String name, SQLiteDatabase.CursorFactory factory, int version) {
        super( context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        db.execSQL("CREATE TABLE "+SENSOR_DATA_TABLE_NAME+" ("+SENSOR_DATA_COLUMN_ID+" INTEGER PRIMARY KEY, "+NODE_COLUMN_NAME+ " STRING, "+TEMP_COLUMN_NAME+" STRING,     "+MOTION_COLUMN_NAME+" STRING, "+GAS_COLUMN_NAME+" STRING, "+ LIGHT_COLUMN_NAME+" STRING)");

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {

        db.execSQL("DROP TABLE IF EXISTS " + SENSOR_DATA_TABLE_NAME);
        onCreate(db);
    }

    public boolean checkExist()
    {

        SQLiteDatabase db = getReadableDatabase();

        String query = "SELECT * FROM "+ SENSOR_DATA_TABLE_NAME;

        Cursor res = db.rawQuery(query, null);

        if(res.getCount() > 0){
            res.close();
            return true;
        }else {
            res.close();
            return false;
        }

    }

    public void updateSensorData(String node_number, String temp_data, String motion_data, String light_data, String gas_data)
    {

        SQLiteDatabase db = getWritableDatabase();
        String query = "SELECT * FROM " + SENSOR_DATA_TABLE_NAME + " WHERE " + NODE_COLUMN_NAME + " ='" + node_number + "'";
        Cursor res = db.rawQuery(query, null);

       if (res.getCount() == 0){
           res.close();
           ContentValues content = new ContentValues();
           content.put(NODE_COLUMN_NAME, node_number);
           content.put(TEMP_COLUMN_NAME, temp_data);
           content.put(MOTION_COLUMN_NAME, motion_data);
           content.put(GAS_COLUMN_NAME, gas_data);
           content.put(LIGHT_COLUMN_NAME, light_data);
           db.insert(SENSOR_DATA_TABLE_NAME, null, content);

       }else{

           /**try to get ID from cursor, not working so hardcoded 1 for now to test**/
           //String ID = Long.toString(res.getLong(res.getColumnIndex(SENSOR_DATA_COLUMN_ID)));
           ContentValues contentValues = new ContentValues();
           contentValues.put(NODE_COLUMN_NAME, node_number);
           contentValues.put(TEMP_COLUMN_NAME, temp_data);
           contentValues.put(MOTION_COLUMN_NAME, motion_data);
           contentValues.put(GAS_COLUMN_NAME, gas_data);
           contentValues.put(LIGHT_COLUMN_NAME, light_data);

           //hardcoded ID = 1 just for testing
           db.update(SENSOR_DATA_TABLE_NAME, contentValues, SENSOR_DATA_COLUMN_ID + " = ? ", new String[] { "1" } );

       }

    }

}

Below is the fragment that interacts with the class from above to insert/update data in the database.  I took the Google BluetoothChat app and modified it to work for my intended purpose. This fragment interacts with the Database class in the handler for MESSAGE_READ. I parse the data sent to me, then pass it as parameters to the Database function updateSensorData where it takes care of inserting then thereafter updating the data.

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

public class Bluetooth extends Fragment
{
    private static final String TAG = "Bluetooth";

    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE_INSECURE = 1;
    private static final int REQUEST_ENABLE_BT = 2;

    // Layout Views
    private Button scan_button;
    private Button move;
    private DatabaseContract dbHelper;

    /**
     * Name of the connected device
     */
    private String mConnectedDeviceName = null;

    /**
     * Local Bluetooth adapter
     */
    private BluetoothAdapter BAdapter = null;

    /**
     * Member object for the chat services
     */
    private BluetoothChatService mChatService = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setHasOptionsMenu(true);
        // Get local Bluetooth adapter
        BAdapter = BluetoothAdapter.getDefaultAdapter();

        if (BAdapter == null)
        {
            FragmentActivity activity = getActivity();
            new AlertDialog.Builder(activity)
                    .setTitle("Error: Not compatible")
                    .setMessage("Your phone does not support Bluetooth")
                    .setPositiveButton("Exit", new DialogInterface.OnClickListener()
                    {
                        public void onClick(DialogInterface dialog, int which)
                        {
                            System.exit(0);
                        }
                    })
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .show();

        }
    }

    @Override
    public void onStart()
    {
        super.onStart();

        if (!BAdapter.isEnabled())
        {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
            // Otherwise, setup the chat session
        }
        else if (mChatService == null)
        {
            setupChat();
        }
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        if (mChatService != null)
        {
            mChatService.stop();
        }
    }

    @Override
    public void onResume()
    {
        super.onResume();

        // Performing this check in onResume() covers the case in which BT was
        // not enabled during onStart(), so we were paused to enable it...
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
        if (mChatService != null)
        {
            // Only if the state is STATE_NONE, do we know that we haven't started already
            if (mChatService.getState() == BluetoothChatService.STATE_NONE)
            {
                // Start the Bluetooth chat services
                mChatService.start();
            }
        }
        scan_button.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View v)
            {

                Intent serverIntent = new Intent(getActivity(), DeviceList.class);
                startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);

            }
        });
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState)
    {
        View v = inflater.inflate(R.layout.bluetooth, container, false);

        Button move = (Button)v.findViewById(R.id.move);
        move.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), Network.class);
                startActivity(intent);
            }
        });
        return v;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
    {
        scan_button = (Button) view.findViewById(R.id.scan_button);
        move = (Button) view.findViewById(R.id.move);
    }

    /**
     * Set up the UI and background operations for chat.
     */
    private void setupChat()
    {

        scan_button.setOnClickListener(new View.OnClickListener()
        {
            public void onClick(View v)
            {

                Intent serverIntent = new Intent(getActivity(), DeviceList.class);
                startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);

            }
        });

        // Initialize the BluetoothChatService to perform bluetooth connections
        mChatService = new BluetoothChatService(getActivity(), mHandler);

    }

    private final Handler mHandler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            FragmentActivity activity = getActivity();
            switch (msg.what)
            {
                case Constants.MESSAGE_STATE_CHANGE:
                    switch (msg.arg1)
                    {
                        case BluetoothChatService.STATE_CONNECTED:
                            Toast.makeText(getActivity(), "Connected to "+mConnectedDeviceName+" setting up network. . .", Toast.LENGTH_SHORT).show();
                            final Handler handler = new Handler();
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    move.setVisibility(View.VISIBLE);
                                    scan_button.setVisibility(View.INVISIBLE);
                                }
                            }, 4000);

                            break;
                        case BluetoothChatService.STATE_CONNECTING:
                            Toast.makeText(getActivity(), "Connecting. . .", Toast.LENGTH_SHORT).show();
                            break;
                        case BluetoothChatService.STATE_LISTEN:

                        case BluetoothChatService.STATE_NONE:

                            scan_button.setVisibility(View.VISIBLE);
                            move.setVisibility(View.INVISIBLE);
                    }
                    break;

                /******************************** where this fragment interacts with SQLiteOpenHelper class for database******************************/

                case Constants.MESSAGE_READ:
                    byte[] readBuf = (byte[]) msg.obj;
                    // construct a string from the valid bytes in the buffer
                    String readMessage = new String(readBuf, 0, msg.arg1);

                    dbHelper = new DatabaseContract(getActivity(), "data transfer for sensors", null, 1);

                    int node = readMessage.indexOf("node");
                    int temp_number = readMessage.indexOf("t");
                    int motion_number = readMessage.indexOf("m");
                    int light_number = readMessage.indexOf("l");
                    int gas_number = readMessage.indexOf("g");

                    String node_number = readMessage.substring(node + 5, node + 6);
                    String temp_data = readMessage.substring(temp_number, motion_number);
                    String motion_data = readMessage.substring(motion_number, light_number);
                    String light_data = readMessage.substring(light_number, gas_number);
                    String gas_data = readMessage.substring(gas_number);

                    dbHelper.updateSensorData(node_number, temp_data, motion_data, light_data, gas_data);

                    break;
                case Constants.MESSAGE_DEVICE_NAME:
                    // save the connected device's name
                    mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);

                    break;
                case Constants.MESSAGE_TOAST:
                    if (null != activity) {
                        Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
                                Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    };

    //automatically invoked when app starts up
    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        switch (requestCode)
        {
            case REQUEST_CONNECT_DEVICE_INSECURE:
                // When DeviceList returns with a device to connect
                if (resultCode == Activity.RESULT_OK)
                {
                    connectDevice(data, false);
                }
                break;
            case REQUEST_ENABLE_BT:
                // When the request to enable Bluetooth returns
                if (resultCode == Activity.RESULT_OK)
                {
                    // Bluetooth is now enabled, so set up a chat session
                    setupChat();
                }
                else
                {
                    FragmentActivity activity = getActivity();
                    new AlertDialog.Builder(activity)
                            .setTitle("Error")
                            .setMessage("Bluetooth is disabled")
                            .setPositiveButton("ENABLE", new DialogInterface.OnClickListener()
                            {
                                public void onClick(DialogInterface dialog, int which)
                                {

                                    Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                                    startActivityForResult(enableIntent, 8);
                                    onDestroy();
                                    onResume();
                                }
                            })
                            .setIcon(android.R.drawable.ic_dialog_alert)
                            .show();
                }
        }
    }

    private void connectDevice(Intent data, boolean insecure)
    {
        // Get the device MAC address
        String address = data.getExtras()
                .getString(DeviceList.EXTRA_DEVICE_ADDRESS);
        // Get the BluetoothDevice object
        BluetoothDevice device = BAdapter.getRemoteDevice(address);
        // Attempt to connect to the device
        mChatService.connect(device, insecure);
    }

}

Below is an example of one of the different classes that needs to access the information in the database. I test it with the checkExist() function and it returns false although in the fragment I do successfully insert then update the sensor data. This is where my problem lies, not sure why it isn't pulling anything from the database

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.TextView;

/**Here is an example of one of the activities that needs to pull readings from the database to display**/

public class NodeData extends AppCompatActivity
{

    private DatabaseContract dbHelper;
    private TextView tempDisplay;
    private TextView motionDisplay;
    private TextView gasDisplay;
    private TextView lightDisplay;
    private ListView dataDisplay;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.nodedata);
        String node_number = getIntent().getExtras().getString("node_number");
        String label = "Node "+node_number+" Data";
        TextView textViewToChange = (TextView) findViewById(R.id.node_data_label);
        textViewToChange.setText(label);

        dbHelper = new DatabaseContract(getApplicationContext(), "data transfer for sensors", null, 1);

        boolean test = dbHelper.checkExist();

        Toast.makeText(getApplicationContext(), "testing: "+test, Toast.LENGTH_SHORT).show();

    }

}


问:
How do I calculate permutation?
I am having a question about permutation in Java.

Suppose I have five different elements in an array [a, b, c, d, e] and I want to select three elements out of them, the order does matter. I know in math we can use 5P3 to get the answer, but can we use Java to get the count and the complete list of elements of the permutation set of 5P3?

答:
Since "1, 2, 3" is different from "2, 1, 3", I will suggest the following code snippet. Note that i can't be identical to j or k to avoid "1, 1, 1" or "1, 3, 3" scenarios. </p>

```<code>   // array with elements
   char[] items = {'a', 'b', 'c', 'd', 'e'};
   int count = 0;

    // first of the "three"
    for (int i = 0; i < upperBound; i++) {
       // second of the "three"
       for (int j = 0; j < upperBound; j++) {
          // can't be identical to i
          if (j == i)
             continue;

          // third of the "three"
          for (int k = 0; k < upperBound; k++) {
             // can't be identical to i or j
             if (k == i || k ==j)
                continue;

             // print some display
             System.out.println(items[i] + ", " + items[j] + ", " + items[k]);

             // increment the total count
             count++;
          }
       }
    }

    System.out.println("Total count is " + count);
</code>```

Title: How do I calculate permutation?

Body:
Since "1, 2, 3" is different from "2, 1, 3", I will suggest the following code snippet. Note that i can't be identical to j or k to avoid "1, 1, 1" or "1, 3, 3" scenarios.

   // array with elements
   char[] items = {'a', 'b', 'c', 'd', 'e'};
   int count = 0;

    // first of the "three"
    for (int i = 0; i < upperBound; i++) {
       // second of the "three"
       for (int j = 0; j < upperBound; j++) {
          // can't be identical to i
          if (j == i)
             continue;

          // third of the "three"
          for (int k = 0; k < upperBound; k++) {
             // can't be identical to i or j
             if (k == i || k ==j)
                continue;

             // print some display
             System.out.println(items[i] + ", " + items[j] + ", " + items[k]);

             // increment the total count
             count++;
          }
       }
    }

    System.out.println("Total count is " + count);