PageRenderTime 37ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/README.md

https://github.com/andrearonsen/zeroclickinfo-goodies
Markdown | 204 lines | 134 code | 70 blank | 0 comment | 0 complexity | 8ade095bc09cc90af78b577fd8a7a449 MD5 | raw file
  1. DuckDuckGo ZeroClickInfo Goodies
  2. =================================
  3. About
  4. -----
  5. See [the contribution page](https://github.com/duckduckgo/duckduckgo/wiki) for a general overview on contributing to DuckDuckGo.
  6. This repository is for contributing goodies, which are special tools that reveal instant answers at the top of search results, e.g. calculations or throwing dice.
  7. Most of the existing goodies are listed on the [goodies page](http://duckduckgo.com/goodies.html) and [tech goodies page](http://duckduckgo.com/tech.html).
  8. We also maintain a list of [requested goodies](https://github.com/duckduckgo/duckduckgo/wiki/Goodies), but whatever you want to attempt is welcome.
  9. Contributing
  10. ------------
  11. Thank you!
  12. Each goodie has its own directory. Some of the directories are in use on the live system, and some are still in development.
  13. Each directory has a structure like this:
  14. ```txt
  15. # Perl file that can be directly inserted into the live system.
  16. goodie.pl
  17. # List of test queries, one per line.
  18. queries.txt
  19. # OPTIONAL: helper files as needed
  20. goodie.txt
  21. goodie.html
  22. ```
  23. ### Testing
  24. You can test your goodie via the goodie-test.pl script in the top level directory.
  25. ```
  26. # Test a particular query.
  27. # Replace goodie with the name of your directory.
  28. # Replace query with your query.
  29. ./goodie-test.pl goodie query
  30. # Test the queries in queries.txt
  31. # Replace goodie with the name of your directory.
  32. ./goodie-test.pl -t goodie
  33. ```
  34. ### goodie.pl
  35. Within the goodie.pl file, a few things are happening, and here is an overview that references live examples, which you can review:
  36. 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:
  37. ```perl
  38. # This is the instant answer that gets printed out.
  39. my $answer_results = '';
  40. # This is a name (lowercase, no spaces) that gets
  41. # passed through to the API that should be defined
  42. # if $answer_results is set.
  43. my $answer_type = '';
  44. # This is defined external to the goodie and tells you
  45. # whether there is other Zero-click info, and if so,
  46. # what type is it (C for category page, etc.).
  47. my $type = '';
  48. ```
  49. In addition, you may want to use:
  50. ```perl
  51. # This is used to indicate whether the results get cached or not.
  52. # If the goodie is supposed to provide some kind of random output
  53. # that changes per page view, then you will want to set this to 0.
  54. my $is_memcached = 1;
  55. ```
  56. Finally, you will want to use a form of the query:
  57. ```perl
  58. # This is the most common form in use.
  59. # It is a lower case version of the query
  60. # with an initial ! and ending ? removed.
  61. my $q_check_lc = 'example query';
  62. # This is the raw query.
  63. my $q = 'Example query';
  64. # This is a lower case version of the query
  65. # with sanitized spaces and special characters removed.
  66. my $q_internal = 'example query';
  67. ```
  68. 2) The goodie needs to know when to be called. This involves some kind of conditional statement that first involves the $type variable.
  69. ```perl
  70. # If there is no 0-click.
  71. if (!$type) {
  72. }
  73. # If there is no other goodie.
  74. # Will kill other 0-click info, e.g. Wikipedia.
  75. if ($type ne 'E') {
  76. }
  77. ```
  78. Secondly you want to segment the query space to queries related to that goodie. [guid](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/guid/goodie.pl) uses a hash to do so.
  79. ```perl
  80. # Uses a hash to segment the query space.
  81. my %guid = (
  82. 'guid' => 0,
  83. 'uuid' => 1,
  84. 'globally unique identifier' => 0,
  85. 'universally unique identifier' => 1,
  86. 'rfc 4122' => 0,
  87. );
  88. if ($type ne 'E' && exists $guid{$q_check_lc}) {
  89. }
  90. ```
  91. [binary](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/binary/goodie.pl) uses a regular expression.
  92. ```perl
  93. if (!$type && $q_check_lc =~ m/^binary (.*)$/i) {
  94. }
  95. ```
  96. 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
  97. 3) 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](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/abc/goodie.pl) looks like.
  98. ```perl
  99. if (!$type && $q_check =~ m/^\!?\s*[A-Za-z]+(\s+or\s+[A-Za-z]+)+\s*$/ ) {
  100. my @choices = split(/\s+or\s+/, $q_check);
  101. my $choice = int(rand(@choices));
  102. $answer_results = $choices[$choice];
  103. $answer_results .= ' (random)';
  104. $answer_type = 'rand';
  105. }
  106. ```
  107. ### Notes
  108. And here are some other things to keep in mind:
  109. 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](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/passphrase/goodie.pl) reads in a list at the top.
  110. ```perl
  111. my %passphrase = ();
  112. open(IN, '<passphrase/goodie.txt');
  113. while (my $line = <IN>) {
  114. chomp($line);
  115. my @res = split(/ /, $line);
  116. $passphrase{$res[0]} = $res[1];
  117. }
  118. close(IN);
  119. ```
  120. Whereas if you need to read in a file for output, do it inside the conditional. For example, [public_dns](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/public_dns/goodie.pl) reads in a list inside.
  121. ```perl
  122. open(IN,"<public_dns/goodie.html");
  123. while (my $line = <IN>) {
  124. $answer_results .= $line;
  125. }
  126. close(IN);
  127. ```
  128. 2) 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](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/private_network/goodie.pl).
  129. ```perl
  130. if ($answer_results) {
  131. $answer_type = 'network';
  132. $type = 'E';
  133. }
  134. ```