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 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 final class User extends Peer {

    @Override
    public boolean isUser() {
        return true;
    }

    @Override
    public Bitmap getPicture() {
        return BitmapFactory.decodeFile(Tarsier.app().getUserPreferences().getPicturePath());
    }
} 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 PeerCipherException extends Exception {

} public class ByteUtils {

    public static byte[] combine(byte[] a, byte[] b) {
        byte[] result = new byte[a.length + b.length];
        System.arraycopy(a, 0, result, 0, a.length);
        System.arraycopy(b, 0, result, a.length, b.length);
        return result;
    }

    public static byte[][] split(byte[] input, int firstLength, int secondLength) {
        byte[][] parts = new byte[2][];

        parts[0] = new byte[firstLength];
        System.arraycopy(input, 0, parts[0], 0, firstLength);

        parts[1] = new byte[secondLength];
        System.arraycopy(input, firstLength, parts[1], 0, secondLength);

        return parts;
    }

    public static byte[] prependInt(int a, byte[] b) {
        byte[] prepended = new byte[1];
        prepended[0] = (byte) a;
        return combine(prepended, b);
    }
} public interface ConnectionInterface {
    List<Peer> getPeersList();

    void broadcastMessage(byte[] message);

    void sendMessage(Peer peer, byte[] message) throws PeerCipherException;
} public class MessageType {

    final public static int SERVER_SOCKET = 8888;

    final public static int MESSAGE_TYPE_HELLO = 0;

    final public static int MESSAGE_TYPE_PEER_LIST = 1;

    final public static int MESSAGE_TYPE_PRIVATE = 2;

    final public static int MESSAGE_TYPE_PUBLIC = 3;

    final public static int MESSAGE_TYPE_DISCONNECT = 10;

    public static int messageTypeFromData(byte[] data) {
        return data[0];
    }
} public final class TarsierWireProtos {

    private TarsierWireProtos() {
    }

    public static void registerAllExtensions(
            com.google.protobuf.ExtensionRegistry registry) {
    }

    public interface HelloMessageOrBuilder extends
            // @@protoc_insertion_point(interface_extends:HelloMessage)
            com.google.protobuf.MessageOrBuilder {

        /**
         * <code>required .Peer peer = 1;</code>
         */
        boolean hasPeer();

        /**
         * <code>required .Peer peer = 1;</code>
         */
        TarsierWireProtos.Peer getPeer();

        /**
         * <code>required .Peer peer = 1;</code>
         */
        TarsierWireProtos.PeerOrBuilder getPeerOrBuilder();
    }

    /**
     * Protobuf type {@code HelloMessage}
     */
    public static final class HelloMessage extends
            com.google.protobuf.GeneratedMessage implements
            // @@protoc_insertion_point(message_implements:HelloMessage)
            HelloMessageOrBuilder {

        // Use HelloMessage.newBuilder() to construct.
        private HelloMessage(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
            super(builder);
            this.unknownFields = builder.getUnknownFields();
        }

        private HelloMessage(boolean noInit) {
            this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();
        }

        private static final HelloMessage defaultInstance;

        public static HelloMessage getDefaultInstance() {
            return defaultInstance;
        }

        public HelloMessage getDefaultInstanceForType() {
            return defaultInstance;
        }

        private final com.google.protobuf.UnknownFieldSet unknownFields;

        @java.lang.Override
        public final com.google.protobuf.UnknownFieldSet
        getUnknownFields() {
            return this.unknownFields;
        }

        private HelloMessage(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            initFields();
            int mutable_bitField0_ = 0;
            com.google.protobuf.UnknownFieldSet.Builder unknownFields =
                    com.google.protobuf.UnknownFieldSet.newBuilder();
            try {
                boolean done = false;
                while (!done) {
                    int tag = input.readTag();
                    switch (tag) {
                        case 0:
                            done = true;
                            break;
                        default: {
                            if (!parseUnknownField(input, unknownFields,
                                    extensionRegistry, tag)) {
                                done = true;
                            }
                            break;
                        }
                        case 10: {
                            TarsierWireProtos.Peer.Builder subBuilder = null;
                            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                                subBuilder = peer_.toBuilder();
                            }
                            peer_ = input
                                    .readMessage(TarsierWireProtos.Peer.PARSER, extensionRegistry);
                            if (subBuilder != null) {
                                subBuilder.mergeFrom(peer_);
                                peer_ = subBuilder.buildPartial();
                            }
                            bitField0_ |= 0x00000001;
                            break;
                        }
                    }
                }
            } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                throw e.setUnfinishedMessage(this);
            } catch (java.io.IOException e) {
                throw new com.google.protobuf.InvalidProtocolBufferException(
                        e.getMessage()).setUnfinishedMessage(this);
            } finally {
                this.unknownFields = unknownFields.build();
                makeExtensionsImmutable();
            }
        }

        public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
            return TarsierWireProtos.internal_static_HelloMessage_descriptor;
        }

        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
        internalGetFieldAccessorTable() {
            return TarsierWireProtos.internal_static_HelloMessage_fieldAccessorTable
                    .ensureFieldAccessorsInitialized(
                            TarsierWireProtos.HelloMessage.class,
                            TarsierWireProtos.HelloMessage.Builder.class);
        }

        public static com.google.protobuf.Parser<HelloMessage> PARSER =
                new com.google.protobuf.AbstractParser<HelloMessage>() {
                    public HelloMessage parsePartialFrom(
                            com.google.protobuf.CodedInputStream input,
                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                            throws com.google.protobuf.InvalidProtocolBufferException {
                        return new HelloMessage(input, extensionRegistry);
                    }
                };

        @java.lang.Override
        public com.google.protobuf.Parser<HelloMessage> getParserForType() {
            return PARSER;
        }

        private int bitField0_;

        public static final int PEER_FIELD_NUMBER = 1;

        private TarsierWireProtos.Peer peer_;

        /**
         * <code>required .Peer peer = 1;</code>
         */
        public boolean hasPeer() {
            return ((bitField0_ & 0x00000001) == 0x00000001);
        }

        /**
         * <code>required .Peer peer = 1;</code>
         */
        public TarsierWireProtos.Peer getPeer() {
            return peer_;
        }

        /**
         * <code>required .Peer peer = 1;</code>
         */
        public TarsierWireProtos.PeerOrBuilder getPeerOrBuilder() {
            return peer_;
        }

        private void initFields() {
            peer_ = TarsierWireProtos.Peer.getDefaultInstance();
        }

        private byte memoizedIsInitialized = -1;

        public final boolean isInitialized() {
            byte isInitialized = memoizedIsInitialized;
            if (isInitialized == 1) {
                return true;
            }
            if (isInitialized == 0) {
                return false;
            }

            if (!hasPeer()) {
                memoizedIsInitialized = 0;
                return false;
            }
            if (!getPeer().isInitialized()) {
                memoizedIsInitialized = 0;
                return false;
            }
            memoizedIsInitialized = 1;
            return true;
        }

        public void writeTo(com.google.protobuf.CodedOutputStream output)
                throws java.io.IOException {
            getSerializedSize();
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                output.writeMessage(1, peer_);
            }
            getUnknownFields().writeTo(output);
        }

        private int memoizedSerializedSize = -1;

        public int getSerializedSize() {
            int size = memoizedSerializedSize;
            if (size != -1) {
                return size;
            }

            size = 0;
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeMessageSize(1, peer_);
            }
            size += getUnknownFields().getSerializedSize();
            memoizedSerializedSize = size;
            return size;
        }

        private static final long serialVersionUID = 0L;

        @java.lang.Override
        protected java.lang.Object writeReplace()
                throws java.io.ObjectStreamException {
            return super.writeReplace();
        }

        public static TarsierWireProtos.HelloMessage parseFrom(
                com.google.protobuf.ByteString data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.HelloMessage parseFrom(
                com.google.protobuf.ByteString data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.HelloMessage parseFrom(byte[] data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.HelloMessage parseFrom(
                byte[] data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.HelloMessage parseFrom(java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.HelloMessage parseFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.HelloMessage parseDelimitedFrom(java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input);
        }

        public static TarsierWireProtos.HelloMessage parseDelimitedFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.HelloMessage parseFrom(
                com.google.protobuf.CodedInputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.HelloMessage parseFrom(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static Builder newBuilder() {
            return Builder.create();
        }

        public Builder newBuilderForType() {
            return newBuilder();
        }

        public static Builder newBuilder(TarsierWireProtos.HelloMessage prototype) {
            return newBuilder().mergeFrom(prototype);
        }

        public Builder toBuilder() {
            return newBuilder(this);
        }

        @java.lang.Override
        protected Builder newBuilderForType(
                com.google.protobuf.GeneratedMessage.BuilderParent parent) {
            Builder builder = new Builder(parent);
            return builder;
        }

        /**
         * Protobuf type {@code HelloMessage}
         */
        public static final class Builder extends
                com.google.protobuf.GeneratedMessage.Builder<Builder> implements
                // @@protoc_insertion_point(builder_implements:HelloMessage)
                TarsierWireProtos.HelloMessageOrBuilder {

            public static final com.google.protobuf.Descriptors.Descriptor
            getDescriptor() {
                return TarsierWireProtos.internal_static_HelloMessage_descriptor;
            }

            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internalGetFieldAccessorTable() {
                return TarsierWireProtos.internal_static_HelloMessage_fieldAccessorTable
                        .ensureFieldAccessorsInitialized(
                                TarsierWireProtos.HelloMessage.class,
                                TarsierWireProtos.HelloMessage.Builder.class);
            }

            // Construct using TarsierWireProtos.HelloMessage.newBuilder()
            private Builder() {
                maybeForceBuilderInitialization();
            }

            private Builder(
                    com.google.protobuf.GeneratedMessage.BuilderParent parent) {
                super(parent);
                maybeForceBuilderInitialization();
            }

            private void maybeForceBuilderInitialization() {
                if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
                    getPeerFieldBuilder();
                }
            }

            private static Builder create() {
                return new Builder();
            }

            public Builder clear() {
                super.clear();
                if (peerBuilder_ == null) {
                    peer_ = TarsierWireProtos.Peer.getDefaultInstance();
                } else {
                    peerBuilder_.clear();
                }
                bitField0_ = (bitField0_ & ~0x00000001);
                return this;
            }

            public Builder clone() {
                return create().mergeFrom(buildPartial());
            }

            public com.google.protobuf.Descriptors.Descriptor
            getDescriptorForType() {
                return TarsierWireProtos.internal_static_HelloMessage_descriptor;
            }

            public TarsierWireProtos.HelloMessage getDefaultInstanceForType() {
                return TarsierWireProtos.HelloMessage.getDefaultInstance();
            }

            public TarsierWireProtos.HelloMessage build() {
                TarsierWireProtos.HelloMessage result = buildPartial();
                if (!result.isInitialized()) {
                    throw newUninitializedMessageException(result);
                }
                return result;
            }

            public TarsierWireProtos.HelloMessage buildPartial() {
                TarsierWireProtos.HelloMessage result = new TarsierWireProtos.HelloMessage(this);
                int from_bitField0_ = bitField0_;
                int to_bitField0_ = 0;
                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
                    to_bitField0_ |= 0x00000001;
                }
                if (peerBuilder_ == null) {
                    result.peer_ = peer_;
                } else {
                    result.peer_ = peerBuilder_.build();
                }
                result.bitField0_ = to_bitField0_;
                onBuilt();
                return result;
            }

            public Builder mergeFrom(com.google.protobuf.Message other) {
                if (other instanceof TarsierWireProtos.HelloMessage) {
                    return mergeFrom((TarsierWireProtos.HelloMessage) other);
                } else {
                    super.mergeFrom(other);
                    return this;
                }
            }

            public Builder mergeFrom(TarsierWireProtos.HelloMessage other) {
                if (other == TarsierWireProtos.HelloMessage.getDefaultInstance()) {
                    return this;
                }
                if (other.hasPeer()) {
                    mergePeer(other.getPeer());
                }
                this.mergeUnknownFields(other.getUnknownFields());
                return this;
            }

            public final boolean isInitialized() {
                if (!hasPeer()) {

                    return false;
                }
                if (!getPeer().isInitialized()) {

                    return false;
                }
                return true;
            }

            public Builder mergeFrom(
                    com.google.protobuf.CodedInputStream input,
                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                    throws java.io.IOException {
                TarsierWireProtos.HelloMessage parsedMessage = null;
                try {
                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
                } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                    parsedMessage = (TarsierWireProtos.HelloMessage) e.getUnfinishedMessage();
                    throw e;
                } finally {
                    if (parsedMessage != null) {
                        mergeFrom(parsedMessage);
                    }
                }
                return this;
            }

            private int bitField0_;

            private TarsierWireProtos.Peer peer_ = TarsierWireProtos.Peer.getDefaultInstance();

            private com.google.protobuf.SingleFieldBuilder<
                    TarsierWireProtos.Peer, TarsierWireProtos.Peer.Builder, TarsierWireProtos.PeerOrBuilder>
                    peerBuilder_;

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public boolean hasPeer() {
                return ((bitField0_ & 0x00000001) == 0x00000001);
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public TarsierWireProtos.Peer getPeer() {
                if (peerBuilder_ == null) {
                    return peer_;
                } else {
                    return peerBuilder_.getMessage();
                }
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public Builder setPeer(TarsierWireProtos.Peer value) {
                if (peerBuilder_ == null) {
                    if (value == null) {
                        throw new NullPointerException();
                    }
                    peer_ = value;
                    onChanged();
                } else {
                    peerBuilder_.setMessage(value);
                }
                bitField0_ |= 0x00000001;
                return this;
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public Builder setPeer(
                    TarsierWireProtos.Peer.Builder builderForValue) {
                if (peerBuilder_ == null) {
                    peer_ = builderForValue.build();
                    onChanged();
                } else {
                    peerBuilder_.setMessage(builderForValue.build());
                }
                bitField0_ |= 0x00000001;
                return this;
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public Builder mergePeer(TarsierWireProtos.Peer value) {
                if (peerBuilder_ == null) {
                    if (((bitField0_ & 0x00000001) == 0x00000001) &&
                            peer_ != TarsierWireProtos.Peer.getDefaultInstance()) {
                        peer_ =
                                TarsierWireProtos.Peer.newBuilder(peer_).mergeFrom(value)
                                        .buildPartial();
                    } else {
                        peer_ = value;
                    }
                    onChanged();
                } else {
                    peerBuilder_.mergeFrom(value);
                }
                bitField0_ |= 0x00000001;
                return this;
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public Builder clearPeer() {
                if (peerBuilder_ == null) {
                    peer_ = TarsierWireProtos.Peer.getDefaultInstance();
                    onChanged();
                } else {
                    peerBuilder_.clear();
                }
                bitField0_ = (bitField0_ & ~0x00000001);
                return this;
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public TarsierWireProtos.Peer.Builder getPeerBuilder() {
                bitField0_ |= 0x00000001;
                onChanged();
                return getPeerFieldBuilder().getBuilder();
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            public TarsierWireProtos.PeerOrBuilder getPeerOrBuilder() {
                if (peerBuilder_ != null) {
                    return peerBuilder_.getMessageOrBuilder();
                } else {
                    return peer_;
                }
            }

            /**
             * <code>required .Peer peer = 1;</code>
             */
            private com.google.protobuf.SingleFieldBuilder<
                    TarsierWireProtos.Peer, TarsierWireProtos.Peer.Builder, TarsierWireProtos.PeerOrBuilder>
            getPeerFieldBuilder() {
                if (peerBuilder_ == null) {
                    peerBuilder_ = new com.google.protobuf.SingleFieldBuilder<
                            TarsierWireProtos.Peer, TarsierWireProtos.Peer.Builder, TarsierWireProtos.PeerOrBuilder>(
                            getPeer(),
                            getParentForChildren(),
                            isClean());
                    peer_ = null;
                }
                return peerBuilder_;
            }

            // @@protoc_insertion_point(builder_scope:HelloMessage)
        }

        static {
            defaultInstance = new HelloMessage(true);
            defaultInstance.initFields();
        }

        // @@protoc_insertion_point(class_scope:HelloMessage)
    }

    public interface PeerUpdatedListOrBuilder extends
            // @@protoc_insertion_point(interface_extends:PeerUpdatedList)
            com.google.protobuf.MessageOrBuilder {

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        java.util.List<TarsierWireProtos.Peer>
        getPeerList();

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        TarsierWireProtos.Peer getPeer(int index);

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        int getPeerCount();

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        java.util.List<? extends TarsierWireProtos.PeerOrBuilder>
        getPeerOrBuilderList();

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        TarsierWireProtos.PeerOrBuilder getPeerOrBuilder(
                int index);
    }

    /**
     * Protobuf type {@code PeerUpdatedList}
     */
    public static final class PeerUpdatedList extends
            com.google.protobuf.GeneratedMessage implements
            // @@protoc_insertion_point(message_implements:PeerUpdatedList)
            PeerUpdatedListOrBuilder {

        // Use PeerUpdatedList.newBuilder() to construct.
        private PeerUpdatedList(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
            super(builder);
            this.unknownFields = builder.getUnknownFields();
        }

        private PeerUpdatedList(boolean noInit) {
            this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();
        }

        private static final PeerUpdatedList defaultInstance;

        public static PeerUpdatedList getDefaultInstance() {
            return defaultInstance;
        }

        public PeerUpdatedList getDefaultInstanceForType() {
            return defaultInstance;
        }

        private final com.google.protobuf.UnknownFieldSet unknownFields;

        @java.lang.Override
        public final com.google.protobuf.UnknownFieldSet
        getUnknownFields() {
            return this.unknownFields;
        }

        private PeerUpdatedList(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            initFields();
            int mutable_bitField0_ = 0;
            com.google.protobuf.UnknownFieldSet.Builder unknownFields =
                    com.google.protobuf.UnknownFieldSet.newBuilder();
            try {
                boolean done = false;
                while (!done) {
                    int tag = input.readTag();
                    switch (tag) {
                        case 0:
                            done = true;
                            break;
                        default: {
                            if (!parseUnknownField(input, unknownFields,
                                    extensionRegistry, tag)) {
                                done = true;
                            }
                            break;
                        }
                        case 10: {
                            if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
                                peer_ = new java.util.ArrayList<TarsierWireProtos.Peer>();
                                mutable_bitField0_ |= 0x00000001;
                            }
                            peer_.add(input.readMessage(TarsierWireProtos.Peer.PARSER,
                                    extensionRegistry));
                            break;
                        }
                    }
                }
            } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                throw e.setUnfinishedMessage(this);
            } catch (java.io.IOException e) {
                throw new com.google.protobuf.InvalidProtocolBufferException(
                        e.getMessage()).setUnfinishedMessage(this);
            } finally {
                if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
                    peer_ = java.util.Collections.unmodifiableList(peer_);
                }
                this.unknownFields = unknownFields.build();
                makeExtensionsImmutable();
            }
        }

        public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
            return TarsierWireProtos.internal_static_PeerUpdatedList_descriptor;
        }

        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
        internalGetFieldAccessorTable() {
            return TarsierWireProtos.internal_static_PeerUpdatedList_fieldAccessorTable
                    .ensureFieldAccessorsInitialized(
                            TarsierWireProtos.PeerUpdatedList.class,
                            TarsierWireProtos.PeerUpdatedList.Builder.class);
        }

        public static com.google.protobuf.Parser<PeerUpdatedList> PARSER =
                new com.google.protobuf.AbstractParser<PeerUpdatedList>() {
                    public PeerUpdatedList parsePartialFrom(
                            com.google.protobuf.CodedInputStream input,
                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                            throws com.google.protobuf.InvalidProtocolBufferException {
                        return new PeerUpdatedList(input, extensionRegistry);
                    }
                };

        @java.lang.Override
        public com.google.protobuf.Parser<PeerUpdatedList> getParserForType() {
            return PARSER;
        }

        public static final int PEER_FIELD_NUMBER = 1;

        private java.util.List<TarsierWireProtos.Peer> peer_;

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        public java.util.List<TarsierWireProtos.Peer> getPeerList() {
            return peer_;
        }

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        public java.util.List<? extends TarsierWireProtos.PeerOrBuilder>
        getPeerOrBuilderList() {
            return peer_;
        }

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        public int getPeerCount() {
            return peer_.size();
        }

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        public TarsierWireProtos.Peer getPeer(int index) {
            return peer_.get(index);
        }

        /**
         * <code>repeated .Peer peer = 1;</code>
         */
        public TarsierWireProtos.PeerOrBuilder getPeerOrBuilder(
                int index) {
            return peer_.get(index);
        }

        private void initFields() {
            peer_ = java.util.Collections.emptyList();
        }

        private byte memoizedIsInitialized = -1;

        public final boolean isInitialized() {
            byte isInitialized = memoizedIsInitialized;
            if (isInitialized == 1) {
                return true;
            }
            if (isInitialized == 0) {
                return false;
            }

            for (int i = 0; i < getPeerCount(); i++) {
                if (!getPeer(i).isInitialized()) {
                    memoizedIsInitialized = 0;
                    return false;
                }
            }
            memoizedIsInitialized = 1;
            return true;
        }

        public void writeTo(com.google.protobuf.CodedOutputStream output)
                throws java.io.IOException {
            getSerializedSize();
            for (int i = 0; i < peer_.size(); i++) {
                output.writeMessage(1, peer_.get(i));
            }
            getUnknownFields().writeTo(output);
        }

        private int memoizedSerializedSize = -1;

        public int getSerializedSize() {
            int size = memoizedSerializedSize;
            if (size != -1) {
                return size;
            }

            size = 0;
            for (int i = 0; i < peer_.size(); i++) {
                size += com.google.protobuf.CodedOutputStream
                        .computeMessageSize(1, peer_.get(i));
            }
            size += getUnknownFields().getSerializedSize();
            memoizedSerializedSize = size;
            return size;
        }

        private static final long serialVersionUID = 0L;

        @java.lang.Override
        protected java.lang.Object writeReplace()
                throws java.io.ObjectStreamException {
            return super.writeReplace();
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(
                com.google.protobuf.ByteString data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(
                com.google.protobuf.ByteString data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(byte[] data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(
                byte[] data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.PeerUpdatedList parseDelimitedFrom(
                java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input);
        }

        public static TarsierWireProtos.PeerUpdatedList parseDelimitedFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(
                com.google.protobuf.CodedInputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.PeerUpdatedList parseFrom(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static Builder newBuilder() {
            return Builder.create();
        }

        public Builder newBuilderForType() {
            return newBuilder();
        }

        public static Builder newBuilder(TarsierWireProtos.PeerUpdatedList prototype) {
            return newBuilder().mergeFrom(prototype);
        }

        public Builder toBuilder() {
            return newBuilder(this);
        }

        @java.lang.Override
        protected Builder newBuilderForType(
                com.google.protobuf.GeneratedMessage.BuilderParent parent) {
            Builder builder = new Builder(parent);
            return builder;
        }

        /**
         * Protobuf type {@code PeerUpdatedList}
         */
        public static final class Builder extends
                com.google.protobuf.GeneratedMessage.Builder<Builder> implements
                // @@protoc_insertion_point(builder_implements:PeerUpdatedList)
                TarsierWireProtos.PeerUpdatedListOrBuilder {

            public static final com.google.protobuf.Descriptors.Descriptor
            getDescriptor() {
                return TarsierWireProtos.internal_static_PeerUpdatedList_descriptor;
            }

            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internalGetFieldAccessorTable() {
                return TarsierWireProtos.internal_static_PeerUpdatedList_fieldAccessorTable
                        .ensureFieldAccessorsInitialized(
                                TarsierWireProtos.PeerUpdatedList.class,
                                TarsierWireProtos.PeerUpdatedList.Builder.class);
            }

            // Construct using TarsierWireProtos.PeerUpdatedList.newBuilder()
            private Builder() {
                maybeForceBuilderInitialization();
            }

            private Builder(
                    com.google.protobuf.GeneratedMessage.BuilderParent parent) {
                super(parent);
                maybeForceBuilderInitialization();
            }

            private void maybeForceBuilderInitialization() {
                if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
                    getPeerFieldBuilder();
                }
            }

            private static Builder create() {
                return new Builder();
            }

            public Builder clear() {
                super.clear();
                if (peerBuilder_ == null) {
                    peer_ = java.util.Collections.emptyList();
                    bitField0_ = (bitField0_ & ~0x00000001);
                } else {
                    peerBuilder_.clear();
                }
                return this;
            }

            public Builder clone() {
                return create().mergeFrom(buildPartial());
            }

            public com.google.protobuf.Descriptors.Descriptor
            getDescriptorForType() {
                return TarsierWireProtos.internal_static_PeerUpdatedList_descriptor;
            }

            public TarsierWireProtos.PeerUpdatedList getDefaultInstanceForType() {
                return TarsierWireProtos.PeerUpdatedList.getDefaultInstance();
            }

            public TarsierWireProtos.PeerUpdatedList build() {
                TarsierWireProtos.PeerUpdatedList result = buildPartial();
                if (!result.isInitialized()) {
                    throw newUninitializedMessageException(result);
                }
                return result;
            }

            public TarsierWireProtos.PeerUpdatedList buildPartial() {
                TarsierWireProtos.PeerUpdatedList result = new TarsierWireProtos.PeerUpdatedList(
                        this);
                int from_bitField0_ = bitField0_;
                if (peerBuilder_ == null) {
                    if (((bitField0_ & 0x00000001) == 0x00000001)) {
                        peer_ = java.util.Collections.unmodifiableList(peer_);
                        bitField0_ = (bitField0_ & ~0x00000001);
                    }
                    result.peer_ = peer_;
                } else {
                    result.peer_ = peerBuilder_.build();
                }
                onBuilt();
                return result;
            }

            public Builder mergeFrom(com.google.protobuf.Message other) {
                if (other instanceof TarsierWireProtos.PeerUpdatedList) {
                    return mergeFrom((TarsierWireProtos.PeerUpdatedList) other);
                } else {
                    super.mergeFrom(other);
                    return this;
                }
            }

            public Builder mergeFrom(TarsierWireProtos.PeerUpdatedList other) {
                if (other == TarsierWireProtos.PeerUpdatedList.getDefaultInstance()) {
                    return this;
                }
                if (peerBuilder_ == null) {
                    if (!other.peer_.isEmpty()) {
                        if (peer_.isEmpty()) {
                            peer_ = other.peer_;
                            bitField0_ = (bitField0_ & ~0x00000001);
                        } else {
                            ensurePeerIsMutable();
                            peer_.addAll(other.peer_);
                        }
                        onChanged();
                    }
                } else {
                    if (!other.peer_.isEmpty()) {
                        if (peerBuilder_.isEmpty()) {
                            peerBuilder_.dispose();
                            peerBuilder_ = null;
                            peer_ = other.peer_;
                            bitField0_ = (bitField0_ & ~0x00000001);
                            peerBuilder_ =
                                    com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
                                            getPeerFieldBuilder() : null;
                        } else {
                            peerBuilder_.addAllMessages(other.peer_);
                        }
                    }
                }
                this.mergeUnknownFields(other.getUnknownFields());
                return this;
            }

            public final boolean isInitialized() {
                for (int i = 0; i < getPeerCount(); i++) {
                    if (!getPeer(i).isInitialized()) {

                        return false;
                    }
                }
                return true;
            }

            public Builder mergeFrom(
                    com.google.protobuf.CodedInputStream input,
                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                    throws java.io.IOException {
                TarsierWireProtos.PeerUpdatedList parsedMessage = null;
                try {
                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
                } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                    parsedMessage = (TarsierWireProtos.PeerUpdatedList) e.getUnfinishedMessage();
                    throw e;
                } finally {
                    if (parsedMessage != null) {
                        mergeFrom(parsedMessage);
                    }
                }
                return this;
            }

            private int bitField0_;

            private java.util.List<TarsierWireProtos.Peer> peer_ =
                    java.util.Collections.emptyList();

            private void ensurePeerIsMutable() {
                if (!((bitField0_ & 0x00000001) == 0x00000001)) {
                    peer_ = new java.util.ArrayList<TarsierWireProtos.Peer>(peer_);
                    bitField0_ |= 0x00000001;
                }
            }

            private com.google.protobuf.RepeatedFieldBuilder<
                    TarsierWireProtos.Peer, TarsierWireProtos.Peer.Builder, TarsierWireProtos.PeerOrBuilder>
                    peerBuilder_;

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public java.util.List<TarsierWireProtos.Peer> getPeerList() {
                if (peerBuilder_ == null) {
                    return java.util.Collections.unmodifiableList(peer_);
                } else {
                    return peerBuilder_.getMessageList();
                }
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public int getPeerCount() {
                if (peerBuilder_ == null) {
                    return peer_.size();
                } else {
                    return peerBuilder_.getCount();
                }
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public TarsierWireProtos.Peer getPeer(int index) {
                if (peerBuilder_ == null) {
                    return peer_.get(index);
                } else {
                    return peerBuilder_.getMessage(index);
                }
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder setPeer(
                    int index, TarsierWireProtos.Peer value) {
                if (peerBuilder_ == null) {
                    if (value == null) {
                        throw new NullPointerException();
                    }
                    ensurePeerIsMutable();
                    peer_.set(index, value);
                    onChanged();
                } else {
                    peerBuilder_.setMessage(index, value);
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder setPeer(
                    int index, TarsierWireProtos.Peer.Builder builderForValue) {
                if (peerBuilder_ == null) {
                    ensurePeerIsMutable();
                    peer_.set(index, builderForValue.build());
                    onChanged();
                } else {
                    peerBuilder_.setMessage(index, builderForValue.build());
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder addPeer(TarsierWireProtos.Peer value) {
                if (peerBuilder_ == null) {
                    if (value == null) {
                        throw new NullPointerException();
                    }
                    ensurePeerIsMutable();
                    peer_.add(value);
                    onChanged();
                } else {
                    peerBuilder_.addMessage(value);
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder addPeer(
                    int index, TarsierWireProtos.Peer value) {
                if (peerBuilder_ == null) {
                    if (value == null) {
                        throw new NullPointerException();
                    }
                    ensurePeerIsMutable();
                    peer_.add(index, value);
                    onChanged();
                } else {
                    peerBuilder_.addMessage(index, value);
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder addPeer(
                    TarsierWireProtos.Peer.Builder builderForValue) {
                if (peerBuilder_ == null) {
                    ensurePeerIsMutable();
                    peer_.add(builderForValue.build());
                    onChanged();
                } else {
                    peerBuilder_.addMessage(builderForValue.build());
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder addPeer(
                    int index, TarsierWireProtos.Peer.Builder builderForValue) {
                if (peerBuilder_ == null) {
                    ensurePeerIsMutable();
                    peer_.add(index, builderForValue.build());
                    onChanged();
                } else {
                    peerBuilder_.addMessage(index, builderForValue.build());
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder addAllPeer(
                    java.lang.Iterable<? extends TarsierWireProtos.Peer> values) {
                if (peerBuilder_ == null) {
                    ensurePeerIsMutable();
                    com.google.protobuf.AbstractMessageLite.Builder.addAll(
                            values, peer_);
                    onChanged();
                } else {
                    peerBuilder_.addAllMessages(values);
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder clearPeer() {
                if (peerBuilder_ == null) {
                    peer_ = java.util.Collections.emptyList();
                    bitField0_ = (bitField0_ & ~0x00000001);
                    onChanged();
                } else {
                    peerBuilder_.clear();
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public Builder removePeer(int index) {
                if (peerBuilder_ == null) {
                    ensurePeerIsMutable();
                    peer_.remove(index);
                    onChanged();
                } else {
                    peerBuilder_.remove(index);
                }
                return this;
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public TarsierWireProtos.Peer.Builder getPeerBuilder(
                    int index) {
                return getPeerFieldBuilder().getBuilder(index);
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public TarsierWireProtos.PeerOrBuilder getPeerOrBuilder(
                    int index) {
                if (peerBuilder_ == null) {
                    return peer_.get(index);
                } else {
                    return peerBuilder_.getMessageOrBuilder(index);
                }
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public java.util.List<? extends TarsierWireProtos.PeerOrBuilder>
            getPeerOrBuilderList() {
                if (peerBuilder_ != null) {
                    return peerBuilder_.getMessageOrBuilderList();
                } else {
                    return java.util.Collections.unmodifiableList(peer_);
                }
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public TarsierWireProtos.Peer.Builder addPeerBuilder() {
                return getPeerFieldBuilder().addBuilder(
                        TarsierWireProtos.Peer.getDefaultInstance());
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public TarsierWireProtos.Peer.Builder addPeerBuilder(
                    int index) {
                return getPeerFieldBuilder().addBuilder(
                        index, TarsierWireProtos.Peer.getDefaultInstance());
            }

            /**
             * <code>repeated .Peer peer = 1;</code>
             */
            public java.util.List<TarsierWireProtos.Peer.Builder>
            getPeerBuilderList() {
                return getPeerFieldBuilder().getBuilderList();
            }

            private com.google.protobuf.RepeatedFieldBuilder<
                    TarsierWireProtos.Peer, TarsierWireProtos.Peer.Builder, TarsierWireProtos.PeerOrBuilder>
            getPeerFieldBuilder() {
                if (peerBuilder_ == null) {
                    peerBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
                            TarsierWireProtos.Peer, TarsierWireProtos.Peer.Builder, TarsierWireProtos.PeerOrBuilder>(
                            peer_,
                            ((bitField0_ & 0x00000001) == 0x00000001),
                            getParentForChildren(),
                            isClean());
                    peer_ = null;
                }
                return peerBuilder_;
            }

            // @@protoc_insertion_point(builder_scope:PeerUpdatedList)
        }

        static {
            defaultInstance = new PeerUpdatedList(true);
            defaultInstance.initFields();
        }

        // @@protoc_insertion_point(class_scope:PeerUpdatedList)
    }

    public interface PeerOrBuilder extends
            // @@protoc_insertion_point(interface_extends:Peer)
            com.google.protobuf.MessageOrBuilder {

        /**
         * <code>required string name = 1;</code>
         */
        boolean hasName();

        /**
         * <code>required string name = 1;</code>
         */
        java.lang.String getName();

        /**
         * <code>required string name = 1;</code>
         */
        com.google.protobuf.ByteString
        getNameBytes();

        /**
         * <code>required bytes publicKey = 2;</code>
         */
        boolean hasPublicKey();

        /**
         * <code>required bytes publicKey = 2;</code>
         */
        com.google.protobuf.ByteString getPublicKey();
    }

    /**
     * Protobuf type {@code Peer}
     */
    public static final class Peer extends
            com.google.protobuf.GeneratedMessage implements
            // @@protoc_insertion_point(message_implements:Peer)
            PeerOrBuilder {

        // Use Peer.newBuilder() to construct.
        private Peer(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
            super(builder);
            this.unknownFields = builder.getUnknownFields();
        }

        private Peer(boolean noInit) {
            this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();
        }

        private static final Peer defaultInstance;

        public static Peer getDefaultInstance() {
            return defaultInstance;
        }

        public Peer getDefaultInstanceForType() {
            return defaultInstance;
        }

        private final com.google.protobuf.UnknownFieldSet unknownFields;

        @java.lang.Override
        public final com.google.protobuf.UnknownFieldSet
        getUnknownFields() {
            return this.unknownFields;
        }

        private Peer(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            initFields();
            int mutable_bitField0_ = 0;
            com.google.protobuf.UnknownFieldSet.Builder unknownFields =
                    com.google.protobuf.UnknownFieldSet.newBuilder();
            try {
                boolean done = false;
                while (!done) {
                    int tag = input.readTag();
                    switch (tag) {
                        case 0:
                            done = true;
                            break;
                        default: {
                            if (!parseUnknownField(input, unknownFields,
                                    extensionRegistry, tag)) {
                                done = true;
                            }
                            break;
                        }
                        case 10: {
                            com.google.protobuf.ByteString bs = input.readBytes();
                            bitField0_ |= 0x00000001;
                            name_ = bs;
                            break;
                        }
                        case 18: {
                            bitField0_ |= 0x00000002;
                            publicKey_ = input.readBytes();
                            break;
                        }
                    }
                }
            } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                throw e.setUnfinishedMessage(this);
            } catch (java.io.IOException e) {
                throw new com.google.protobuf.InvalidProtocolBufferException(
                        e.getMessage()).setUnfinishedMessage(this);
            } finally {
                this.unknownFields = unknownFields.build();
                makeExtensionsImmutable();
            }
        }

        public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
            return TarsierWireProtos.internal_static_Peer_descriptor;
        }

        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
        internalGetFieldAccessorTable() {
            return TarsierWireProtos.internal_static_Peer_fieldAccessorTable
                    .ensureFieldAccessorsInitialized(
                            TarsierWireProtos.Peer.class, TarsierWireProtos.Peer.Builder.class);
        }

        public static com.google.protobuf.Parser<Peer> PARSER =
                new com.google.protobuf.AbstractParser<Peer>() {
                    public Peer parsePartialFrom(
                            com.google.protobuf.CodedInputStream input,
                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                            throws com.google.protobuf.InvalidProtocolBufferException {
                        return new Peer(input, extensionRegistry);
                    }
                };

        @java.lang.Override
        public com.google.protobuf.Parser<Peer> getParserForType() {
            return PARSER;
        }

        private int bitField0_;

        public static final int NAME_FIELD_NUMBER = 1;

        private java.lang.Object name_;

        /**
         * <code>required string name = 1;</code>
         */
        public boolean hasName() {
            return ((bitField0_ & 0x00000001) == 0x00000001);
        }

        /**
         * <code>required string name = 1;</code>
         */
        public java.lang.String getName() {
            java.lang.Object ref = name_;
            if (ref instanceof java.lang.String) {
                return (java.lang.String) ref;
            } else {
                com.google.protobuf.ByteString bs =
                        (com.google.protobuf.ByteString) ref;
                java.lang.String s = bs.toStringUtf8();
                if (bs.isValidUtf8()) {
                    name_ = s;
                }
                return s;
            }
        }

        /**
         * <code>required string name = 1;</code>
         */
        public com.google.protobuf.ByteString
        getNameBytes() {
            java.lang.Object ref = name_;
            if (ref instanceof java.lang.String) {
                com.google.protobuf.ByteString b =
                        com.google.protobuf.ByteString.copyFromUtf8(
                                (java.lang.String) ref);
                name_ = b;
                return b;
            } else {
                return (com.google.protobuf.ByteString) ref;
            }
        }

        public static final int PUBLICKEY_FIELD_NUMBER = 2;

        private com.google.protobuf.ByteString publicKey_;

        /**
         * <code>required bytes publicKey = 2;</code>
         */
        public boolean hasPublicKey() {
            return ((bitField0_ & 0x00000002) == 0x00000002);
        }

        /**
         * <code>required bytes publicKey = 2;</code>
         */
        public com.google.protobuf.ByteString getPublicKey() {
            return publicKey_;
        }

        private void initFields() {
            name_ = "";
            publicKey_ = com.google.protobuf.ByteString.EMPTY;
        }

        private byte memoizedIsInitialized = -1;

        public final boolean isInitialized() {
            byte isInitialized = memoizedIsInitialized;
            if (isInitialized == 1) {
                return true;
            }
            if (isInitialized == 0) {
                return false;
            }

            if (!hasName()) {
                memoizedIsInitialized = 0;
                return false;
            }
            if (!hasPublicKey()) {
                memoizedIsInitialized = 0;
                return false;
            }
            memoizedIsInitialized = 1;
            return true;
        }

        public void writeTo(com.google.protobuf.CodedOutputStream output)
                throws java.io.IOException {
            getSerializedSize();
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                output.writeBytes(1, getNameBytes());
            }
            if (((bitField0_ & 0x00000002) == 0x00000002)) {
                output.writeBytes(2, publicKey_);
            }
            getUnknownFields().writeTo(output);
        }

        private int memoizedSerializedSize = -1;

        public int getSerializedSize() {
            int size = memoizedSerializedSize;
            if (size != -1) {
                return size;
            }

            size = 0;
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(1, getNameBytes());
            }
            if (((bitField0_ & 0x00000002) == 0x00000002)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(2, publicKey_);
            }
            size += getUnknownFields().getSerializedSize();
            memoizedSerializedSize = size;
            return size;
        }

        private static final long serialVersionUID = 0L;

        @java.lang.Override
        protected java.lang.Object writeReplace()
                throws java.io.ObjectStreamException {
            return super.writeReplace();
        }

        public static TarsierWireProtos.Peer parseFrom(
                com.google.protobuf.ByteString data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.Peer parseFrom(
                com.google.protobuf.ByteString data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.Peer parseFrom(byte[] data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.Peer parseFrom(
                byte[] data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.Peer parseFrom(java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.Peer parseFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.Peer parseDelimitedFrom(java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input);
        }

        public static TarsierWireProtos.Peer parseDelimitedFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.Peer parseFrom(
                com.google.protobuf.CodedInputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.Peer parseFrom(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static Builder newBuilder() {
            return Builder.create();
        }

        public Builder newBuilderForType() {
            return newBuilder();
        }

        public static Builder newBuilder(TarsierWireProtos.Peer prototype) {
            return newBuilder().mergeFrom(prototype);
        }

        public Builder toBuilder() {
            return newBuilder(this);
        }

        @java.lang.Override
        protected Builder newBuilderForType(
                com.google.protobuf.GeneratedMessage.BuilderParent parent) {
            Builder builder = new Builder(parent);
            return builder;
        }

        /**
         * Protobuf type {@code Peer}
         */
        public static final class Builder extends
                com.google.protobuf.GeneratedMessage.Builder<Builder> implements
                // @@protoc_insertion_point(builder_implements:Peer)
                TarsierWireProtos.PeerOrBuilder {

            public static final com.google.protobuf.Descriptors.Descriptor
            getDescriptor() {
                return TarsierWireProtos.internal_static_Peer_descriptor;
            }

            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internalGetFieldAccessorTable() {
                return TarsierWireProtos.internal_static_Peer_fieldAccessorTable
                        .ensureFieldAccessorsInitialized(
                                TarsierWireProtos.Peer.class, TarsierWireProtos.Peer.Builder.class);
            }

            // Construct using TarsierWireProtos.Peer.newBuilder()
            private Builder() {
                maybeForceBuilderInitialization();
            }

            private Builder(
                    com.google.protobuf.GeneratedMessage.BuilderParent parent) {
                super(parent);
                maybeForceBuilderInitialization();
            }

            private void maybeForceBuilderInitialization() {
                if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
                }
            }

            private static Builder create() {
                return new Builder();
            }

            public Builder clear() {
                super.clear();
                name_ = "";
                bitField0_ = (bitField0_ & ~0x00000001);
                publicKey_ = com.google.protobuf.ByteString.EMPTY;
                bitField0_ = (bitField0_ & ~0x00000002);
                return this;
            }

            public Builder clone() {
                return create().mergeFrom(buildPartial());
            }

            public com.google.protobuf.Descriptors.Descriptor
            getDescriptorForType() {
                return TarsierWireProtos.internal_static_Peer_descriptor;
            }

            public TarsierWireProtos.Peer getDefaultInstanceForType() {
                return TarsierWireProtos.Peer.getDefaultInstance();
            }

            public TarsierWireProtos.Peer build() {
                TarsierWireProtos.Peer result = buildPartial();
                if (!result.isInitialized()) {
                    throw newUninitializedMessageException(result);
                }
                return result;
            }

            public TarsierWireProtos.Peer buildPartial() {
                TarsierWireProtos.Peer result = new TarsierWireProtos.Peer(this);
                int from_bitField0_ = bitField0_;
                int to_bitField0_ = 0;
                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
                    to_bitField0_ |= 0x00000001;
                }
                result.name_ = name_;
                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
                    to_bitField0_ |= 0x00000002;
                }
                result.publicKey_ = publicKey_;
                result.bitField0_ = to_bitField0_;
                onBuilt();
                return result;
            }

            public Builder mergeFrom(com.google.protobuf.Message other) {
                if (other instanceof TarsierWireProtos.Peer) {
                    return mergeFrom((TarsierWireProtos.Peer) other);
                } else {
                    super.mergeFrom(other);
                    return this;
                }
            }

            public Builder mergeFrom(TarsierWireProtos.Peer other) {
                if (other == TarsierWireProtos.Peer.getDefaultInstance()) {
                    return this;
                }
                if (other.hasName()) {
                    bitField0_ |= 0x00000001;
                    name_ = other.name_;
                    onChanged();
                }
                if (other.hasPublicKey()) {
                    setPublicKey(other.getPublicKey());
                }
                this.mergeUnknownFields(other.getUnknownFields());
                return this;
            }

            public final boolean isInitialized() {
                if (!hasName()) {

                    return false;
                }
                if (!hasPublicKey()) {

                    return false;
                }
                return true;
            }

            public Builder mergeFrom(
                    com.google.protobuf.CodedInputStream input,
                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                    throws java.io.IOException {
                TarsierWireProtos.Peer parsedMessage = null;
                try {
                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
                } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                    parsedMessage = (TarsierWireProtos.Peer) e.getUnfinishedMessage();
                    throw e;
                } finally {
                    if (parsedMessage != null) {
                        mergeFrom(parsedMessage);
                    }
                }
                return this;
            }

            private int bitField0_;

            private java.lang.Object name_ = "";

            /**
             * <code>required string name = 1;</code>
             */
            public boolean hasName() {
                return ((bitField0_ & 0x00000001) == 0x00000001);
            }

            /**
             * <code>required string name = 1;</code>
             */
            public java.lang.String getName() {
                java.lang.Object ref = name_;
                if (!(ref instanceof java.lang.String)) {
                    com.google.protobuf.ByteString bs =
                            (com.google.protobuf.ByteString) ref;
                    java.lang.String s = bs.toStringUtf8();
                    if (bs.isValidUtf8()) {
                        name_ = s;
                    }
                    return s;
                } else {
                    return (java.lang.String) ref;
                }
            }

            /**
             * <code>required string name = 1;</code>
             */
            public com.google.protobuf.ByteString
            getNameBytes() {
                java.lang.Object ref = name_;
                if (ref instanceof String) {
                    com.google.protobuf.ByteString b =
                            com.google.protobuf.ByteString.copyFromUtf8(
                                    (java.lang.String) ref);
                    name_ = b;
                    return b;
                } else {
                    return (com.google.protobuf.ByteString) ref;
                }
            }

            /**
             * <code>required string name = 1;</code>
             */
            public Builder setName(
                    java.lang.String value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000001;
                name_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required string name = 1;</code>
             */
            public Builder clearName() {
                bitField0_ = (bitField0_ & ~0x00000001);
                name_ = getDefaultInstance().getName();
                onChanged();
                return this;
            }

            /**
             * <code>required string name = 1;</code>
             */
            public Builder setNameBytes(
                    com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000001;
                name_ = value;
                onChanged();
                return this;
            }

            private com.google.protobuf.ByteString publicKey_
                    = com.google.protobuf.ByteString.EMPTY;

            /**
             * <code>required bytes publicKey = 2;</code>
             */
            public boolean hasPublicKey() {
                return ((bitField0_ & 0x00000002) == 0x00000002);
            }

            /**
             * <code>required bytes publicKey = 2;</code>
             */
            public com.google.protobuf.ByteString getPublicKey() {
                return publicKey_;
            }

            /**
             * <code>required bytes publicKey = 2;</code>
             */
            public Builder setPublicKey(com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000002;
                publicKey_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required bytes publicKey = 2;</code>
             */
            public Builder clearPublicKey() {
                bitField0_ = (bitField0_ & ~0x00000002);
                publicKey_ = getDefaultInstance().getPublicKey();
                onChanged();
                return this;
            }

            // @@protoc_insertion_point(builder_scope:Peer)
        }

        static {
            defaultInstance = new Peer(true);
            defaultInstance.initFields();
        }

        // @@protoc_insertion_point(class_scope:Peer)
    }

    public interface TarsierPrivateMessageOrBuilder extends
            // @@protoc_insertion_point(interface_extends:TarsierPrivateMessage)
            com.google.protobuf.MessageOrBuilder {

        /**
         * <code>required bytes cipherText = 1;</code>
         */
        boolean hasCipherText();

        /**
         * <code>required bytes cipherText = 1;</code>
         */
        com.google.protobuf.ByteString getCipherText();

        /**
         * <code>required bytes receiverPublicKey = 2;</code>
         */
        boolean hasReceiverPublicKey();

        /**
         * <code>required bytes receiverPublicKey = 2;</code>
         */
        com.google.protobuf.ByteString getReceiverPublicKey();

        /**
         * <code>required bytes senderPublicKey = 3;</code>
         */
        boolean hasSenderPublicKey();

        /**
         * <code>required bytes senderPublicKey = 3;</code>
         */
        com.google.protobuf.ByteString getSenderPublicKey();

        /**
         * <code>required bytes IV = 4;</code>
         */
        boolean hasIV();

        /**
         * <code>required bytes IV = 4;</code>
         */
        com.google.protobuf.ByteString getIV();
    }

    /**
     * Protobuf type {@code TarsierPrivateMessage}
     */
    public static final class TarsierPrivateMessage extends
            com.google.protobuf.GeneratedMessage implements
            // @@protoc_insertion_point(message_implements:TarsierPrivateMessage)
            TarsierPrivateMessageOrBuilder {

        // Use TarsierPrivateMessage.newBuilder() to construct.
        private TarsierPrivateMessage(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
            super(builder);
            this.unknownFields = builder.getUnknownFields();
        }

        private TarsierPrivateMessage(boolean noInit) {
            this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();
        }

        private static final TarsierPrivateMessage defaultInstance;

        public static TarsierPrivateMessage getDefaultInstance() {
            return defaultInstance;
        }

        public TarsierPrivateMessage getDefaultInstanceForType() {
            return defaultInstance;
        }

        private final com.google.protobuf.UnknownFieldSet unknownFields;

        @java.lang.Override
        public final com.google.protobuf.UnknownFieldSet
        getUnknownFields() {
            return this.unknownFields;
        }

        private TarsierPrivateMessage(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            initFields();
            int mutable_bitField0_ = 0;
            com.google.protobuf.UnknownFieldSet.Builder unknownFields =
                    com.google.protobuf.UnknownFieldSet.newBuilder();
            try {
                boolean done = false;
                while (!done) {
                    int tag = input.readTag();
                    switch (tag) {
                        case 0:
                            done = true;
                            break;
                        default: {
                            if (!parseUnknownField(input, unknownFields,
                                    extensionRegistry, tag)) {
                                done = true;
                            }
                            break;
                        }
                        case 10: {
                            bitField0_ |= 0x00000001;
                            cipherText_ = input.readBytes();
                            break;
                        }
                        case 18: {
                            bitField0_ |= 0x00000002;
                            receiverPublicKey_ = input.readBytes();
                            break;
                        }
                        case 26: {
                            bitField0_ |= 0x00000004;
                            senderPublicKey_ = input.readBytes();
                            break;
                        }
                        case 34: {
                            bitField0_ |= 0x00000008;
                            iV_ = input.readBytes();
                            break;
                        }
                    }
                }
            } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                throw e.setUnfinishedMessage(this);
            } catch (java.io.IOException e) {
                throw new com.google.protobuf.InvalidProtocolBufferException(
                        e.getMessage()).setUnfinishedMessage(this);
            } finally {
                this.unknownFields = unknownFields.build();
                makeExtensionsImmutable();
            }
        }

        public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
            return TarsierWireProtos.internal_static_TarsierPrivateMessage_descriptor;
        }

        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
        internalGetFieldAccessorTable() {
            return TarsierWireProtos.internal_static_TarsierPrivateMessage_fieldAccessorTable
                    .ensureFieldAccessorsInitialized(
                            TarsierWireProtos.TarsierPrivateMessage.class,
                            TarsierWireProtos.TarsierPrivateMessage.Builder.class);
        }

        public static com.google.protobuf.Parser<TarsierPrivateMessage> PARSER =
                new com.google.protobuf.AbstractParser<TarsierPrivateMessage>() {
                    public TarsierPrivateMessage parsePartialFrom(
                            com.google.protobuf.CodedInputStream input,
                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                            throws com.google.protobuf.InvalidProtocolBufferException {
                        return new TarsierPrivateMessage(input, extensionRegistry);
                    }
                };

        @java.lang.Override
        public com.google.protobuf.Parser<TarsierPrivateMessage> getParserForType() {
            return PARSER;
        }

        private int bitField0_;

        public static final int CIPHERTEXT_FIELD_NUMBER = 1;

        private com.google.protobuf.ByteString cipherText_;

        /**
         * <code>required bytes cipherText = 1;</code>
         */
        public boolean hasCipherText() {
            return ((bitField0_ & 0x00000001) == 0x00000001);
        }

        /**
         * <code>required bytes cipherText = 1;</code>
         */
        public com.google.protobuf.ByteString getCipherText() {
            return cipherText_;
        }

        public static final int RECEIVERPUBLICKEY_FIELD_NUMBER = 2;

        private com.google.protobuf.ByteString receiverPublicKey_;

        /**
         * <code>required bytes receiverPublicKey = 2;</code>
         */
        public boolean hasReceiverPublicKey() {
            return ((bitField0_ & 0x00000002) == 0x00000002);
        }

        /**
         * <code>required bytes receiverPublicKey = 2;</code>
         */
        public com.google.protobuf.ByteString getReceiverPublicKey() {
            return receiverPublicKey_;
        }

        public static final int SENDERPUBLICKEY_FIELD_NUMBER = 3;

        private com.google.protobuf.ByteString senderPublicKey_;

        /**
         * <code>required bytes senderPublicKey = 3;</code>
         */
        public boolean hasSenderPublicKey() {
            return ((bitField0_ & 0x00000004) == 0x00000004);
        }

        /**
         * <code>required bytes senderPublicKey = 3;</code>
         */
        public com.google.protobuf.ByteString getSenderPublicKey() {
            return senderPublicKey_;
        }

        public static final int IV_FIELD_NUMBER = 4;

        private com.google.protobuf.ByteString iV_;

        /**
         * <code>required bytes IV = 4;</code>
         */
        public boolean hasIV() {
            return ((bitField0_ & 0x00000008) == 0x00000008);
        }

        /**
         * <code>required bytes IV = 4;</code>
         */
        public com.google.protobuf.ByteString getIV() {
            return iV_;
        }

        private void initFields() {
            cipherText_ = com.google.protobuf.ByteString.EMPTY;
            receiverPublicKey_ = com.google.protobuf.ByteString.EMPTY;
            senderPublicKey_ = com.google.protobuf.ByteString.EMPTY;
            iV_ = com.google.protobuf.ByteString.EMPTY;
        }

        private byte memoizedIsInitialized = -1;

        public final boolean isInitialized() {
            byte isInitialized = memoizedIsInitialized;
            if (isInitialized == 1) {
                return true;
            }
            if (isInitialized == 0) {
                return false;
            }

            if (!hasCipherText()) {
                memoizedIsInitialized = 0;
                return false;
            }
            if (!hasReceiverPublicKey()) {
                memoizedIsInitialized = 0;
                return false;
            }
            if (!hasSenderPublicKey()) {
                memoizedIsInitialized = 0;
                return false;
            }
            if (!hasIV()) {
                memoizedIsInitialized = 0;
                return false;
            }
            memoizedIsInitialized = 1;
            return true;
        }

        public void writeTo(com.google.protobuf.CodedOutputStream output)
                throws java.io.IOException {
            getSerializedSize();
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                output.writeBytes(1, cipherText_);
            }
            if (((bitField0_ & 0x00000002) == 0x00000002)) {
                output.writeBytes(2, receiverPublicKey_);
            }
            if (((bitField0_ & 0x00000004) == 0x00000004)) {
                output.writeBytes(3, senderPublicKey_);
            }
            if (((bitField0_ & 0x00000008) == 0x00000008)) {
                output.writeBytes(4, iV_);
            }
            getUnknownFields().writeTo(output);
        }

        private int memoizedSerializedSize = -1;

        public int getSerializedSize() {
            int size = memoizedSerializedSize;
            if (size != -1) {
                return size;
            }

            size = 0;
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(1, cipherText_);
            }
            if (((bitField0_ & 0x00000002) == 0x00000002)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(2, receiverPublicKey_);
            }
            if (((bitField0_ & 0x00000004) == 0x00000004)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(3, senderPublicKey_);
            }
            if (((bitField0_ & 0x00000008) == 0x00000008)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(4, iV_);
            }
            size += getUnknownFields().getSerializedSize();
            memoizedSerializedSize = size;
            return size;
        }

        private static final long serialVersionUID = 0L;

        @java.lang.Override
        protected java.lang.Object writeReplace()
                throws java.io.ObjectStreamException {
            return super.writeReplace();
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(
                com.google.protobuf.ByteString data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(
                com.google.protobuf.ByteString data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(byte[] data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(
                byte[] data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseDelimitedFrom(
                java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseDelimitedFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(
                com.google.protobuf.CodedInputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.TarsierPrivateMessage parseFrom(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static Builder newBuilder() {
            return Builder.create();
        }

        public Builder newBuilderForType() {
            return newBuilder();
        }

        public static Builder newBuilder(TarsierWireProtos.TarsierPrivateMessage prototype) {
            return newBuilder().mergeFrom(prototype);
        }

        public Builder toBuilder() {
            return newBuilder(this);
        }

        @java.lang.Override
        protected Builder newBuilderForType(
                com.google.protobuf.GeneratedMessage.BuilderParent parent) {
            Builder builder = new Builder(parent);
            return builder;
        }

        /**
         * Protobuf type {@code TarsierPrivateMessage}
         */
        public static final class Builder extends
                com.google.protobuf.GeneratedMessage.Builder<Builder> implements
                // @@protoc_insertion_point(builder_implements:TarsierPrivateMessage)
                TarsierWireProtos.TarsierPrivateMessageOrBuilder {

            public static final com.google.protobuf.Descriptors.Descriptor
            getDescriptor() {
                return TarsierWireProtos.internal_static_TarsierPrivateMessage_descriptor;
            }

            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internalGetFieldAccessorTable() {
                return TarsierWireProtos.internal_static_TarsierPrivateMessage_fieldAccessorTable
                        .ensureFieldAccessorsInitialized(
                                TarsierWireProtos.TarsierPrivateMessage.class,
                                TarsierWireProtos.TarsierPrivateMessage.Builder.class);
            }

            // Construct using TarsierWireProtos.TarsierPrivateMessage.newBuilder()
            private Builder() {
                maybeForceBuilderInitialization();
            }

            private Builder(
                    com.google.protobuf.GeneratedMessage.BuilderParent parent) {
                super(parent);
                maybeForceBuilderInitialization();
            }

            private void maybeForceBuilderInitialization() {
                if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
                }
            }

            private static Builder create() {
                return new Builder();
            }

            public Builder clear() {
                super.clear();
                cipherText_ = com.google.protobuf.ByteString.EMPTY;
                bitField0_ = (bitField0_ & ~0x00000001);
                receiverPublicKey_ = com.google.protobuf.ByteString.EMPTY;
                bitField0_ = (bitField0_ & ~0x00000002);
                senderPublicKey_ = com.google.protobuf.ByteString.EMPTY;
                bitField0_ = (bitField0_ & ~0x00000004);
                iV_ = com.google.protobuf.ByteString.EMPTY;
                bitField0_ = (bitField0_ & ~0x00000008);
                return this;
            }

            public Builder clone() {
                return create().mergeFrom(buildPartial());
            }

            public com.google.protobuf.Descriptors.Descriptor
            getDescriptorForType() {
                return TarsierWireProtos.internal_static_TarsierPrivateMessage_descriptor;
            }

            public TarsierWireProtos.TarsierPrivateMessage getDefaultInstanceForType() {
                return TarsierWireProtos.TarsierPrivateMessage.getDefaultInstance();
            }

            public TarsierWireProtos.TarsierPrivateMessage build() {
                TarsierWireProtos.TarsierPrivateMessage result = buildPartial();
                if (!result.isInitialized()) {
                    throw newUninitializedMessageException(result);
                }
                return result;
            }

            public TarsierWireProtos.TarsierPrivateMessage buildPartial() {
                TarsierWireProtos.TarsierPrivateMessage result
                        = new TarsierWireProtos.TarsierPrivateMessage(this);
                int from_bitField0_ = bitField0_;
                int to_bitField0_ = 0;
                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
                    to_bitField0_ |= 0x00000001;
                }
                result.cipherText_ = cipherText_;
                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
                    to_bitField0_ |= 0x00000002;
                }
                result.receiverPublicKey_ = receiverPublicKey_;
                if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
                    to_bitField0_ |= 0x00000004;
                }
                result.senderPublicKey_ = senderPublicKey_;
                if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
                    to_bitField0_ |= 0x00000008;
                }
                result.iV_ = iV_;
                result.bitField0_ = to_bitField0_;
                onBuilt();
                return result;
            }

            public Builder mergeFrom(com.google.protobuf.Message other) {
                if (other instanceof TarsierWireProtos.TarsierPrivateMessage) {
                    return mergeFrom((TarsierWireProtos.TarsierPrivateMessage) other);
                } else {
                    super.mergeFrom(other);
                    return this;
                }
            }

            public Builder mergeFrom(TarsierWireProtos.TarsierPrivateMessage other) {
                if (other == TarsierWireProtos.TarsierPrivateMessage.getDefaultInstance()) {
                    return this;
                }
                if (other.hasCipherText()) {
                    setCipherText(other.getCipherText());
                }
                if (other.hasReceiverPublicKey()) {
                    setReceiverPublicKey(other.getReceiverPublicKey());
                }
                if (other.hasSenderPublicKey()) {
                    setSenderPublicKey(other.getSenderPublicKey());
                }
                if (other.hasIV()) {
                    setIV(other.getIV());
                }
                this.mergeUnknownFields(other.getUnknownFields());
                return this;
            }

            public final boolean isInitialized() {
                if (!hasCipherText()) {

                    return false;
                }
                if (!hasReceiverPublicKey()) {

                    return false;
                }
                if (!hasSenderPublicKey()) {

                    return false;
                }
                if (!hasIV()) {

                    return false;
                }
                return true;
            }

            public Builder mergeFrom(
                    com.google.protobuf.CodedInputStream input,
                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                    throws java.io.IOException {
                TarsierWireProtos.TarsierPrivateMessage parsedMessage = null;
                try {
                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
                } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                    parsedMessage = (TarsierWireProtos.TarsierPrivateMessage) e
                            .getUnfinishedMessage();
                    throw e;
                } finally {
                    if (parsedMessage != null) {
                        mergeFrom(parsedMessage);
                    }
                }
                return this;
            }

            private int bitField0_;

            private com.google.protobuf.ByteString cipherText_
                    = com.google.protobuf.ByteString.EMPTY;

            /**
             * <code>required bytes cipherText = 1;</code>
             */
            public boolean hasCipherText() {
                return ((bitField0_ & 0x00000001) == 0x00000001);
            }

            /**
             * <code>required bytes cipherText = 1;</code>
             */
            public com.google.protobuf.ByteString getCipherText() {
                return cipherText_;
            }

            /**
             * <code>required bytes cipherText = 1;</code>
             */
            public Builder setCipherText(com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000001;
                cipherText_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required bytes cipherText = 1;</code>
             */
            public Builder clearCipherText() {
                bitField0_ = (bitField0_ & ~0x00000001);
                cipherText_ = getDefaultInstance().getCipherText();
                onChanged();
                return this;
            }

            private com.google.protobuf.ByteString receiverPublicKey_
                    = com.google.protobuf.ByteString.EMPTY;

            /**
             * <code>required bytes receiverPublicKey = 2;</code>
             */
            public boolean hasReceiverPublicKey() {
                return ((bitField0_ & 0x00000002) == 0x00000002);
            }

            /**
             * <code>required bytes receiverPublicKey = 2;</code>
             */
            public com.google.protobuf.ByteString getReceiverPublicKey() {
                return receiverPublicKey_;
            }

            /**
             * <code>required bytes receiverPublicKey = 2;</code>
             */
            public Builder setReceiverPublicKey(com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000002;
                receiverPublicKey_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required bytes receiverPublicKey = 2;</code>
             */
            public Builder clearReceiverPublicKey() {
                bitField0_ = (bitField0_ & ~0x00000002);
                receiverPublicKey_ = getDefaultInstance().getReceiverPublicKey();
                onChanged();
                return this;
            }

            private com.google.protobuf.ByteString senderPublicKey_
                    = com.google.protobuf.ByteString.EMPTY;

            /**
             * <code>required bytes senderPublicKey = 3;</code>
             */
            public boolean hasSenderPublicKey() {
                return ((bitField0_ & 0x00000004) == 0x00000004);
            }

            /**
             * <code>required bytes senderPublicKey = 3;</code>
             */
            public com.google.protobuf.ByteString getSenderPublicKey() {
                return senderPublicKey_;
            }

            /**
             * <code>required bytes senderPublicKey = 3;</code>
             */
            public Builder setSenderPublicKey(com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000004;
                senderPublicKey_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required bytes senderPublicKey = 3;</code>
             */
            public Builder clearSenderPublicKey() {
                bitField0_ = (bitField0_ & ~0x00000004);
                senderPublicKey_ = getDefaultInstance().getSenderPublicKey();
                onChanged();
                return this;
            }

            private com.google.protobuf.ByteString iV_ = com.google.protobuf.ByteString.EMPTY;

            /**
             * <code>required bytes IV = 4;</code>
             */
            public boolean hasIV() {
                return ((bitField0_ & 0x00000008) == 0x00000008);
            }

            /**
             * <code>required bytes IV = 4;</code>
             */
            public com.google.protobuf.ByteString getIV() {
                return iV_;
            }

            /**
             * <code>required bytes IV = 4;</code>
             */
            public Builder setIV(com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000008;
                iV_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required bytes IV = 4;</code>
             */
            public Builder clearIV() {
                bitField0_ = (bitField0_ & ~0x00000008);
                iV_ = getDefaultInstance().getIV();
                onChanged();
                return this;
            }

            // @@protoc_insertion_point(builder_scope:TarsierPrivateMessage)
        }

        static {
            defaultInstance = new TarsierPrivateMessage(true);
            defaultInstance.initFields();
        }

        // @@protoc_insertion_point(class_scope:TarsierPrivateMessage)
    }

    public interface TarsierPublicMessageOrBuilder extends
            // @@protoc_insertion_point(interface_extends:TarsierPublicMessage)
            com.google.protobuf.MessageOrBuilder {

        /**
         * <code>required bytes plainText = 1;</code>
         */
        boolean hasPlainText();

        /**
         * <code>required bytes plainText = 1;</code>
         */
        com.google.protobuf.ByteString getPlainText();

        /**
         * <code>required bytes senderPublicKey = 2;</code>
         */
        boolean hasSenderPublicKey();

        /**
         * <code>required bytes senderPublicKey = 2;</code>
         */
        com.google.protobuf.ByteString getSenderPublicKey();
    }

    /**
     * Protobuf type {@code TarsierPublicMessage}
     */
    public static final class TarsierPublicMessage extends
            com.google.protobuf.GeneratedMessage implements
            // @@protoc_insertion_point(message_implements:TarsierPublicMessage)
            TarsierPublicMessageOrBuilder {

        // Use TarsierPublicMessage.newBuilder() to construct.
        private TarsierPublicMessage(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
            super(builder);
            this.unknownFields = builder.getUnknownFields();
        }

        private TarsierPublicMessage(boolean noInit) {
            this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance();
        }

        private static final TarsierPublicMessage defaultInstance;

        public static TarsierPublicMessage getDefaultInstance() {
            return defaultInstance;
        }

        public TarsierPublicMessage getDefaultInstanceForType() {
            return defaultInstance;
        }

        private final com.google.protobuf.UnknownFieldSet unknownFields;

        @java.lang.Override
        public final com.google.protobuf.UnknownFieldSet
        getUnknownFields() {
            return this.unknownFields;
        }

        private TarsierPublicMessage(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            initFields();
            int mutable_bitField0_ = 0;
            com.google.protobuf.UnknownFieldSet.Builder unknownFields =
                    com.google.protobuf.UnknownFieldSet.newBuilder();
            try {
                boolean done = false;
                while (!done) {
                    int tag = input.readTag();
                    switch (tag) {
                        case 0:
                            done = true;
                            break;
                        default: {
                            if (!parseUnknownField(input, unknownFields,
                                    extensionRegistry, tag)) {
                                done = true;
                            }
                            break;
                        }
                        case 10: {
                            bitField0_ |= 0x00000001;
                            plainText_ = input.readBytes();
                            break;
                        }
                        case 18: {
                            bitField0_ |= 0x00000002;
                            senderPublicKey_ = input.readBytes();
                            break;
                        }
                    }
                }
            } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                throw e.setUnfinishedMessage(this);
            } catch (java.io.IOException e) {
                throw new com.google.protobuf.InvalidProtocolBufferException(
                        e.getMessage()).setUnfinishedMessage(this);
            } finally {
                this.unknownFields = unknownFields.build();
                makeExtensionsImmutable();
            }
        }

        public static final com.google.protobuf.Descriptors.Descriptor
        getDescriptor() {
            return TarsierWireProtos.internal_static_TarsierPublicMessage_descriptor;
        }

        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
        internalGetFieldAccessorTable() {
            return TarsierWireProtos.internal_static_TarsierPublicMessage_fieldAccessorTable
                    .ensureFieldAccessorsInitialized(
                            TarsierWireProtos.TarsierPublicMessage.class,
                            TarsierWireProtos.TarsierPublicMessage.Builder.class);
        }

        public static com.google.protobuf.Parser<TarsierPublicMessage> PARSER =
                new com.google.protobuf.AbstractParser<TarsierPublicMessage>() {
                    public TarsierPublicMessage parsePartialFrom(
                            com.google.protobuf.CodedInputStream input,
                            com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                            throws com.google.protobuf.InvalidProtocolBufferException {
                        return new TarsierPublicMessage(input, extensionRegistry);
                    }
                };

        @java.lang.Override
        public com.google.protobuf.Parser<TarsierPublicMessage> getParserForType() {
            return PARSER;
        }

        private int bitField0_;

        public static final int PLAINTEXT_FIELD_NUMBER = 1;

        private com.google.protobuf.ByteString plainText_;

        /**
         * <code>required bytes plainText = 1;</code>
         */
        public boolean hasPlainText() {
            return ((bitField0_ & 0x00000001) == 0x00000001);
        }

        /**
         * <code>required bytes plainText = 1;</code>
         */
        public com.google.protobuf.ByteString getPlainText() {
            return plainText_;
        }

        public static final int SENDERPUBLICKEY_FIELD_NUMBER = 2;

        private com.google.protobuf.ByteString senderPublicKey_;

        /**
         * <code>required bytes senderPublicKey = 2;</code>
         */
        public boolean hasSenderPublicKey() {
            return ((bitField0_ & 0x00000002) == 0x00000002);
        }

        /**
         * <code>required bytes senderPublicKey = 2;</code>
         */
        public com.google.protobuf.ByteString getSenderPublicKey() {
            return senderPublicKey_;
        }

        private void initFields() {
            plainText_ = com.google.protobuf.ByteString.EMPTY;
            senderPublicKey_ = com.google.protobuf.ByteString.EMPTY;
        }

        private byte memoizedIsInitialized = -1;

        public final boolean isInitialized() {
            byte isInitialized = memoizedIsInitialized;
            if (isInitialized == 1) {
                return true;
            }
            if (isInitialized == 0) {
                return false;
            }

            if (!hasPlainText()) {
                memoizedIsInitialized = 0;
                return false;
            }
            if (!hasSenderPublicKey()) {
                memoizedIsInitialized = 0;
                return false;
            }
            memoizedIsInitialized = 1;
            return true;
        }

        public void writeTo(com.google.protobuf.CodedOutputStream output)
                throws java.io.IOException {
            getSerializedSize();
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                output.writeBytes(1, plainText_);
            }
            if (((bitField0_ & 0x00000002) == 0x00000002)) {
                output.writeBytes(2, senderPublicKey_);
            }
            getUnknownFields().writeTo(output);
        }

        private int memoizedSerializedSize = -1;

        public int getSerializedSize() {
            int size = memoizedSerializedSize;
            if (size != -1) {
                return size;
            }

            size = 0;
            if (((bitField0_ & 0x00000001) == 0x00000001)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(1, plainText_);
            }
            if (((bitField0_ & 0x00000002) == 0x00000002)) {
                size += com.google.protobuf.CodedOutputStream
                        .computeBytesSize(2, senderPublicKey_);
            }
            size += getUnknownFields().getSerializedSize();
            memoizedSerializedSize = size;
            return size;
        }

        private static final long serialVersionUID = 0L;

        @java.lang.Override
        protected java.lang.Object writeReplace()
                throws java.io.ObjectStreamException {
            return super.writeReplace();
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(
                com.google.protobuf.ByteString data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(
                com.google.protobuf.ByteString data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(byte[] data)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(
                byte[] data,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws com.google.protobuf.InvalidProtocolBufferException {
            return PARSER.parseFrom(data, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseDelimitedFrom(
                java.io.InputStream input)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseDelimitedFrom(
                java.io.InputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseDelimitedFrom(input, extensionRegistry);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(
                com.google.protobuf.CodedInputStream input)
                throws java.io.IOException {
            return PARSER.parseFrom(input);
        }

        public static TarsierWireProtos.TarsierPublicMessage parseFrom(
                com.google.protobuf.CodedInputStream input,
                com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                throws java.io.IOException {
            return PARSER.parseFrom(input, extensionRegistry);
        }

        public static Builder newBuilder() {
            return Builder.create();
        }

        public Builder newBuilderForType() {
            return newBuilder();
        }

        public static Builder newBuilder(TarsierWireProtos.TarsierPublicMessage prototype) {
            return newBuilder().mergeFrom(prototype);
        }

        public Builder toBuilder() {
            return newBuilder(this);
        }

        @java.lang.Override
        protected Builder newBuilderForType(
                com.google.protobuf.GeneratedMessage.BuilderParent parent) {
            Builder builder = new Builder(parent);
            return builder;
        }

        /**
         * Protobuf type {@code TarsierPublicMessage}
         */
        public static final class Builder extends
                com.google.protobuf.GeneratedMessage.Builder<Builder> implements
                // @@protoc_insertion_point(builder_implements:TarsierPublicMessage)
                TarsierWireProtos.TarsierPublicMessageOrBuilder {

            public static final com.google.protobuf.Descriptors.Descriptor
            getDescriptor() {
                return TarsierWireProtos.internal_static_TarsierPublicMessage_descriptor;
            }

            protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internalGetFieldAccessorTable() {
                return TarsierWireProtos.internal_static_TarsierPublicMessage_fieldAccessorTable
                        .ensureFieldAccessorsInitialized(
                                TarsierWireProtos.TarsierPublicMessage.class,
                                TarsierWireProtos.TarsierPublicMessage.Builder.class);
            }

            // Construct using TarsierWireProtos.TarsierPublicMessage.newBuilder()
            private Builder() {
                maybeForceBuilderInitialization();
            }

            private Builder(
                    com.google.protobuf.GeneratedMessage.BuilderParent parent) {
                super(parent);
                maybeForceBuilderInitialization();
            }

            private void maybeForceBuilderInitialization() {
                if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
                }
            }

            private static Builder create() {
                return new Builder();
            }

            public Builder clear() {
                super.clear();
                plainText_ = com.google.protobuf.ByteString.EMPTY;
                bitField0_ = (bitField0_ & ~0x00000001);
                senderPublicKey_ = com.google.protobuf.ByteString.EMPTY;
                bitField0_ = (bitField0_ & ~0x00000002);
                return this;
            }

            public Builder clone() {
                return create().mergeFrom(buildPartial());
            }

            public com.google.protobuf.Descriptors.Descriptor
            getDescriptorForType() {
                return TarsierWireProtos.internal_static_TarsierPublicMessage_descriptor;
            }

            public TarsierWireProtos.TarsierPublicMessage getDefaultInstanceForType() {
                return TarsierWireProtos.TarsierPublicMessage.getDefaultInstance();
            }

            public TarsierWireProtos.TarsierPublicMessage build() {
                TarsierWireProtos.TarsierPublicMessage result = buildPartial();
                if (!result.isInitialized()) {
                    throw newUninitializedMessageException(result);
                }
                return result;
            }

            public TarsierWireProtos.TarsierPublicMessage buildPartial() {
                TarsierWireProtos.TarsierPublicMessage result
                        = new TarsierWireProtos.TarsierPublicMessage(this);
                int from_bitField0_ = bitField0_;
                int to_bitField0_ = 0;
                if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
                    to_bitField0_ |= 0x00000001;
                }
                result.plainText_ = plainText_;
                if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
                    to_bitField0_ |= 0x00000002;
                }
                result.senderPublicKey_ = senderPublicKey_;
                result.bitField0_ = to_bitField0_;
                onBuilt();
                return result;
            }

            public Builder mergeFrom(com.google.protobuf.Message other) {
                if (other instanceof TarsierWireProtos.TarsierPublicMessage) {
                    return mergeFrom((TarsierWireProtos.TarsierPublicMessage) other);
                } else {
                    super.mergeFrom(other);
                    return this;
                }
            }

            public Builder mergeFrom(TarsierWireProtos.TarsierPublicMessage other) {
                if (other == TarsierWireProtos.TarsierPublicMessage.getDefaultInstance()) {
                    return this;
                }
                if (other.hasPlainText()) {
                    setPlainText(other.getPlainText());
                }
                if (other.hasSenderPublicKey()) {
                    setSenderPublicKey(other.getSenderPublicKey());
                }
                this.mergeUnknownFields(other.getUnknownFields());
                return this;
            }

            public final boolean isInitialized() {
                if (!hasPlainText()) {

                    return false;
                }
                if (!hasSenderPublicKey()) {

                    return false;
                }
                return true;
            }

            public Builder mergeFrom(
                    com.google.protobuf.CodedInputStream input,
                    com.google.protobuf.ExtensionRegistryLite extensionRegistry)
                    throws java.io.IOException {
                TarsierWireProtos.TarsierPublicMessage parsedMessage = null;
                try {
                    parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
                } catch (com.google.protobuf.InvalidProtocolBufferException e) {
                    parsedMessage = (TarsierWireProtos.TarsierPublicMessage) e
                            .getUnfinishedMessage();
                    throw e;
                } finally {
                    if (parsedMessage != null) {
                        mergeFrom(parsedMessage);
                    }
                }
                return this;
            }

            private int bitField0_;

            private com.google.protobuf.ByteString plainText_
                    = com.google.protobuf.ByteString.EMPTY;

            /**
             * <code>required bytes plainText = 1;</code>
             */
            public boolean hasPlainText() {
                return ((bitField0_ & 0x00000001) == 0x00000001);
            }

            /**
             * <code>required bytes plainText = 1;</code>
             */
            public com.google.protobuf.ByteString getPlainText() {
                return plainText_;
            }

            /**
             * <code>required bytes plainText = 1;</code>
             */
            public Builder setPlainText(com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000001;
                plainText_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required bytes plainText = 1;</code>
             */
            public Builder clearPlainText() {
                bitField0_ = (bitField0_ & ~0x00000001);
                plainText_ = getDefaultInstance().getPlainText();
                onChanged();
                return this;
            }

            private com.google.protobuf.ByteString senderPublicKey_
                    = com.google.protobuf.ByteString.EMPTY;

            /**
             * <code>required bytes senderPublicKey = 2;</code>
             */
            public boolean hasSenderPublicKey() {
                return ((bitField0_ & 0x00000002) == 0x00000002);
            }

            /**
             * <code>required bytes senderPublicKey = 2;</code>
             */
            public com.google.protobuf.ByteString getSenderPublicKey() {
                return senderPublicKey_;
            }

            /**
             * <code>required bytes senderPublicKey = 2;</code>
             */
            public Builder setSenderPublicKey(com.google.protobuf.ByteString value) {
                if (value == null) {
                    throw new NullPointerException();
                }
                bitField0_ |= 0x00000002;
                senderPublicKey_ = value;
                onChanged();
                return this;
            }

            /**
             * <code>required bytes senderPublicKey = 2;</code>
             */
            public Builder clearSenderPublicKey() {
                bitField0_ = (bitField0_ & ~0x00000002);
                senderPublicKey_ = getDefaultInstance().getSenderPublicKey();
                onChanged();
                return this;
            }

            // @@protoc_insertion_point(builder_scope:TarsierPublicMessage)
        }

        static {
            defaultInstance = new TarsierPublicMessage(true);
            defaultInstance.initFields();
        }

        // @@protoc_insertion_point(class_scope:TarsierPublicMessage)
    }

    private static final com.google.protobuf.Descriptors.Descriptor
            internal_static_HelloMessage_descriptor;

    private static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internal_static_HelloMessage_fieldAccessorTable;

    private static final com.google.protobuf.Descriptors.Descriptor
            internal_static_PeerUpdatedList_descriptor;

    private static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internal_static_PeerUpdatedList_fieldAccessorTable;

    private static final com.google.protobuf.Descriptors.Descriptor
            internal_static_Peer_descriptor;

    private static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internal_static_Peer_fieldAccessorTable;

    private static final com.google.protobuf.Descriptors.Descriptor
            internal_static_TarsierPrivateMessage_descriptor;

    private static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internal_static_TarsierPrivateMessage_fieldAccessorTable;

    private static final com.google.protobuf.Descriptors.Descriptor
            internal_static_TarsierPublicMessage_descriptor;

    private static
    com.google.protobuf.GeneratedMessage.FieldAccessorTable
            internal_static_TarsierPublicMessage_fieldAccessorTable;

    public static com.google.protobuf.Descriptors.FileDescriptor
    getDescriptor() {
        return descriptor;
    }

    private static com.google.protobuf.Descriptors.FileDescriptor
            descriptor;

    static {
        java.lang.String[] descriptorData = {
                "\n\027TarsierWireProtos.proto\"#\n\014HelloMessag" +
                        "e\022\023\n\004peer\030\001 \002(\0132\005.Peer\"&\n\017PeerUpdatedLis" +
                        "t\022\023\n\004peer\030\001 \003(\0132\005.Peer\"\'\n\004Peer\022\014\n\004name\030\001"
                        +
                        " \002(\t\022\021\n\tpublicKey\030\002 \002(\014\"k\n\025TarsierPrivat" +
                        "eMessage\022\022\n\ncipherText\030\001 \002(\014\022\031\n\021receiver" +
                        "PublicKey\030\002 \002(\014\022\027\n\017senderPublicKey\030\003 \002(\014"
                        +
                        "\022\n\n\002IV\030\004 \002(\014\"B\n\024TarsierPublicMessage\022\021\n\t"
                        +
                        "plainText\030\001 \002(\014\022\027\n\017senderPublicKey\030\002 \002(\014"
        };
        com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
                new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
                    public com.google.protobuf.ExtensionRegistry assignDescriptors(
                            com.google.protobuf.Descriptors.FileDescriptor root) {
                        descriptor = root;
                        return null;
                    }
                };
        com.google.protobuf.Descriptors.FileDescriptor
                .internalBuildGeneratedFileFrom(descriptorData,
                        new com.google.protobuf.Descriptors.FileDescriptor[]{
                        }, assigner);
        internal_static_HelloMessage_descriptor =
                getDescriptor().getMessageTypes().get(0);
        internal_static_HelloMessage_fieldAccessorTable = new
                com.google.protobuf.GeneratedMessage.FieldAccessorTable(
                internal_static_HelloMessage_descriptor,
                new java.lang.String[]{"Peer",});
        internal_static_PeerUpdatedList_descriptor =
                getDescriptor().getMessageTypes().get(1);
        internal_static_PeerUpdatedList_fieldAccessorTable = new
                com.google.protobuf.GeneratedMessage.FieldAccessorTable(
                internal_static_PeerUpdatedList_descriptor,
                new java.lang.String[]{"Peer",});
        internal_static_Peer_descriptor =
                getDescriptor().getMessageTypes().get(2);
        internal_static_Peer_fieldAccessorTable = new
                com.google.protobuf.GeneratedMessage.FieldAccessorTable(
                internal_static_Peer_descriptor,
                new java.lang.String[]{"Name", "PublicKey",});
        internal_static_TarsierPrivateMessage_descriptor =
                getDescriptor().getMessageTypes().get(3);
        internal_static_TarsierPrivateMessage_fieldAccessorTable = new
                com.google.protobuf.GeneratedMessage.FieldAccessorTable(
                internal_static_TarsierPrivateMessage_descriptor,
                new java.lang.String[]{"CipherText", "ReceiverPublicKey", "SenderPublicKey",
                        "IV",});
        internal_static_TarsierPublicMessage_descriptor =
                getDescriptor().getMessageTypes().get(4);
        internal_static_TarsierPublicMessage_fieldAccessorTable = new
                com.google.protobuf.GeneratedMessage.FieldAccessorTable(
                internal_static_TarsierPublicMessage_descriptor,
                new java.lang.String[]{"PlainText", "SenderPublicKey",});
    }

    // @@protoc_insertion_point(outer_class_scope)
} public class TarsierMessageFactory {

    public static byte[] wirePrivateProto(byte[] peerPublicKey, byte[] message)
            throws PeerCipherException {

        byte[] myPublicKey = getPublicKey();
        TarsierPrivateMessage.Builder privateMessage = TarsierPrivateMessage.newBuilder();

        privateMessage.setReceiverPublicKey(ByteString.copyFrom(peerPublicKey));
        privateMessage.setSenderPublicKey(ByteString.copyFrom(myPublicKey));

        PeerCipher cipher = new PeerCipher(peerPublicKey);
        CBCEncryptionProduct encryptionProduct = cipher.encrypt(message);
        byte[] cipherText = encryptionProduct.getCiphertext();
        byte[] IV         = encryptionProduct.getIV();

        // privateMessage.setCipherText(ByteString.copyFrom(cipherText));
        privateMessage.setCipherText(ByteString.copyFrom(message));
        privateMessage.setIV(ByteString.copyFrom(IV));

        byte[] messageProto = privateMessage.build().toByteArray();

        return ByteUtils.prependInt(MessageType.MESSAGE_TYPE_PRIVATE, messageProto);
    }

    public static byte[] wirePublicProto(byte[] message) {
        TarsierPublicMessage.Builder publicMessage = TarsierPublicMessage.newBuilder();
        publicMessage.setSenderPublicKey(ByteString.copyFrom(getPublicKey()));
        publicMessage.setPlainText(ByteString.copyFrom(message));

        byte[] messageProto =  publicMessage.build().toByteArray();

        return ByteUtils.prependInt(MessageType.MESSAGE_TYPE_PUBLIC, messageProto);
    }

    public static byte[] getPublicKey() {
        return Tarsier.app().getUserPreferences().getKeyPair().getPublicKey();
    }

    //TODO: Handle incoming methods too
}
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import android.os.Handler;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import ch.tarsier.tarsier.Tarsier;
import ch.tarsier.tarsier.domain.model.Peer;
import ch.tarsier.tarsier.domain.model.User;
import ch.tarsier.tarsier.domain.model.value.PublicKey;
import ch.tarsier.tarsier.exception.PeerCipherException;
import ch.tarsier.tarsier.util.ByteUtils;
import ch.tarsier.tarsier.network.ConnectionInterface;
import ch.tarsier.tarsier.network.messages.MessageType;
import ch.tarsier.tarsier.network.messages.TarsierWireProtos;
import ch.tarsier.tarsier.util.TarsierMessageFactory;
package ch.tarsier.tarsier.network.server;





/**
 * Represents the connection as the server, which maintain connections with
 * the clients and takes care of routing new messages and peers list to them.
 *
 * @author FredericJacobs
 * @author amirrezaw
 */
public class ServerConnection implements Runnable, ConnectionInterface {

    private static final String TAG = "TarsierServerConnection";

    private LinkedHashMap<String, ConnectionHandler> mConnectionMap
            = new LinkedHashMap<>();

    private LinkedHashMap<String, Peer> mPeersMap = new LinkedHashMap<>();

    private User mLocalUser = Tarsier.app().getUserRepository().getUser();

    private ServerSocket mServer;

    private Handler mHandler;

    public ServerConnection(Handler handler) throws IOException {
        Log.d(TAG, "ServerConnection Created.");
        this.mServer = new ServerSocket();
        this.mServer.setReuseAddress(true);
        this.mServer.bind(new InetSocketAddress(MessageType.SERVER_SOCKET));
        this.mHandler = handler;
        Thread t = new Thread(this);
        t.start();
    }

    private void selfAdd(ConnectionHandler handler) {
        TarsierWireProtos.Peer.Builder peer = TarsierWireProtos.Peer.newBuilder();
        peer.setName(mLocalUser.getUserName());
        peer.setPublicKey(ByteString.copyFrom(mLocalUser.getPublicKey().getBytes()));
        addPeer(peer.build(), handler);
    }

    @Override
    public void run() {
        while (true) {
            try {
                Socket socket = mServer.accept();
                new ConnectionHandler(this, socket, mHandler);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    protected void addPeer(TarsierWireProtos.Peer peer, ConnectionHandler handler) {
        mConnectionMap.put(new String(peer.getPublicKey().toByteArray()), handler);
        mPeersMap.put(new String(peer.getPublicKey().toByteArray()),
                new Peer(peer.getName(), new PublicKey(peer.getPublicKey().toByteArray())));

        Log.d(TAG, "Peer " + peer.getName() + " added with key " + new String(
                peer.getPublicKey().toByteArray()));
    }

    protected void peerDisconnected(TarsierWireProtos.Peer peer) {
        mConnectionMap.remove(new String(peer.getPublicKey().toByteArray()));
        mPeersMap.remove(peer.getPublicKey().toByteArray());
        Log.d(TAG, "Peer " + peer.getName() + " is out: " + mPeersMap.values().toString());
    }

    @Override
    public void broadcastMessage(byte[] message) {
        byte[] wireMessage = TarsierMessageFactory.wirePublicProto(message);
        broadcastMessage(mLocalUser.getPublicKey(), wireMessage);
    }

    //This sends all public messages.
    public void broadcastMessage(PublicKey publicKey, byte[] wireMessage) {
        Log.d(TAG, "PeerList " + getPeersList());
        for (Peer peer : getPeersList()) {
            Log.d(TAG, "publicKey : " + publicKey);
            Log.d(TAG, "peer publicKey : " + peer.getPublicKey());
            Log.d(TAG, "peer publicKey == publicKey : " + (peer.getPublicKey().equals(publicKey)));
            if (!peer.getPublicKey().equals(publicKey) && !peer.getPublicKey().equals(mLocalUser.getPublicKey())) {
                Log.d(TAG, "sending message to : " + peer.getUserName());
                ConnectionHandler connection = mConnectionMap.get(new String(peer.getPublicKey().toByteArray()));
                connection.write(wireMessage);
            }
        }

        Log.d(TAG, "A public message is sent to all peers.");
    }

    protected void broadcastUpdatedPeerList() {
        TarsierWireProtos.PeerUpdatedList.Builder peerList = TarsierWireProtos.PeerUpdatedList
                .newBuilder();

        for (Peer aPeer : getPeersList()) {
            TarsierWireProtos.Peer.Builder tarsierPeer = TarsierWireProtos.Peer.newBuilder();
            tarsierPeer.setPublicKey(ByteString.copyFrom(aPeer.getPublicKey().getBytes()));
            tarsierPeer.setName(aPeer.getUserName());
            peerList.addPeer(tarsierPeer.build());
        }

        for (Peer peer : getPeersList()) {
            ConnectionHandler connection = mConnectionMap.get(new String(peer.getPublicKey().toByteArray()));
            if (peer == null) {
                Log.d(TAG, "peer is null");
            } else if (connection == null) {
                Log.d(TAG, "Connection is null");
            } else {

                connection.write(ByteUtils.prependInt(MessageType.MESSAGE_TYPE_PEER_LIST,
                        peerList.build().toByteArray()));
            }
        }

        Log.d(TAG, "Updated peerList is broadcast.");
    }

    public void sendMessage(Peer peer, byte[] message) {
        sendMessage(peer.getPublicKey().getBytes(), message);
    }

    protected void sendMessage(byte[] publicKey, byte[] message) {
        ConnectionHandler connection = mConnectionMap.get(new String(publicKey));
        if (connection != null) {
            byte[] wireMessage = new byte[0];
            try {
                wireMessage = TarsierMessageFactory.wirePrivateProto(publicKey, message);
            } catch (PeerCipherException e) {