org.botlibre.sense.twitter.Twitter.java Source code

Java tutorial

Introduction

Here is the source code for org.botlibre.sense.twitter.Twitter.java

Source

/******************************************************************************
 *
 *  Copyright 2014 Paphus Solutions Inc.
 *
 *  Licensed under the Eclipse Public License, Version 1.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.eclipse.org/legal/epl-v10.html
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
package org.botlibre.sense.twitter;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

import org.botlibre.Bot;
import org.botlibre.BotException;
import org.botlibre.api.knowledge.Network;
import org.botlibre.api.knowledge.Relationship;
import org.botlibre.api.knowledge.Vertex;
import org.botlibre.knowledge.Primitive;
import org.botlibre.self.SelfCompiler;
import org.botlibre.sense.BasicSense;
import org.botlibre.sense.http.Http;
import org.botlibre.thought.language.Language;
import org.botlibre.thought.language.Language.LanguageState;
import org.botlibre.util.TextStream;
import org.botlibre.util.Utils;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import twitter4j.Paging;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.StatusUpdate;
import twitter4j.Trends;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.api.SearchResource;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import twitter4j.conf.ConfigurationBuilder;

/**
 * Enables receiving a sending messages through Twitter.
 */
public class Twitter extends BasicSense {
    public static int TREND_CHECK = 1000 * 60 * 60 * 1; // 1 hour.
    public static int MAX_LOOKUP = 100;
    public static String oauthKey = "key";
    public static String oauthSecret = "secret";

    protected String userName = "";
    protected String token = "";
    protected String tokenSecret = "";

    protected boolean initProperties;

    protected boolean autoFollow = false;
    protected boolean autoFollowFriendsFriends = false;
    protected boolean autoFollowFriendsFollowers = false;
    protected boolean followMessages = false;
    protected String welcomeMessage = "";
    protected int maxFriends = 100;
    protected int maxFriendsPerCycle = 5;
    protected int maxWelcomesPerCycle = 20;
    protected int maxPage = 5;
    protected int maxStatus = 20;
    protected int maxFeed = 20;
    protected int maxSearch = 20;
    protected int maxErrors = 5;
    protected int errors;
    protected boolean processStatus = false;
    protected boolean listenStatus = false;
    protected boolean tweetChats = true;
    protected boolean replyToMentions = true;
    protected boolean replyToMessages = true;
    protected boolean ignoreReplies = true;
    protected boolean autoTweet = false;
    protected boolean learn = false;
    protected boolean learnFromSelf = false;
    protected int autoTweetHours = 24;
    protected List<String> retweet = new ArrayList<String>();
    protected List<String> tweetRSS = new ArrayList<String>();
    protected List<String> rssKeywords = new ArrayList<String>();
    protected List<String> tweetSearch = new ArrayList<String>();
    protected List<String> statusKeywords = new ArrayList<String>();
    protected List<String> autoFollowKeywords = new ArrayList<String>();
    protected List<String> autoFollowSearch = new ArrayList<String>();

    protected boolean checkTrends = false;
    protected long lastTrendsCheck;
    protected Set<Long> processedTweets = new HashSet<Long>();

    protected int tweets;
    protected int tweetsProcessed;
    protected int retweets;

    protected twitter4j.Twitter connection;

    public Twitter(boolean enabled) {
        this.isEnabled = enabled;
        this.languageState = LanguageState.Discussion;
    }

    public Twitter() {
        this(false);
    }

    public boolean getListenStatus() {
        initProperties();
        return listenStatus;
    }

    public void setListenStatus(boolean listenStatus) {
        initProperties();
        this.listenStatus = listenStatus;
    }

    public int getTweets() {
        return tweets;
    }

    public void setTweets(int tweets) {
        this.tweets = tweets;
    }

    public int getTweetsProcessed() {
        return tweetsProcessed;
    }

    public void setTweetsProcessed(int tweetsProcessed) {
        this.tweetsProcessed = tweetsProcessed;
    }

    public int getRetweets() {
        return retweets;
    }

    public void setRetweets(int retweets) {
        this.retweets = retweets;
    }

    public String getWelcomeMessage() {
        initProperties();
        return welcomeMessage;
    }

    public void setWelcomeMessage(String welcomeMessage) {
        initProperties();
        this.welcomeMessage = welcomeMessage;
    }

    public List<String> getRssKeywords() {
        initProperties();
        return rssKeywords;
    }

    public void setRssKeywords(List<String> rssKeywords) {
        initProperties();
        this.rssKeywords = rssKeywords;
    }

    public int getMaxSearch() {
        initProperties();
        return maxSearch;
    }

    public void setMaxSearch(int maxSearch) {
        initProperties();
        this.maxSearch = maxSearch;
    }

    public List<String> getAutoFollowSearch() {
        initProperties();
        return autoFollowSearch;
    }

    public void setAutoFollowSearch(List<String> autoFollowSearch) {
        initProperties();
        this.autoFollowSearch = autoFollowSearch;
    }

    public boolean getAutoFollowFriendsFriends() {
        initProperties();
        return autoFollowFriendsFriends;
    }

    public void setAutoFollowFriendsFriends(boolean autoFollowFriendsFriends) {
        initProperties();
        this.autoFollowFriendsFriends = autoFollowFriendsFriends;
    }

    public boolean getAutoFollowFriendsFollowers() {
        initProperties();
        return autoFollowFriendsFollowers;
    }

    public void setAutoFollowFriendsFollowers(boolean autoFollowFriendsFollowers) {
        initProperties();
        this.autoFollowFriendsFollowers = autoFollowFriendsFollowers;
    }

    public int getMaxFeed() {
        initProperties();
        return maxFeed;
    }

    public void setMaxFeed(int maxFeed) {
        initProperties();
        this.maxFeed = maxFeed;
    }

    public boolean getAutoTweet() {
        initProperties();
        return autoTweet;
    }

    public void setAutoTweet(boolean autoTweet) {
        initProperties();
        this.autoTweet = autoTweet;
    }

    public int getAutoTweetHours() {
        initProperties();
        return autoTweetHours;
    }

    public void setAutoTweetHours(int autoTweetHours) {
        initProperties();
        this.autoTweetHours = autoTweetHours;
    }

    public List<Vertex> getAutoTweets(Network network) {
        return network.createVertex(getPrimitive()).orderedRelations(Primitive.AUTOTWEETS);
    }

    public boolean getIgnoreReplies() {
        initProperties();
        return ignoreReplies;
    }

    public void setIgnoreReplies(boolean ignoreReplies) {
        initProperties();
        this.ignoreReplies = ignoreReplies;
    }

    public List<String> getStatusKeywords() {
        initProperties();
        return statusKeywords;
    }

    public void setStatusKeywords(List<String> statusKeywords) {
        initProperties();
        this.statusKeywords = statusKeywords;
    }

    public List<String> getAutoFollowKeywords() {
        initProperties();
        return autoFollowKeywords;
    }

    public void setAutoFollowKeywords(List<String> autoFollowKeywords) {
        initProperties();
        this.autoFollowKeywords = autoFollowKeywords;
    }

    /**
     * Authorise a new account to be accessible by Bot.
     * Return the request token that contains the URL that the user must use to authorise twitter.
     */
    public RequestToken authorizeAccount() throws TwitterException {
        twitter4j.Twitter twitter = new TwitterFactory().getInstance();
        twitter.setOAuthConsumer(getOauthKey(), getOauthSecret());
        RequestToken requestToken = twitter.getOAuthRequestToken();
        setConnection(twitter);
        return requestToken;
    }

    /**
     * Authorise a new account to be accessible by Bot.
     */
    public void authorizeComplete() throws TwitterException {
        AccessToken token = getConnection().getOAuthAccessToken();
        setToken(token.getToken());
        setTokenSecret(token.getTokenSecret());
    }

    /**
     * Authorise a new account to be accessible by Bot.
     */
    public void authorizeComplete(String pin) throws TwitterException {
        AccessToken token = getConnection().getOAuthAccessToken(pin);
        setToken(token.getToken());
        setTokenSecret(token.getTokenSecret());
    }

    /**
     * Start sensing.
     */
    @Override
    public void awake() {
        super.awake();
        String user = this.bot.memory().getProperty("Twitter.user");
        if (user != null) {
            this.userName = user;
        }
        String token = this.bot.memory().getProperty("Twitter.token");
        if (token != null) {
            this.token = token;
        }
        String secret = this.bot.memory().getProperty("Twitter.secret");
        if (secret != null) {
            String data = secret;
            // Check if encrypted from && prefix.
            if (data.startsWith("&&")) {
                try {
                    this.tokenSecret = Utils.decrypt(Utils.KEY, data.substring(2, data.length()));
                } catch (Exception exception) {
                    this.tokenSecret = data;
                }
            } else {
                this.tokenSecret = data;
            }
            setIsEnabled(true);
        }
        String property = this.bot.memory().getProperty("Twitter.tweetChats");
        if (property != null) {
            this.tweetChats = Boolean.valueOf(property);
        }
    }

    /**
     * Migrate to new properties system.
     */
    public void migrateProperties() {
        Network memory = getBot().memory().newMemory();
        Vertex twitter = memory.createVertex(getPrimitive());
        Vertex user = twitter.getRelationship(Primitive.USER);
        if (user != null) {
            this.userName = (String) user.getData();
        }
        Vertex token = twitter.getRelationship(Primitive.TOKEN);
        if (token != null) {
            this.token = (String) token.getData();
        }
        Vertex secret = twitter.getRelationship(Primitive.SECRET);
        if (secret != null) {
            String data = (String) secret.getData();
            // Check if encrypted from && prefix.
            if (data.startsWith("&&")) {
                try {
                    this.tokenSecret = Utils.decrypt(Utils.KEY, data.substring(2, data.length()));
                } catch (Exception exception) {
                    this.tokenSecret = data;
                }
            } else {
                this.tokenSecret = data;
            }
            setIsEnabled(true);
        }
        Vertex property = twitter.getRelationship(Primitive.TWEETCHATS);
        if (property != null) {
            this.tweetChats = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.WELCOME);
        if (property != null) {
            this.welcomeMessage = (String) property.getData();
        }
        property = twitter.getRelationship(Primitive.AUTOFOLLOW);
        if (property != null) {
            this.autoFollow = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.AUTOFOLLOWFRIENDSFRIENDS);
        if (property != null) {
            this.autoFollowFriendsFriends = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.AUTOFOLLOWFRIENDSFOLLOWERS);
        if (property != null) {
            this.autoFollowFriendsFollowers = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.FOLLOWMESSAGES);
        if (property != null) {
            this.followMessages = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.MAXFRIENDS);
        if (property != null) {
            this.maxFriends = ((Number) property.getData()).intValue();
        }
        property = twitter.getRelationship(Primitive.MAXSTATUSCHECKS);
        if (property != null) {
            this.maxStatus = ((Number) property.getData()).intValue();
        }
        property = twitter.getRelationship(Primitive.PROCESSSTATUS);
        if (property != null) {
            this.processStatus = (Boolean) property.getData();
        }
        this.statusKeywords = new ArrayList<String>();
        List<Relationship> keywords = twitter.orderedRelationships(Primitive.STATUSKEYWORDS);
        if (keywords != null) {
            for (Relationship relationship : keywords) {
                String text = ((String) relationship.getTarget().getData()).trim();
                if (!text.isEmpty()) {
                    this.statusKeywords.add(text);
                }
            }
        }
        this.retweet = new ArrayList<String>();
        keywords = twitter.orderedRelationships(Primitive.RETWEET);
        if (keywords != null) {
            for (Relationship relationship : keywords) {
                String text = ((String) relationship.getTarget().getData()).trim();
                if (!text.isEmpty()) {
                    this.retweet.add(text);
                }
            }
        }
        this.autoFollowKeywords = new ArrayList<String>();
        List<Relationship> search = twitter.orderedRelationships(Primitive.AUTOFOLLOWKEYWORDS);
        if (search != null) {
            for (Relationship relationship : search) {
                String text = ((String) relationship.getTarget().getData()).trim();
                if (!text.isEmpty()) {
                    this.autoFollowKeywords.add(text);
                }
            }
        }
        this.autoFollowSearch = new ArrayList<String>();
        search = twitter.orderedRelationships(Primitive.AUTOFOLLOWSEARCH);
        if (search != null) {
            for (Relationship relationship : search) {
                String text = ((String) relationship.getTarget().getData()).trim();
                if (!text.isEmpty()) {
                    this.autoFollowSearch.add(text);
                }
            }
        }
        this.tweetSearch = new ArrayList<String>();
        search = twitter.orderedRelationships(Primitive.TWEETSEARCH);
        if (search != null) {
            for (Relationship relationship : search) {
                String text = ((String) relationship.getTarget().getData()).trim();
                if (!text.isEmpty()) {
                    this.tweetSearch.add(text);
                }
            }
        }
        this.tweetRSS = new ArrayList<String>();
        List<Relationship> rss = twitter.orderedRelationships(Primitive.TWEETRSS);
        if (rss != null) {
            for (Relationship relationship : rss) {
                String text = ((String) relationship.getTarget().getData()).trim();
                if (!text.isEmpty()) {
                    this.tweetRSS.add(text);
                }
            }
        }
        this.rssKeywords = new ArrayList<String>();
        keywords = twitter.orderedRelationships(Primitive.RSSKEYWORDS);
        if (keywords != null) {
            for (Relationship relationship : keywords) {
                String text = ((String) relationship.getTarget().getData()).trim();
                this.rssKeywords.add(text);
            }
        }
        property = twitter.getRelationship(Primitive.REPLYTOMENTIONS);
        if (property != null) {
            this.replyToMentions = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.REPLYTOMESSAGES);
        if (property != null) {
            this.replyToMessages = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.AUTOTWEET);
        if (property != null) {
            this.autoTweet = (Boolean) property.getData();
        }
        property = twitter.getRelationship(Primitive.AUTOTWEETHOURS);
        if (property != null) {
            this.autoTweetHours = ((Number) property.getData()).intValue();
        }

        // Remove old properties.
        twitter.internalRemoveRelationships(Primitive.USER);
        twitter.internalRemoveRelationships(Primitive.TOKEN);
        twitter.internalRemoveRelationships(Primitive.SECRET);
        twitter.internalRemoveRelationships(Primitive.TWEETCHATS);
        twitter.internalRemoveRelationships(Primitive.WELCOME);
        twitter.internalRemoveRelationships(Primitive.AUTOFOLLOW);
        twitter.internalRemoveRelationships(Primitive.AUTOFOLLOWFRIENDSFOLLOWERS);
        twitter.internalRemoveRelationships(Primitive.FOLLOWMESSAGES);
        twitter.internalRemoveRelationships(Primitive.MAXFRIENDS);
        twitter.internalRemoveRelationships(Primitive.MAXSTATUSCHECKS);
        twitter.internalRemoveRelationships(Primitive.PROCESSSTATUS);
        twitter.internalRemoveRelationships(Primitive.REPLYTOMENTIONS);
        twitter.internalRemoveRelationships(Primitive.REPLYTOMESSAGES);
        twitter.internalRemoveRelationships(Primitive.AUTOTWEET);
        twitter.internalRemoveRelationships(Primitive.AUTOTWEETHOURS);

        memory.save();

        saveProperties(null);
    }

    /**
     * Load settings.
     */
    public void initProperties() {
        if (this.initProperties) {
            return;
        }
        synchronized (this) {
            if (this.initProperties) {
                return;
            }
            getBot().memory().loadProperties("Twitter");
            String property = this.bot.memory().getProperty("Twitter.welcomeMessage");
            if (property != null) {
                this.welcomeMessage = property;
            }
            property = this.bot.memory().getProperty("Twitter.autoFollow");
            if (property != null) {
                this.autoFollow = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.autoFollowFriendsFriends");
            if (property != null) {
                this.autoFollowFriendsFriends = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.autoFollowFriendsFollowers");
            if (property != null) {
                this.autoFollowFriendsFollowers = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.followMessages");
            if (property != null) {
                this.followMessages = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.maxFriends");
            if (property != null) {
                this.maxFriends = Integer.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.maxStatus");
            if (property != null) {
                this.maxStatus = Integer.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.maxSearch");
            if (property != null) {
                this.maxSearch = Integer.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.processStatus");
            if (property != null) {
                this.processStatus = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.listenStatus");
            if (property != null) {
                this.listenStatus = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.learn");
            if (property != null) {
                this.learn = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.learnFromSelf");
            if (property != null) {
                this.learnFromSelf = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.replyToMentions");
            if (property != null) {
                this.replyToMentions = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.replyToMessages");
            if (property != null) {
                this.replyToMessages = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.ignoreReplies");
            if (property != null) {
                this.ignoreReplies = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.autoTweet");
            if (property != null) {
                this.autoTweet = Boolean.valueOf(property);
            }
            property = this.bot.memory().getProperty("Twitter.autoTweetHours");
            if (property != null) {
                this.autoTweetHours = Integer.valueOf(property);
            }

            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            this.statusKeywords = new ArrayList<String>();
            List<Relationship> keywords = twitter.orderedRelationships(Primitive.STATUSKEYWORDS);
            if (keywords != null) {
                for (Relationship relationship : keywords) {
                    String text = ((String) relationship.getTarget().getData()).trim();
                    if (!text.isEmpty()) {
                        this.statusKeywords.add(text);
                    }
                }
            }
            this.retweet = new ArrayList<String>();
            keywords = twitter.orderedRelationships(Primitive.RETWEET);
            if (keywords != null) {
                for (Relationship relationship : keywords) {
                    String text = ((String) relationship.getTarget().getData()).trim();
                    if (!text.isEmpty()) {
                        this.retweet.add(text);
                    }
                }
            }
            this.autoFollowKeywords = new ArrayList<String>();
            List<Relationship> search = twitter.orderedRelationships(Primitive.AUTOFOLLOWKEYWORDS);
            if (search != null) {
                for (Relationship relationship : search) {
                    String text = ((String) relationship.getTarget().getData()).trim();
                    if (!text.isEmpty()) {
                        this.autoFollowKeywords.add(text);
                    }
                }
            }
            this.autoFollowSearch = new ArrayList<String>();
            search = twitter.orderedRelationships(Primitive.AUTOFOLLOWSEARCH);
            if (search != null) {
                for (Relationship relationship : search) {
                    String text = ((String) relationship.getTarget().getData()).trim();
                    if (!text.isEmpty()) {
                        this.autoFollowSearch.add(text);
                    }
                }
            }
            this.tweetSearch = new ArrayList<String>();
            search = twitter.orderedRelationships(Primitive.TWEETSEARCH);
            if (search != null) {
                for (Relationship relationship : search) {
                    String text = ((String) relationship.getTarget().getData()).trim();
                    if (!text.isEmpty()) {
                        this.tweetSearch.add(text);
                    }
                }
            }
            this.tweetRSS = new ArrayList<String>();
            List<Relationship> rss = twitter.orderedRelationships(Primitive.TWEETRSS);
            if (rss != null) {
                for (Relationship relationship : rss) {
                    String text = ((String) relationship.getTarget().getData()).trim();
                    if (!text.isEmpty()) {
                        this.tweetRSS.add(text);
                    }
                }
            }
            this.rssKeywords = new ArrayList<String>();
            keywords = twitter.orderedRelationships(Primitive.RSSKEYWORDS);
            if (keywords != null) {
                for (Relationship relationship : keywords) {
                    String text = ((String) relationship.getTarget().getData()).trim();
                    this.rssKeywords.add(text);
                }
            }

            this.initProperties = true;
        }
    }

    public void saveProperties(List<String> autoTweets) {
        Network memory = getBot().memory().newMemory();
        Vertex twitter = memory.createVertex(getPrimitive());
        twitter.unpinChildren();

        memory.saveProperty("Twitter.user", this.userName, true);
        memory.saveProperty("Twitter.token", this.token, true);
        memory.saveProperty("Twitter.secret", "&&" + Utils.encrypt(Utils.KEY, this.tokenSecret), true);
        memory.saveProperty("Twitter.tweetChats", String.valueOf(this.tweetChats), true);

        memory.saveProperty("Twitter.welcomeMessage", this.welcomeMessage, false);
        memory.saveProperty("Twitter.autoFollow", String.valueOf(this.autoFollow), false);
        memory.saveProperty("Twitter.autoFollowFriendsFriends", String.valueOf(this.autoFollowFriendsFriends),
                false);
        memory.saveProperty("Twitter.autoFollowFriendsFollowers", String.valueOf(this.autoFollowFriendsFollowers),
                false);
        memory.saveProperty("Twitter.followMessages", String.valueOf(this.followMessages), false);
        memory.saveProperty("Twitter.maxFriends", String.valueOf(this.maxFriends), false);
        memory.saveProperty("Twitter.maxStatus", String.valueOf(this.maxStatus), false);
        memory.saveProperty("Twitter.maxSearch", String.valueOf(this.maxSearch), false);
        memory.saveProperty("Twitter.processStatus", String.valueOf(this.processStatus), false);
        memory.saveProperty("Twitter.listenStatus", String.valueOf(this.listenStatus), false);
        memory.saveProperty("Twitter.learn", String.valueOf(this.learn), false);
        memory.saveProperty("Twitter.learnFromSelf", String.valueOf(this.learnFromSelf), false);
        memory.saveProperty("Twitter.replyToMentions", String.valueOf(this.replyToMentions), false);
        memory.saveProperty("Twitter.replyToMessages", String.valueOf(this.replyToMessages), false);
        memory.saveProperty("Twitter.ignoreReplies", String.valueOf(this.ignoreReplies), false);
        memory.saveProperty("Twitter.autoTweet", String.valueOf(this.autoTweet), false);
        memory.saveProperty("Twitter.autoTweetHours", String.valueOf(this.autoTweetHours), false);

        twitter.internalRemoveRelationships(Primitive.STATUSKEYWORDS);
        for (String text : this.statusKeywords) {
            Vertex keywords = memory.createVertex(text);
            twitter.addRelationship(Primitive.STATUSKEYWORDS, keywords);
        }
        twitter.internalRemoveRelationships(Primitive.RETWEET);
        for (String text : this.retweet) {
            Vertex keywords = memory.createVertex(text);
            twitter.addRelationship(Primitive.RETWEET, keywords);
        }
        twitter.internalRemoveRelationships(Primitive.AUTOFOLLOWKEYWORDS);
        for (String text : this.autoFollowKeywords) {
            Vertex search = memory.createVertex(text);
            twitter.addRelationship(Primitive.AUTOFOLLOWKEYWORDS, search);
        }
        twitter.internalRemoveRelationships(Primitive.AUTOFOLLOWSEARCH);
        for (String text : this.autoFollowSearch) {
            Vertex search = memory.createVertex(text);
            twitter.addRelationship(Primitive.AUTOFOLLOWSEARCH, search);
        }
        twitter.internalRemoveRelationships(Primitive.TWEETSEARCH);
        for (String text : this.tweetSearch) {
            Vertex search = memory.createVertex(text);
            twitter.addRelationship(Primitive.TWEETSEARCH, search);
        }
        twitter.internalRemoveRelationships(Primitive.TWEETRSS);
        for (String text : this.tweetRSS) {
            Vertex rss = memory.createVertex(text);
            twitter.addRelationship(Primitive.TWEETRSS, rss);
        }
        twitter.internalRemoveRelationships(Primitive.RSSKEYWORDS);
        for (String text : this.rssKeywords) {
            Vertex keywords = memory.createVertex(text);
            twitter.addRelationship(Primitive.RSSKEYWORDS, keywords);
        }
        if (autoTweets != null) {
            Collection<Relationship> old = twitter.getRelationships(Primitive.AUTOTWEETS);
            if (old != null) {
                for (Relationship tweet : old) {
                    if (tweet.getTarget().instanceOf(Primitive.FORMULA)) {
                        SelfCompiler.getCompiler().unpin(tweet.getTarget());
                    }
                }
            }
            twitter.internalRemoveRelationships(Primitive.AUTOTWEETS);
            for (String text : autoTweets) {
                Vertex tweet = memory.createSentence(text);
                if (tweet.instanceOf(Primitive.FORMULA)) {
                    SelfCompiler.getCompiler().pin(tweet);
                }
                tweet.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
                twitter.addRelationship(Primitive.AUTOTWEETS, tweet);
            }
        }

        twitter.pinChildren();
        memory.save();
    }

    public void connect() throws TwitterException {
        initProperties();
        ConfigurationBuilder config = new ConfigurationBuilder();
        config.setOAuthConsumerKey(getOauthKey());
        config.setOAuthConsumerSecret(getOauthSecret());
        config.setOAuthAccessToken(getToken());
        config.setOAuthAccessTokenSecret(getTokenSecret());
        twitter4j.Twitter twitter = new TwitterFactory(config.build()).getInstance();
        User user = twitter.verifyCredentials();
        if (!this.userName.equals(user.getScreenName())) {
            this.userName = user.getScreenName();
            saveProperties(null);
        }
        //AccessToken accessToken = new AccessToken(getToken(), getTokenSecret());
        //twitter4j.Twitter twitter = new TwitterFactory().getInstance(accessToken);
        //twitter4j.Twitter twitter = new TwitterFactory().getInstance(getOauthKey(), getOauthSecret(), accessToken);
        //twitter4j.Twitter twitter = new TwitterFactory().getInstance(getUsername(), getPassword());
        setConnection(twitter);
    }

    /**
     * Check profile for messages.
     */
    public void checkProfile() {
        log("Checking profile.", Level.INFO);
        this.processedTweets = new HashSet<Long>();
        try {
            if (getConnection() == null) {
                connect();
            }
            if (this.checkTrends) {
                checkTrends();
            }
            checkFollowers();
            checkStatus();
            checkMentions();
            checkSearch();
            checkRSS();
            checkAutoTweet();
        } catch (Exception exception) {
            log(exception);
        }
        log("Done checking profile.", Level.INFO);
    }

    /**
     * Add the follower.
     */
    public void addFriend(String friend) {
        try {
            getConnection().createFriendship(friend);
        } catch (TwitterException exception) {
            log(exception);
        }
    }

    /**
     * Add the follower.
     */
    public void removeFriend(String friend) {
        try {
            getConnection().destroyFriendship(friend);
        } catch (TwitterException exception) {
            log(exception);
        }
    }

    /**
     * Check status.
     */
    public void checkStatus() {
        if (!getProcessStatus()) {
            return;
        }
        log("Checking status", Level.FINE);
        try {
            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            Vertex vertex = twitter.getRelationship(Primitive.LASTTIMELINE);
            long last = 0;
            if (vertex != null) {
                last = ((Number) vertex.getData()).longValue();
            }
            long max = 0;
            ResponseList<Status> timeline = null;
            boolean more = true;
            int page = 1;
            int count = 0;
            this.errors = 0;
            while (more && (count <= this.maxStatus) && page <= this.maxPage) {
                if (last == 0) {
                    timeline = getConnection().getHomeTimeline();
                    more = false;
                } else {
                    Paging paging = new Paging(page, last);
                    timeline = getConnection().getHomeTimeline(paging);
                    if ((timeline == null) || (timeline.size() < 20)) {
                        more = false;
                    }
                    page++;
                }
                if ((timeline == null) || timeline.isEmpty()) {
                    break;
                }
                log("Processing status", Level.INFO, timeline.size());
                for (int index = timeline.size() - 1; index >= 0; index--) {
                    if (count >= this.maxStatus) {
                        break;
                    }
                    if (this.errors > this.maxErrors) {
                        break;
                    }
                    Status status = timeline.get(index);
                    String name = status.getUser().getScreenName();
                    if (!name.equals(this.userName)) {
                        long statusTime = status.getCreatedAt().getTime();
                        long statusId = status.getId();
                        if (statusId > max) {
                            max = statusId;
                        }
                        if ((System.currentTimeMillis() - statusTime) > DAY) {
                            log("Day old status", Level.INFO, statusId, statusTime);
                            more = false;
                            continue;
                        }
                        if (statusId > last) {
                            if (Utils.checkProfanity(status.getText())) {
                                continue;
                            }
                            boolean match = false;
                            List<String> statusWords = new TextStream(status.getText().toLowerCase()).allWords();
                            if (getListenStatus()) {
                                this.languageState = LanguageState.Listening;
                                match = true;
                            } else {
                                for (String text : getStatusKeywords()) {
                                    List<String> keywords = new TextStream(text.toLowerCase()).allWords();
                                    if (!keywords.isEmpty() && statusWords.containsAll(keywords)) {
                                        match = true;
                                        break;
                                    }
                                }
                            }
                            if (getLearn()) {
                                learnTweet(status, true, true, memory);
                            }
                            if (match) {
                                count++;
                                input(status);
                                Utils.sleep(500);
                            } else {
                                log("Skipping status, missing keywords", Level.FINE, status.getText());
                                if (!status.isRetweet() && !status.getUser().isProtected()
                                        && !status.isRetweetedByMe()) {
                                    boolean retweeted = false;
                                    // Check retweet.
                                    for (String keywords : getRetweet()) {
                                        List<String> keyWords = new TextStream(keywords.toLowerCase()).allWords();
                                        if (!keyWords.isEmpty()) {
                                            if (statusWords.containsAll(keyWords)) {
                                                retweeted = true;
                                                count++;
                                                retweet(status);
                                                Utils.sleep(500);
                                                break;
                                            }
                                        }
                                    }
                                    if (!retweeted) {
                                        log("Skipping rewteet, missing keywords", Level.FINE, status.getText());
                                    }
                                } else if (!getRetweet().isEmpty()) {
                                    if (status.isRetweet()) {
                                        log("Skipping rewteet", Level.FINE, status.getText());
                                    } else if (status.getUser().isProtected()) {
                                        log("Skipping protected user", Level.FINE, status.getText());
                                    } else if (status.isRetweetedByMe()) {
                                        log("Skipping already retweeted", Level.FINE, status.getText());
                                    }
                                }
                            }
                        } else {
                            log("Old status", Level.INFO, statusId, statusTime);
                        }
                    }
                }
            }
            if (max != 0) {
                twitter.setRelationship(Primitive.LASTTIMELINE, memory.createVertex(max));
                memory.save();
            }
        } catch (Exception exception) {
            log(exception);
        }
        // Wait for language processing.
        int count = 0;
        while (count < 60 && !getBot().memory().getActiveMemory().isEmpty()) {
            Utils.sleep(1000);
        }
    }

    /**
     * Learn responses from the tweet search.
     */
    public void learnSearch(String tweetSearch, int maxSearch, boolean processTweets, boolean processReplies) {
        log("Learning from tweet search", Level.INFO, tweetSearch);
        try {
            Network memory = getBot().memory().newMemory();
            int count = 0;
            this.errors = 0;
            Set<Long> processed = new HashSet<Long>();
            Query query = new Query(tweetSearch);
            query.count(100);
            SearchResource search = getConnection().search();
            QueryResult result = search.search(query);
            List<Status> tweets = result.getTweets();
            if (tweets != null) {
                log("Processing search results", Level.INFO, tweets.size(), tweetSearch);
                for (Status tweet : tweets) {
                    if (count > maxSearch) {
                        log("Max search results processed", Level.INFO, maxSearch);
                        break;
                    }
                    if (!processed.contains(tweet.getId())) {
                        log("Processing search result", Level.INFO, tweet.getUser().getScreenName(), tweetSearch,
                                tweet.getText());
                        processed.add(tweet.getId());
                        learnTweet(tweet, processTweets, processReplies, memory);
                        count++;
                    }
                }
                memory.save();
            }
            // Search only returns 7 days, search for users as well.
            TextStream stream = new TextStream(tweetSearch);
            while (!stream.atEnd()) {
                stream.skipToAll("from:", true);
                if (stream.atEnd()) {
                    break;
                }
                String user = stream.nextWord();
                String arg[] = new String[1];
                arg[0] = user;
                ResponseList<User> users = getConnection().lookupUsers(arg);
                if (!users.isEmpty()) {
                    long id = users.get(0).getId();
                    boolean more = true;
                    int page = 1;
                    while (more) {
                        Paging pageing = new Paging(page);
                        ResponseList<Status> timeline = getConnection().getUserTimeline(id, pageing);
                        if ((timeline == null) || (timeline.size() < 20)) {
                            more = false;
                        }
                        page++;
                        if ((timeline == null) || timeline.isEmpty()) {
                            more = false;
                            break;
                        }
                        log("Processing user timeline", Level.INFO, user, timeline.size());
                        for (int index = timeline.size() - 1; index >= 0; index--) {
                            if (count >= maxSearch) {
                                more = false;
                                break;
                            }
                            Status tweet = timeline.get(index);
                            if (!processed.contains(tweet.getId())) {
                                log("Processing user timeline result", Level.INFO, tweet.getUser().getScreenName(),
                                        tweet.getText());
                                processed.add(tweet.getId());
                                learnTweet(tweet, processTweets, processReplies, memory);
                                count++;
                            }
                        }
                        memory.save();
                    }
                    if (count >= maxSearch) {
                        log("Max search results processed", Level.INFO, maxSearch);
                        break;
                    }
                }
            }
        } catch (Exception exception) {
            log(exception);
        }
    }

    /**
     * Learn from the profiles posts.
     */
    public void checkLearning() {
        if (!getLearnFromSelf()) {
            return;
        }
        log("Checking learning", Level.FINE);
        try {
            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            Vertex vertex = twitter.getRelationship(Primitive.LASTLEARN);
            long last = 0;
            if (vertex != null) {
                last = ((Number) vertex.getData()).longValue();
            }
            long max = 0;
            ResponseList<Status> timeline = getConnection().getUserTimeline();
            if ((timeline == null) || timeline.isEmpty()) {
                return;
            }
            log("Processing status", Level.INFO, timeline.size());
            for (int index = timeline.size() - 1; index >= 0; index--) {
                Status tweet = timeline.get(index);
                long statusTime = tweet.getCreatedAt().getTime();
                long statusId = tweet.getId();
                if (statusId > max) {
                    max = statusId;
                }
                if ((System.currentTimeMillis() - statusTime) > DAY) {
                    log("Day old status", Level.INFO, statusId, statusTime);
                    continue;
                }
                if (statusId > last) {
                    learnTweet(tweet, true, true, memory);
                } else {
                    log("Old status", Level.INFO, statusId, statusTime);
                }
            }
            if (max != 0) {
                twitter.setRelationship(Primitive.LASTTIMELINE, memory.createVertex(max));
                memory.save();
            }
        } catch (Exception exception) {
            log(exception);
        }
    }

    public void learnTweet(Status tweet, boolean processTweets, boolean processReplies, Network memory)
            throws Exception {
        String text = tweet.getText();
        // Exclude retweets
        if (tweet.isRetweet()) {
            log("Tweet is retweet", Level.FINER, tweet.getText());
            return;
        }
        if (Utils.checkProfanity(text)) {
            log("Ignoring profanity", Level.INFO, text);
            return;
        }
        // Exclude protected
        if (tweet.getUser().isProtected() && !tweet.getUser().getScreenName().equals(getUserName())) {
            log("Tweet is protected", Level.FINER, tweet.getText());
            return;
        }
        log("Learning status", Level.INFO, text);
        // Exclude replies/mentions
        if (tweet.getText().indexOf('@') != -1) {
            log("Tweet is reply", Level.FINER, tweet.getText());
            if (!processReplies) {
                return;
            }
            long id = tweet.getInReplyToStatusId();
            if (id > 0) {
                try {
                    Status reply = getConnection().showStatus(id);
                    String replyText = reply.getText();
                    if (replyText != null && !replyText.isEmpty()) {
                        // Filter out @users
                        for (String word : new TextStream(text).allWords()) {
                            if (word.startsWith("@")) {
                                text = text.replace(word, "");
                            }
                        }
                        for (String word : new TextStream(replyText).allWords()) {
                            if (word.startsWith("@")) {
                                replyText = replyText.replace(word, "");
                            }
                        }
                        Vertex question = memory.createSentence(replyText.trim());
                        Vertex sentence = memory.createSentence(text.trim());
                        Language.addResponse(question, sentence, memory);
                    }
                } catch (Exception ignore) {
                    log(ignore.toString(), Level.WARNING);
                }

            }
            return;
        }
        if (!processTweets) {
            return;
        }
        Vertex sentence = memory.createSentence(text);
        String keywords = "";
        for (String word : new TextStream(text).allWords()) {
            if (word.startsWith("#")) {
                keywords = keywords + " " + word + " " + word.substring(1, word.length());
            }
        }
        Language.addResponse(sentence, sentence, null, keywords, null, memory);
    }

    /**
     * Check messages to this user.
     */
    public void checkMentions() {
        if (!getReplyToMentions()) {
            return;
        }
        try {
            log("Checking mentions", Level.FINE);
            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            Vertex vertex = twitter.getRelationship(Primitive.LASTMENTION);
            long last = 0;
            if (vertex != null) {
                last = ((Number) vertex.getData()).longValue();
            }
            long max = 0;
            ResponseList<Status> mentions = null;
            boolean more = true;
            int page = 1;
            while (more) {
                if (last == 0) {
                    mentions = getConnection().getMentionsTimeline();
                    more = false;
                } else {
                    Paging paging = new Paging(page, last);
                    mentions = getConnection().getMentionsTimeline(paging);
                    if ((mentions == null) || (mentions.size() < 20)) {
                        more = false;
                    }
                    page++;
                }
                if ((mentions == null) || mentions.isEmpty()) {
                    break;
                }
                log("Processing mentions", Level.FINE, mentions.size());
                for (int index = mentions.size() - 1; index >= 0; index--) {
                    Status tweet = mentions.get(index);
                    long statusTime = tweet.getCreatedAt().getTime();
                    long statusId = tweet.getId();
                    if (statusId > max) {
                        max = statusId;
                    }
                    if ((System.currentTimeMillis() - statusTime) > DAY) {
                        log("Day old mention", Level.INFO, statusId, statusTime);
                        more = false;
                        continue;
                    }
                    // Exclude self
                    if (tweet.getUser().getScreenName().equals(getUserName())) {
                        continue;
                    }
                    if (statusId > last) {
                        log("Processing mention", Level.INFO, tweet.getText(), tweet.getUser().getScreenName());
                        input(tweet);
                        Utils.sleep(100);
                    } else {
                        log("Old mention", Level.INFO, statusId, statusTime);
                    }
                }
            }
            if (max != 0) {
                twitter.setRelationship(Primitive.LASTMENTION, memory.createVertex(max));
                memory.save();
            }
        } catch (Exception exception) {
            log(exception);
        }
        // Wait for language processing.
        int count = 0;
        while (count < 60 && !getBot().memory().getActiveMemory().isEmpty()) {
            Utils.sleep(1000);
        }
        this.languageState = LanguageState.Discussion;
    }

    /**
     * Check search keywords.
     */
    public void checkSearch() {
        if (getTweetSearch().isEmpty()) {
            return;
        }
        log("Processing search", Level.FINE, getTweetSearch());
        try {
            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            Vertex vertex = twitter.getRelationship(Primitive.LASTSEARCH);
            long last = 0;
            long max = 0;
            int count = 0;
            this.errors = 0;
            if (vertex != null) {
                last = ((Number) vertex.getData()).longValue();
            }
            Set<Long> processed = new HashSet<Long>();
            for (String tweetSearch : getTweetSearch()) {
                Query query = new Query(tweetSearch);
                if (vertex != null) {
                    query.setSinceId(last);
                }
                SearchResource search = getConnection().search();
                QueryResult result = search.search(query);
                List<Status> tweets = result.getTweets();
                if (tweets != null) {
                    log("Processing search results", Level.FINE, tweets.size(), tweetSearch);
                    for (Status tweet : tweets) {
                        if (count > this.maxSearch) {
                            log("Max search results processed", Level.FINE, this.maxSearch);
                            break;
                        }
                        if (tweet.getId() > last && !processed.contains(tweet.getId())) {
                            if (tweet.getId() > max) {
                                max = tweet.getId();
                            }
                            boolean match = false;
                            // Exclude replies/mentions
                            if (getIgnoreReplies() && tweet.getText().indexOf('@') != -1) {
                                log("Ignoring: Tweet is reply", Level.FINER, tweet.getText());
                                continue;
                            }
                            // Exclude retweets
                            if (tweet.isRetweet()) {
                                log("Ignoring: Tweet is retweet", Level.FINER, tweet.getText());
                                continue;
                            }
                            // Exclude protected
                            if (tweet.getUser().isProtected()) {
                                log("Ignoring: Tweet is protected", Level.FINER, tweet.getText());
                                continue;
                            }
                            // Exclude self
                            if (tweet.getUser().getScreenName().equals(getUserName())) {
                                log("Ignoring: Tweet is from myself", Level.FINER, tweet.getText());
                                continue;
                            }
                            // Ignore profanity
                            if (Utils.checkProfanity(tweet.getText())) {
                                log("Ignoring: Tweet contains profanity", Level.FINER, tweet.getText());
                                continue;
                            }
                            List<String> statusWords = new TextStream(tweet.getText().toLowerCase()).allWords();
                            for (String text : getStatusKeywords()) {
                                List<String> keywords = new TextStream(text.toLowerCase()).allWords();
                                if (statusWords.containsAll(keywords)) {
                                    match = true;
                                    break;
                                }
                            }
                            if (getLearn()) {
                                learnTweet(tweet, true, true, memory);
                            }
                            if (match) {
                                processed.add(tweet.getId());
                                log("Processing search", Level.INFO, tweet.getUser().getScreenName(), tweetSearch,
                                        tweet.getText());
                                input(tweet);
                                Utils.sleep(500);
                                count++;
                            } else {
                                if (!tweet.isRetweetedByMe()) {
                                    boolean found = false;
                                    // Check retweet.
                                    for (String keywords : getRetweet()) {
                                        List<String> keyWords = new TextStream(keywords).allWords();
                                        if (!keyWords.isEmpty()) {
                                            if (statusWords.containsAll(keyWords)) {
                                                found = true;
                                                processed.add(tweet.getId());
                                                count++;
                                                retweet(tweet);
                                                Utils.sleep(500);
                                                break;
                                            }
                                        }
                                    }
                                    if (!found) {
                                        log("Missing keywords", Level.FINER, tweet.getText());
                                    }
                                } else {
                                    log("Already retweeted", Level.FINER, tweet.getText());
                                }
                            }
                        }
                    }
                }
                if (count > this.maxSearch) {
                    break;
                }
                if (this.errors > this.maxErrors) {
                    break;
                }
            }
            if (max != 0) {
                twitter.setRelationship(Primitive.LASTSEARCH, memory.createVertex(max));
                memory.save();
            }
        } catch (Exception exception) {
            log(exception);
        }
        // Wait for language processing.
        int count = 0;
        while (count < 60 && !getBot().memory().getActiveMemory().isEmpty()) {
            Utils.sleep(1000);
        }
    }

    /**
     * Check search keywords.
     */
    public void checkAutoFollowSearch(int friendCount) {
        if (getAutoFollowSearch().isEmpty()) {
            return;
        }
        log("Processing autofollow search", Level.FINE, getAutoFollowSearch());
        try {
            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            Vertex vertex = twitter.getRelationship(Primitive.LASTAUTOFOLLOWSEARCH);
            long last = 0;
            long max = 0;
            int count = 0;
            if (vertex != null) {
                last = ((Number) vertex.getData()).longValue();
            }
            for (String followSearch : getAutoFollowSearch()) {
                Query query = new Query(followSearch);
                if (vertex != null) {
                    query.setSinceId(last);
                }
                SearchResource search = getConnection().search();
                QueryResult result = search.search(query);
                List<Status> tweets = result.getTweets();
                if (tweets != null) {
                    for (Status tweet : tweets) {
                        if (count > this.maxSearch) {
                            break;
                        }
                        if (tweet.getId() > last) {
                            log("Autofollow search", Level.FINE, tweet.getText(), tweet.getUser().getScreenName(),
                                    followSearch);
                            if (checkFriendship(tweet.getUser().getId(), false)) {
                                friendCount++;
                                if (friendCount >= getMaxFriends()) {
                                    log("Max friend limit", Level.FINE, getMaxFriends());
                                    return;
                                }
                            }
                            count++;
                            if (tweet.getId() > max) {
                                max = tweet.getId();
                            }
                        }
                    }
                }
                if (count > this.maxSearch) {
                    break;
                }
            }
            if (max != 0) {
                twitter.setRelationship(Primitive.LASTAUTOFOLLOWSEARCH, memory.createVertex(max));
                memory.save();
            }
        } catch (Exception exception) {
            log(exception);
        }
    }

    /**
     * Check RSS feed.
     */
    public void checkRSS() {
        if (getTweetRSS().isEmpty()) {
            return;
        }
        log("Processing RSS", Level.FINE, getTweetRSS());
        try {
            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            Vertex vertex = twitter.getRelationship(Primitive.LASTRSS);
            long last = 0;
            if (vertex != null) {
                last = ((Number) vertex.getData()).longValue();
            }
            int rssIndex = 0;
            String keywordsText = "";
            List<String> keywords = new ArrayList<String>();
            for (String rss : getTweetRSS()) {
                if (rssIndex < getRssKeywords().size()) {
                    keywordsText = getRssKeywords().get(rssIndex);
                    keywords = new TextStream(keywordsText.toLowerCase()).allWords();
                }
                rssIndex++;
                TextStream stream = new TextStream(rss);
                String prefix = stream.upToAll("http").trim();
                if (prefix.isEmpty()) {
                    prefix = "";
                }
                prefix = prefix + " ";
                String url = stream.nextWord();
                String postfix = " " + stream.upToEnd().trim();
                List<Map<String, Object>> feed = getBot().awareness().getSense(Http.class)
                        .parseRSSFeed(new URL(url), last);
                if (feed != null) {
                    long max = 0;
                    int count = 0;
                    this.errors = 0;
                    log("Processing RSS feed", Level.FINE, feed.size(), rss);
                    for (int index = feed.size() - 1; index >= 0; index--) {
                        Map<String, Object> entry = feed.get(index);
                        long time = (Long) entry.get("published");
                        if ((System.currentTimeMillis() - time) > DAY) {
                            continue;
                        }
                        if (time > last) {
                            if (count > this.maxFeed) {
                                break;
                            }
                            if (this.errors > this.maxErrors) {
                                break;
                            }
                            String text = (String) entry.get("title");
                            if (!keywords.isEmpty()) {
                                if (!new TextStream(text.toLowerCase()).allWords().containsAll(keywords)) {
                                    log("Skipping RSS, missing keywords", Level.FINE, keywords, text);
                                    continue;
                                }
                            }
                            log("Tweeting RSS", Level.FINE, entry.get("title"));
                            text = prefix + text + postfix;
                            if (text.length() > 120) {
                                text = text.substring(0, 120);
                            }
                            tweet(text + " " + entry.get("link"), 0L);
                            Utils.sleep(500);
                            count++;
                            if (time > max) {
                                max = time;
                            }
                        }
                    }
                    if (max != 0) {
                        twitter.setRelationship(Primitive.LASTRSS, memory.createVertex(max));
                        memory.save();
                    }
                }
            }
        } catch (Exception exception) {
            log(exception);
        }
    }

    /**
     * Auto tweet.
     */
    public void checkAutoTweet() {
        if (!getAutoTweet()) {
            return;
        }
        log("Autotweeting", Level.FINE);
        try {
            Network memory = getBot().memory().newMemory();
            Vertex twitter = memory.createVertex(getPrimitive());
            Vertex vertex = twitter.getRelationship(Primitive.LASTTWEET);
            long last = 0;
            if (vertex != null) {
                last = ((Timestamp) vertex.getData()).getTime();
            }
            long millis = getAutoTweetHours() * 60 * 60 * 1000;
            if ((System.currentTimeMillis() - last) < millis) {
                log("Autotweeting hours not reached", Level.FINE, getAutoTweetHours());
                return;
            }
            List<Vertex> autotweets = getAutoTweets(memory);
            if (autotweets != null && !autotweets.isEmpty()) {
                int index = Utils.random().nextInt(autotweets.size());
                Vertex tweet = autotweets.get(index);
                String text = null;
                // Check for labels and formulas
                if (tweet.instanceOf(Primitive.LABEL)) {
                    tweet = tweet.mostConscious(Primitive.RESPONSE);
                }
                if (tweet.instanceOf(Primitive.FORMULA)) {
                    Map<Vertex, Vertex> variables = new HashMap<Vertex, Vertex>();
                    SelfCompiler.addGlobalVariables(memory.createInstance(Primitive.INPUT), null, memory,
                            variables);
                    Vertex result = getBot().mind().getThought(Language.class).evaluateFormula(tweet, variables,
                            memory);
                    if (result != null) {
                        text = getBot().mind().getThought(Language.class).getWord(result, memory).getDataValue();
                    } else {
                        log("Invalid autotweet template formula", Level.WARNING, tweet);
                        text = null;
                    }
                } else {
                    text = tweet.printString();
                }
                if (text != null) {
                    log("Autotweeting", Level.INFO, tweet);
                    tweet(text, 0L);
                    Utils.sleep(100);
                    twitter.setRelationship(Primitive.LASTTWEET, memory.createTimestamp());
                    memory.save();
                }
            }
        } catch (Exception exception) {
            log(exception);
        }
    }

    /**
     * Return the list of followers names.
     */
    public List<String> getFollowers() {
        List<String> followers = new ArrayList<String>();
        try {
            long[] ids = getConnection().getFollowersIDs(-1).getIDs();
            if (ids.length == 0) {
                return followers;
            }
            int index = 0;
            while (ids.length > index) {
                long[] lookup = ids;
                if (index > 0) {
                    lookup = Arrays.copyOfRange(ids, index, Math.min(ids.length, index + MAX_LOOKUP));
                } else if (ids.length > MAX_LOOKUP) {
                    lookup = Arrays.copyOf(ids, MAX_LOOKUP);
                }
                index = index + MAX_LOOKUP;
                ResponseList<User> users = getConnection().lookupUsers(lookup);
                for (User user : users) {
                    followers.add(user.getScreenName());
                }
                // Only return first 100.
                break;
            }
        } catch (Exception exception) {
            log(exception);
        }
        return followers;
    }

    /**
     * Return the time-line.
     */
    public List<String> getTimeline() {
        List<String> timeline = new ArrayList<String>();
        try {
            ResponseList<Status> statuses = getConnection().getHomeTimeline();
            for (Status status : statuses) {
                timeline.add(status.getCreatedAt() + " - <b>" + status.getUser().getScreenName() + "</b>:  "
                        + status.getText());
            }
        } catch (Exception exception) {
            log(exception);
            throw new BotException(exception);
        }
        return timeline;
    }

    /**
     * Return the total number of friends.
     */
    public int getFriendsCount() {
        try {
            return getConnection().getFriendsIDs(-1).getIDs().length;
        } catch (Exception exception) {
            log(exception);
            return 0;
        }
    }

    /**
     * Return the total number of followers.
     */
    public int getFollowersCount() {
        try {
            return getConnection().getFollowersIDs(-1).getIDs().length;
        } catch (Exception exception) {
            log(exception);
            return 0;
        }
    }

    /**
     * Return the list of friends names.
     */
    public List<String> getFriends() {
        List<String> friends = new ArrayList<String>();
        try {
            long[] friendIds = getConnection().getFriendsIDs(-1).getIDs();
            int index = 0;
            while (friendIds.length > index) {
                long[] lookup = friendIds;
                if (index > 0) {
                    lookup = Arrays.copyOfRange(friendIds, index, Math.min(friendIds.length, index + MAX_LOOKUP));
                } else if (friendIds.length > MAX_LOOKUP) {
                    lookup = Arrays.copyOf(friendIds, MAX_LOOKUP);
                }
                index = index + MAX_LOOKUP;
                ResponseList<User> users = getConnection().lookupUsers(lookup);
                for (User user : users) {
                    friends.add(user.getScreenName());
                }
                // Only return first 100.
                break;
            }
        } catch (Exception exception) {
            log(exception);
        }
        return friends;
    }

    /**
     * Check followers.
     */
    public void checkFollowers() {
        if (!getAutoFollow() && getWelcomeMessage().isEmpty()) {
            return;
        }
        try {
            log("Checking followers", Level.FINE);
            long[] followerIds = getConnection().getFollowersIDs(-1).getIDs(); //max 5000
            long[] friends = getConnection().getFriendsIDs(-1).getIDs();
            int friendCount = friends.length;
            int count = 0;
            boolean welcomeOnly = false;
            if (friendCount >= getMaxFriends()) {
                if (!getWelcomeMessage().isEmpty()) {
                    welcomeOnly = true;
                } else {
                    log("Max friend limit", Level.FINE, getMaxFriends());
                    return;
                }
            }
            for (int index = 0; index < followerIds.length; index++) {
                boolean found = false;
                long followerId = followerIds[index];
                for (long friend : friends) {
                    if (followerId == friend) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    log("Checking new follower", Level.FINE, followerId);
                    boolean isNewFriend = checkFriendship(followerId, welcomeOnly);
                    if (!isNewFriend) {
                        // Followers are ordered, so if already followed ignore the rest.
                        break;
                    }
                    friendCount++;
                    if (friendCount >= getMaxFriends()) {
                        if (!getWelcomeMessage().isEmpty()) {
                            welcomeOnly = true;
                        } else {
                            return;
                        }
                    }
                    count++;
                    if (count >= this.maxFriendsPerCycle) {
                        if (!getWelcomeMessage().isEmpty() && count < this.maxWelcomesPerCycle) {
                            welcomeOnly = true;
                        } else {
                            log("Max friend per cycle limit", Level.FINE, this.maxFriendsPerCycle);
                            return;
                        }
                    }
                    if (!welcomeOnly && getAutoFollowFriendsFriends()) {
                        log("Checking friends friends", Level.FINE, followerId);
                        long[] friendsFriends = getConnection().getFriendsIDs(followerId, -1).getIDs();
                        for (long friendsFriend : friendsFriends) {
                            if (checkFriendship(friendsFriend, welcomeOnly)) {
                                friendCount++;
                                if (friendCount >= getMaxFriends()) {
                                    log("Max friend limit", Level.FINE, getMaxFriends());
                                    return;
                                }
                                count++;
                                if (count >= this.maxFriendsPerCycle) {
                                    log("Max friend per cycle limit", Level.FINE, this.maxFriendsPerCycle);
                                    return;
                                }
                            }
                        }
                    }
                    if (!welcomeOnly && getAutoFollowFriendsFollowers()) {
                        log("Checking friends followers", Level.FINE, followerId);
                        long[] friendsFollowers = getConnection().getFollowersIDs(followerId, -1).getIDs();
                        for (long friendsFollower : friendsFollowers) {
                            if (checkFriendship(friendsFollower, welcomeOnly)) {
                                friendCount++;
                                if (friendCount >= getMaxFriends()) {
                                    log("Max friend limit", Level.FINE, getMaxFriends());
                                    return;
                                }
                                count++;
                                if (count >= this.maxFriendsPerCycle) {
                                    log("Max friend per cycle limit", Level.FINE, this.maxFriendsPerCycle);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            checkAutoFollowSearch(friendCount);
        } catch (Exception exception) {
            log(exception);
        }
    }

    public boolean checkFriendship(long friendId, boolean welcomeOnly) throws TwitterException {
        long[] lookup = new long[1];
        lookup[0] = friendId;
        ResponseList<User> users = getConnection().lookupUsers(lookup);
        User friend = users.get(0);
        if (friend.getScreenName().equals(getUserName())) {
            return false;
        }
        if (!getAutoFollowKeywords().isEmpty()) {
            StringWriter writer = new StringWriter();
            writer.write(friend.getScreenName().toLowerCase());
            writer.write(" ");
            writer.write(friend.getDescription().toLowerCase());
            writer.write(" ");
            writer.write(friend.getLocation().toLowerCase());
            writer.write(" ");
            writer.write(friend.getLang().toLowerCase());
            writer.write(" ");
            writer.write(friend.getName().toLowerCase());
            boolean match = false;
            for (String text : getAutoFollowKeywords()) {
                List<String> keywords = new TextStream(text.toLowerCase()).allWords();
                if (new TextStream(writer.toString()).allWords().containsAll(keywords)) {
                    match = true;
                    break;
                }
            }
            if (!match) {
                log("Autofollow skipping friend, does not match keywords", Level.FINE, friend.getScreenName());
                return false;
            }
        }
        Network memory = getBot().memory().newMemory();
        Vertex speaker = memory.createSpeaker(friend.getScreenName());
        speaker.setPinned(true);
        // Only try to follow a user once.
        if (!speaker.hasRelationship(Primitive.FOLLOWED)) {
            speaker.addRelationship(Primitive.FOLLOWED, memory.createTimestamp());
            memory.save();
            if (!welcomeOnly && getAutoFollow()) {
                log("Adding autofollow friend.", Level.INFO, friend.getScreenName());
                getConnection().createFriendship(friendId);
                Utils.sleep(1000);
            }
            if (!getWelcomeMessage().isEmpty()) {
                log("Sending welcome message.", Level.INFO, friend.getScreenName());
                sendMessage(getWelcomeMessage(), friend.getScreenName());
                Utils.sleep(1000);
            }
            if (welcomeOnly) {
                return false;
            }
            return true;
        }
        log("Autofollow skipping friend, already followed once", Level.FINE, friend.getScreenName());
        return false;
    }

    public void log(TwitterException exception) {
        log(new TextStream(exception.toString()).nextLine(), Bot.WARNING);
    }

    /**
     * Check trends.
     */
    public void checkTrends() {
        try {
            Network network = getBot().memory().newMemory();
            if ((this.lastTrendsCheck == 0)
                    || ((System.currentTimeMillis() - this.lastTrendsCheck) > TREND_CHECK)) {
                Vertex twitter = network.createVertex(getPrimitive());
                Vertex lastCheck = twitter.getRelationship(Primitive.TREND);
                if (lastCheck == null) {
                    twitter.addRelationship(Primitive.TREND, network.createTimestamp());
                } else {
                    long lastCheckTime = ((Timestamp) lastCheck.getData()).getTime();
                    if ((System.currentTimeMillis() - lastCheckTime) < TREND_CHECK) { // 1 hours.
                        return;
                    }
                }
                log("Checking trends", Bot.FINE);
                twitter.setRelationship(Primitive.TREND, network.createTimestamp());
                /**List<Trends> dailyTrends = getConnection().getDailyTrends();
                List<String> trendNames = new ArrayList<String>();
                if (dailyTrends.size() > 0) {
                   for (Trend trend : dailyTrends.get(0).getTrends()) {
                      trendNames.add(trend.getName());
                   }
                }
                for (String text : trendNames) {
                   if (text.charAt(0) == '#') {
                      text = text.substring(1, text.length());
                   }
                   log("Trend:", Bot.FINE, text);
                   Vertex word = network.createWord(text);
                       
                   network.save();
                   getBot().memory().addActiveMemory(word);
                }*/
                this.lastTrendsCheck = System.currentTimeMillis();
            }
        } catch (Exception exception) {
            log(exception);
        }
    }

    /**
     * Tweet.
     */
    public void tweet(String html, Long reply) {
        String text = format(html);
        if (text.length() > 140) {
            int index = text.indexOf("http://");
            if (index == -1) {
                text = text.substring(0, 140);
            } else if (index > 120) {
                text = text.substring(0, 120) + " " + text.substring(index, text.length());
            }
        }
        this.tweets++;
        log("Tweeting:", Level.INFO, text);
        try {
            if (getConnection() == null) {
                connect();
            }
            StatusUpdate update = new StatusUpdate(text);
            if (reply != null) {
                update.setInReplyToStatusId(reply);
            }

            // Check for linked media.
            if ((html.indexOf('<') != -1) && (html.indexOf('>') != -1)) {
                String media = null;
                Element root = getBot().awareness().getSense(Http.class).parseHTML(html);
                NodeList nodes = root.getElementsByTagName("img");
                if (nodes.getLength() > 0) {
                    String src = ((Element) nodes.item(0)).getAttribute("src");
                    if (src != null && !src.isEmpty()) {
                        media = src;
                    }
                }
                if (media == null) {
                    nodes = root.getElementsByTagName("video");
                    if (nodes.getLength() > 0) {
                        String src = ((Element) nodes.item(0)).getAttribute("src");
                        if (src != null && !src.isEmpty()) {
                            media = src;
                        }
                    }
                }
                if (media == null) {
                    nodes = root.getElementsByTagName("audio");
                    if (nodes.getLength() > 0) {
                        String src = ((Element) nodes.item(0)).getAttribute("src");
                        if (src != null && !src.isEmpty()) {
                            media = src;
                        }
                    }
                }
                if (media != null) {
                    try {
                        URL url = new URL(media);
                        URLConnection urlConnection = url.openConnection();
                        InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
                        update.setMedia("image.png", stream);
                    } catch (Exception exception) {
                        log(exception);
                    }
                }
            }

            getConnection().updateStatus(update);
        } catch (Exception exception) {
            this.errors++;
            log(exception.getMessage(), Level.WARNING, text);
        }
    }

    public String format(String text) {
        text = text.replace("<br/>", "\n");
        text = text.replace("<br>", "\n");
        text = text.replace("</br>", "");
        text = text.replace("<p/>", "\n");
        text = text.replace("<p>", "\n");
        text = text.replace("</p>", "");
        text = text.replace("<li>", "\n");
        text = text.replace("</li>", "");
        text = text.replace("<ul>", "");
        text = text.replace("</ul>", "\n");
        text = text.replace("<ol>", "");
        text = text.replace("</ol>", "\n");
        text = Utils.stripTags(text);
        return text;
    }

    /**
     * Send a message to the user.
     */
    public void sendMessage(String text, String replyUser) {
        log("Sending message:", Level.INFO, text, replyUser);
        try {
            text = format(text);
            getConnection().sendDirectMessage(replyUser, text);
        } catch (Exception exception) {
            this.errors++;
            log(exception);
        }
    }

    /**
     * Retweet the tweet.
     */
    public void retweet(Status tweet) {
        if (tweet.isRetweet()) {
            tweet = tweet.getRetweetedStatus();
        }
        if (tweet.getUser().isProtected()) {
            log("Cannot retweet protected user", Level.INFO, tweet.getUser().getScreenName(), tweet.getText());
            return;
        }
        this.retweets++;
        log("Retweeting:", Level.INFO, tweet.getText(), tweet.getUser().getScreenName());
        try {
            if (getConnection() == null) {
                connect();
            }
            getConnection().retweetStatus(tweet.getId());
        } catch (Exception exception) {
            if (exception.getMessage() != null && exception.getMessage().contains("authorized")
                    && exception.getMessage().contains("endpoint")) {
                this.errors = this.errors + 5;
            }
            this.errors++;
            log(exception.toString(), Level.WARNING, tweet.getText());
        }
    }

    /**
     * Output the tweet if twitter is connected.
     */
    public void outputTweet(String tweet) {
        if (!isEnabled() || !getTweetChats()) {
            return;
        }
        Network network = getBot().memory().newMemory();
        Vertex setence = network.createSentence(tweet);
        Vertex output = network.createInstance(Primitive.INPUT);
        output.setName(tweet);
        output.addRelationship(Primitive.INPUT, setence);
        output.addRelationship(Primitive.SENSE, getPrimitive());
        output.addRelationship(Primitive.SPEAKER, Primitive.SELF);
        output.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
        Vertex target = output.mostConscious(Primitive.TARGET);
        if (target != null) {
            String replyTo = target.mostConscious(Primitive.WORD).getData().toString();
            tweet = "@" + replyTo + " " + tweet;
        }
        network.save();
        tweet(tweet, null);
    }

    /**
     * Process the email message.
     */
    @Override
    public void input(Object input, Network network) {
        if (!isEnabled()) {
            return;
        }
        try {
            if (input instanceof Status) {
                Status tweet = (Status) input;
                log("Processing status", Bot.FINE, tweet.getText(), tweet.getId());
                if ((System.currentTimeMillis() - tweet.getCreatedAt().getTime()) > DAY) {
                    log("Day old status", Bot.FINE, tweet.getId(), tweet.getCreatedAt().getTime());
                    return;
                }
                if (this.processedTweets.contains(tweet.getId())) {
                    log("Already processed status", Bot.FINE, tweet.getText(), tweet.getId());
                    return;
                }
                this.processedTweets.add(tweet.getId());
                String name = tweet.getUser().getScreenName();
                String replyTo = tweet.getInReplyToScreenName();
                String text = tweet.getText().trim();
                TextStream stream = new TextStream(text);
                String firstWord = null;
                if (getIgnoreReplies()) {
                    if (stream.peek() == '@') {
                        stream.next();
                        String replyTo2 = stream.nextWord();
                        firstWord = stream.peekWord();
                        text = stream.upToEnd().trim();
                        if (!replyTo2.equals(replyTo)) {
                            log("Reply to does not match:", Bot.FINE, replyTo2, replyTo);
                        }
                        replyTo = replyTo2;
                        if (replyTo.equals(this.userName) && getFollowMessages()) {
                            if ("follow".equals(firstWord)) {
                                log("Adding friend", Level.INFO, tweet.getUser().getScreenName());
                                getConnection().createFriendship(tweet.getUser().getId());
                            } else if ("unfollow".equals(firstWord)) {
                                log("Removing friend", Level.INFO, tweet.getUser().getScreenName());
                                getConnection().destroyFriendship(tweet.getUser().getId());
                            }
                        }
                    }
                } else {
                    // Ignore the reply user, force the bot to reply.
                    replyTo = null;
                }
                if (!tweet.isRetweet() && !tweet.getUser().isProtected()) {
                    stream.reset();
                    List<String> words = stream.allWords();
                    for (String keywords : getRetweet()) {
                        List<String> keyWords = new TextStream(keywords).allWords();
                        if (!keyWords.isEmpty()) {
                            if (words.containsAll(keyWords)) {
                                retweet(tweet);
                                break;
                            }
                        }
                    }
                }
                log("Input status", Level.FINE, tweet.getText(), name, replyTo);
                this.tweetsProcessed++;
                inputSentence(text, name, replyTo, tweet, network);
            }
        } catch (Exception exception) {
            log(exception);
        }
    }

    /**
     * Output the status or direct message reply.
     */
    public void output(Vertex output) {
        if (!isEnabled()) {
            return;
        }
        Vertex sense = output.mostConscious(Primitive.SENSE);
        // If not output to twitter, ignore.
        if ((sense == null) || (!getPrimitive().equals(sense.getData()))) {
            return;
        }
        output.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
        String text = printInput(output);
        // Don't send empty tweets.
        if (text.isEmpty()) {
            return;
        }
        Vertex target = output.mostConscious(Primitive.TARGET);
        if (target != null) {
            String replyTo = target.mostConscious(Primitive.WORD).getData().toString();
            text = "@" + replyTo + " " + text;
        }
        Vertex question = output.getRelationship(Primitive.QUESTION);
        Long reply = null;
        if (question != null) {
            Vertex id = question.getRelationship(Primitive.ID);
            if (id != null) {
                reply = ((Number) id.getData()).longValue();
            }
        }
        tweet(text, reply);
    }

    public String getUserName() {
        return userName;
    }

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

    /**
     * Process the text sentence.
     */
    public void inputSentence(String text, String userName, String targetUserName, Status status, Network network) {
        Vertex input = createInput(text.trim(), network);
        Vertex sentence = input.getRelationship(Primitive.INPUT);
        Vertex id = network.createVertex(status.getId());
        if (sentence.hasRelationship(Primitive.TWEET, id)) {
            log("Status already processed", Bot.FINE, status.getId(), status.getCreatedAt().getTime());
            return;
        }
        sentence.addRelationship(Primitive.TWEET, id);
        input.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
        input.addRelationship(Primitive.CREATEDAT, network.createVertex(status.getCreatedAt().getTime()));
        input.addRelationship(Primitive.ID, id);
        Vertex conversation = network.createInstance(Primitive.CONVERSATION);
        conversation.addRelationship(Primitive.TYPE, Primitive.TWEET);
        Language.addToConversation(input, conversation);
        Vertex user = network.createSpeaker(userName);
        conversation.addRelationship(Primitive.SPEAKER, user);
        input.addRelationship(Primitive.SPEAKER, user);
        if (targetUserName != null) {
            Vertex targetUser = null;
            if (targetUserName.equals(getUserName())) {
                targetUser = network.createVertex(Primitive.SELF);
            } else {
                targetUser = network.createSpeaker(targetUserName);
            }
            input.addRelationship(Primitive.TARGET, targetUser);
            conversation.addRelationship(Primitive.SPEAKER, targetUser);
        }

        network.save();
        getBot().memory().addActiveMemory(input);
    }

    /**
     * Create an input based on the sentence.
     */
    protected Vertex createInput(String text, Network network) {
        Vertex sentence = network.createSentence(text);
        Vertex input = network.createInstance(Primitive.INPUT);
        input.setName(text);
        input.addRelationship(Primitive.SENSE, getPrimitive());
        input.addRelationship(Primitive.INPUT, sentence);
        sentence.addRelationship(Primitive.INSTANTIATION, Primitive.TWEET);
        return input;
    }

    public String getOauthKey() {
        return oauthKey;
    }

    public void setOauthKey(String oauthKey) {
        Twitter.oauthKey = oauthKey;
    }

    public String getOauthSecret() {
        return oauthSecret;
    }

    public void setOauthSecret(String oauthSecret) {
        Twitter.oauthSecret = oauthSecret;
    }

    public String getTokenSecret() {
        return tokenSecret;
    }

    public void setTokenSecret(String tokenSecret) {
        this.tokenSecret = tokenSecret;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public twitter4j.Twitter getConnection() throws TwitterException {
        if (connection == null) {
            connect();
        }
        return connection;
    }

    public void setConnection(twitter4j.Twitter connection) {
        this.connection = connection;
    }

    public boolean getAutoFollow() {
        initProperties();
        return autoFollow;
    }

    public void setAutoFollow(boolean autoFollow) {
        initProperties();
        this.autoFollow = autoFollow;
    }

    public int getMaxFriends() {
        initProperties();
        return maxFriends;
    }

    public void setMaxFriends(int maxFriends) {
        initProperties();
        this.maxFriends = maxFriends;
    }

    public boolean getLearn() {
        initProperties();
        return learn;
    }

    public void setLearn(boolean learn) {
        initProperties();
        this.learn = learn;
    }

    public boolean getLearnFromSelf() {
        initProperties();
        return learnFromSelf;
    }

    public void setLearnFromSelf(boolean learnFromSelf) {
        initProperties();
        this.learnFromSelf = learnFromSelf;
    }

    public boolean getProcessStatus() {
        initProperties();
        return processStatus;
    }

    public void setProcessStatus(boolean processStatus) {
        initProperties();
        this.processStatus = processStatus;
    }

    public boolean getTweetChats() {
        return tweetChats;
    }

    public boolean getReplyToMentions() {
        initProperties();
        return replyToMentions;
    }

    public boolean getReplyToMessages() {
        initProperties();
        return replyToMessages;
    }

    public void setTweetChats(boolean tweetChats) {
        this.tweetChats = tweetChats;
    }

    public void setReplyToMentions(boolean replyToMentions) {
        this.replyToMentions = replyToMentions;
    }

    public void setReplyToMessages(boolean replyToMessages) {
        this.replyToMessages = replyToMessages;
    }

    public List<String> getRetweet() {
        initProperties();
        return retweet;
    }

    public void setRetweet(List<String> retweet) {
        initProperties();
        this.retweet = retweet;
    }

    public List<String> getTweetRSS() {
        initProperties();
        return tweetRSS;
    }

    public void setTweetRSS(List<String> tweetRSS) {
        initProperties();
        this.tweetRSS = tweetRSS;
    }

    public boolean getCheckTrends() {
        return checkTrends;
    }

    public void setCheckTrends(boolean checkTrends) {
        this.checkTrends = checkTrends;
    }

    public List<String> getTweetSearch() {
        initProperties();
        return tweetSearch;
    }

    public void setTweetSearch(List<String> tweetSearch) {
        initProperties();
        this.tweetSearch = tweetSearch;
    }

    public boolean getFollowMessages() {
        initProperties();
        return followMessages;
    }

    public void setFollowMessages(boolean followMessages) {
        initProperties();
        this.followMessages = followMessages;
    }

    public int getMaxStatus() {
        initProperties();
        return maxStatus;
    }

    public void setMaxStatus(int maxStatus) {
        initProperties();
        this.maxStatus = maxStatus;
    }

    // Self API
    public void tweet(Vertex source, Vertex sentence) {
        if (sentence.instanceOf(Primitive.FORMULA)) {
            Map<Vertex, Vertex> variables = new HashMap<Vertex, Vertex>();
            SelfCompiler.addGlobalVariables(sentence.getNetwork().createInstance(Primitive.INPUT), null,
                    sentence.getNetwork(), variables);
            sentence = getBot().mind().getThought(Language.class).evaluateFormula(sentence, variables,
                    sentence.getNetwork());
            if (sentence == null) {
                log("Invalid template formula", Level.WARNING, sentence);
                return;
            }
        }
        String tweet = getBot().mind().getThought(Language.class).getWord(sentence, sentence.getNetwork())
                .getDataValue();
        getBot().stat("twitter.tweet");
        tweet(tweet, 0L);
    }

    /**
     * Self API
     * Send a message to the user.
     */
    public void message(Vertex source, Vertex replyUser, Vertex text) {
        sendMessage(text.printString(), replyUser.printString());
    }

    /**
     * Self API
     * Send a message to the user.
     */
    public void sendMessage(Vertex source, Vertex text, Vertex replyUser) {
        sendMessage(text.printString(), replyUser.printString());
    }

    // Self API
    public Vertex trend(Network network) throws TwitterException {
        Trends trends = getConnection().getPlaceTrends(1);
        if (trends.getTrends().length > 0) {
            return network.createObject(trends.getTrends()[0].getName());
        }
        return null;
    }

}