public class Tarsier extends Application {

    private static final String TARSIER_TAG = "TarsierApp";
    private static Tarsier app;

    private UserPreferences mUserPreferences;
    private Database mDatabase;
    private EventHandler mEventHandler;

    private PeerRepository mPeerRepository;
    private ChatRepository mChatRepository;
    private MessageRepository mMessageRepository;
    private UserRepository mUserRepository;

    private Notifications mNotifications;

    private Bus mEventBus;

    private MessagingManager mMessagingManager;

    public static Tarsier app() {
        return app;
    }

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

        app = this;

        initDatabase();
        initNetwork();
        initNotifications();
    }

    private void initNotifications() {
        mNotifications = new Notifications(mEventBus, getApplicationContext());
        mNotifications.register();
    }

    private void initDatabase() {
        mDatabase = new Database(getApplicationContext());
        mEventHandler = new EventHandler();
        mEventHandler.register();

        // new FillDatabase().execute();
    }

    public void initNetwork() {
        Log.d(TARSIER_TAG, "Network initialized");
        WifiP2pManager mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        WifiP2pManager.Channel mWifiP2pChannel = mWifiP2pManager.initialize(this, getMainLooper(), null);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        mMessagingManager = new MessagingManager(mWifiP2pManager, mWifiP2pChannel);
        mMessagingManager.setEventBus(getEventBus());

        registerReceiver(mMessagingManager, intentFilter);
    }

    public UserPreferences getUserPreferences() {
        if (mUserPreferences == null) {
            mUserPreferences = new UserPreferences();
        }

        return mUserPreferences;
    }

    public void setUserPreferences(UserPreferences userPreferences) {
        mUserPreferences = userPreferences;
    }

    public MessagingManager getMessagingManager() {
        return mMessagingManager;
    }

    public void setMessagingManager(MessagingManager messagingManager) {
        mMessagingManager = messagingManager;
    }

    public Database getDatabase() {
        return mDatabase;
    }

    public void setDatabase(Database database) {
        mDatabase = database;
    }

    public PeerRepository getPeerRepository() {
        if (mPeerRepository == null) {
            mPeerRepository = new PeerRepository(getDatabase());
        }

        return mPeerRepository;
    }

    public void setPeerRepository(PeerRepository peerRepository) {
        mPeerRepository = peerRepository;
    }

    public ChatRepository getChatRepository() {
        if (mChatRepository == null) {
            mChatRepository = new ChatRepository(getDatabase());
        }

        return mChatRepository;
    }

    public void setChatRepository(ChatRepository chatRepository) {
        mChatRepository = chatRepository;
    }

    public MessageRepository getMessageRepository() {
        if (mMessageRepository == null) {
            mMessageRepository = new MessageRepository(getDatabase());
        }

        return mMessageRepository;
    }

    public void setMessageRepository(MessageRepository messageRepository) {
        mMessageRepository = messageRepository;
    }

    public Bus getEventBus() {
        if (mEventBus == null) {
            mEventBus = new MainThreadBus();
        }

        return mEventBus;
    }

    public void setEventBus(Bus eventBus) {
        mEventBus = eventBus;
    }

    public UserRepository getUserRepository() {
        if (mUserRepository == null) {
            mUserRepository = new UserRepository();
        }

        return mUserRepository;
    }

    public void setUserRepository(UserRepository userRepository) {
        mUserRepository = userRepository;
    }

    /**
     * FillDatabase is the class that fill the database with fictional data
     */
    private class FillDatabase extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            while (!Tarsier.app().getDatabase().isReady()) { }

            if (getUserPreferences().isDatabaseEmpty()) {
                // Pass true to force clear and populate the database,
                // even if there's already some data.
                FillDatabaseWithFictionalData.populate(false);
                getUserPreferences().setIsDatabaseEmpty(false);
            }

            return null;
        }
    }
} public class EC25519 {
    private static final int ECC_KEY_LENGTH = 32;

    private static final int ECC_SIGNATURE_RANDOM_BYTES_NUM = 64;

    static {
        System.loadLibrary("curve25519");
        try {
            mRandom = SecureRandom.getInstance("SHA1PRNG");
        } catch (NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
    }

    private static SecureRandom mRandom;

    private static native byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic);
    private static native byte[] generatePublicKey(byte[] privateKey);
    private static native byte[] generatePrivateKey(byte[] random);

    private static native byte[]  calculateSignature(byte[] random, byte[] privateKey, byte[] message);
    private static native boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature);


    /**
     * Generates a new Curve25519 keys (Montgomery space)
     * @return Generated key pair
     */
    public static KeyPair generateKeyPair() {
        byte[] privateKey = generatePrivateKey();
        byte[] publicKey  = generatePublicKey(privateKey);

        return new KeyPair(publicKey, privateKey);
    }

    private static byte[] generatePrivateKey() {
        byte[] privateKey = new byte[ECC_KEY_LENGTH];
        mRandom.nextBytes(privateKey);

        return generatePrivateKey(privateKey);
    }

    private static byte[] getRandom(int size) {
        try {
            byte[] random = new byte[size];
            SecureRandom.getInstance("SHA1PRNG").nextBytes(random);

            return random;
        } catch (NoSuchAlgorithmException e) {
            throw new AssertionError(e);
        }
    }

    /**
     * Computes the shared secret on the Curve2119 curve
     * @param ourPrivate  Our private key
     * @param theirPublic Their public key
     * @return Curve25519 Shared secret
     */
    public static byte[] calculateCurve25519KeyAgreement(byte[] ourPrivate, byte[] theirPublic) {
        if (ourPrivate.length != ECC_KEY_LENGTH || theirPublic.length != ECC_KEY_LENGTH) {
            throw new InvalidParameterException();
        }
        return calculateAgreement(ourPrivate, theirPublic);
    }

    /**
     * Signs the data with Curve25519 keys. Keys are transposed from a Montgomery to an Edwards space
     * to enable us to produce a ed25519 signature output.
     * @param privateKey Curve25519 key
     * @param message    Message to be signed
     * @return Signed message
     * @throws InvalidParameterException
     */
    public static byte[] calculateEd25519Signature(byte[] privateKey, byte[] message) throws InvalidParameterException {
        if (privateKey.length != ECC_KEY_LENGTH) {
            throw new InvalidParameterException();
        }
        byte[] randomBytes = getRandom(ECC_SIGNATURE_RANDOM_BYTES_NUM);
        return calculateSignature(randomBytes, privateKey, message);
    }

    public static boolean verifyEd25519Signature(byte[] publicKey, byte[] message, byte[] signature)
            throws InvalidParameterException {

        if (publicKey.length != ECC_KEY_LENGTH) {
            throw new InvalidParameterException();
        }
        return verifySignature(publicKey, message, signature);
    }
} public class Peer implements ByteArraySerializable, Serializable {

    private static final int CASE_THREE = 3;
    private static final int CASE_FOUR = 4;
    private static final int NUMBER_OF_PLACEHOLDERS = 5;

    private long mId;
    private PublicKey mPublicKey;
    private String mUserName;
    private String mStatusMessage;
    private boolean mOnline;
    // not used yet
    private String mPicturePath;

    public Peer() {
        mId = -1;
    }

    public Peer(String name) {
        this();
        mUserName = name;
    }

    public Peer(String name, PublicKey publicKey) {
        this();
        mUserName = name;
        mPublicKey = publicKey;
    }

    /**
     * Create a new peer by unpacking its data from a ProtocolBuffer byte array.
     *
     * @param data The ProtocolBuffer byte array.
     * @throws InvalidProtocolBufferException
     */
    public Peer(byte[] data) throws InvalidProtocolBufferException {
        this();
        TarsierWireProtos.Peer peer = TarsierWireProtos.Peer.parseFrom(data);
        mUserName = peer.getName();
        mPublicKey = new PublicKey(peer.getPublicKey().toByteArray());
    }

    public long getId() {
        return mId;
    }

    public void setId(long id) {
        mId = id;
    }

    public PublicKey getPublicKey() {
        return mPublicKey;
    }

    public void setPublicKey(PublicKey publicKey) {
        mPublicKey = publicKey;
    }

    public String getUserName() {
        return mUserName;
    }

    public void setUserName(String userName) {
        this.mUserName = userName;
    }

    public String getStatusMessage() {
        return mStatusMessage;
    }

    public void setStatusMessage(String statusMessage) {
        this.mStatusMessage = statusMessage;
    }

    public void setOnline(boolean online) {
        mOnline = online;
    }

    public boolean isOnline() {
        return mOnline;
    }

    /**
     * As the network protocol cannot transfer profile pictures,
     * we need this dirty hack to show different profile pictures for up to 5 peers.
     *
     * @return A bitmap representation of a profile picture.
     */
    public Bitmap getPicture() {
        int mod5 = (int) this.getId() % NUMBER_OF_PLACEHOLDERS;

        switch (mod5) {
            case 0:
                return BitmapFactory.decodeResource(Tarsier.app().getResources(),
                        R.drawable.tarsier_placeholder);
            case 1:
                return BitmapFactory.decodeResource(Tarsier.app().getResources(),
                        R.drawable.tarsier1_placeholder);
            case 2:
                return BitmapFactory.decodeResource(Tarsier.app().getResources(),
                        R.drawable.tarsier2_placeholder);
            case CASE_THREE:
                return BitmapFactory.decodeResource(Tarsier.app().getResources(),
                        R.drawable.tarsier3_placeholder);
            case CASE_FOUR:
                return BitmapFactory.decodeResource(Tarsier.app().getResources(),
                        R.drawable.tarsier4_placeholder);
            default:
                return BitmapFactory.decodeResource(Tarsier.app().getResources(),
                        R.drawable.tarsier_placeholder);
        }
    }

    /**
     * Check whether this peer is the actual user of the app, by comparing its public
     * key with the public key stored in the UserPreferences.
     *
     * @return true if they match, false otherwise
     */
    public boolean isUser() {
        return Tarsier.app().getUserRepository().getUser().getPublicKey().equals(getPublicKey());
    }

    public void setPicturePath(String picturePath) {
        mPicturePath = picturePath;
    }

    public String getPicturePath() {
        return mPicturePath;
    }

    public byte[] toByteArray() {
        TarsierWireProtos.Peer.Builder peerBuilder = TarsierWireProtos.Peer.newBuilder();
        peerBuilder.setName(mUserName);
        peerBuilder.setPublicKey(ByteString.copyFrom(mPublicKey.getBytes()));

        return peerBuilder.build().toByteArray();
    }
} public class PublicKey implements Serializable, ByteArraySerializable {

    private byte[] mBytes;

    public PublicKey(byte[] bytes) {
        mBytes = bytes;
    }

    public PublicKey(String base64Encoded) {
        mBytes = Base64.decode(base64Encoded, Base64.NO_WRAP);
    }

    public byte[] getBytes() {
        return mBytes;
    }
    public byte[] toByteArray() {
        return mBytes;
    }

    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }

        // noinspection SimplifiableIfStatement
        if (that == null || ((Object) this).getClass() != that.getClass()) {
            return false;
        }

        return Arrays.equals(mBytes, ((PublicKey) that).getBytes());
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(mBytes);
    }

    public String base64Encoded() {
        return Base64.encodeToString(mBytes, Base64.NO_WRAP);
    }

    public String toString() {
        return base64Encoded();
    }

} public class ConnectedEvent {

    private final boolean mIsGroupOwner;

    public ConnectedEvent(boolean isGroupOwner) {
        mIsGroupOwner = isGroupOwner;
    }

    public boolean isGroupOwner() {
        return mIsGroupOwner;
    }
} public class ReceivedChatroomPeersListEvent {

    private final List<Peer> mPeers;

    public ReceivedChatroomPeersListEvent(List<Peer> peers) {
        mPeers = peers;
    }

    public List<Peer> getPeers() {
        return mPeers;
    }
} public class ReceivedMessageEvent {

    private final String mMessage;

    private final Peer mSender;

    private final boolean mIsPrivate;

    public ReceivedMessageEvent(String message, Peer sender, boolean isPrivate) {
        mMessage = message;
        mSender = sender;
        mIsPrivate = isPrivate;
    }

    public String getMessage() {
        return mMessage;
    }

    public Peer getSender() {
        return mSender;
    }

    public boolean isPrivate() {
        return mIsPrivate;
    }

    public boolean isPublic() {
        return !isPrivate();
    }
} public class ReceivedNearbyPeersListEvent {

    private final List<WifiP2pDevice> mPeers;

    public ReceivedNearbyPeersListEvent(List<WifiP2pDevice> peers) {
        mPeers = peers;
    }

    public List<WifiP2pDevice> getPeers() {
        return mPeers;
    }
} public class UserPreferences extends AbstractPreferences {

    public static final String PROFILE_PICTURE_NAME = "profile_picture_temp.png";
    private KeyPair mKeyPair;

    @Override
    protected String getPreferencesFile() {
        return Tarsier.app().getString(R.string.pref_filename);
    }

    public KeyPair getKeyPair() {
        if (mKeyPair == null) {
            if (!hasPublicKey()) {
                mKeyPair = generateKeyPair();
            } else {
                mKeyPair = fetchKeyPair();
            }
        }

        return mKeyPair;
    }

    /**
     * Generate a KeyPair and store it in the user preferences
     */
    private KeyPair generateKeyPair() {
        KeyPair keyPair = EC25519.generateKeyPair();

        setString(R.string.pref_public_key, keyPair.getBase64EncodedPublicKey());
        setString(R.string.pref_private_key, keyPair.getBase64EncodedPrivateKey());

        return keyPair;
    }

    private KeyPair fetchKeyPair() {
        String publicKey = getString(R.string.pref_public_key);
        String privateKey = getString(R.string.pref_private_key);

        return new KeyPair(publicKey, privateKey);
    }

    private boolean hasPublicKey() {
        String publicKey = getString(R.string.pref_public_key);

        return publicKey != null && !publicKey.equals("");
    }

    public String getUsername() {
        return getString(R.string.pref_username);
    }

    public void setUsername(String username) {
        setString(R.string.pref_username, username);
    }

    public String getStatusMessage() {
        return getString(R.string.pref_status_message);
    }

    public void setStatusMessage(String statusMessage) {
        setString(R.string.pref_status_message, statusMessage);
    }

    public String getPicturePath() {
        return Environment.getExternalStorageDirectory()
                + "/" + PROFILE_PICTURE_NAME;
    }

    public Uri getPictureUri() {
        return Uri.parse(getPicturePath());
    }

    public boolean isDatabaseEmpty() {
        return getBoolean(R.string.pref_database_filled, true);
    }

    public void setIsDatabaseEmpty(boolean isDatabaseEmpty) {
        setBoolean(R.string.pref_database_filled, isDatabaseEmpty);
    }
} public class HomeActivity extends Activity {

    private static final String TAG = "HomeActivity";
    private EditText mUsername;
    private EditText mStatusMessage;
    private ImageView mProfilePicture;
    private UserPreferences mUserPreferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        mUserPreferences = Tarsier.app().getUserPreferences();

        mUsername = (EditText) findViewById(R.id.username_home);
        mStatusMessage = (EditText) findViewById(R.id.status_message_home);
        mProfilePicture = (ImageView) findViewById(R.id.picture);

        if (!mUserPreferences.getUsername().equals("")
                && !mUserPreferences.getStatusMessage().equals("")) {

            this.finish();
            Intent chatListIntent = new Intent(this, ChatListActivity.class);
            startActivity(chatListIntent);
        }

        Button start = (Button) findViewById(R.id.lets_chat);
        start.setClickable(true);

        refreshFields();

        ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(false);
            actionBar.setDisplayShowHomeEnabled(false);
        }

    }

    public void onClickLetsChat(View view) {
        //create intent with username and launch the list of rooms
        this.validateUsername();
        this.validateStatusMessage();

        if (validateFields()) {
            saveProfileInfos();
            //remove this activity from the stack.
            this.finish();
            Intent nearbyIntent = new Intent(this, NearbyListActivity.class);
            nearbyIntent.putExtra(NearbyListActivity.EXTRA_FROM_HOME_KEY, true);
            startActivity(nearbyIntent);
        }
    }

    /**
     * Check if the username's length is within the bounds, and
     * set an error message otherwise.
     *
     * @return Whether it is valid or not
     */
    private boolean validateUsername() {
        return new UsernameValidator().validate(mUsername);
    }

    /**
     * Check if the status message's length is within the bounds, and
     * set an error message otherwise.
     *
     * @return Whether it is valid or not
     */
    private boolean validateStatusMessage() {
        return new StatusMessageValidator().validate(mStatusMessage);
    }

    /**
     * Validate the username and status message.
     *
     * @return Whether or not both are valid.
     */
    private boolean validateFields() {
        return validateUsername() && validateStatusMessage();
    }

    public void onClickAddPicture(View view) {
        //launch Activity to have the user choose the picture
        Intent picture = new Intent(this, AddProfilePictureActivity.class);
        this.startActivity(picture);
    }

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

        refreshFields();
    }

    private void refreshFields() {
        String username = mUserPreferences.getUsername();
        mUsername.setText(username);

        String statusMessage = mUserPreferences.getStatusMessage();
        mStatusMessage.setText(statusMessage);

        // check existence of picture profile. put default if non existent.
        String filePath = mUserPreferences.getPicturePath();
        Bitmap profilePicture = BitmapFromPath.getBitmapFromPath(this, filePath);
        mProfilePicture.setImageBitmap(profilePicture);
    }

    private void saveProfileInfos() {
        mUserPreferences.setUsername(mUsername.getText().toString());
        mUserPreferences.setStatusMessage(mStatusMessage.getText().toString());
    }

}
import android.net.wifi.p2p.WifiP2pDevice;
import android.util.Log;
import com.squareup.otto.Bus;
import java.util.ArrayList;
import java.util.List;
import ch.tarsier.tarsier.R;
import ch.tarsier.tarsier.Tarsier;
import ch.tarsier.tarsier.crypto.EC25519;
import ch.tarsier.tarsier.domain.model.Peer;
import ch.tarsier.tarsier.domain.model.value.PublicKey;
import ch.tarsier.tarsier.event.ConnectedEvent;
import ch.tarsier.tarsier.event.ReceivedChatroomPeersListEvent;
import ch.tarsier.tarsier.event.ReceivedMessageEvent;
import ch.tarsier.tarsier.event.ReceivedNearbyPeersListEvent;
import ch.tarsier.tarsier.prefs.UserPreferences;
import ch.tarsier.tarsier.ui.activity.HomeActivity;
import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView;
import static com.google.android.apps.common.testing.ui.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
import static com.google.android.apps.common.testing.ui.espresso.Espresso.pressBack;
import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.clearText;
import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click;
import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.closeSoftKeyboard;
import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.typeText;
import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withContentDescription;
import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId;
import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
package ch.tarsier.tarsier.test;






/**
 * This test aims to visit every activity in the app and verify a usual use of the app
 *
 * @author benpac
 */
public class EndToEndTest extends TarsierTestCase<HomeActivity> {

    private UserPreferences mUserPrefMock;
    private UserPreferences mUserPrefStore;

    private final static String EMPTY_STRING = "";
    private final static int SLEEP_TIME = 1000;
    private Bus mEventBus;
    private List<WifiP2pDevice> listWifiP2pDevices;
    private List<Peer> listPeers;

    public EndToEndTest() {
        super(HomeActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        mEventBus = Tarsier.app().getEventBus();

        //store old user pref
        mUserPrefStore = Tarsier.app().getUserPreferences();
        //mock UserPreferences
        mUserPrefMock = mock(UserPreferences.class);
        when(mUserPrefMock.getKeyPair()).thenReturn(mUserPrefStore.getKeyPair());
        when(mUserPrefMock.getPicturePath()).thenReturn(mUserPrefStore.getPicturePath());
        when(mUserPrefMock.getPictureUri()).thenReturn(mUserPrefStore.getPictureUri());
        when(mUserPrefMock.getStatusMessage()).thenReturn(EMPTY_STRING);
        when(mUserPrefMock.getUsername()).thenReturn(EMPTY_STRING);
        Tarsier.app().setUserPreferences(mUserPrefMock);

        //create list of WifiP2pDevices
        setListWifiP2pDevices();
        setListPeers();

        //Get activity AFTER mocking components...
        getActivity();
    }

    protected void tearDown() throws Exception {
        Tarsier.app().setUserPreferences(mUserPrefStore);
        super.tearDown();
    }

    private void setListWifiP2pDevices() {
        listWifiP2pDevices = new ArrayList<>();
        WifiP2pDevice ben = new WifiP2pDevice();
        ben.deviceName = "Benpac";
        ben.status = WifiP2pDevice.AVAILABLE;
        ben.deviceAddress = "his.home";
        WifiP2pDevice gluthier = new WifiP2pDevice();
        gluthier.deviceName = "Gabriel";
        gluthier.status = WifiP2pDevice.AVAILABLE;
        gluthier.deviceAddress = "gluthier.ch";
        WifiP2pDevice amirezza = new WifiP2pDevice();
        amirezza.deviceName = "Gabriel";
        amirezza.status = WifiP2pDevice.AVAILABLE;
        amirezza.deviceAddress = "his.bed";
        listWifiP2pDevices.add(ben);
        listWifiP2pDevices.add(gluthier);
        listWifiP2pDevices.add(amirezza);
    }

    private void setListPeers() {
        listPeers = new ArrayList<>();
        Peer ben = new Peer("Benpac");
        ben.setPublicKey(new PublicKey(EC25519.generateKeyPair().getPublicKey()));
        ben.setStatusMessage("I love potatoes");
        ben.setPicturePath(mUserPrefMock.getPicturePath());
        listPeers.add(ben);
        Peer gluthier = new Peer("Gab");
        gluthier.setPublicKey(new PublicKey(EC25519.generateKeyPair().getPublicKey()));
        gluthier.setStatusMessage("I love chips");
        listPeers.add(gluthier);
        Peer amirezza = new Peer("Amirezza");
        amirezza.setPublicKey(new PublicKey(EC25519.generateKeyPair().getPublicKey()));
        amirezza.setStatusMessage("I love french fries");
        listPeers.add(amirezza);
    }

    public void testEndToEnd() {
        //setting username and status
        onView(withId(R.id.username_home)).perform(clearText(), typeText("Benpac"), closeSoftKeyboard());
        onView(withId(R.id.status_message_home)).perform(clearText(), typeText("I love SwEng!"), closeSoftKeyboard());
        onView(withId(R.id.lets_chat)).perform(click());
        //entering nearby
        //post false peers
        mEventBus.post(new ReceivedNearbyPeersListEvent(listWifiP2pDevices));
        // create chatroom
        onView(withId(R.id.create_new_chat_from_nearby)).perform(click());
        mEventBus.post(new ConnectedEvent(true));