问:
(Android) implementing swipe gestures on a collection of objects
* UPDATE  -> the swipe gesture now works (classes "PieceViewFragment" and "OnSwipeTouchListener" have been updated accordingly) , but I would really like to get the nice visual effect (movement) that you get when swipping from one item to the other. Right now it just switches to the next or previous item.

* NEW UPDATE  -> I was able to get that nice visual effect (movement) that you get when swipping from one item to the other (thanks to Nobby_Nobody's last comment and link).

get the code here –> My Project on github

I need help to implement swiping gesture through a collection of items in an Android personnal project (an inventory list). I've seen tons of examples already but I can't seem to implement it correctly.

The application is simple. It's just an inventory (InventairesPieces) implemented as a scrolling list (InventairesPiecesActivity and InventairesPiecesFragment) of items (PieceModel) and once an item is clicked, the details (PieceViewActivity and PieceViewFragment) open in another activity.

It's in the details activity (PieceViewActivity and PieceViewFragment) that I want to be able to swipe accross items instead of going back to the scrolling list each time.

So far I tried implementing “ViewPager” set to an adapter that extends FragmentStatePagerAdapter on my fragment (PieceViewFragment) but it’s not working properly:

* when an item is clicked, it shows the first item of the list, no matter which item was clicked. Also the title in the action bar doesn't match. *

Here's the "PieceViewActivity" class:

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

private InventairePieces inventairePieces;

private PieceModel piece;

private int position;

/**
 * The pager widget, which handles animation and allows swiping horizontally to access previous
 * and next wizard steps.
 */
private ViewPager mViewPager;

/**
 * The pager adapter, which provides the pages to the view pager widget.
 */
private InventairePiecesPagerAdapter inventairePiecesPagerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_piece_view);

    // receives the intent
    Intent intent = this.getIntent();
    inventairePieces = (InventairePieces) intent.getSerializableExtra("inventairePieces");
    position = (int) intent.getSerializableExtra("posClicked");

    // Instantiate a ViewPager and a PagerAdapter.
    inventairePiecesPagerAdapter = new InventairePiecesPagerAdapter(getSupportFragmentManager());
    mViewPager = (ViewPager) findViewById(R.id.activity_piece_view_container);
    mViewPager.setAdapter(inventairePiecesPagerAdapter);
}

public class InventairePiecesPagerAdapter extends FragmentStatePagerAdapter {

    public InventairePiecesPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int posView) {
        return PieceViewFragment.create(posView, position, inventairePieces);
    }

    @Override
    //the amount of items in the inventory
    public int getCount() {
        return inventairePieces.getInventairePieces().size();
    }

}
</code>```

}

Here's the "PieceViewFragment" class (the details or card):

```<code>public class PieceViewFragment extends Fragment {

protected OnSwipeTouchListener onSwipeTouchListener;

private InventairePieces inventairePieces;

private PieceModel piece;

private int positionClicked;

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    final View rootView = inflater.inflate(R.layout.fragment_piece_view, null, false);

    // receives the intent
    Intent intent = getActivity().getIntent();
    inventairePieces = (InventairePieces) intent.getSerializableExtra("inventairePieces");
    positionClicked = (int) intent.getSerializableExtra("posClicked");
    piece = inventairePieces.getInventairePieces().get(positionClicked);

    // sets the title in the action bar
    getActivity().setTitle(piece.getNomPiece());

    Log.v("Fragment", "Pos Clicked: " + positionClicked);
    Log.v("Fragment" , "Piece: " + piece.getNomPiece());
    Log.v("Fragment", "Inventaire: " + inventairePieces.getInventairePieces().size());

    // the item card
    ((TextView) rootView.findViewById(R.id.codePiece_text)).setText(String.valueOf("# " + piece.getCodePiece()));
    ((TextView) rootView.findViewById(R.id.nomPiece_text)).setText(piece.getNomPiece());
    ((TextView) rootView.findViewById(R.id.descriptionPiece_text)).setText(piece.getDescriptionPiece());
    ((TextView) rootView.findViewById(R.id.dimensionPiece_text)).setText(String.valueOf(piece.getDimensionPiece()) + " mm");
    ((TextView) rootView.findViewById(R.id.prixCoutantPiece_text)).setText(String.valueOf(piece.getPrixCoutantPiece()) + " $");
    ((TextView) rootView.findViewById(R.id.qtyPiece_text)).setText(String.valueOf(piece.getQtyPiece()));
    ((TextView) rootView.findViewById(R.id.typePiece_text)).setText(piece.getTypePiece());
    ((TextView) rootView.findViewById(R.id.categoriePiece_text)).setText(piece.getCategoriePiece());

    rootView.setOnTouchListener(new OnSwipeTouchListener(getContext()){
        @Override
        public void onSwipeRight() {
            super.onSwipeRight();
            Log.v("Fragment", "onSwipeRight - ");
            if (positionClicked > 0) {
                positionClicked--;
                piece = inventairePieces.getInventairePieces().get(positionClicked);

                // sets the title in the action bar
                getActivity().setTitle(piece.getNomPiece());

                // the item card
                ((TextView) rootView.findViewById(R.id.codePiece_text)).setText(String.valueOf("# " + piece.getCodePiece()));
                ((TextView) rootView.findViewById(R.id.nomPiece_text)).setText(piece.getNomPiece());
                ((TextView) rootView.findViewById(R.id.descriptionPiece_text)).setText(piece.getDescriptionPiece());
                ((TextView) rootView.findViewById(R.id.dimensionPiece_text)).setText(String.valueOf(piece.getDimensionPiece()) + " mm");
                ((TextView) rootView.findViewById(R.id.prixCoutantPiece_text)).setText(String.valueOf(piece.getPrixCoutantPiece()) + " $");
                ((TextView) rootView.findViewById(R.id.qtyPiece_text)).setText(String.valueOf(piece.getQtyPiece()));
                ((TextView) rootView.findViewById(R.id.typePiece_text)).setText(piece.getTypePiece());
                ((TextView) rootView.findViewById(R.id.categoriePiece_text)).setText(piece.getCategoriePiece());

                Log.v("Fragment", "Pos Clicked: " + positionClicked);
                Log.v("Fragment" , "Piece: " + piece.getNomPiece());
                Log.v("Fragment", "Inventaire: " + inventairePieces.getInventairePieces().size());
            }
        }
        @Override
        public void onSwipeLeft() {
            super.onSwipeLeft();
            Log.v("Fragment", "onSwipeLeft + ");
            if(positionClicked < inventairePieces.getInventairePieces().size()-1) {
                positionClicked++;
                piece = inventairePieces.getInventairePieces().get(positionClicked);

                // sets the title in the action bar
                getActivity().setTitle(piece.getNomPiece());

                // the item card
                ((TextView) rootView.findViewById(R.id.codePiece_text)).setText(String.valueOf("# " + piece.getCodePiece()));
                ((TextView) rootView.findViewById(R.id.nomPiece_text)).setText(piece.getNomPiece());
                ((TextView) rootView.findViewById(R.id.descriptionPiece_text)).setText(piece.getDescriptionPiece());
                ((TextView) rootView.findViewById(R.id.dimensionPiece_text)).setText(String.valueOf(piece.getDimensionPiece()) + " mm");
                ((TextView) rootView.findViewById(R.id.prixCoutantPiece_text)).setText(String.valueOf(piece.getPrixCoutantPiece()) + " $");
                ((TextView) rootView.findViewById(R.id.qtyPiece_text)).setText(String.valueOf(piece.getQtyPiece()));
                ((TextView) rootView.findViewById(R.id.typePiece_text)).setText(piece.getTypePiece());
                ((TextView) rootView.findViewById(R.id.categoriePiece_text)).setText(piece.getCategoriePiece());

                Log.v("Fragment", "Pos Clicked: " + positionClicked);
                Log.v("Fragment" , "Piece: " + piece.getNomPiece());
                Log.v("Fragment", "Inventaire: " + inventairePieces.getInventairePieces().size());
            }
        }
    });

    return rootView;
}
</code>```

}

Here the new OnSwipeTouchListener class that handles gestures:

```<code>public class OnSwipeTouchListener implements View.OnTouchListener {

private GestureDetector gestureDetector;

public OnSwipeTouchListener(Context c) {
    gestureDetector = new GestureDetector(c, new GestureListener());
}

public boolean onTouch(final View view, final MotionEvent motionEvent) {
    return gestureDetector.onTouchEvent(motionEvent);
}

private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    // Determines the fling velocity and then fires the appropriate swipe event accordingly
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        onSwipeRight();
                    } else {
                        onSwipeLeft();
                    }
                }
            } else {
                if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        onSwipeDown();
                    } else {
                        onSwipeUp();
                    }
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}

public void onSwipeRight() {
}

public void onSwipeLeft() {
}

public void onSwipeUp() {
}

public void onSwipeDown() {
}
</code>```

}

And here's the "InventairesPiecesFragment" class from where you click on an item in a scrolling list:

```<code>public class InventairePiecesFragment extends Fragment{

private ArrayAdapter<PieceModel> inventairePiecesAdapter;

private InventairePieces inventairePieces;

private PieceModel piece;

private Bundle bundle;

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    FloatingActionButton fab = (FloatingActionButton) container.findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(getActivity(), PieceEditActivity.class);
            intent.putExtra("piece", piece);
            intent.putExtra("inventairePieces", inventairePieces);
            startActivityForResult(intent, 1);
        }
    });

    inventairePieces = new InventairePieces(new ArrayList<PieceModel>());
    this.readInventairePiece();

    inventairePiecesAdapter = new ArrayAdapter<>(
            getActivity(),
            R.layout.liste_pieces_inventaire,
            R.id.liste_pieces_inventaire_textview,
            inventairePieces.getInventairePieces());

    View rootView = inflater.inflate(R.layout.fragment_pieces_inventaire, container, false);

    ListView inventairePiecesAdapterView = (ListView) rootView.findViewById(R.id.listview_pieces_inventaire);
    inventairePiecesAdapterView.setAdapter(inventairePiecesAdapter);

    inventairePiecesAdapterView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            piece = inventairePiecesAdapter.getItem(i);
            Intent intent = new Intent(getActivity(), PieceViewActivity.class);
            intent.putExtra("inventairePieces", inventairePieces);
            intent.putExtra("posClicked", i);
            startActivityForResult(intent, 1);

            Log.v("short clicked","pos: " + i);
        }
    });
    inventairePiecesAdapterView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int i, long id) {
            piece = inventairePiecesAdapter.getItem(i);
            ConfirmeSuppDialogFragment dialogFrag = new ConfirmeSuppDialogFragment();
            bundle = new Bundle();
            bundle.putSerializable("piece",piece);
            bundle.putSerializable("inventairePieces",inventairePieces);
            dialogFrag.setArguments(bundle);
            dialogFrag.setTargetFragment(InventairePiecesFragment.this, 2);
            dialogFrag.show(getFragmentManager(), "dialog");

            Log.v("long clicked","pos: " + i);

            return true;
        }
    });

    return rootView;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    this.writeInventairePiece();
    return super.onOptionsItemSelected(item);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(resultCode == 1) {
        piece = (PieceModel) data.getSerializableExtra("piece");
        inventairePieces.addToInventairePieces(piece);
        this.writeInventairePiece();
        inventairePiecesAdapter.notifyDataSetChanged();
        printConfirmerState(piece, "ajoutée");
    }
    else if(resultCode == 2){
        inventairePieces.removeFromInventairePieces(piece);
        this.writeInventairePiece();
        inventairePiecesAdapter.notifyDataSetChanged();
        printConfirmerState(piece, "supprimée");
    }
}

private void writeInventairePiece(){
    try {
        FileOutputStream outputFile = this.getContext().openFileOutput("InventairePiece.ser", Context.MODE_PRIVATE);
        ObjectOutputStream outputStream = new ObjectOutputStream(outputFile);
        outputStream.writeObject(inventairePieces);
        outputStream.close();
        outputFile.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

private void readInventairePiece(){
    try {
        FileInputStream inputFile = this.getContext().openFileInput("InventairePiece.ser");
        ObjectInputStream inputStream = new ObjectInputStream(inputFile);
        inventairePieces = (InventairePieces) inputStream.readObject();
        inputStream.close();
        inputFile.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

private void printConfirmerState(PieceModel piece, String state){
    String confirm = state;
    for(int i = 0; i < inventairePieces.getInventairePieces().size(); i++) {
        if(i == inventairePieces.getInventairePieces().indexOf(piece) && state.equals("ajoutée")) {
            confirm = ("La pièce '" + piece.getNomPiece() + "' est " + state + ".");
        }else if(i == inventairePieces.getInventairePieces().indexOf(piece) && state.equals("supprimée")) {
            confirm = ("La pièce '" + piece.getNomPiece() + "' est " + state + ".");
        }
    }
    Toast.makeText(getContext(), confirm, Toast.LENGTH_SHORT).show();
}

/*@Override
public void updateResult(int result) {
    this.result = result;
}*/
</code>```

}

I thank you in advance.

And just in case, here's the full application as I have it so far:
My Project on gitHub

答:
Let me see if I got it right, you have a list of items right? and whenever you select any item you're showing an Activity with all the details of that item (PieceModel); and you want to implement a gesture recognizer in this fragment to switch between the previous and next item without having to go back to the list and select the new item tight?.

If my understanding is good you can do it like this:

Implement a gesture recognizer to handle the left and right swipes over the fragment.

Depending on gesture you get the new item object (PieceModel) from the data source you're using also when you create your list adapter, and update the current instance stored in your fragment.

Update the UI using this "new" item as if the fragment has been loaded from scratch.

And voila!!!, some links here :

https://developer.android.com/training/gestures/detector.html

http://guides.codepath.com/android/gestures-and-touch-events

By the way, when you pass the index of the selected item to the new Activity you should retrieve it as :

```<code>position = getIntent().getIntExtra("posClicked");
</code>```

I highly recommend you to pass the item Id instead the position, by the way, is InventairePieces implementing the Serializable interface?

Body:
* UPDATE  -> the swipe gesture now works (classes "PieceViewFragment" and "OnSwipeTouchListener" have been updated accordingly) , but I would really like to get the nice visual effect (movement) that you get when swipping from one item to the other. Right now it just switches to the next or previous item.

* NEW UPDATE  -> I was able to get that nice visual effect (movement) that you get when swipping from one item to the other (thanks to Nobby_Nobody's last comment and link).

get the code here –> My Project on github

I need help to implement swiping gesture through a collection of items in an Android personnal project (an inventory list). I've seen tons of examples already but I can't seem to implement it correctly.

The application is simple. It's just an inventory (InventairesPieces) implemented as a scrolling list (InventairesPiecesActivity and InventairesPiecesFragment) of items (PieceModel) and once an item is clicked, the details (PieceViewActivity and PieceViewFragment) open in another activity.

It's in the details activity (PieceViewActivity and PieceViewFragment) that I want to be able to swipe accross items instead of going back to the scrolling list each time.

So far I tried implementing “ViewPager” set to an adapter that extends FragmentStatePagerAdapter on my fragment (PieceViewFragment) but it’s not working properly:

* when an item is clicked, it shows the first item of the list, no matter which item was clicked. Also the title in the action bar doesn't match. *

Here's the "PieceViewActivity" class:

public class PieceViewActivity extends AppCompatActivity {

private InventairePieces inventairePieces;

private PieceModel piece;

private int position;

/**
 * The pager widget, which handles animation and allows swiping horizontally to access previous
 * and next wizard steps.
 */
private ViewPager mViewPager;

/**
 * The pager adapter, which provides the pages to the view pager widget.
 */
private InventairePiecesPagerAdapter inventairePiecesPagerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_piece_view);

    // receives the intent
    Intent intent = this.getIntent();
    inventairePieces = (InventairePieces) intent.getSerializableExtra("inventairePieces");
    position = (int) intent.getSerializableExtra("posClicked");

    // Instantiate a ViewPager and a PagerAdapter.
    inventairePiecesPagerAdapter = new InventairePiecesPagerAdapter(getSupportFragmentManager());
    mViewPager = (ViewPager) findViewById(R.id.activity_piece_view_container);
    mViewPager.setAdapter(inventairePiecesPagerAdapter);
}

public class InventairePiecesPagerAdapter extends FragmentStatePagerAdapter {

    public InventairePiecesPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int posView) {
        return PieceViewFragment.create(posView, position, inventairePieces);
    }

    @Override
    //the amount of items in the inventory
    public int getCount() {
        return inventairePieces.getInventairePieces().size();
    }

}

}

Here's the "PieceViewFragment" class (the details or card):

public class PieceViewFragment extends Fragment {

protected OnSwipeTouchListener onSwipeTouchListener;

private InventairePieces inventairePieces;

private PieceModel piece;

private int positionClicked;

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    final View rootView = inflater.inflate(R.layout.fragment_piece_view, null, false);

    // receives the intent
    Intent intent = getActivity().getIntent();
    inventairePieces = (InventairePieces) intent.getSerializableExtra("inventairePieces");
    positionClicked = (int) intent.getSerializableExtra("posClicked");
    piece = inventairePieces.getInventairePieces().get(positionClicked);

    // sets the title in the action bar
    getActivity().setTitle(piece.getNomPiece());

    Log.v("Fragment", "Pos Clicked: " + positionClicked);
    Log.v("Fragment" , "Piece: " + piece.getNomPiece());
    Log.v("Fragment", "Inventaire: " + inventairePieces.getInventairePieces().size());

    // the item card
    ((TextView) rootView.findViewById(R.id.codePiece_text)).setText(String.valueOf("# " + piece.getCodePiece()));
    ((TextView) rootView.findViewById(R.id.nomPiece_text)).setText(piece.getNomPiece());
    ((TextView) rootView.findViewById(R.id.descriptionPiece_text)).setText(piece.getDescriptionPiece());
    ((TextView) rootView.findViewById(R.id.dimensionPiece_text)).setText(String.valueOf(piece.getDimensionPiece()) + " mm");
    ((TextView) rootView.findViewById(R.id.prixCoutantPiece_text)).setText(String.valueOf(piece.getPrixCoutantPiece()) + " $");
    ((TextView) rootView.findViewById(R.id.qtyPiece_text)).setText(String.valueOf(piece.getQtyPiece()));
    ((TextView) rootView.findViewById(R.id.typePiece_text)).setText(piece.getTypePiece());
    ((TextView) rootView.findViewById(R.id.categoriePiece_text)).setText(piece.getCategoriePiece());

    rootView.setOnTouchListener(new OnSwipeTouchListener(getContext()){
        @Override
        public void onSwipeRight() {
            super.onSwipeRight();
            Log.v("Fragment", "onSwipeRight - ");
            if (positionClicked > 0) {
                positionClicked--;
                piece = inventairePieces.getInventairePieces().get(positionClicked);

                // sets the title in the action bar
                getActivity().setTitle(piece.getNomPiece());

                // the item card
                ((TextView) rootView.findViewById(R.id.codePiece_text)).setText(String.valueOf("# " + piece.getCodePiece()));
                ((TextView) rootView.findViewById(R.id.nomPiece_text)).setText(piece.getNomPiece());
                ((TextView) rootView.findViewById(R.id.descriptionPiece_text)).setText(piece.getDescriptionPiece());
                ((TextView) rootView.findViewById(R.id.dimensionPiece_text)).setText(String.valueOf(piece.getDimensionPiece()) + " mm");
                ((TextView) rootView.findViewById(R.id.prixCoutantPiece_text)).setText(String.valueOf(piece.getPrixCoutantPiece()) + " $");
                ((TextView) rootView.findViewById(R.id.qtyPiece_text)).setText(String.valueOf(piece.getQtyPiece()));
                ((TextView) rootView.findViewById(R.id.typePiece_text)).setText(piece.getTypePiece());
                ((TextView) rootView.findViewById(R.id.categoriePiece_text)).setText(piece.getCategoriePiece());

                Log.v("Fragment", "Pos Clicked: " + positionClicked);
                Log.v("Fragment" , "Piece: " + piece.getNomPiece());
                Log.v("Fragment", "Inventaire: " + inventairePieces.getInventairePieces().size());
            }
        }
        @Override
        public void onSwipeLeft() {
            super.onSwipeLeft();
            Log.v("Fragment", "onSwipeLeft + ");
            if(positionClicked < inventairePieces.getInventairePieces().size()-1) {
                positionClicked++;
                piece = inventairePieces.getInventairePieces().get(positionClicked);

                // sets the title in the action bar
                getActivity().setTitle(piece.getNomPiece());

                // the item card
                ((TextView) rootView.findViewById(R.id.codePiece_text)).setText(String.valueOf("# " + piece.getCodePiece()));
                ((TextView) rootView.findViewById(R.id.nomPiece_text)).setText(piece.getNomPiece());
                ((TextView) rootView.findViewById(R.id.descriptionPiece_text)).setText(piece.getDescriptionPiece());
                ((TextView) rootView.findViewById(R.id.dimensionPiece_text)).setText(String.valueOf(piece.getDimensionPiece()) + " mm");
                ((TextView) rootView.findViewById(R.id.prixCoutantPiece_text)).setText(String.valueOf(piece.getPrixCoutantPiece()) + " $");
                ((TextView) rootView.findViewById(R.id.qtyPiece_text)).setText(String.valueOf(piece.getQtyPiece()));
                ((TextView) rootView.findViewById(R.id.typePiece_text)).setText(piece.getTypePiece());
                ((TextView) rootView.findViewById(R.id.categoriePiece_text)).setText(piece.getCategoriePiece());

                Log.v("Fragment", "Pos Clicked: " + positionClicked);
                Log.v("Fragment" , "Piece: " + piece.getNomPiece());
                Log.v("Fragment", "Inventaire: " + inventairePieces.getInventairePieces().size());
            }
        }
    });

    return rootView;
}

}

Here the new OnSwipeTouchListener class that handles gestures:

public class OnSwipeTouchListener implements View.OnTouchListener {

private GestureDetector gestureDetector;

public OnSwipeTouchListener(Context c) {
    gestureDetector = new GestureDetector(c, new GestureListener());
}

public boolean onTouch(final View view, final MotionEvent motionEvent) {
    return gestureDetector.onTouchEvent(motionEvent);
}

private final class GestureListener extends GestureDetector.SimpleOnGestureListener {

    private static final int SWIPE_THRESHOLD = 100;
    private static final int SWIPE_VELOCITY_THRESHOLD = 100;

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    // Determines the fling velocity and then fires the appropriate swipe event accordingly
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean result = false;
        try {
            float diffY = e2.getY() - e1.getY();
            float diffX = e2.getX() - e1.getX();
            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffX > 0) {
                        onSwipeRight();
                    } else {
                        onSwipeLeft();
                    }
                }
            } else {
                if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                    if (diffY > 0) {
                        onSwipeDown();
                    } else {
                        onSwipeUp();
                    }
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}

public void onSwipeRight() {
}

public void onSwipeLeft() {
}

public void onSwipeUp() {
}

public void onSwipeDown() {
}

}

And here's the "InventairesPiecesFragment" class from where you click on an item in a scrolling list:

public class InventairePiecesFragment extends Fragment{

private ArrayAdapter<PieceModel> inventairePiecesAdapter;

private InventairePieces inventairePieces;

private PieceModel piece;

private Bundle bundle;

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    FloatingActionButton fab = (FloatingActionButton) container.findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(getActivity(), PieceEditActivity.class);
            intent.putExtra("piece", piece);
            intent.putExtra("inventairePieces", inventairePieces);
            startActivityForResult(intent, 1);
        }
    });

    inventairePieces = new InventairePieces(new ArrayList<PieceModel>());
    this.readInventairePiece();

    inventairePiecesAdapter = new ArrayAdapter<>(
            getActivity(),
            R.layout.liste_pieces_inventaire,
            R.id.liste_pieces_inventaire_textview,
            inventairePieces.getInventairePieces());

    View rootView = inflater.inflate(R.layout.fragment_pieces_inventaire, container, false);

    ListView inventairePiecesAdapterView = (ListView) rootView.findViewById(R.id.listview_pieces_inventaire);
    inventairePiecesAdapterView.setAdapter(inventairePiecesAdapter);

    inventairePiecesAdapterView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            piece = inventairePiecesAdapter.getItem(i);
            Intent intent = new Intent(getActivity(), PieceViewActivity.class);
            intent.putExtra("inventairePieces", inventairePieces);
            intent.putExtra("posClicked", i);
            startActivityForResult(intent, 1);

            Log.v("short clicked","pos: " + i);
        }
    });
    inventairePiecesAdapterView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int i, long id) {
            piece = inventairePiecesAdapter.getItem(i);
            ConfirmeSuppDialogFragment dialogFrag = new ConfirmeSuppDialogFragment();
            bundle = new Bundle();
            bundle.putSerializable("piece",piece);
            bundle.putSerializable("inventairePieces",inventairePieces);
            dialogFrag.setArguments(bundle);
            dialogFrag.setTargetFragment(InventairePiecesFragment.this, 2);
            dialogFrag.show(getFragmentManager(), "dialog");

            Log.v("long clicked","pos: " + i);

            return true;
        }
    });

    return rootView;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    this.writeInventairePiece();
    return super.onOptionsItemSelected(item);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(resultCode == 1) {
        piece = (PieceModel) data.getSerializableExtra("piece");
        inventairePieces.addToInventairePieces(piece);
        this.writeInventairePiece();
        inventairePiecesAdapter.notifyDataSetChanged();
        printConfirmerState(piece, "ajoutée");
    }
    else if(resultCode == 2){
        inventairePieces.removeFromInventairePieces(piece);
        this.writeInventairePiece();
        inventairePiecesAdapter.notifyDataSetChanged();
        printConfirmerState(piece, "supprimée");
    }
}

private void writeInventairePiece(){
    try {
        FileOutputStream outputFile = this.getContext().openFileOutput("InventairePiece.ser", Context.MODE_PRIVATE);
        ObjectOutputStream outputStream = new ObjectOutputStream(outputFile);
        outputStream.writeObject(inventairePieces);
        outputStream.close();
        outputFile.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

private void readInventairePiece(){
    try {
        FileInputStream inputFile = this.getContext().openFileInput("InventairePiece.ser");
        ObjectInputStream inputStream = new ObjectInputStream(inputFile);
        inventairePieces = (InventairePieces) inputStream.readObject();
        inputStream.close();
        inputFile.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

private void printConfirmerState(PieceModel piece, String state){
    String confirm = state;
    for(int i = 0; i < inventairePieces.getInventairePieces().size(); i++) {
        if(i == inventairePieces.getInventairePieces().indexOf(piece) && state.equals("ajoutée")) {
            confirm = ("La pièce '" + piece.getNomPiece() + "' est " + state + ".");
        }else if(i == inventairePieces.getInventairePieces().indexOf(piece) && state.equals("supprimée")) {
            confirm = ("La pièce '" + piece.getNomPiece() + "' est " + state + ".");
        }
    }
    Toast.makeText(getContext(), confirm, Toast.LENGTH_SHORT).show();
}

/*@Override
public void updateResult(int result) {
    this.result = result;
}*/

}

I thank you in advance.

And just in case, here's the full application as I have it so far:
My Project on gitHub

Body:
Let me see if I got it right, you have a list of items right? and whenever you select any item you're showing an Activity with all the details of that item (PieceModel); and you want to implement a gesture recognizer in this fragment to switch between the previous and next item without having to go back to the list and select the new item tight?.

If my understanding is good you can do it like this:

Implement a gesture recognizer to handle the left and right swipes over the fragment.

Depending on gesture you get the new item object (PieceModel) from the data source you're using also when you create your list adapter, and update the current instance stored in your fragment.

Update the UI using this "new" item as if the fragment has been loaded from scratch.

And voila!!!, some links here :

https://developer.android.com/training/gestures/detector.html

http://guides.codepath.com/android/gestures-and-touch-events

By the way, when you pass the index of the selected item to the new Activity you should retrieve it as :

position = getIntent().getIntExtra("posClicked");

I highly recommend you to pass the item Id instead the position, by the way, is InventairePieces implementing the Serializable interface?


来源: stackexchange

问:
Modal works, until duplicated
I have a javascript modal that I created, which works fine, unless there are 2 on the page. When 2 of them exist on the page, the first one will work, but the next ones do now.

Here is the JS that controls it:

```<code>// Get the button that opens the modal
let trigger = document.getElementsByClassName("js-modal")[0];
trigger.onclick = function() {
  modal.style.display = "block";
};

// Get the modal linked with with trigger element
let modal = document.getElementById(
  trigger.href.substring(trigger.href.indexOf("#") + 1)
);

// When the user clicks the button, open the modal
let allClose = modal.getElementsByClassName("js-modal-close");

// All elments linked to the modal can close the modal
for (let i = 0; i < allClose.length; i++) {
  allClose[i].onclick = function() {
    modal.style.display = "none";
  };
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(e) {
  if (e.target == modal) {
     modal.style.display = "none";
  }
};
</code>```

and here is a working example. I've tried messing around with using var instead of let, but not 100% sure on how to scope them to their specific html structures programtically.

答:
You need to use unique IDs for each modal:

```<code><div id="modal-1" class="m-modal">...</div>
<div id="modal-2" class="m-modal">...</div>
</code>```

and set up the trigger for each one, instead of just the first one:

```<code>let triggers = [].slice.call(document.getElementsByClassName('js-modal'))

triggers.forEach(function(trigger) {
 // ...
}
</code>```

JSFiddle Demo: https://jsfiddle.net/eoy2erpp/1/

ContentLicense: CC BY-SA 3.0

Title: Modal works, until duplicated

Body:
I have a javascript modal that I created, which works fine, unless there are 2 on the page. When 2 of them exist on the page, the first one will work, but the next ones do now.

Here is the JS that controls it:

// Get the button that opens the modal
let trigger = document.getElementsByClassName("js-modal")[0];
trigger.onclick = function() {
  modal.style.display = "block";
};

// Get the modal linked with with trigger element
let modal = document.getElementById(
  trigger.href.substring(trigger.href.indexOf("#") + 1)
);

// When the user clicks the button, open the modal
let allClose = modal.getElementsByClassName("js-modal-close");

// All elments linked to the modal can close the modal
for (let i = 0; i < allClose.length; i++) {
  allClose[i].onclick = function() {
    modal.style.display = "none";
  };
}
// When the user clicks anywhere outside of the modal, close it
window.onclick = function(e) {
  if (e.target == modal) {
     modal.style.display = "none";
  }
};

and here is a working example. I've tried messing around with using var instead of let, but not 100% sure on how to scope them to their specific html structures programtically.

Body:
You need to use unique IDs for each modal:

<div id="modal-1" class="m-modal">...</div>
<div id="modal-2" class="m-modal">...</div>

and set up the trigger for each one, instead of just the first one:

let triggers = [].slice.call(document.getElementsByClassName('js-modal'))

triggers.forEach(function(trigger) {
 // ...
}

JSFiddle Demo: https://jsfiddle.net/eoy2erpp/1/


问:
Button_Click event in Access VBA code doesn't open queries as expected
I've written the following VBA code to execute some queries off of a form with two text boxes and a button to run the appropriate query. When I perform the click event though, nothing happens... my queries don't open regardless of input, and even with no input the error msgbox doesn't display. I'm still pretty new to VBA and coding in general so I might be missing something obvious, but I can't see any glaring issues. On button click the debug.print does print, so the code is being accessed, it just isn't doing anything. I imagine it has to do with the nested If statements and specifically the opening of the queries, but I can't figure it out despite multiple hours of googling.

This is the button click event.

```<code>Private Sub RunQ_Click()

Dim Frm As Form
Dim MdlF As TextBox
Dim PartF As TextBox

Set Frm = Forms("SearchFormParts")
Set MdlF = Forms!SearchFormParts.Controls("ModelNoF")
Set PartF = Forms!SearchFormParts.Controls("PartNoF")
Debug.Print "this code is working2"
With Forms!SearchFormParts.Controls("RunQ")
    If .OnClick = "" Then
        If MdlF = vbNullString Then
            If PartF = vbNullString Then
                DoCmd.OpenQuery ("CCModel")
            Else
                DoCmd.OpenQuery ("CCBoth")
            End If
        ElseIf PartF = vbNullString Then
            If MdlF = vbNullString Then
                DoCmd.OpenQuery ("CCPart")
            Else
                DoCmd.OpenQuery ("CCBoth")
            End If
        Else: MsgBox ("Please enter a value in either or both fields!")
        End If
    End If
End With

End Sub
</code>```

Thank you :)

答:
If .OnClick = "" Then results to false. It is set to [Event Procedure].

This causes none of your query code to be run.
Remove it, and the corresponding End If

Body:
I've written the following VBA code to execute some queries off of a form with two text boxes and a button to run the appropriate query. When I perform the click event though, nothing happens... my queries don't open regardless of input, and even with no input the error msgbox doesn't display. I'm still pretty new to VBA and coding in general so I might be missing something obvious, but I can't see any glaring issues. On button click the debug.print does print, so the code is being accessed, it just isn't doing anything. I imagine it has to do with the nested If statements and specifically the opening of the queries, but I can't figure it out despite multiple hours of googling.

This is the button click event.

Private Sub RunQ_Click()

Dim Frm As Form
Dim MdlF As TextBox
Dim PartF As TextBox

Set Frm = Forms("SearchFormParts")
Set MdlF = Forms!SearchFormParts.Controls("ModelNoF")
Set PartF = Forms!SearchFormParts.Controls("PartNoF")
Debug.Print "this code is working2"
With Forms!SearchFormParts.Controls("RunQ")
    If .OnClick = "" Then
        If MdlF = vbNullString Then
            If PartF = vbNullString Then
                DoCmd.OpenQuery ("CCModel")
            Else
                DoCmd.OpenQuery ("CCBoth")
            End If
        ElseIf PartF = vbNullString Then
            If MdlF = vbNullString Then
                DoCmd.OpenQuery ("CCPart")
            Else
                DoCmd.OpenQuery ("CCBoth")
            End If
        Else: MsgBox ("Please enter a value in either or both fields!")
        End If
    End If
End With

End Sub

Thank you :)


问:
Loop through tables last row and set the data cell values
I am using clone() to add new row to the table.  But the clone is copying the  ID values also.  How can I change the ids and the values of the rows that were copied? Also, I have a <select> in one  cell how can I attach onchange event to this select.

答:
```<code>clonedRow.find('*').attr('id', '');
</code>```

to attach an event:

```<code>clonedRow.find('select').change(function() {});
</code>```

ContentLicense: CC BY-SA 2.5

Body:
clonedRow.find('*').attr('id', '');

to attach an event:

clonedRow.find('select').change(function() {});


问:
How i can SELECT with multiple WHERE in one table
i have table in database with rows:

id, kills, deaths, week

How i can select kills where week=1 AND deaths where week=2 in ONE TABLE?

答:
You can use conditional aggregated</p>

```<code>SELECT SUM (CASE WHEN week = 1 THEN kills END) as total_kills_week1,
       SUM (CASE WHEN week = 2 THEN deaths END) as total_deaths_week2
FROM YourTable
</code>```

Body:
You can use conditional aggregated

SELECT SUM (CASE WHEN week = 1 THEN kills END) as total_kills_week1,
       SUM (CASE WHEN week = 2 THEN deaths END) as total_deaths_week2
FROM YourTable


问:
Measuring distance of values / strings
martin fownler was discussing event sourcing

https://martinfowler.com/eaaDev/EventSourcing.html

e.g. storing data as a set of events.

Now an example would be an account. You create an account with balance 0.

Then you put 10$. You withdraw 5$. You put another 100$. Now the balance is 105$, but you don't store 105$. What you do store is

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

as a series of events in the database.

Now if I want I can say "undo the last 2 steps." then I just remove the 2 last changes in the database -> account is 10

Now: how can you do that with strings?

Say account name first is empty string. Then
dirk dietmeier then hans hansenmann then foo bar how can you capture this data as set of changes? While letting it be reversable e.g. the events need to be able to reverse itself. E.g. you could just say 'delete everything and then put foo bar but is there no better solution?

is there like a svn or git like algorithm? some encoding (hex, binary?)?

答:
There are many ways you could represent the change from one string to another string as a reversible operation.  It really would depend on requirements.

I would not expect the deltification in a source control system to necessarily meet the general needs you've outlined above.  For example, git's purpose in deltifying files for storage (which it only does when generating a pack) is to save space.  Older versions of an object may be stored as deltas from newer versions, but there is never a need to reconstruct the newer version via delta from the older version - it's stored in its entirety specifically so that it can be accessed quickly (without need to combine deltas).  So storing enough information for the delta to be used as a two-way transformation would be wasteful from git's point of view.

Instead of looking at the pack deltas, you could think about how diff represents a change.  This is more line-oriented than you seem to want.  If you have an edited file, you might represent the edits as

```<code>d37
- Line 37 used to contain this text, but it was removed
a42
+ We added this text on line 42
c99
- Line 99 used to have this text
+ Line 99 now has this text
</code>```

You could do a character-oriented version of this.  Say you define operators for "add characters at offset", "remove characters at offset", and "change characters at offset".  You either have to be careful with escaping delimiters, or use explicit lengths instead of simply delimiting strings.  And you also should consider that each edit might change the offset of the subsequent edits.  Technically pre-image offsets have all the information you need, but reversal of the patch is more intuitive if you also store the post-image offsets.

So given

```<code>well, here is the original string
</code>```

you might have a reversible delta like

```<code>0/0d6:well, 14/8c12:the original1:a33/16a11: with edits
</code>```

to yield

```<code>here is a string with edits
</code>```

Of course, calculating the "most correct" patch may not be easy.

```<code>0/0c33:well, here is the original string27:here is a string with edits
</code>```

would be equally valid but degenerates to the line-oriented approach.

But that's just one example; like I said, you could define any number of ways, depending on requirements.

Title: Measuring distance of values / strings

Body:
martin fownler was discussing event sourcing

https://martinfowler.com/eaaDev/EventSourcing.html

e.g. storing data as a set of events.

Now an example would be an account. You create an account with balance 0.

Then you put 10$. You withdraw 5$. You put another 100$. Now the balance is 105$, but you don't store 105$. What you do store is

+10
-5
+100

as a series of events in the database.

Now if I want I can say "undo the last 2 steps." then I just remove the 2 last changes in the database -> account is 10

Now: how can you do that with strings?

Say account name first is empty string. Then
dirk dietmeier then hans hansenmann then foo bar how can you capture this data as set of changes? While letting it be reversable e.g. the events need to be able to reverse itself. E.g. you could just say 'delete everything and then put foo bar but is there no better solution?

is there like a svn or git like algorithm? some encoding (hex, binary?)?

Body:
There are many ways you could represent the change from one string to another string as a reversible operation.  It really would depend on requirements.

I would not expect the deltification in a source control system to necessarily meet the general needs you've outlined above.  For example, git's purpose in deltifying files for storage (which it only does when generating a pack) is to save space.  Older versions of an object may be stored as deltas from newer versions, but there is never a need to reconstruct the newer version via delta from the older version - it's stored in its entirety specifically so that it can be accessed quickly (without need to combine deltas).  So storing enough information for the delta to be used as a two-way transformation would be wasteful from git's point of view.

Instead of looking at the pack deltas, you could think about how diff represents a change.  This is more line-oriented than you seem to want.  If you have an edited file, you might represent the edits as

d37
- Line 37 used to contain this text, but it was removed
a42
+ We added this text on line 42
c99
- Line 99 used to have this text
+ Line 99 now has this text

You could do a character-oriented version of this.  Say you define operators for "add characters at offset", "remove characters at offset", and "change characters at offset".  You either have to be careful with escaping delimiters, or use explicit lengths instead of simply delimiting strings.  And you also should consider that each edit might change the offset of the subsequent edits.  Technically pre-image offsets have all the information you need, but reversal of the patch is more intuitive if you also store the post-image offsets.

So given

well, here is the original string

you might have a reversible delta like

0/0d6:well, 14/8c12:the original1:a33/16a11: with edits

to yield

here is a string with edits

Of course, calculating the "most correct" patch may not be easy.

0/0c33:well, here is the original string27:here is a string with edits

would be equally valid but degenerates to the line-oriented approach.

But that's just one example; like I said, you could define any number of ways, depending on requirements.


问:
python: pandas: Merge multiple tables according to a index table
For example, I have three tables A, B, C

Table A:

```<code>id1   value1
1     23
2     34
3     2342
4     333
</code>```

Table B:

```<code>id2   value2
1     apple
2     banana
3     berry
</code>```

Table C:

```<code>id3   value3   value4
1     red      batman
2     green    superman
3     white    wonder woman
4     gray     aquaman
5     yellow   flash
</code>```

I want to merge these three tables according to an index table D

Table D:

```<code>Table_A    Table_B    Table_C
1          3           2
3                      4
2          2           3
4          1           1
                       5
</code>```

And my resulting table should like:

```<code>id1   value1    id2   value2    id3   value3  value4
1     23        3     berry     2     green    superman
3     2342                      4     gray     aquaman
2     34        2     banana    3     white    wonder woman
4     333       1     apple     1     red      batman
                                5     yellow   flash
</code>```

Can I do it via Python Pandas or I need do it in Spark?

答:
Let's try:

```<code>table_d['value1'] = table_d['Table_A'].map(table_a.set_index('id1')['value1'])

table_d['value2'] = table_d['Table_B'].map(table_b.set_index('id2')['value2'])

table_d.merge(table_c, left_on='Table_C', right_on='id3')
</code>```

Output:

```<code>   Table_A  Table_B  Table_C  value1  value2  id3  value3        value4
0      1.0      3.0        2    23.0   berry    2   green      superman
1      3.0      NaN        4  2342.0     NaN    4    gray       aquaman
2      2.0      2.0        3    34.0  banana    3   white  wonder woman
3      4.0      1.0        1   333.0   apple    1     red        batman
4      NaN      NaN        5     NaN     NaN    5  yellow         flash
</code>```

Body:
For example, I have three tables A, B, C

Table A:

id1   value1
1     23
2     34
3     2342
4     333

Table B:

id2   value2
1     apple
2     banana
3     berry

Table C:

id3   value3   value4
1     red      batman
2     green    superman
3     white    wonder woman
4     gray     aquaman
5     yellow   flash

I want to merge these three tables according to an index table D

Table D:

Table_A    Table_B    Table_C
1          3           2
3                      4
2          2           3
4          1           1
                       5

And my resulting table should like:

id1   value1    id2   value2    id3   value3  value4
1     23        3     berry     2     green    superman
3     2342                      4     gray     aquaman
2     34        2     banana    3     white    wonder woman
4     333       1     apple     1     red      batman
                                5     yellow   flash

Can I do it via Python Pandas or I need do it in Spark?

Body:
Let's try:

table_d['value1'] = table_d['Table_A'].map(table_a.set_index('id1')['value1'])

table_d['value2'] = table_d['Table_B'].map(table_b.set_index('id2')['value2'])

table_d.merge(table_c, left_on='Table_C', right_on='id3')

Output:

   Table_A  Table_B  Table_C  value1  value2  id3  value3        value4
0      1.0      3.0        2    23.0   berry    2   green      superman
1      3.0      NaN        4  2342.0     NaN    4    gray       aquaman
2      2.0      2.0        3    34.0  banana    3   white  wonder woman
3      4.0      1.0        1   333.0   apple    1     red        batman
4      NaN      NaN        5     NaN     NaN    5  yellow         flash


问:
Error: Cannot find control with path: 'x ' angular 2
I am trying to make a specific form field in my overall form dynamic so that x amount of objects can be added to the array of that field.
However, every time the page inits I get a

Error: Cannot find control with path: 'media -> '

This is my form.ts

```<code>this.cardForm = new FormGroup({
  'title': new FormControl(cardTitle),
  media: this._fb.array([
    this.initMedia(),
  ]),
  'links': new FormGroup({
    'news': new FormControl(news),
  }),

  initMedia() {
   return this._fb.group({
   type: new FormControl(),
   raw: new FormControl(),
   primary: new FormControl(),
   thumbs: this._fb.group({
    default: new FormControl()
  })
})
}

addMedia(){
 const control = <FormArray>this.cardForm.controls['media'];
 control.push(this._fb.control(['']));
}
removeMedia(i: number){
 const control = <FormArray>this.cardForm.controls['media'];
 control.removeAt(i);
}
</code>```

this is my form.html:

```<code><div class="row">
  <div class="col-xs-12">
    <form [formGroup]="cardForm" (ngSubmit)="onSubmit(cardForm.value)">
      <div class="row">
        <div class="col-xs-12">
          <button
            type="submit"
            class="btn btn-success">
            Update Card</button>
          <button
            type="button"
            class="btn btn-danger"
            (click)="onCancel()">
            Cancel</button>
        </div>
      </div>

    <div formArrayName="media">
      <div class="row">
        <div class="col-xs-12">
          <div class="form-group">
            <div *ngFor= "let media of cardForm.controls.media.controls; let i=index">
              <span>Media {{i + 1}}</span>
              <span *ngIf="cardForm.controls.media.controls.length > 1" (click)="removeMedia(i)"></span>
          </div>
          <div [formGroupName]="i">
            <div>
              <label>Url</label>
                <md-input-container class="mdcontainer">
                  <input mdInput placeholder="Media Url" type="text" formControlName="raw">
                </md-input-container>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</code>```

And the media[] looks like this:

```<code>media: [
        {
          raw:'string',
          primary: boolean,
          type: 'string',
          thumb: {
                 default: 'string'
                 {
        }
      ]
</code>```

What am I missing/doing wrong here for that error to come up?
Any help/tips/suggestions would be much appreciated.

答:
[formGroupName]="i" should be inside of *ngFor. In this case i variable will have non undefined value

```<code><div *ngFor="let media of cardForm.controls.media.controls; let i=index">
  <span>Media {{i + 1}}</span>
  <span *ngIf="cardForm.controls.media.controls.length > 1" (click)="removeMedia(i)"></span>
  <div [formGroupName]="i">
    <div>
      <label>Url</label>
      <md-input-container class="mdcontainer">
        <input mdInput placeholder="Media Url" type="text" formControlName="raw">
      </md-input-container>
    </div>
  </div>
</div>
</code>```

Plunker Example

Body:
I am trying to make a specific form field in my overall form dynamic so that x amount of objects can be added to the array of that field.
However, every time the page inits I get a

Error: Cannot find control with path: 'media -> '

This is my form.ts

this.cardForm = new FormGroup({
  'title': new FormControl(cardTitle),
  media: this._fb.array([
    this.initMedia(),
  ]),
  'links': new FormGroup({
    'news': new FormControl(news),
  }),

  initMedia() {
   return this._fb.group({
   type: new FormControl(),
   raw: new FormControl(),
   primary: new FormControl(),
   thumbs: this._fb.group({
    default: new FormControl()
  })
})
}

addMedia(){
 const control = <FormArray>this.cardForm.controls['media'];
 control.push(this._fb.control(['']));
}
removeMedia(i: number){
 const control = <FormArray>this.cardForm.controls['media'];
 control.removeAt(i);
}

this is my form.html:

    <form [formGroup]="cardForm" (ngSubmit)="onSubmit(cardForm.value)">

          <button
            type="submit"
            class="btn btn-success">
            Update Card</button>
          <button
            type="button"
            class="btn btn-danger"
            (click)="onCancel()">
            Cancel</button>

              Media {{i + 1}}
               1" (click)="removeMedia(i)">

              Url
                <md-input-container class="mdcontainer">
                  <input mdInput placeholder="Media Url" type="text" formControlName="raw">
                </md-input-container>

And the media[] looks like this:

media: [
        {
          raw:'string',
          primary: boolean,
          type: 'string',
          thumb: {
                 default: 'string'
                 {
        }
      ]

What am I missing/doing wrong here for that error to come up?
Any help/tips/suggestions would be much appreciated.

Body:
[formGroupName]="i" should be inside of *ngFor. In this case i variable will have non undefined value

<div *ngFor="let media of cardForm.controls.media.controls; let i=index">
  <span>Media {{i + 1}}</span>
  <span *ngIf="cardForm.controls.media.controls.length > 1" (click)="removeMedia(i)"></span>
  <div [formGroupName]="i">
    <div>
      <label>Url</label>
      <md-input-container class="mdcontainer">
        <input mdInput placeholder="Media Url" type="text" formControlName="raw">
      </md-input-container>
    </div>
  </div>
</div>

Plunker Example


问:
popToViewController isn't popping all of the view controllers
So I have 3 view controllers: TableViewController, A, and B. The user is able to navigate to any view controller from any view controller.

When the user goes back and forth between A, and B view controllers I want them to be pushed onto the nav. stack. When the "home" button is pressed, I would like for the view controllers to all be popped back to the TableViewController using popToViewController, not popToRootViewController (for reasons).

I have partly working code that pops the last visited view controller, but now all the ones in between.

```<code>func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    if indexPath.row == 0 {
        if let navController = self.navigationController {
            for controller in navController.viewControllers {
                if controller is TableViewController {
                    navController.popToViewController(controller, animated: true)
                    break
                }
            }
        }
    } else {

        let vcName = identities[indexPath.row]
        let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
        self.navigationController?.pushViewController(viewController!, animated: true)
    }

}
</code>```

I'm not sure why all the view controllers aren't being popped.

Code I use to check what's being pushed and popped:

```<code>override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(true)

    if self.isMovingToParentViewController {
        print("A is pushed")
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(true)

    if self.isMovingFromParentViewController {
        print("A is popped")
    }
}
</code>```

I'm also checking increase in memory.

I will provide more code/info in needed.

Any help would be greatly appreciated.

答:
Try something like this:    </p>

```<code> var theControllerIWantToPopTo = controllerB // or whatever other condition
 if let navController = self.navigationController {
    for controller in navController.viewControllers {
        if controller is TableViewController {
           if controller == theControllerIWantToPopTo {
              navController.popToViewController(controller, animated: true)
              break
           }
        }
     }
 }
</code>```

<p>Remember, popToViewController will pop all controllers until the chosen one is on top, as opposed to popViewController which will only pop the top controller. If you want to pop them one at a time with animation on each pop see: Completion block for popViewController </p>

Body:
So I have 3 view controllers: TableViewController, A, and B. The user is able to navigate to any view controller from any view controller.

When the user goes back and forth between A, and B view controllers I want them to be pushed onto the nav. stack. When the "home" button is pressed, I would like for the view controllers to all be popped back to the TableViewController using popToViewController, not popToRootViewController (for reasons).

I have partly working code that pops the last visited view controller, but now all the ones in between.

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    if indexPath.row == 0 {
        if let navController = self.navigationController {
            for controller in navController.viewControllers {
                if controller is TableViewController {
                    navController.popToViewController(controller, animated: true)
                    break
                }
            }
        }
    } else {

        let vcName = identities[indexPath.row]
        let viewController = storyboard?.instantiateViewController(withIdentifier: vcName)
        self.navigationController?.pushViewController(viewController!, animated: true)
    }

}

I'm not sure why all the view controllers aren't being popped.

Code I use to check what's being pushed and popped:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(true)

    if self.isMovingToParentViewController {
        print("A is pushed")
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(true)

    if self.isMovingFromParentViewController {
        print("A is popped")
    }
}

I'm also checking increase in memory.

I will provide more code/info in needed.

Any help would be greatly appreciated.

Body:
Try something like this:

 var theControllerIWantToPopTo = controllerB // or whatever other condition
 if let navController = self.navigationController {
    for controller in navController.viewControllers {
        if controller is TableViewController {
           if controller == theControllerIWantToPopTo {
              navController.popToViewController(controller, animated: true)
              break
           }
        }
     }
 }

Remember, popToViewController will pop all controllers until the chosen one is on top, as opposed to popViewController which will only pop the top controller. If you want to pop them one at a time with animation on each pop see: Completion block for popViewController


问:
TypeError: 'module' object is not callable - using datetime
Sorry didn't find any other fix, so I created a new question.
I'm trying to run a code that prints to the screen the current hour, minute and second. The piece of code I'm using to do this is:

```<code>def time():
    import datetime
    import time
    time.sleep(1)
    nowTime = datetime.now()
    print ('Right now it's %s hours, %s minutes and %s seconds.' % (nowTime.hour,nowTime.minute,nowTime.second))
    time.sleep(5)
</code>```

I get the following error when this piece of code tries to execute:

```<code>Traceback (most recent call last):
  File "/Users/Teolicht/Desktop/Python/testy.py", line 219, in <module>
    start()
  File "/Users/Teolicht/Desktop/Python/testy.py", line 18, in start
    questions()
  File "/Users/Teolicht/Desktop/Python/testy.py", line 34, in questions
    day()
  File "/Users/Teolicht/Desktop/Python/testy.py", line 52, in day
    time()
TypeError: 'module' object is not callable
</code>```

start(), questions() and day() are some other functions the program went through before going through time(). If I try executing time() directly, it works! So, here's the entire code from the start till the end of the time() function:

```<code>from datetime import datetime
import time
import random
import sys

def start():
    import time
    name = input('Hi. What is your name? ')
    print ('Nice to meet you, ' + str(name) + '.')
    time.sleep(1)
    print ('How old are you?')
    age = input()
    time.sleep(1)
    print (age + '! Cool.')
    time.sleep(2)
    questions()

def questions():
    import time
    print ('Some things you can ask me:')
    time.sleep(1)
    print ('• What day is today? (qdh)')
    time.sleep(1)
    print ('• What time is it? (qhs)')
    time.sleep(1)
    print ('• I want to play a game! (qjj)')
    time.sleep(1)
    print ('• How many days till my birthday? (qda)')
    time.sleep(1)
    questionsAnswer = input()
    if questionsAnswer == 'qdh':
        day()
    elif questionsAnswer == 'qhs':
        time()
    elif questionsAnswer == 'qjj':
        game()
    else:
        birthday()

def day():
    import time
    time.sleep(1)
    nowDay = datetime.now()
    print ('Today is %s/%s/%s' % (nowDay.day,nowDay.month,nowDay.year))
    time.sleep(2)
    dayAnswer = input('Want to know what time it is? "Y" for yes and "N" for no: ').lower()
    if dayAnswer == 'n':
        questions()
    else:
        time()

def time():
    import time
    time.sleep(1)
    nowTime = datetime.now()
    print ('Right now it's %s hours, %s minutes and %s seconds.' % (nowTime.hour,nowTime.minute,nowTime.second))
    time.sleep(5)
        questions()
       ...
</code>```

It might be something in start(), questions() or day() causing the error. Any ideas? Thanks a bunch!

答: Replace your import time to from time import time.

ContentLicense: CC BY-SA 4.0

Body:
Sorry didn't find any other fix, so I created a new question.
I'm trying to run a code that prints to the screen the current hour, minute and second. The piece of code I'm using to do this is:

def time():
    import datetime
    import time
    time.sleep(1)
    nowTime = datetime.now()
    print ('Right now it's %s hours, %s minutes and %s seconds.' % (nowTime.hour,nowTime.minute,nowTime.second))
    time.sleep(5)

I get the following error when this piece of code tries to execute:

Traceback (most recent call last):
  File "/Users/Teolicht/Desktop/Python/testy.py", line 219, in <module>
    start()
  File "/Users/Teolicht/Desktop/Python/testy.py", line 18, in start
    questions()
  File "/Users/Teolicht/Desktop/Python/testy.py", line 34, in questions
    day()
  File "/Users/Teolicht/Desktop/Python/testy.py", line 52, in day
    time()
TypeError: 'module' object is not callable

start(), questions() and day() are some other functions the program went through before going through time(). If I try executing time() directly, it works! So, here's the entire code from the start till the end of the time() function:

from datetime import datetime
import time
import random
import sys

def start():
    import time
    name = input('Hi. What is your name? ')
    print ('Nice to meet you, ' + str(name) + '.')
    time.sleep(1)
    print ('How old are you?')
    age = input()
    time.sleep(1)
    print (age + '! Cool.')
    time.sleep(2)
    questions()

def questions():
    import time
    print ('Some things you can ask me:')
    time.sleep(1)
    print ('• What day is today? (qdh)')
    time.sleep(1)
    print ('• What time is it? (qhs)')
    time.sleep(1)
    print ('• I want to play a game! (qjj)')
    time.sleep(1)
    print ('• How many days till my birthday? (qda)')
    time.sleep(1)
    questionsAnswer = input()
    if questionsAnswer == 'qdh':
        day()
    elif questionsAnswer == 'qhs':
        time()
    elif questionsAnswer == 'qjj':
        game()
    else:
        birthday()

def day():
    import time
    time.sleep(1)
    nowDay = datetime.now()
    print ('Today is %s/%s/%s' % (nowDay.day,nowDay.month,nowDay.year))
    time.sleep(2)
    dayAnswer = input('Want to know what time it is? "Y" for yes and "N" for no: ').lower()
    if dayAnswer == 'n':
        questions()
    else:
        time()

def time():
    import time
    time.sleep(1)
    nowTime = datetime.now()
    print ('Right now it's %s hours, %s minutes and %s seconds.' % (nowTime.hour,nowTime.minute,nowTime.second))
    time.sleep(5)
        questions()
       ...

It might be something in start(), questions() or day() causing the error. Any ideas? Thanks a bunch!


问:
SQL select where group by order by distinct
I got a one table Search, and columns are:

```<code>id(int), title(nvarchar), count(int), expression(nvarchar)
</code>```

with values:

```<code>1, aaa, 5, car
2, aaa, 5, car poster
3, bbb, 8, car magazine
4, bbb, 8, car tv
5, ccc, 12, boat
6, ccc, 12 , boat tv
</code>```

I need the following result

```<code>4, bbb, 8, car tv
3, bbb, 8, car magazine
2, aaa, 5, car poster
1, aaa, 5, car
</code>```

or better result whatever from 4,3 and 2,1
like this:

```<code>3, bbb, 8, car magazine
2, aaa, 5, car poster
</code>```

I tried this:

```<code>SELECT   title
FROM
    (SELECT *
     FROM Search
     ORDER BY count DESC)
WHERE expression
LIKE '%car%'
GROUP BY  title
</code>```

I have also tried a DISTINCT

答:
Use a CTE with the ROW_NUMBER function to find the matching rows and order them by descending count along with id for a tie breaker. Then select the first numbered row within each partition (title).</p>

```<code>WITH cteFindCar AS (
    SELECT id, title, count, expression,
           ROW_NUMBER() OVER(PARTITION BY title ORDER BY count DESC, id) AS RowNum
        FROM search
        WHERE expression LIKE '%car%'
)
SELECT id, title, count, expression
    FROM cteFindCar
    WHERE RowNum = 1;
</code>```

Body:
I got a one table Search, and columns are:

id(int), title(nvarchar), count(int), expression(nvarchar)

with values:

1, aaa, 5, car
2, aaa, 5, car poster
3, bbb, 8, car magazine
4, bbb, 8, car tv
5, ccc, 12, boat
6, ccc, 12 , boat tv

I need the following result

4, bbb, 8, car tv
3, bbb, 8, car magazine
2, aaa, 5, car poster
1, aaa, 5, car

or better result whatever from 4,3 and 2,1
like this:

3, bbb, 8, car magazine
2, aaa, 5, car poster

I tried this:

SELECT   title
FROM
    (SELECT *
     FROM Search
     ORDER BY count DESC)
WHERE expression
LIKE '%car%'
GROUP BY  title

I have also tried a DISTINCT

Body:
Use a CTE with the ROW_NUMBER function to find the matching rows and order them by descending count along with id for a tie breaker. Then select the first numbered row within each partition (title).

WITH cteFindCar AS (
    SELECT id, title, count, expression,
           ROW_NUMBER() OVER(PARTITION BY title ORDER BY count DESC, id) AS RowNum
        FROM search
        WHERE expression LIKE '%car%'
)
SELECT id, title, count, expression
    FROM cteFindCar
    WHERE RowNum = 1;


问:
How to use AppAuth-Android with IdentityServer4?
I have successfully configured a Identityserver4 for my ASP.Net MVC client, and everything is working fine.
Now I'm looking to develop an Android app client. The MVC client and the Android client uses the same Identity Server for authentication and authorization.
So for Android client I'm looking for "AppAuth-Android" GitHub library. But I couldn't find any sample or help to use the library with IdentityServer4. I have read the documentation of the "AppAuth-Android" library and it says

In general, AppAuth can work with any Authorization Server (AS) that supports native apps.

So my question is 1) how can I configure my Identity Server to work with Android app.

2) How to authenticate my Android app with the help of "AppAuth-Android".

Any help is greatly appreciated.

Can some one please create a tag for "AppAuth-Android"?

答:
The data in the server side should be the same as the data used in the android app.

Add a client to the server side

```<code>  new Client
        {
            ClientId = "myClientId",
            ClientName = "myClientName",
            AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
            RequireConsent = false,

            ClientSecrets =
            {
                new Secret("myClientSecret".Sha256())
            },

            RedirectUris = { "myRedirectUri://callback" },

            AllowedScopes =
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.Email,
                IdentityServerConstants.StandardScopes.Phone,
            },

            AllowOfflineAccess = true
        }
</code>```

In the android app you should have the same clientId,clientSecret,redirectUri ..

I have made a sample using AppAuth-android library you should just edit the data in the gradle.properties check it here

Body:
The data in the server side should be the same as the data used in the android app.

Add a client to the server side

  new Client
        {
            ClientId = "myClientId",
            ClientName = "myClientName",
            AllowedGrantTypes = GrantTypes.CodeAndClientCredentials,
            RequireConsent = false,

            ClientSecrets =
            {
                new Secret("myClientSecret".Sha256())
            },

            RedirectUris = { "myRedirectUri://callback" },

            AllowedScopes =
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.Email,
                IdentityServerConstants.StandardScopes.Phone,
            },

            AllowOfflineAccess = true
        }

In the android app you should have the same clientId,clientSecret,redirectUri ..

I have made a sample using AppAuth-android library you should just edit the data in the gradle.properties check it here


问:
Overlay around annotation
Hi I'm trying to create an overlay around my annotations, like apples reminders app, I have already created an MKCircle object which I think I should use to show the overlay but how do I convert my MKCircle object into an MKOVerlay object? maybe there's a better way to add annotations? I'm new to swift and programming. Any suggestions? </p>

答:
MKCircle is a MKOverlay object. You just need to add it as an overlay:

```<code>let circle = MKCircle(center: coordinate, radius: 1000)
mapView.add(circle)
</code>```

Of course, you have to tell the map how to render it by implementing mapView(_:rendererFor:) in your delegate and instantiate a MKCircleRenderer for the MKCircle that’s passed as an overlay.

```<code>extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        let renderer = MKCircleRenderer(overlay: overlay)
        renderer.fillColor = UIColor.cyan.withAlphaComponent(0.5)
        renderer.strokeColor = UIColor.cyan.withAlphaComponent(0.8)
        return renderer
    }
}
</code>```

Clearly, make sure you specified the delegate for your MKMapView, too. And if you have other types of renderers, you might implement specific logic for those, too, e.g.

```<code>extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if let circle = overlay as? MKCircle {
            let renderer = MKCircleRenderer(circle: circle)
            renderer.fillColor = UIColor.cyan.withAlphaComponent(0.5)
            renderer.strokeColor = UIColor.cyan.withAlphaComponent(0.8)
            return renderer
        }

        if let polygon = overlay as? MKPolygon {
            let renderer = MKPolygonRenderer(polygon: polygon)
            renderer.fillColor = UIColor.blue.withAlphaComponent(0.5)
            renderer.strokeColor = UIColor.blue.withAlphaComponent(0.8)
            return renderer
        }

        if let polyline = overlay as? MKPolyline {
            let renderer = MKPolylineRenderer(polyline: polyline)
            renderer.fillColor = UIColor.red.withAlphaComponent(0.5)
            renderer.strokeColor = UIColor.red.withAlphaComponent(0.8)
            return renderer
        }

        fatalError("Unexpected overlay type")
    }
}
</code>```

Title: Overlay around annotation

Body:
MKCircle is a MKOverlay object. You just need to add it as an overlay:

let circle = MKCircle(center: coordinate, radius: 1000)
mapView.add(circle)

Of course, you have to tell the map how to render it by implementing mapView(_:rendererFor:) in your delegate and instantiate a MKCircleRenderer for the MKCircle that’s passed as an overlay.

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        let renderer = MKCircleRenderer(overlay: overlay)
        renderer.fillColor = UIColor.cyan.withAlphaComponent(0.5)
        renderer.strokeColor = UIColor.cyan.withAlphaComponent(0.8)
        return renderer
    }
}

Clearly, make sure you specified the delegate for your MKMapView, too. And if you have other types of renderers, you might implement specific logic for those, too, e.g.

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if let circle = overlay as? MKCircle {
            let renderer = MKCircleRenderer(circle: circle)
            renderer.fillColor = UIColor.cyan.withAlphaComponent(0.5)
            renderer.strokeColor = UIColor.cyan.withAlphaComponent(0.8)
            return renderer
        }

        if let polygon = overlay as? MKPolygon {
            let renderer = MKPolygonRenderer(polygon: polygon)
            renderer.fillColor = UIColor.blue.withAlphaComponent(0.5)
            renderer.strokeColor = UIColor.blue.withAlphaComponent(0.8)
            return renderer
        }

        if let polyline = overlay as? MKPolyline {
            let renderer = MKPolylineRenderer(polyline: polyline)
            renderer.fillColor = UIColor.red.withAlphaComponent(0.5)
            renderer.strokeColor = UIColor.red.withAlphaComponent(0.8)
            return renderer
        }

        fatalError("Unexpected overlay type")
    }
}


问:
Knockoutjs operates extremely slow in Internet Explorer
In brief: I've got a page with KO-code that operates absolutely cool in Google Chrome, Firefox, Safari, etc. But the performance is gone in Internet Explorer. I tried IE10, IE11. It takes from 10 to 25 seconds to render about 150 rows.

Details: There page represents a work queue for users, where their tasks are shown. The requirement is not to use any paging on that page. Each row of the table has at least a dozen of variants to display (links, buttons, inputs, css styling, handling user events, custom js plugins, etc.). The average number of rows on prod is 100-200+. User is able to apply different filters and sortings.

Things I've already tried:

reduced the number of computed properties (changed to pureComputed, where possible)

reduced the number of using the template, if and ifnot bindings (according to profiler they are the most time consuming task) - I use the visible, where possible

tried to use the knockout-fast-foreach custom binding (https://github.com/brianmhunt/knockout-fast-foreach)

profiled the code with IE and Chrome tools to eliminate the memory leaks

profiled the code with ko.bindingReport.js (https://gist.github.com/kamranayub/65399fa247a6c182bc65)

The approaches specifed above tuned the code (according to ko.bindingReport.js) almost two times faster in Chrome. But IE is still too slow - about 10 seconds for rendering.

Chrome:

Internet Explorer:

Folks, any ideas?

答:
"The table binding provides a fast method for displaying tables of data using Knockout. table is about ten times faster than nested foreach bindings."

This claims to be 10x faster.
https://github.com/mbest/knockout-table


问:
Redirecting stderr to multiple streams
I'm trying to understand how a part of a Bash script works. Relevant code is:

sqlprogram -f $filename.sql > $date.log 2>&1

It looks like if there's no error with the sqlprogram -f $filename.sql part, then the contents of stdout are written to $date.log but if there is an error, then stderr is written to $date.log. So basically, one of stderr and stdout is written to $date.log. Is that correct?

How do I redirect stderr to another file as well, say $errorlog.file? I've tried playing around with tee but struggled for a bit

答:
The command:

```<code>sqlprogram -f "$filename.sql"  >info.log 2>error.log
</code>```

will redirect stdout to info.log file and stderr to error.log file.

The part of your command 2>&1 tells the shell to redirect stderr (file descriptor 2) to file descriptor 1 (which is stdout).

To redirect stdout to info.log, and stderr to both info.log and error.log, you can use this:

```<code>sqlprogram -f "$filename.sql"  >info.log 2> >(tee error.log)
</code>```

Title: Redirecting stderr to multiple streams

Body:
The command:

sqlprogram -f "$filename.sql"  >info.log 2>error.log

will redirect stdout to info.log file and stderr to error.log file.

The part of your command 2>&1 tells the shell to redirect stderr (file descriptor 2) to file descriptor 1 (which is stdout).

To redirect stdout to info.log, and stderr to both info.log and error.log, you can use this:

sqlprogram -f "$filename.sql"  >info.log 2> >(tee error.log)


问:
What is the compile-time type of the "throw" expression in C# 7?
In C# 7 it is possible to raise an exception inside an expression:

```<code>int n = list != null ? list.Count : throw new NullReferenceException("list");
</code>```

In this position, the throw expression can substitute an expression of any type.

Now I want to define a function that executes some action before raising an exception:

```<code>??? DoSomethingAndThrowException(Exception e)
{
    MessageBox.Show("Prepare for an exception!");
    throw e;
}
</code>```

What would be the return type of such function, so that it can be used in the same places as the original throw expression:

```<code>int n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));
</code>```

There's the option to declare it as a generic method:

```<code>T DoSomethingAndThrowException<T>(Exception e) {...}
</code>```

But this seems cumbersome, as the generic type doesn't occur anywhere in the function body. Is this the only way to do it, or is there some type I don't know of, and which is assignable to any type (an "anti-object" type, so to speak)?

答:
The ternary operator won't compile unless both expressions return the same type or there's a conversion from one type to the other. So it doesn't really matter what the type of the throw expression is. Unless DoSomethingAndThrowException returns int or something which can be implicitly converted to int it won't compile.

The ternary operator is just for convenience, shorthand for an if statement. But in this case it's evidently not convenient, so there's no benefit to using it or writing extra code in other places so that you can use it.

This would be clearer:

```<code>int n;
if(list!=null)
    n = list.Count;
else
    DoSomethingAndThrowException(new NullReferenceException("list"));
</code>```

Better yet,

```<code>if(list==null) DoSomethingAndThrowException(new NullReferenceException("list"));
var n = list.Count;
</code>```

This would be even more explicit and clear:

```<code>if(list==null)
{
    DoSomething();
    throw new NullReferenceException("list");
}
var n = list.Count();
</code>```

It may seem like splitting hairs, but cases like these it's often better to follow the typical conventions than to do something creative that works the same way. The execution is the same, but someone reading the code later could spend ten extra seconds trying to figure out what's going on.

Body:
In C# 7 it is possible to raise an exception inside an expression:

int n = list != null ? list.Count : throw new NullReferenceException("list");

In this position, the throw expression can substitute an expression of any type.

Now I want to define a function that executes some action before raising an exception:

??? DoSomethingAndThrowException(Exception e)
{
    MessageBox.Show("Prepare for an exception!");
    throw e;
}

What would be the return type of such function, so that it can be used in the same places as the original throw expression:

int n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));

There's the option to declare it as a generic method:

T DoSomethingAndThrowException<T>(Exception e) {...}

But this seems cumbersome, as the generic type doesn't occur anywhere in the function body. Is this the only way to do it, or is there some type I don't know of, and which is assignable to any type (an "anti-object" type, so to speak)?

Body:
The ternary operator won't compile unless both expressions return the same type or there's a conversion from one type to the other. So it doesn't really matter what the type of the throw expression is. Unless DoSomethingAndThrowException returns int or something which can be implicitly converted to int it won't compile.

The ternary operator is just for convenience, shorthand for an if statement. But in this case it's evidently not convenient, so there's no benefit to using it or writing extra code in other places so that you can use it.

This would be clearer:

int n;
if(list!=null)
    n = list.Count;
else
    DoSomethingAndThrowException(new NullReferenceException("list"));

Better yet,

if(list==null) DoSomethingAndThrowException(new NullReferenceException("list"));
var n = list.Count;

This would be even more explicit and clear:

if(list==null)
{
    DoSomething();
    throw new NullReferenceException("list");
}
var n = list.Count();

It may seem like splitting hairs, but cases like these it's often better to follow the typical conventions than to do something creative that works the same way. The execution is the same, but someone reading the code later could spend ten extra seconds trying to figure out what's going on.