Go to file
Torsten Raudssus 3293d0dffc Starting of reorganisation of zeroclickinfo-goodies to fit v2 of developer API 2012-02-29 04:11:55 +01:00
abc make all goodies testable 2011-10-21 13:55:28 -04:00
average added root mean square/quadratic mean 2012-01-01 14:44:38 -05:00
base32 add base32 goodie 2011-12-07 17:42:49 -07:00
binary updated regex to reflect user complaints 2012-02-20 21:13:41 -05:00
dice changing rolled dice result to show operators 2011-11-03 21:25:11 -04:00
em_to_px integrate with main system -- added parenthical modifier about 16px base font 2011-11-13 13:30:17 -05:00
golden_ratio Fixed typo 2011-10-22 02:22:29 +02:00
guid make all goodies testable 2011-10-21 13:55:28 -04:00
length integrate length 2011-11-13 13:21:44 -05:00
lib/DDG Starting of reorganisation of zeroclickinfo-goodies to fit v2 of developer API 2012-02-29 04:11:55 +01:00
passphrase Merge branch 'master' into refactor-passphrase 2011-11-29 16:41:37 -05:00
percent-error more regex changes 2012-01-02 15:47:14 -05:00
perimeter integrate perimeter 2011-11-04 11:09:34 -04:00
private_network make all goodies testable 2011-10-21 13:55:28 -04:00
public_dns make all goodies testable 2011-10-21 13:55:28 -04:00
roman Added first version of roman numerals 2011-12-02 09:00:53 +00:00
share Starting of reorganisation of zeroclickinfo-goodies to fit v2 of developer API 2012-02-29 04:11:55 +01:00
sigfigs simpler and faster rewrite 2012-01-20 23:47:39 -05:00
xor xor: added multi-number functionality 2012-02-03 07:37:51 -08:00
.gitignore Starting of reorganisation of zeroclickinfo-goodies to fit v2 of developer API 2012-02-29 04:11:55 +01:00
README.md reflect new wiki structure 2012-01-23 15:16:42 -05:00
dist.ini Starting of reorganisation of zeroclickinfo-goodies to fit v2 of developer API 2012-02-29 04:11:55 +01:00
goodie-test.pl Added -b batchmode to goodie test and made it display Cached also 2011-10-21 20:45:33 +02:00

README.md

Goodies Zero-click Info Plugins

See the contribution page for a general overview on contributing to DuckDuckGo.

This repository is for contributing Perl-based Zero-click Info plugins. Each goodie plugin reacts to a set of queries and produces instant answers at the top of search results, e.g. calculations or throwing dice.

We maintain a list of requested goodie plugins, which are colored yellow on the Trello board, but whatever you want to attempt is welcome!

Contributing

First off, thank you!

Process

  1. Develop your plugin using the Structure below in either a fork or a branch (if a collaborator).

  2. Test your plugin via Testing procedure below.

  3. Submit a pull request.

Feel free to ask questions!

Structure

Each goodie has its own directory. Some of the directories are in use on the live system, and some are still in development.

Each directory has a structure like this:

# Perl file that can be directly inserted into the live system.
# This file is included, so does not need a shebang 
# or a use warnings/strict line.
goodie.pl 

# List of test queries, one per line.
queries.txt

# OPTIONAL: helper files as needed
goodie.txt
goodie.html

Testing

Please, please test your goodie via the goodie-test.pl script in the top level directory before making a pull request. We developed this script to make sure integration goes smoothly.

# Test a particular query.
# Replace goodie with the name of your directory.
# Replace query with your query.
./goodie-test.pl goodie query

# Test the queries in queries.txt
# Replace goodie with the name of your directory.
./goodie-test.pl -t goodie

goodie.pl

Within the goodie.pl file, a few things are happening, and here is an overview that references live examples, which you can review:

  1. There are some variables that are used in the system that operate outside the goodie, but which the goodie uses. Every goodie will use:

# This is the instant answer that gets printed out.
my $answer_results = '';

# This is a name (lowercase, no spaces) that gets 
# passed through to the API that should be defined 
# if $answer_results is set.
my $answer_type = '';

# This is defined external to the goodie and tells you 
# whether there is other Zero-click Info, and if so, 
# what type is it (C for category page, etc.).
my $type = '';

In addition, you may want to use:


# This is used to indicate whether the results get cached or not. 
# If the goodie is supposed to provide some kind of random output 
# that changes per page view, then you will want to set this to 0.
my $is_memcached = 1;

Finally, you will want to use a form of the query:


# This is the most common form in use. 
# It is a lower case version of the query 
# with an initial ! and ending ? removed.
my $q_check_lc = 'example query';

# This is the raw query.
my $q = 'Example query';

# This is a lower case version of the query 
# with sanitized spaces and special characters removed.
my $q_internal = 'example query';
  1. The goodie needs to know when to be called. This involves some kind of conditional statement that first involves the $type variable.

# If there is no Zero-click.
if (!$type) {

}


# If there is no other goodie. 
# Will kill other Zero-click Info, e.g. Wikipedia. 
if ($type ne 'E') {

}

Secondly you want to segment the query space to queries related to that goodie. guid uses a hash to do so.


# Uses a hash to segment the query space.
my %guid = (
    'guid' => 0,
    'uuid' => 1,
    'globally unique identifier' => 0,
    'universally unique identifier' => 1,
    'rfc 4122' => 0,
    );

if ($type ne 'E' && exists $guid{$q_check_lc}) {

}

binary uses a regular expression.


if (!$type && $q_check_lc =~ m/^binary (.*)$/i) {

}

For regular expressions, we need to watch out for false positives and speed. You can do this easily by adding a lot of queries to queries.txt

  1. Once inside the conditional, the goodie formulates the answer. This could vary slightly depending on input, but results in setting the $answer_results variable. Here's what abc looks like.
if (!$type && $q_check =~ m/^\!?\s*[A-Za-z]+(\s+or\s+[A-Za-z]+)+\s*$/ ) {
    my @choices = split(/\s+or\s+/, $q_check);
    my $choice = int(rand(@choices));

    $answer_results = $choices[$choice];
    $answer_results .= ' (random)';
    $answer_type = 'rand';
}

Notes

And here are some other things to keep in mind:

  1. If you need a helper file, name it goodie.txt or goodie.html as needed. If you need to read in that file to be used over and over again, do it outside the conditional. For example passphrase reads in a list at the top.
my %passphrase = ();
open(IN, '<passphrase/goodie.txt');
while (my $line = <IN>) {
    chomp($line);
    my @res = split(/ /, $line);
    $passphrase{$res[0]} = $res[1];
    
}
close(IN);

Whereas if you need to read in a file for output, do it inside the conditional. For example, public_dns reads in a list inside.

    open(IN,"<public_dns/goodie.html");
    while (my $line = <IN>) {
    $answer_results .= $line;
    }
    close(IN);
  1. If it is possible that the conditional gets called, but $answer_results still may not be set, then wrap $answer_type (and possibly other variables) in a separate conditional like in private_network.
    if ($answer_results) {
       $answer_type = 'network';
       $type = 'E';
    }
  1. Goodies should only display results when they are better than algorithmic results.

  2. It generally helps to give a bit of context around the answer_results, e.g. '(random password)' after a random password or 'Answer:' before.