r.searches function, fixes, SharedLibraries configuration inclusion

This commit is contained in:
DarkFeather 2016-12-04 19:55:52 -06:00
parent 1b4d0190e0
commit df636e8706
16 changed files with 97 additions and 182 deletions

View File

@ -1,22 +1,20 @@
CONFDIR := /usr/local/etc/TheRaven CONFDIR = /usr/local/etc/TheRaven
compile: /usr/bin/mcs /usr/bin/mono clean ./raven.csharp ./connection.csharp ./ravencommand.csharp /bin/bash /usr/bin/mail /usr/bin/wget /usr/local/bin/djinni ./chatbot-support.bash compile: clean /usr/bin/mcs /usr/bin/mono clean /bin/bash /usr/bin/mail /usr/bin/wget /usr/local/bin/djinni ./chatbot-support.bash
if [ ! -d ../Djinni ]; then git clone -C '..' https://aninix.net/foundation/Djinni; fi if [ ! -d ../Djinni ]; then git clone -C '..' https://aninix.net/foundation/Djinni; fi
git -C ../Djinni pull git -C ../Djinni pull
if [ ! -d ../SharedLibraries ]; then git clone -C '..' https://aninix.net/foundation/SharedLibraries; fi if [ ! -d ../SharedLibraries ]; then git clone -C '..' https://aninix.net/foundation/SharedLibraries; fi
git -C ../SharedLibraries pull git -C ../SharedLibraries pull
mcs -out:raven.mono ../SharedLibraries/CSharp/*.csharp *.csharp mcs -out:raven.mono ../SharedLibraries/CSharp/*.csharp *.csharp Raven.csharp
clean: clean:
if [ "$$(ls ./*~ 2>/dev/null | wc -l)" -gt 0 ]; then rm -Rf *~; fi for i in raven.mono; do if [ -f $$i ]; then rm $$i; fi; done
if [ "$$(ls ./*.mono 2>/dev/null | wc -l)" -gt 0 ]; then rm -Rf *.mono; fi
if [ "$$(ls ./\#* 2>/dev/null | wc -l)" -gt 0 ]; then rm -Rf \#*; fi
edit: edit:
emacs -nw raven.csharp emacs -nw raven.csharp
test: compile test: compile
script -c "mono ./raven.mono -c ${CONFDIR}-Test -v" /tmp/raven-test.log script -c "mono ./raven.mono -c raven-test.conf -v" /tmp/raven-test.log
check-for-verbosity: check-for-verbosity:
grep Console.WriteLine *.csharp | egrep -v 'verbosity|raven.csharp'; echo grep Console.WriteLine *.csharp | egrep -v 'verbosity|raven.csharp'; echo

View File

@ -17,16 +17,17 @@ namespace AniNIX.TheRaven {
public string Nick { get; private set; } // This is the Nickname for this Raven to use. public string Nick { get; private set; } // This is the Nickname for this Raven to use.
private string _nickServPass; // This is the password we will send to NickServ to identify private string _nickServPass; // This is the password we will send to NickServ to identify
private string _autoSend; // This is the command we will automatically send to the Host private string _autoSend; // This is the command we will automatically send to the Host
private string configDir; // This is the configuration directory. private string _configFile; // This is the configuration directory.
private Connection _connection; //This is the socket to the Host private Connection _connection; //This is the socket to the Host
public List<String> channels = new List<String>(); //This is the list of channels to join public List<String> channels; //This is the list of channels to join
public List<String> whitelist = new List<String>(); //This is the list of admin users. public List<String> whitelist; //This is the list of admin users.
public List<String> blacklist = new List<String>(); // This is the list of blocked people. public List<String> blacklist; // This is the list of blocked people.
public String helpText = null; // This is the text to send when people ask for help -- this is configurable to allow for skinning public String helpText; // This is the text to send when people ask for help -- this is configurable to allow for skinning
public List<String> searches = new List<String>(); //These are the searches public List<String> searches; //These are the searches
public String[] magic8 = null; //These are the strings to return like a Magic 8-ball to questions. public String searchesIndex; //This is the helptext for the searches
public String[] crowFacts = null; //These are the possible CrowFacts public List<String> magic8; //These are the strings to return like a Magic 8-ball to questions.
public List<String> crowFacts; //These are the possible CrowFacts
public List<String> crowFactsSubscribers = new List<String>(); //These are the subscribers to CrowFacts public List<String> crowFactsSubscribers = new List<String>(); //These are the subscribers to CrowFacts
public Dictionary<String,String> notifications = new Dictionary<String,String>(); // This is the notifications list for TheRaven. public Dictionary<String,String> notifications = new Dictionary<String,String>(); // This is the notifications list for TheRaven.
@ -46,74 +47,55 @@ namespace AniNIX.TheRaven {
sb.Append(String.Format("Nick: {0}\n",Nick)); sb.Append(String.Format("Nick: {0}\n",Nick));
sb.Append("NickServPass: ****\n"); sb.Append("NickServPass: ****\n");
sb.Append(String.Format("Auto: {0}\n",_autoSend)); sb.Append(String.Format("Auto: {0}\n",_autoSend));
sb.Append(String.Format("Conf: {0}\n",configDir)); sb.Append(String.Format("Conf: {0}\n",_configFile));
sb.Append(String.Format("Verbosity: {0}\n",ReportMessage.verbosity)); sb.Append(String.Format("Verbosity: {0}\n",ReportMessage.verbosity));
return sb.ToString(); return sb.ToString();
} }
/// <summary> /// <summary>
/// Read from the files in the directory to configure this Raven /// Read from the files in the /usr/local/etc/TheRaven directory to configure this Raven
/// </summary> /// </summary>
// TODO: This and ParseArgs may get punted into their own static class to improve readability. // TODO: This and ParseArgs may get punted into their own static class to improve readability.
private void ConfigureSelfFromFiles(String configDir) { private void ConfigureSelfFromFiles() {
if (configDir==null || configDir == "" || !Directory.Exists(configDir)) { String confFilePath = String.Format("/usr/local/etc/TheRaven/{0}",_configFile);
ReportMessage.Log(Verbosity.Error,"Configuration directory does not exist!");
if (!File.Exists(confFilePath)) {
ReportMessage.Log(Verbosity.Error,"Configuration file doesn't exist.");
return; return;
} }
ReportMessage.Log(Verbosity.Always,String.Format("Reading from config file in /usr/local/etc/{0} and the global files in the same directory...",_configFile));
ReportMessage.Log(Verbosity.Always,String.Format("Reading from files in {0}...",configDir)); Configure conf = new Configure(confFilePath);
//These are locals that will be used throughout //These are locals that will be used throughout
ReportMessage.Log(Verbosity.Verbose,"Reading login defaults"); Dictionary<String,String> loginDefaults = conf.ReadSection("Login");
String[] loginDefaults = RavenConfigure.ReadLineDelimitedFile(Path.Combine(configDir,"loginDefaults.txt")).ToArray(); this.Host = loginDefaults["host"];
//We have to populate these properties fom the list explicitly this.Port = Int32.Parse(loginDefaults["port"]);
if (loginDefaults.Length < 4) { this.Nick = loginDefaults["username"];
ReportMessage.Log(Verbosity.Error,"Login defaults are incomplete. No changes made."); this._nickServPass = loginDefaults["password"];
} else {
Host = (Host==null) ? loginDefaults[0] : Host;
try {
Port = (Port == 0) ? Int32.Parse(loginDefaults[1]) : Port;
} catch (Exception e) {
ReportMessage.Log(Verbosity.Verbose,"Cannot parse Port.");
e.ToString();
Port = 6667;
}
Nick = (Nick == null) ? loginDefaults[2] : Nick;
_nickServPass = (_nickServPass == null) ? loginDefaults[3] : _nickServPass;
}
//Read all the channels to join. channels=new List<String>();
List<String> tempChannels = RavenConfigure.ReadLineDelimitedFile(Path.Combine(configDir,"rooms.txt")); foreach (String channel in conf.ReadSectionLines("Rooms")) {
// Because the convention is to use # for comments, channels in the rooms.txt file do not start with a #
foreach (String channel in tempChannels) {
channels.Add(String.Format("#{0}",channel)); channels.Add(String.Format("#{0}",channel));
} }
//Read the whitelist of folks allowed to execute administrative commands //Parse the lists.
whitelist = RavenConfigure.ReadLineDelimitedFile(Path.Combine(configDir,"whitelist.txt")); notifications = conf.ReadSection("Notifications");
whitelist = conf.ReadSectionLines("Whitelist");
//Read the blacklist of folks not allowed to do anything. blacklist = conf.ReadSectionLines("Blacklist");
blacklist = RavenConfigure.ReadLineDelimitedFile(Path.Combine(configDir,"blacklist.txt")); helpText = "Available commands are r.raven, r.magic8, r.uptime, r.heartbeat, r.msg <memo for admin>, r.d <dice test>, r.tinyurl <url>, and r.searches";
searches = conf.ReadSectionLines("Searches");
//Read the helptext StringBuilder searchIndexBuilder = new StringBuilder();
helpText = RavenConfigure.ReadFirstLineFromFile(Path.Combine(configDir,"helptext.txt")); foreach (String searchLine in searches) {
String[] byPipe = searchLine.Split('|');
//Read the searches to use if (byPipe.Length > 3) searchIndexBuilder.Append(String.Format("{0} <{1} search>, ",byPipe[0],byPipe[3]));
searches = RavenConfigure.ReadLineDelimitedFile(Path.Combine(configDir,"searches.txt"));
//Read the Magic8 options
magic8 = RavenConfigure.ReadLineDelimitedFileToArr(Path.Combine(configDir,"magic8.txt"));
//Read the CrowFacts
crowFacts = RavenConfigure.ReadLineDelimitedFileToArr(Path.Combine(configDir,"crowfacts.txt"));
//Read the notifications
foreach (String combo in RavenConfigure.ReadLineDelimitedFileToArr(Path.Combine(configDir,"notifications.txt"))) {
String[] byPipe = combo.Split('|');
notifications.Add(String.Format("#{0}",byPipe[0]),byPipe[1]);
} }
searchesIndex = searchIndexBuilder.ToString();
//Read the globals
magic8 = (new Configure("/usr/local/etc/TheRaven/magic8.txt")).GetLines();
crowFacts = (new Configure("/usr/local/etc/TheRaven/crowfacts.txt")).GetLines();
} }
/// <summary> /// <summary>
@ -156,7 +138,10 @@ namespace AniNIX.TheRaven {
//TODO Add helptext //TODO Add helptext
break; break;
case "-c": case "-c":
if (i < args.Length-1) configDir = args[++i]; if (i < args.Length-1) _configFile = args[++i];
break;
case "--version":
ReportMessage.Log(Verbosity.Always,"AniNIX::TheRaven version 0.2");
break; break;
} }
} }
@ -170,33 +155,24 @@ namespace AniNIX.TheRaven {
/// The arguments for creating the bot /// The arguments for creating the bot
/// </param> /// </param>
public Raven(string[] args) { public Raven(string[] args) {
ReportMessage.Log(Verbosity.Always,"Reading arguments..."); ReportMessage.Log(Verbosity.Always,"Reading arguments...");
// If we have arguments // If we have arguments
this.ParseArguments(args); this.ParseArguments(args);
this.ConfigureSelfFromFiles();
this.ConfigureSelfFromFiles(configDir);
ReportMessage.Log(Verbosity.VeryVerbose,"Started with these values:"); ReportMessage.Log(Verbosity.VeryVerbose,"Started with these values:");
ReportMessage.Log(Verbosity.VeryVerbose,this.ToString()); ReportMessage.Log(Verbosity.VeryVerbose,this.ToString());
} }
/// <summary>
/// Populate the name recognition
/// </summary>
/// <summary> /// <summary>
/// Create a raven with default settings. /// Create a raven with default settings.
/// </summary> /// </summary>
public Raven(String host = "localhost", int port = 6667, String nick = "TheRaven-Guest", String nickServPass = "null", String autoSend = null, String configDir = "/usr/local/etc/TheRaven-Local", Verbosity verbosity = Verbosity.Verbose) { public Raven(String host = "localhost", int port = 6667, String nick = "TheRaven-Guest", String nickServPass = "null", String autoSend = null, String _configFile = "raven.conf", Verbosity verbosity = Verbosity.Verbose) {
this.Host = host; this.Host = host;
Port = port; Port = port;
Nick = nick; Nick = nick;
_nickServPass = nickServPass; _nickServPass = nickServPass;
_autoSend = autoSend; _autoSend = autoSend;
this.configDir = configDir; this._configFile = _configFile;
ReportMessage.verbosity = verbosity; ReportMessage.verbosity = verbosity;
} }
@ -219,8 +195,8 @@ namespace AniNIX.TheRaven {
send.CreateCustomMessage(String.Format("NICK {0}\nUSER {0} * * :{0}",Nick)); send.CreateCustomMessage(String.Format("NICK {0}\nUSER {0} * * :{0}",Nick));
_connection.Write(send); _connection.Write(send);
ReportMessage.Log(Verbosity.VeryVerbose,"USER and NICK sent"); ReportMessage.Log(Verbosity.VeryVerbose,"USER and NICK sent");
//thanks to cfrayne for the refactor
//thanks to cfrayne for the refactor
do { do {
response = _connection.Read(); response = _connection.Read();
if (response.msgCode != null && response.msgCode.Equals("433")) throw new AlreadyIdentifiedException(); if (response.msgCode != null && response.msgCode.Equals("433")) throw new AlreadyIdentifiedException();
@ -284,16 +260,20 @@ namespace AniNIX.TheRaven {
/* CROWFACTS the deserving */ /* CROWFACTS the deserving */
else if (crowFactsSubscribers.Contains(response.user) && randomSeed.Next(10) < 8) { else if (crowFactsSubscribers.Contains(response.user) && randomSeed.Next(10) < 8) {
IRCClientMessage send = new IRCClientMessage(); IRCClientMessage send = new IRCClientMessage();
int location = randomSeed.Next(crowFacts.Length); int location = randomSeed.Next(crowFacts.Count);
send.PrivMsg(crowFacts[location],response.user); send.PrivMsg(crowFacts[location],response.user);
_connection.Write(send); _connection.Write(send);
} }
// If the WebPage
if (WebPageAPI.URLRegEx.Match(response.message).Success) { if (WebPageAPI.URLRegEx.Match(response.message).Success) {
try { try {
String title = WebPageAPI.GetPageTitle(WebPageAPI.URLRegEx.Match(response.message).Value);
if (!String.IsNullOrWhiteSpace(title)) {
IRCClientMessage send = new IRCClientMessage(); IRCClientMessage send = new IRCClientMessage();
send.PrivMsg(String.Format("Web page title: {0}",WebPageAPI.GetPageTitle(WebPageAPI.URLRegEx.Match(response.message).Value)),(response.target.Equals(Nick))?response.user:response.target); send.PrivMsg(String.Format("Web page title: {0}",title),(response.target.Equals(Nick))?response.user:response.target);
_connection.Write(send); _connection.Write(send);
}
} catch (Exception e) { } catch (Exception e) {
e.ToString(); e.ToString();
} }
@ -362,8 +342,7 @@ namespace AniNIX.TheRaven {
Host = null; Host = null;
Port = 0; Port = 0;
_nickServPass = null; _nickServPass = null;
_autoSend = null; _autoSend = null; _configFile = null;
configDir = null;
whitelist = null; whitelist = null;
blacklist = null; blacklist = null;
magic8 = null; magic8 = null;

View File

@ -46,7 +46,7 @@ namespace AniNIX.TheRaven {
if (theRaven.magic8 == null) { if (theRaven.magic8 == null) {
send.PrivMsg("Magic8 not loaded",(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target); send.PrivMsg("Magic8 not loaded",(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target);
} else { } else {
int location = theRaven.randomSeed.Next(theRaven.magic8.Length); int location = theRaven.randomSeed.Next(theRaven.magic8.Count);
send.PrivMsg(theRaven.magic8[location],(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target); send.PrivMsg(theRaven.magic8[location],(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target);
} }
connection.Write(send); connection.Write(send);
@ -135,7 +135,10 @@ namespace AniNIX.TheRaven {
send.PrivMsg("Can't get heartbeat",incoming.user); send.PrivMsg("Can't get heartbeat",incoming.user);
} }
return; return;
case "r.searches":
send.PrivMsg(theRaven.searchesIndex,(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target);
connection.Write(send);
return;
} }
/* SEARCHES */ /* SEARCHES */
@ -168,7 +171,6 @@ namespace AniNIX.TheRaven {
connection.Write(send); connection.Write(send);
} }
send.PrivMsg("End subscribers",incoming.user); send.PrivMsg("End subscribers",incoming.user);
send.PrivMsg(theRaven.helpText,(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target);
} else if (theRaven.crowFacts == null) { } else if (theRaven.crowFacts == null) {
send.PrivMsg("CrowFacts not loaded.",(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target); send.PrivMsg("CrowFacts not loaded.",(incoming.target.Equals(theRaven.Nick))?incoming.user:incoming.target);
} else { } else {

View File

@ -1,9 +1,9 @@
[Unit] [Unit]
Description=AniNIX::Raven IRC Bot for ACWiki Description=AniNIX::Raven IRC Bot
After=network.target After=network.target
[Service] [Service]
ExecStart=/usr/bin/mono /opt/raven.mono -c /usr/local/etc/TheRaven ExecStart=/usr/bin/mono /opt/raven.mono -c raven.conf
ExecReload=/bin/kill -HUP $MAINPID ExecReload=/bin/kill -HUP $MAINPID
KillMode=process KillMode=process
Restart=always Restart=always

View File

@ -1 +0,0 @@
TheRaven

View File

@ -1,52 +0,0 @@
There's an old nonsense song called the Old Carrion Crow.
From 2000 to 2003 the world's best wooden roller coaster was called The Raven.
The average raven has a four-foot wingspan.
The average crow has a three-foot wingspan.
Crows and ravens are members of the corvid family, the most adaptable and intelligent family of birds in the world.
Crows and ravens can mimic sounds and associate sounds with events.
Crows roost in flocks of several thousand in the winter.
Crows are omnivorous, making them capable scavangers and opportunistic hunters.
Crows prefer coniferous trees to build their homes at least 60 feet above the ground.
Paired males and females share in the raising of the four to six eggs.
One crow baby will frequently remain in the nest to assist in the caring for the next nestlings.
While crows have a reputation for eating corn, they often eat the bugs that plague crops.
Crows and ravens are territorial when young are in the nest, dive-bombing passersby.
The Sioux have a story of a white crow warning buffalo of approaching hunting parties. The bird turned black when a hunter threw it into the fire in rage.
Crows have been hunted and even had bounties placed on them by several governments, including by Kings of England.
Crows can use a number of calls to communicate situations and emotions.
Crows mate for life and share the care of nestlings.
Crows are often challenged by larger hunting birds, like owls and hawks; they use superior numbers when outmatched.
Crows only migrate long distances in harsh winters.
A group of crows or ravens is called a murder.
Crows live everywhere except Antarctica.
Crows are susceptible to West Nile Virus, which has felled many of them since 1999.
Crows' association with death comes from their scavenger natures -- they are often seen near the dead on battlefields.
Ravens are acrobatic fliers on par with hawks and falcons. In mating season, they put on acrobatic shows for potential mates.
Native Americans often honor ravens in their stories for their playful nature.
Ravens hunt in groups to bring down prey too large for a single bird.
Ravens range from the Arctic to the Mediterranean, building large stick nests.
Ravens have an average wild lifespan of 13 years.
Common ravens range from 24 to 30 inches long with up to a 5 foot (1.5m) wingspan, weighing in at 2.3 pounds.
Legend has it that if ravens leave the Tower of London, the fortress will fall and the British kingdom along with it.
Ravens are the largest passerine (perching) birds in North America.
Ravens can live up to 40 years in captivity or protected conditions.
https://upload.wikimedia.org/wikipedia/commons/9/92/Krummi_1.jpg
Ravens have one of the largest bills of perching birds.
Common ravens have quarrelsome family lives, but they are extremely devoted to their families.
Common ravens (Corvus corax) store food, hiding it from other ravens.
A group of ravens is commonly called a flock.
Ravens don't migrate except in the harshest winters.
In addition to their bills, ravens may drop rocks as weapons.
Young ravens are fascinated with all things new, but older ravens become more cautious and neophobic with experience.
Ravens are known to play, sliding down snowdrifts for fun and play games with wolves and other animals.
Ravens are one of only a few species known to make toys, breaking off branches for social play.
The raven is the national bird of Bhutan and the official bird of the Yukon.
The raven was the first bird sent forth by Noah but didn't return until the flood waters receded.
Ravens feed the prophet Elijah in 1 Kings 17:1 and are a subject of a parable in Luke 12:24, as a sign for man not to be materialistic.
The Native Americans saw the Raven as a creator and world-shaper.
Native American mythology holds that Raven brought the sun, moon, stars, and fire into the world.
The Norse god Odin had two ravens Huginn and Muninn (Thought and Mind) to serve as his eyes in the world.
The raven is the symbol of the Celtic figure Morrigan and the namesake of Lugh, the god responsible for creating arts and science.
The raven appears in the Quran but once, only to teach man to bury the dead in the story of Cain and Abel.
GI_Auditore finds Mutated Ravens in Prototype 2 extremely annoying.
Lost_Fragment will lose in a fight with TheRaven.

View File

@ -1 +0,0 @@
Available commands are r.raven, r.magic8, r.msg <Memo for DarkFeather>, r.google <Google search>, r.sound <Soundcloud search>, r.image <Image search>, r.wiki <Wikipedia search>, r.dict <Dictionary search>, r.yt <youtube search>, r.urban <Urban dictionary search>, r.hoogle <Haskell Hoogle search>, r.so <StackOverflow search>, r.man <manpage search>, and r.tropes <TV Tropes search>

View File

@ -1,4 +0,0 @@
localhost
6667
TheRaven-Test
somepass

View File

@ -1,20 +0,0 @@
It is certain
It is decidedly so
Without a doubt
Yes definitely
You may rely on it
As I see it yes
Most likely
Outlook good
Yes
Signs point to yes
Reply hazy try again
Ask again later
Better not tell you now
Cannot predict now
Concentrate and ask again
Don't count on it
My reply is no
My sources say no
Outlook not so good
Very doubtful

View File

@ -1 +0,0 @@
TheRaven|Surprise

View File

@ -1,3 +0,0 @@
TheRafters
lobby
#thisisacomment

View File

@ -1,11 +0,0 @@
r.google|http://google.com/search?q=|+
r.images|http://images.google.com/search?tbm=isch&q=%s|+
r.wiki|http://en.wikipedia.org/wiki/|_
r.sound|http://www.soundcloud.com/search?q=|%20
r.dict|http://www.merriam-webster.com/dictionary/|+
r.tropes|http://tvtropes.org/pmwiki/search_result.php?cx=partner-pub-6610802604051523%3Aamzitfn8e7v&cof=FORID%3A10&ie=ISO-8859-1&siteurl=&ref=&ss=&siteurl=tvtropes.org%2F&ref=www.google.com%2F&ss=5135j1581675j28&q=|+
r.yt|https://www.youtube.com/results?search_query=|+
r.urban|http://www.urbandictionary.com/define.php?term=|+
r.man|http://www.die.net/search/?q=|+
r.hoogle|https://www.haskell.org/hoogle/?hoogle=|+
r.so|http://stackoverflow.com/search?q=|+

View File

@ -1 +0,0 @@
DarkFeather

30
sample.conf Normal file
View File

@ -0,0 +1,30 @@
[ Login ]
host=localhost
port=6667
username=TheRaven
password=password
[ Whitelist ]
Admin
[ Blacklist ]
[ Notifications ]
[ Rooms ]
TheRaven
[ Searches ]
r.google|http://google.com/search?q=|+|Google
r.image|http://images.google.com/search?tbm=isch&q=|+|Google Images
r.wiki|http://en.wikipedia.org/wiki/|_|Wikipedia
r.sound|http://www.soundcloud.com/search?q=|%20|Soundcloud
r.dict|http://www.merriam-webster.com/dictionary/|+|Dictionary
r.tropes|http://tvtropes.org/pmwiki/search_result.php?cx=partner-pub-6610802604051523%3Aamzitfn8e7v&cof=FORID%3A10&ie=ISO-8859-1&siteurl=&ref=&ss=&siteurl=tvtropes.org%2F&ref=www.google.com%2F&ss=5135j1581675j28&q=|+|Tropes
r.yt|https://www.youtube.com/results?search_query=|+|YouTube
r.urban|http://www.urbandictionary.com/define.php?term=|+|Urban Dictionary
r.man|http://www.die.net/search/?q=|+|Man-page
r.hoogle|https://www.haskell.org/hoogle/?hoogle=|+|Hoogle
r.so|http://stackoverflow.com/search?q=|+|Stack Overflow
r.aninix|https://aninix.net/|_|AniNIX
r.map|https://www.google.com/maps/search/|+|Google Maps