eu.powet.groundcopter.views.BaseGroundCopterUI.java Source code

Java tutorial

Introduction

Here is the source code for eu.powet.groundcopter.views.BaseGroundCopterUI.java

Source

/**
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3, 29 June 2007;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3, 29 June 2007;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package eu.powet.groundcopter.views;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.List;

import org.osmdroid.DefaultResourceProxyImpl;
import org.osmdroid.ResourceProxy;
import org.osmdroid.api.IGeoPoint;
import org.osmdroid.tileprovider.IRegisterReceiver;
import org.osmdroid.tileprovider.MapTileProviderBasic;
import org.osmdroid.tileprovider.modules.INetworkAvailablityCheck;
import org.osmdroid.tileprovider.modules.NetworkAvailabliltyCheck;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.osmdroid.tileprovider.util.SimpleRegisterReceiver;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.MapController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.Overlay;

import com.mavlink.messages.common.msg_attitude;
import com.mavlink.messages.common.msg_nav_controller_output;
import com.mavlink.messages.common.msg_sys_status;

import android.app.Activity;
import android.app.AlertDialog;

import android.content.Context;
import android.content.DialogInterface;
import android.os.Vibrator;
import android.support.v4.view.GestureDetectorCompat;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.*;
import eu.powet.groundcopter.GeoPointMission;
import eu.powet.groundcopter.MapPosition;
import eu.powet.groundcopter.TrackMap;
import eu.powet.groundcopter.WaypointsUI;

import eu.powet.groundcopter.controller.IController;
import eu.powet.groundcopter.controller.Request;

import eu.powet.groundcopter.utils.FTDriver;
import eu.powet.groundcopter.utils.EventUpdaterUI;
import eu.powet.groundcopter.utils.ViewChangeListener;
import eu.powet.groundcopter.views.widgets.HUD;

/**
 * Created by jed
 * User: jedartois@gmail.com
 * Date: 08/03/12
 * Time: 16:27
 */
public class BaseGroundCopterUI extends LinearLayout {

    private Activity ctx = null;
    private IController kController;
    //ui

    private HUD hud;
    private MapView mapView;
    private MapController mapController;

    private TrackMap track;
    private MapPosition copter_position;
    private MapPosition tablet_position;
    private WaypointsUI waypoints;

    private RelativeLayout layout_hud_map;
    private LinearLayout layout_buttons;

    // buttons
    private Button bt_connect;
    private Button bt_deconnect;
    private Button bt_follow_me;
    private Button bt_request_stream;
    private Button bt_arm_disarm;
    private Button bt_display_hud;
    private Button bt_exit;
    private Button bt_set_home_location;
    private Button bt_goto_home_location;
    private Button bt_read_mission;
    private Button bt_write_mission;
    private Button bt_clean_mission;
    private Button bt_record;
    private Button bt_pilot;

    private TextView heading_error;
    private TextView bearing;
    private TextView distance;
    private TextView winddirection;

    private CheckBox baudrate_115200;
    private CheckBox baudrate_57600;

    // strings
    private final String txt_stream_start = "Start Stream";
    private final String txt_stream_stop = "Stop Stream";
    private final String txt_arm = "ARMED";
    private final String txt_disarm = "DISARMED";
    private final String txt_followme_start = "Start Follow ME";
    private final String txt_followme_stop = "Stop Follow ME";

    private final String txt_auto = "Dmarrer la Mission";
    private final String txt_manuel = "Stopper la Mission";

    // states
    private boolean b_display_hud = false;
    private boolean b_request_stream = true;
    private boolean b_copter_is_armed = false;
    private boolean pilot_auto = false;
    private boolean b_copter_is_followingme = false;
    private boolean b_copter_record = false;

    public BaseGroundCopterUI(IController kController) {
        super(kController.getCurrentActivity());
        ctx = kController.getCurrentActivity();
        this.kController = kController;

        copter_position = new MapPosition(ctx, MapPosition.Type.Quadcopter);
        tablet_position = new MapPosition(ctx, MapPosition.Type.User);

        init_gui();
        init_buttons();
        init_map();
        init_hud();
        init_callbacks();

        addView(layout_buttons);
        layout_hud_map.addView(mapView);
        layout_hud_map.addView(hud);
        addView(layout_hud_map);

        // 
        kController.getViewsmanager().addEventListener(new ViewChangeListener() {
            @Override
            public void update(EventUpdaterUI evt) {

                switch (evt.getReq()) {

                case HEARTBEAT:

                    break;

                case UPDATE_IA_INFO:

                    msg_nav_controller_output infos = (msg_nav_controller_output) evt.getData();

                    bearing.setText("Heading  " + infos.nav_bearing);
                    bearing.setText("Target Heading  " + infos.target_bearing);
                    heading_error.setText("Heading error  " + infos.xtrack_error);
                    winddirection.setText("Wind " + infos.nav_roll);
                    distance.setText("Distance " + infos.wp_dist);

                    break;

                case ENABLE_BUTTONS:
                    enable_buttons();
                    break;

                case DISABLE_BUTTONS:
                    disable_buttons();
                    break;
                case DISABLE_HUD:
                    display_hud(false);
                    break;

                case ANIMATE_TO_MAP_WAYPOINT:
                    mapController.animateTo((IGeoPoint) evt.getData());
                    break;

                case ENABLE_HUD:
                    display_hud(true);
                    break;

                case UPDATE_HUD_ALTITUDE:
                    hud.setAltitude((Float) evt.getData());
                    break;

                case UPDATE_HUD_GPSFIX:
                    hud.setGPSFix(evt.getData().toString());

                    break;

                case UPDATE_FLIGHTDATA:
                    msg_attitude t = (msg_attitude) evt.getData();
                    hud.newFlightData(t.roll, t.pitch, t.yaw);

                    break;

                case ADD_TRACK:
                    track.addPoint((GeoPoint) evt.getData());
                    break;

                case SET_USER_POSITION:
                    tablet_position.setPositiongps((GeoPointMission) evt.getData());
                    break;
                case SET_DRONE_POSITION:
                    copter_position.setPositiongps((GeoPointMission) evt.getData());
                    break;
                case SYS_STATUS:
                    msg_sys_status t1 = (msg_sys_status) evt.getData();
                    hud.setbatteryMVolt(t1.voltage_battery);
                    hud.setBatteryRemaining(t1.battery_remaining);
                    break;
                case CLEAN_TRACK:
                    track.clean();
                    break;

                case UPDATE_MAP:

                    mapView.invalidate();
                    break;

                case IS_ARMED:
                    hud.setNavMode(txt_arm);
                    b_copter_is_armed = false;
                    bt_arm_disarm.setText("SET " + txt_disarm);
                    break;

                case IS_DISARMED:
                    hud.setNavMode(txt_disarm);
                    b_copter_is_armed = true;
                    bt_arm_disarm.setText("SET " + txt_arm);
                    break;
                }
            }

        });
    }

    public void init_gui() {
        setOrientation(LinearLayout.VERTICAL);

    }

    public void init_buttons() {

        // Buttons 
        bt_connect = new Button(ctx);
        bt_connect.setText("Connect");
        bt_deconnect = new Button(ctx);
        bt_deconnect.setText("Disconnect");
        bt_deconnect.setEnabled(false);
        bt_follow_me = new Button(ctx);
        bt_follow_me.setText(txt_followme_start);
        bt_follow_me.setEnabled(false);
        bt_request_stream = new Button(ctx);
        bt_request_stream.setText(txt_stream_start);
        bt_request_stream.setEnabled(false);
        bt_display_hud = new Button(ctx);
        bt_display_hud.setText("Disable HUD");
        bt_arm_disarm = new Button(ctx);
        bt_arm_disarm.setText(txt_disarm);
        bt_exit = new Button(ctx);
        bt_exit.setText("Quitter");
        bt_set_home_location = new Button(ctx);
        bt_set_home_location.setText("Set Home");
        bt_goto_home_location = new Button(ctx);
        bt_goto_home_location.setText("Go to Home");
        bt_read_mission = new Button(ctx);
        bt_read_mission.setText("Tlcharger la Mission");
        bt_write_mission = new Button(ctx);
        bt_write_mission.setText("Envoyer la Mission");
        bt_clean_mission = new Button(ctx);
        bt_clean_mission.setText("Effacer la Mission");
        bt_record = new Button(ctx);
        bt_record.setText("Start Record");

        heading_error = new TextView(ctx);

        heading_error.setText("0");
        bearing = new TextView(ctx);
        bearing.setText("0");
        distance = new TextView(ctx);
        distance.setText("0");
        winddirection = new TextView(ctx);
        winddirection.setText("0");

        bt_pilot = new Button(ctx);
        bt_pilot.setText(txt_auto);

        baudrate_115200 = new CheckBox(ctx);
        baudrate_115200.setText("115200");
        baudrate_115200.setChecked(true);
        baudrate_57600 = new CheckBox(ctx);
        baudrate_57600.setText("57600");

        layout_buttons = new LinearLayout(ctx);
        layout_buttons.setOrientation(LinearLayout.HORIZONTAL);

        layout_buttons.addView(bt_connect);
        layout_buttons.addView(bt_deconnect);
        layout_buttons.addView(baudrate_57600);
        layout_buttons.addView(baudrate_115200);
        layout_buttons.addView(bt_pilot);

        layout_buttons.addView(bt_display_hud);
        //layout_buttons.addView(bt_request_stream);
        //   layout_buttons.addView(bt_arm_disarm);
        layout_buttons.addView(bt_read_mission);
        layout_buttons.addView(bt_write_mission);
        layout_buttons.addView(bt_clean_mission);
        //   layout_buttons.addView(bt_follow_me);
        //   layout_buttons.addView(bt_set_home_location);
        //   layout_buttons.addView(bt_goto_home_location);
        //layout_buttons.addView(bt_record);

        addView(heading_error);
        addView(bearing);
        addView(distance);
        addView(winddirection);

        layout_buttons.addView(bt_exit);

    }

    public void init_hud() {

        layout_hud_map = new RelativeLayout(ctx);
        hud = new HUD(ctx);
        hud.setMinimumHeight(100);
        hud.setMinimumWidth(100);

    }

    public void init_map() {
        IRegisterReceiver receiver = new SimpleRegisterReceiver(ctx);
        INetworkAvailablityCheck networkAvailablityCheck = new NetworkAvailabliltyCheck(ctx);
        ResourceProxy resProxy = new DefaultResourceProxyImpl(ctx);
        MapTileProviderBasic tileProvider = new MapTileProviderBasic(receiver, networkAvailablityCheck,
                TileSourceFactory.MAPQUESTOSM);
        mapView = new MapView(ctx, 256, resProxy, tileProvider);
        mapController = mapView.getController();
        mapController.setZoom(16);

        //   mapView.setBuiltInZoomControls(true);
        mapView.setMultiTouchControls(true);
        mapView.setMinimumHeight(ctx.getWindowManager().getDefaultDisplay().getHeight());
        mapView.setMinimumWidth(ctx.getWindowManager().getDefaultDisplay().getWidth());

        List<Overlay> listOfOverlays = mapView.getOverlays();
        track = new TrackMap(ctx, mapView);
        waypoints = new WaypointsUI(ctx, kController);
        listOfOverlays.add(copter_position);
        listOfOverlays.add(tablet_position);
        listOfOverlays.add(waypoints);
        GeoPoint gPt = new GeoPoint(48.120282, -1.650592); // default location at IRISA
        mapController.setCenter(gPt);

    }

    public void init_callbacks() {

        final GestureDetectorCompat mGestureDetector2 = new GestureDetectorCompat(ctx,
                new GestureDetector.OnGestureListener() {

                    @Override
                    public boolean onSingleTapUp(MotionEvent e) {
                        // TODO Auto-generated method stub
                        return false;
                    }

                    @Override
                    public void onShowPress(MotionEvent e) {
                        // TODO Auto-generated method stub

                    }

                    @Override
                    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                        // TODO Auto-generated method stub
                        return false;
                    }

                    @Override
                    public void onLongPress(final MotionEvent e) {
                        ctx.runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                System.out.println(e.toString());

                                GeoPoint m = (GeoPoint) mapView.getProjection().fromPixels(e.getX(), e.getY());

                                GeoPointMission wp = new GeoPointMission(m, 0);
                                kController.handleMessage(Request.ADD_WAYPOINT, wp);

                                Vibrator v = (Vibrator) ctx.getSystemService(Context.VIBRATOR_SERVICE);
                                // Vibrate for 500 milliseconds
                                v.vibrate(100);

                            }
                        });

                    }

                    @Override
                    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                        // TODO Auto-generated method stub
                        return false;
                    }

                    @Override
                    public boolean onDown(MotionEvent e) {
                        // TODO Auto-generated method stub
                        return false;
                    }
                });

        mapView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent e) {
                return mGestureDetector2.onTouchEvent(e);
            }

        });
        bt_read_mission.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {
                kController.handleMessage(Request.CLEAR_UI_WAYPOINTS);
                kController.handleMessage(Request.READ_WAYPOINTS);
            }

        });
        bt_write_mission.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {
                kController.handleMessage(Request.WRITE_WAYPOINTS);
            }

        });

        bt_clean_mission.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {
                kController.handleMessage(Request.DELETE_WAYPOINTS);
            }

        });

        bt_record.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (b_copter_record) {
                    b_copter_record = false;
                    kController.handleMessage(Request.DISABLE_LOG);
                    bt_record.setText("Start Record");
                } else {
                    b_copter_record = true;
                    kController.handleMessage(Request.ENABLE_LOG);
                    bt_record.setText("Stop Record");
                }
            }
        });

        bt_set_home_location.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {

                /*MAV_CMD_DO_SET_HOME   Changes the home location either to the current location or a specified location.
                   Mission Param #1   Use current (1=use current location, 0=use specified location)
                   Mission Param #2   Empty
                   Mission Param #3   Empty
                   Mission Param #4   Empty
                   Mission Param #5   Latitude
                   Mission Param #6   Longitude
                   Mission Param #7   Altitude
                    
                    
                double lat =   48.727209;
                double lon =  -2.00267;
                int  alt = 15;
                GeoPointMission here = new GeoPointMission(new GeoPoint(lat, lon,alt));
                    
                    
                   MavlinkHelper.flyhere(mavlink, here);
                    
                 */

            }

        });

        bt_goto_home_location.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {
                DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        switch (which) {
                        case DialogInterface.BUTTON_POSITIVE:

                            kController.handleMessage(Request.RETURN_TO_LAUNCH);

                            break;
                        }
                    }
                };

                AlertDialog.Builder builder = new AlertDialog.Builder(ctx);

                builder.setMessage("Are you sure to go to home?").setPositiveButton("Yes", dialogClickListener)
                        .setNegativeButton("No", dialogClickListener).show();

            }

        });

        bt_request_stream.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (b_request_stream) {
                    kController.handleMessage(Request.START_STREAM);
                    b_request_stream = false;
                    bt_request_stream.setText(txt_stream_stop);
                } else {
                    b_request_stream = true;
                    kController.handleMessage(Request.STOP_STREAM);
                    bt_request_stream.setText(txt_stream_start);
                }
            }

        });
        bt_display_hud.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (b_display_hud) {
                    kController.handleMessage(Request.ENABLE_HUD);
                    b_display_hud = false;
                } else {
                    b_display_hud = true;
                    kController.handleMessage(Request.DISABLE_HUD);
                }

            }

        });

        bt_connect.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {
                bt_connect.setEnabled(false);
                bt_deconnect.setEnabled(true);

                baudrate_57600.setEnabled(false);
                baudrate_115200.setEnabled(false);

                kController.handleMessage(Request.CONNECT);
            }

        });

        bt_deconnect.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {

                bt_connect.setEnabled(true);
                bt_deconnect.setEnabled(false);
                baudrate_57600.setEnabled(true);
                baudrate_115200.setEnabled(true);
                kController.handleMessage(Request.STOP_STREAM);
                kController.handleMessage(Request.DISABLE_BUTTONS);
                kController.handleMessage(Request.DISCONNECT);
            }

        });

        bt_pilot.setOnClickListener(new OnClickListener() {

            @Override

            public void onClick(View v) {

                if (pilot_auto == false) {

                    kController.handleMessage(Request.PILOT_AUTO);
                    pilot_auto = true;
                    bt_pilot.setText(txt_manuel);
                } else {
                    kController.handleMessage(Request.PILOT_MANUEL);
                    pilot_auto = false;
                    bt_pilot.setText(txt_auto);

                }
                /*
                DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
                   @Override
                   public void onClick(DialogInterface dialog, int which) {
                      switch (which){
                      case DialogInterface.BUTTON_POSITIVE:
                    
                     
                          
                 break;
                    
                      case DialogInterface.BUTTON_NEGATIVE:
                 //No button clicked
                 break;
                      }
                   }
                };
                    
                AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
                    
                builder.setMessage("Confirmez vous le changement de mode ?").setPositiveButton("Yes", dialogClickListener)
                .setNegativeButton("No", dialogClickListener).show();
                */

            }

        });

        bt_exit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                kController.handleMessage(Request.DISCONNECT);
                kController.handleMessage(Request.EXIT);
            }

        });
        baudrate_115200.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                baudrate_57600.setChecked(false);
                baudrate_115200.setChecked(true);

                kController.handleMessage(Request.CHANGE_BAUDRATE, FTDriver.BAUD115200);

            }

        });

        baudrate_57600.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                baudrate_115200.setChecked(false);
                baudrate_57600.setChecked(true);

                kController.handleMessage(Request.CHANGE_BAUDRATE, FTDriver.BAUD57600);
            }

        });

        bt_arm_disarm.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                /*
                 *           In a MAVLINK_MSG_ID_COMMAND_LONG
                 A MAV_CMD of type MAV_CMD_COMPONENT_ARM_DISARM
                 with component id MAV_COMP_ID_SYSTEM_CONTROL = 250,
                 uses param index 1 to specify an arm/disarm motors event: 1 to arm,
                 0 to disarm
                   //MAVLINK_MSG_ID_COMMAND_LONG*/
                DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        switch (which) {
                        case DialogInterface.BUTTON_POSITIVE:

                            if (!b_copter_is_armed) {
                                kController.handleMessage(Request.SET_ARMED);
                            } else {
                                kController.handleMessage(Request.SET_DISARMED);
                            }
                            break;

                        case DialogInterface.BUTTON_NEGATIVE:
                            //No button clicked
                            break;
                        }
                    }
                };

                AlertDialog.Builder builder = new AlertDialog.Builder(ctx);

                builder.setMessage("Are you sure to ARM/DISARM ?").setPositiveButton("Yes", dialogClickListener)
                        .setNegativeButton("No", dialogClickListener).show();

            }

        });

        bt_follow_me.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                if (!b_copter_is_followingme) {

                    AlertDialog.Builder alert = new AlertDialog.Builder(ctx);

                    alert.setTitle("Follow Me ");
                    alert.setMessage("Set Altitude");

                    final EditText input_altitude = new EditText(ctx);

                    input_altitude.setText("10");

                    alert.setView(input_altitude);
                    alert.setPositiveButton("ok", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            try {
                                int altitude = Integer.parseInt(input_altitude.getText().toString());
                                kController.handleMessage(Request.DELETE_WAYPOINTS);
                                kController.handleMessage(Request.SET_FOLLOWME_ALTITUDE, altitude);
                                kController.handleMessage(Request.START_FOLLOWME);
                                bt_follow_me.setText(txt_followme_stop);
                                b_copter_is_followingme = true;
                            } catch (Exception e) {
                                kController.handleMessage(Request.TOAST_MSG, "Error ", e.getMessage());
                            }

                        }
                    });
                    alert.setNegativeButton("cancel", new DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // TODO Auto-generated method stub

                        }

                    });
                    alert.show();

                } else {
                    kController.handleMessage(Request.STOP_FOLLOWME);
                    bt_follow_me.setText(txt_followme_start);
                    b_copter_is_followingme = false;
                }

            }

        });
    }

    public void display_hud(boolean enable) {
        if (enable) {
            hud.setVisibility(0);
            bt_display_hud.setText("Disable HUD");

        } else {
            hud.setVisibility(4);
            bt_display_hud.setText("Enable HUD");
        }

    }

    public void enable_buttons() {
        bt_follow_me.setEnabled(true);
        bt_request_stream.setEnabled(true);
        bt_arm_disarm.setEnabled(true);
        bt_set_home_location.setEnabled(true);
        bt_read_mission.setEnabled(true);
        bt_write_mission.setEnabled(true);
        bt_clean_mission.setEnabled(true);
        bt_goto_home_location.setEnabled(true);
        bt_pilot.setEnabled(true);

    }

    public void disable_buttons() {
        bt_deconnect.setEnabled(false);
        bt_follow_me.setEnabled(false);
        bt_request_stream.setEnabled(false);
        bt_arm_disarm.setEnabled(false);
        bt_set_home_location.setEnabled(false);
        bt_read_mission.setEnabled(false);
        bt_write_mission.setEnabled(false);
        bt_clean_mission.setEnabled(false);
        bt_goto_home_location.setEnabled(false);
        bt_pilot.setEnabled(false);
        baudrate_57600.setEnabled(true);
        baudrate_115200.setEnabled(true);
        bt_connect.setEnabled(true);
    }

}