Skip to content
This repository was archived by the owner on Jan 10, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Summary

* [Introduction](README.md)
* [Welcome](duckduckhack/welcome/ddh-intro.md)
* [Setting up your development environment](duckduckhack/welcome/setup-dev-environment.md)

450 changes: 450 additions & 0 deletions duckduckhack/api-answers/forum-lookup.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions duckduckhack/api-answers/local-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# How to Add a Local Search

(NY Bike Share)
3 changes: 3 additions & 0 deletions duckduckhack/api-answers/transit-schedule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# How to Make a Transit Times Lookup

(SEPTA Train)
Binary file added duckduckhack/assets/air_quality.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/alternative_spotify.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/blue_pill.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/bpm_ms.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/gcf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/heads_tails.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/parking_ny.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/sales_tax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added duckduckhack/assets/url_encode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
##Spice Handlers
# API Reference

- [Multiple Placeholders in Spice To URL](http://duck.co/duckduckhack/spice_advanced_backend#Multiple-Placeholders-in-Spice-To-URL)
## API Criteria

- [Returning Multiple Values (to Spice From)](http://duck.co/duckduckhack/spice_advanced_backend#Returning-Multiple-Values-to-Spice-From)
With millions of search queries triggering Instant Answers every day, it's important to choose APIs wisely. There are several criteria for APIs used in Spice Instant Answers.

- [API Keys](http://duck.co/duckduckhack/spice_advanced_backend#api-keys)
### Technical constraints

- [JSON -> JSONP](http://duck.co/duckduckhack/spice_advanced_backend#json-gt-jsonp)
- APIs called by Spice Instant Answers **must use the JSON or JSONP formats**. We do not support the use of XML (it's coming soon though!), HTML, or plain text responses.
- APIs should respond to requests in **less than one second** (< 1s).
- Avoid **static JSON files**. These often have large payloads and require heavy local processing. Not sure? [Talk to us about your idea](mailto:[email protected]).

- [Pure JS functions](http://duck.co/duckduckhack/spice_advanced_backend#pure-js-functions)
### Reliability

- [Caching API Responses](http://duck.co/duckduckhack/spice_advanced_backend#caching-api-responses)
- APIs used should be **reliable**. Pick sources that will be most likely be around and accurate for the foreseeable future.
- APIs created by contributors solely for the purpose of an Instant Answer cannot be accepted.

- [Caching API Calls](http://duck.co/duckduckhack/spice_advanced_backend#caching-api-calls)
### Credibility

## Multiple Placeholders in Spice To URL
- APIs used should represent the **most credible source** for the information. This means it should draw upon the preferred data source of the relevant community. Look for posts and sources like [these](https://duck.co/forum/thread/37/great-resources-for-instant-answer-ideas) which have been suggested by others.
- APIs must have the appropriate permissions or rights to serve their information.

If you need to substitute multiple parameters into the API call like how the [RandWord Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/RandWord.pm) uses two numbers to specify the min and max length of the random word, you can use the **Spice from** keyword:
## Multiple API endpoints

Learn how to handle multiple API endpoints when developing a DuckDuckGo Instant Answer.

[Watch video on Vimeo](https://vimeo.com/137152536)

![https://vimeo.com/137152536](https://images.duckduckgo.com/iu/?u=https%3A%2F%2Fraw.githubusercontent.com%2Fduckduckgo%2Fduckduckgo-documentation%2Fmaster%2Fduckduckhack%2Fassets%2Fscreencast_multiple-endpoints.jpg&f=1)

## Multiple Placeholders in API URL

If you need to substitute multiple parameters into the API call you can use the **Spice from** keyword. In the following example, the [RandWord Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/RandWord.pm) uses two numbers to specify the min and max length of the random word:

```perl
spice from => '(?:([0-9]+)\-([0-9]+)|)';
Expand All @@ -37,8 +51,6 @@ handle remainder => sub {
}
```

<!-- /summary -->

Then the the string `10-100` would be sent to the `spice from` regexp, which would capture the two numbers into `$1` and `$2`. These two placeholders are then used to replace `$1` and `$2` in the `spice to` URL:

```perl
Expand All @@ -47,7 +59,7 @@ spice to => 'http://api.wordnik.com/v4/words.json/randomWord?minLength=$1&maxLen

**Note:** The reason why you do not need to specify a **from** keyword by default, is that the default value of `spice from` is **(.*)**, which means whatever you return gets gets captured into `$1`.

## Returning Multiple Values (to Spice From)
## Passing Multiple Values to Spice From

You can have multiple return values in your handle function like the [AlternativeTo Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/AlternativeTo.pm).

Expand Down Expand Up @@ -89,24 +101,6 @@ Some APIs don't do JSONP by default, i.e. don't have the ability to return the J
spice wrap_jsonp_callback => 1;
```

## Pure JS functions

Sometimes no external API is necessary to deliver the Instant Answer like how the [Flash Version Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/FlashVersion.pm) just prints out your [Flash Player version](https://duckduckgo.com/?q=flash+version) using an [internal call](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/share/spice/flash_version/flash_version.js).

In cases like these you can define a **spice\_call\_type** as 'self' like this:

```perl
spice call_type => 'self';
```

Then in the handle function you can return call, e.g.:

```perl
return $_ eq 'flash version' ? call : ();
```

The return of **call** will run whatever is in the **call\_type** setting. **self** is a special keyword to just run the callback function directly, in this case **ddg\_spice\_flash_version()**.

## Caching

Spice Instant Answers have two forms of caching: API Response caching (remembers the JSON returned from the API) and API Call caching (remembers the API call URL created for a given query). Both of these will be explained with examples.
Expand Down
53 changes: 53 additions & 0 deletions duckduckhack/backend-reference/data-files.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Data Files

Instant Answers - particularly Goodies - can use simple text files for display or processing. These files can be read once and reused to answer many queries without cluttering up your source code.

The `share` function gives each Instant Answer access to a subdirectory of the repository's [`share`](https://github.com/duckduckgo/zeroclickinfo-goodies/tree/master/share/goodie) directory. The subdirectory for your Instant Answer is based on its Perl package name which is transformed from CamelCase to underscore_separated_words.

## Usage


The [MAC Address Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/andrey/js-keycodes-cheatsheet/lib/DDG/Goodie/MacAddress.pm) uses the `share` directory to hold data for processing purposes:

```perl
my %oui_db = share("oui_database.txt")->slurp;
```

Here the `share` function grabs the `oui_database.txt` file. The returned object's `slurp` method is called which pushes each line of the file into an array.

The full code performs some additional parsing on each line of the `slurp`-ed array:

```perl
my %oui_db = map { chomp; my (@f) = split(/\\n/, $_, 2); ($f[0] => $f[1]); } share("oui_database.txt")->slurp;
```

You may decide to take advantage of particular data formats, such as JSON, as does the [Independence Day Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/IndependenceDay.pm):

```perl
my $data = share('independence_days.json')->slurp;
$data = decode_json($data);
```

Another example involves parsing a YAML file, as does the [Paper Size Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Paper.pm):

```perl
use YAML::XS 'LoadFile';

my $sizes = LoadFile(share('sizes.yml'));
```

## UTF-8 Encoding

One further consideration is whether your data file contains non-ASCII characters. If so, you will want to prepare the file with UTF-8 encoding. The [Shortcut Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Shortcut.pm) uses a UTF-8 data file:

```perl
my @shortcuts = share('shortcuts.csv')->slurp(iomode => '<:encoding(UTF-8)');
```

As with the Passphrase Goodie example above, each line becomes an entry in the resulting array. With this `iomode` set, the UTF-8 characters used to denote system-specific keys will be handled properly throughout the rest of the processing.

## Generating Data Files

In some cases, you may need to generate the data files you will `slurp` from the share directory. If so, please put the required generation scripts in the Goodie's `share` directory. While **shell scripts are preferred**, your scripts can be written in the language of your choice.

As an example, the [CurrencyIn Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/CurrencyIn.pm) uses a [combination of Shell and Python scripts](https://github.com/duckduckgo/zeroclickinfo-goodies/tree/master/share/goodie/currency_in) to generate its input data, `currency.txt`.
3 changes: 1 addition & 2 deletions duckduckhack/goodie/goodie_helpers.md → ...khack/backend-reference/goodie-helpers.md
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Goodie Helpers

A few commonly used functions are wrapped up into useful helpers that can be easily used by any goodie. These are implemented as "roles" that can be used adding the following line to your Goodie's Perl module (.pm file):
We've wrapped several commonly used functions into useful helpers that can be used by any Goodie Instant Answer. These are implemented as "roles" that can be used adding the following line to your Goodie's Perl module (.pm file):

```perl
with 'DDG::GoodieRole::RoleName';
```


## Numbers

Often matching and outputting numbers intelligently is required, for this the NumberStyler role is ideal:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Including metadata helps us to categorize and describe your Instant Answer. This
Metadata is added to your Instant Answer Perl file, above the triggers. For example, the ["Alternative To" Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/AlternativeTo.pm) has the following metadata:

```perl

name "AlternativeTo";
primary_example_queries "alternative to notepad";
secondary_example_queries "alternative to photoshop for mac", "free alternative to spotify for windows";
Expand All @@ -23,7 +22,7 @@ Metadata will be used in several places relating to your Instant Answer, includi

------

## name
## `name`

A unique name for this Instant Answer.

Expand All @@ -33,15 +32,15 @@ While this can be arbitrary, it is considered good practice to have the chosen n
name "Subreddit Search";
```

## source
## `source`

The name of the data source used for your Instant Answer.

```perl
source "Reddit";
```

## icon_url (optional)
## `icon_url` (optional)

The favicon URL for the data source used.

Expand All @@ -59,31 +58,31 @@ or, for DuckDuckGo-sourced favicons,
icon_url "/i/reddit.com.ico";
```

## description
## `description`

A succinct explanation of what the Instant Answer does. For clarity, *exclude* the source name if possible.

```perl
description "Search for Subreddits";
```

## primary_example_queries
## `primary_example_queries`

Examples of the most common types of queries which will trigger the Instant Answer.

```perl
primary_example_queries "/r/pizza", "subreddit nature";
```

## secondary_example_queries (optional)
## `secondary_example_queries` (optional)

Examples of other, less common, trigger words or phrases for the Instant Answer, if applicable.

```perl
secondary_example_queries "r/accounting";
```

## category
## `category`

The category into which your Instant Answer best fits.

Expand Down Expand Up @@ -124,7 +123,7 @@ Supported categories include:
category "forums";
```

## topics
## `topics`

A list of the topics to which your Instant Answer applies.

Expand Down Expand Up @@ -159,15 +158,15 @@ Supported topics include:
topics "social", "entertainment", "special_interest";
```

## code_url
## `code_url`

URL for the Instant Answer code on github.

```perl
code_url "https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/RedditSubSearch.pm";
```

## attribution
## `attribution`

Information about you, the author.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,38 @@
## Triggers
# Triggers

There are two types of triggers, **words** and **regex**. We insist that you use word triggers whenever possible as they are simpler and faster.
Triggers tell DuckDuckGo on which search queries to initiate an Instant Answer. There are two types of triggers, **words** and **regex**.

[Word trigger example](http://duck.co/duckduckhack/spice_triggers#word-triggeres)

```perl
triggers start => "trigger my instant answer", "trigger myIA", "myIA";
```

[Trigger locations](http://duck.co/duckduckhack/spice_triggers#trigger-locations)

- `start` &mdash; Word exists at the start of the query
- `end` &mdash; Word exists at the end of the query
- `startend` &mdash; Word is at the beginning or end of the query
- `any` &mdash; Word is anywhere in the query
The two types of triggers cannot be combined, but you may consider a third option of [Regex Guards](#regex-guards). We insist that you use word triggers whenever possible as they are simpler and faster.

## Word Triggers

### Usage
Word triggers specify *what* to look for, and *where* to look for it:

```perl
triggers <location> => <array of words and phrases>
```

<!-- /summary -->

#### Examples
For example:

```perl
triggers start => "trigger my instant answer", "trigger myIA", "myIA";
triggers start => "stackoverflow", "stack overflow", "SO";
```

or
You may find the [qw](http://perlmeme.org/howtos/perlfunc/qw_function.html) function convenient:

```perl
@triggers = qw(these are separate triggers for my instant answer);
@triggers = qw(john jacob jingleheimer schmidt);
triggers any => @triggers;
```

or
You can also use multiple trigger statements together:

```perl
triggers start => "starting phrase of query";
triggers end => "ending phrase of query";
triggers start => "tv", "television";
triggers end => "schedule", "hours";
```

## Trigger Locations
### Word Trigger Locations

- `start` &mdash; Word exists at the start of the query
- `end` &mdash; Word exists at the end of the query
Expand All @@ -56,7 +43,11 @@ triggers end => "ending phrase of query";

## Regex Triggers

### Usage
***We insist that you use word triggers whenever possible as they are simpler and faster.***

***Note that you cannot combine the use of Regex Triggers with Word Triggers.***

Regex triggers specify *which version of the query*, and a *regular expression* to apply.

```perl
triggers <query_format> => <regular expression>
Expand Down Expand Up @@ -85,13 +76,11 @@ triggers query_raw => $regex;
- `query_nowhitespace` &mdash; `query` with all whitespace removed
- `query_clean` &mdash; `query_lc`, but with whitespace and non-alphanumeric ascii removed

**Note:** You **cannot** combine the use of **Regex Triggers** with **Word Triggers**.

## Regex Guards

We much prefer you use **trigger words** when possible because they are faster on the backend. In some cases however, **regular expressions** are necessary, e.g. you need to trigger on sub-words. In this case we suggest you consider using a **word trigger** and supplement it with a **regex guard**. A regex guard is a return clause immediately inside the `handle` function.
Trigger words are coarse filters; they may send you queries you cannot handle. Your Instant Answer should return nothing in these cases. As such, you generally need to further qualify the query in your code.

<!-- /summary -->
We much prefer you use Word Triggers when possible because they are faster on the backend. In some cases however, **regular expressions** are necessary, e.g., you need to trigger on sub-words. In this case we suggest you consider using a **word trigger** and supplement it with a **regex guard**. A regex guard is a return clause immediately inside the `handle` function.

A good example of this is the Base64 goodie. In this case we want to trigger on queries with the form "base64 encode/decode \<string\>". Here's an excerpt from [Base64.pm](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Base64.pm) which shows how this case is handled using a word trigger, with a regex guard:

Expand All @@ -100,9 +89,18 @@ triggers startend => "base64";

handle remainder => sub {
return unless $_ =~ /^(encode|decode|)\s*(.*)$/i;
```

Another example, the [Base Goodie's](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Base.pm) has a `return` statement paired with an `unless` right on the first line of its `handle` function:

```perl
handle remainder => sub {
return unless /^([0-9]+)\s*(?:(?:in|as)\s+)?(hex|hexadecimal|octal|oct|binary|base\s*([0-9]+))$/;
...
}
```


## Triggers in Multiple Languages

We have plans to make it possible to trigger Instant Answers in many different languages. Until an internationalization mechanism is place, to uphold maintainability and consistency, **we cannot accept pull requests that add languages directly in the code.**
1 change: 1 addition & 0 deletions duckduckhack/cheat-sheets/key-bindings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# How to Make a Key Bindings Cheat Sheet
1 change: 1 addition & 0 deletions duckduckhack/cheat-sheets/language-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# How to Make a Language Reference Cheat Sheet
Loading