Merge branch 'master' into RegexCheatSheet

Conflicts:
	lib/DDG/Goodie/RegexCheatSheet.pm
master
Rob Emery 2013-11-06 16:48:19 +00:00
commit 9cefa77e70
30 changed files with 820 additions and 664 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
DDG-*
.build
*.sw*
*~

70
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,70 @@
# Contributing to Goodie
At DuckDuckGo, we truly appreciate our community members taking the time to contribute to our open-source repositories. In an effort to ensure contributions are easy for you to make and for us to manage, we have written some guidelines that we ask our contributors to follow so that we can handle pull requests in a timely manner with as little friction as possible.
## Getting Started
Before you can do anything, you first need a [GitHub account](https://github.com/signup/free). This is required because we use GitHub to handle all incoming *Pull Requests* (code modifications) and *Issues* (bug reports) which cannot be made without a GitHub account.
## Submitting a **Bug** or **Suggestion**
- Firstly, please make sure the bug is related to the Goodie repository. If this bug is about the DuckDuckGo API, or the relevancy of our search results, please visit our feedback page at <https://duckduckgo.com/feedback>. If you're unsure, its best to use the feedback page (your message will be passed along to the correct people).
- Check the Goodie [issues](https://github.com/duckduckgo/zeroclickinfo-goodies/issues) to see if an issue already exists for the given bug or suggestion
- If one doesn't exist, create a GitHub issue in the Goodie repository
- Clearly describe the bug/improvemnt, including steps to reproduce when it is a bug
- If one already exists, please add any additional comments you have regarding the matter
If you're submitting a **pull request** (bugfix/addition):
- Fork the Goodie repository on GitHub
## Making Changes
- Before making any changes, refer to the [DuckDuckHack Styleguide](https://dukgo.com/duckduckhack/styleguide_overview) to ensure your changes are made in the correct fashion
- Make sure your commits are of a reasonable size. They shouldn't be too big (or too small)
- Make sure your commit messages effectively explain what changes have been made, and please identify which instant answer or file has been modified:
```shell
CONTRIBUTING.md - Added the example commit message because it was missing
```
is much better than:
```shell
<bad_commit_example>
```
- Make sure you have added the necessary tests for your changes
- Run `dzil test` (executes all tests in t/) to ensure nothing else was accidentally broken
- If your change affects an instant answer, remember to add yourself to the Metadata attribution list in the appropriate `.pm` file
## Submitting Changes
1. Commit your changes.
```shell
git commit -a -m "My first instant answer that does X is ready to go!"
```
2. Get your commit history [how you like it](http://book.git-scm.com/4_interactive_rebasing.html).
```shell
git rebase -i origin/master
```
or
```shell
git pull --rebase origin/master
```
3. Push your forked repository back to GitHub.
```shell
git push
```
4. Add your info to the instant answer so we can give you credit for it on the [Goodies page](https://duckduckgo.com/goodies). You'll see your name or handle on the live site!
Check out the [Metadata documentation](https://dukgo.com/duckduckhack/metadata) for detailed instructions on how to include your name and links.
5. Go into GitHub and submit a [pull request!](http://help.github.com/send-pull-requests/) to the Goodie repository, making sure to use the Goodie repository's **[Pull Request Template](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/goodie_pr_template.md)**. This will let us know about your changes and start the conversation about integrating it into the live code.

11
LICENSE Normal file
View File

@ -0,0 +1,11 @@
Copyright 2010 Duck Duck Go, Inc.
Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
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.

View File

@ -1,12 +1,11 @@
DuckDuckHack Goodies
====
# DuckDuckHack Goodie Instant Answers
Goodies are DuckDuckGo plugins that work with pure [Perl](https://en.wikipedia.org/wiki/Perl).
This repository contains all the Goodie instant answers. If you are developing a Goodie instant answer you will need to fork this repository.
**If you would like to contribute to DuckDuckHack, please start by reading the [DuckDuckHack Documentation](https://dukgo.com/duckduckhack/ddh-intro).**
------
### Goodie Instant Answer Example
![morse code example](https://s3.amazonaws.com/ddg-assets/docs/goodie_example.png)
We recommend starting at the [DuckDuckHack Intro Site](http://duckduckhack.com). If you've read that, but are still looking for more detail, checkout the [DuckDuckHack Goodie Overview](https://github.com/duckduckgo/duckduckgo/blob/master/README.md).
### Writing a Goodie
If you're ready to start writing a Goodie, go to the [Goodies Overview](https://github.com/duckduckgo/duckduckgo#goodies-overview).

View File

@ -29,6 +29,7 @@ Locale::Codes = 3.25
Gravatar::URL = 1.06
CGI = 3.60
Email::Valid = 0.190
Net::Domain::TLD = 0.170
; ParseCron
Schedule::Cron::Events = 0
Convert::Color = 0.08

85
goodie_pr_template.md Normal file
View File

@ -0,0 +1,85 @@
# Goodie Pull Request Template
We ask that you please use this template when submitting an instant answer pull request so we can better understand it and help you along when necessary.
**What does your instant answer do?**
**What problem does your instant answer solve (Why is it better than organic links)?**
**What is the data source for your instant answer? (Provide a link if possible)**
**Why did you choose this data source?**
**Are there any other alternative (better) data sources?**
**What are some example queries that trigger this instant answer?**
**Which communities will this instant answer be especially useful for? (gamers, book lovers, etc)**
**Is this instant answer connected to an [Ideas.DuckDuckHack](https://duckduckhack.uservoice.com/forums/5168-ideas-for-duckduckgo-instant-answer-plugins) or [Duck.co](http://duck.co/) thread?**
**Which existing instant answers will this one supercede/overlap with?**
**Are you having any problems? Do you need our help with anything?**
**\*\*Note:** Please attach a screenshot for new instant answer pull requests, and for pull requests which modify the look/design of existing instant answers.
##Checklist
Please place a ✔ where appropriate.
```
[] Added metadata and attribution information
[] Wrote test file and added to t/ directory
[] Verified that instant answer adheres to design guidelines(https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/styleguides/design_styleguide.md)
[] Tested cross-browser compatability
Please let us know which browsers/devices you've tested on:
- Windows 8
[] Google Chrome
[] Firefox
[] Opera
[] IE 10
- Windows 7
[] Google Chrome
[] Firefox
[] Opera
[] IE 8
[] IE 9
[] IE 10
- Windows XP
[] IE 7
[] IE 8
- Mac OSX
[] Google Chrome
[] Firefox
[] Opera
[] Safari
- iOS (iPhone)
[] Safari Mobile
[] Google Chrome
[] Opera
- iOS (iPad)
[] Safari Mobile
[] Google Chrome
[] Opera
- Android
[] Firefox
[] Native Browser
[] Google Chrome
[] Opera
```

View File

@ -21,7 +21,7 @@ attribution twitter => 'crazedpsyc',
handle query => sub {
return if $_ =~ /^root/i && $_ !~ /^root mean square/i;
s/^[a-zA-Z\s]+//; s/\s+[a-zA-Z]+$//; s/[;,\s]+/ /g;
s/^[a-zA-Z\s]+//; s/\s+[a-zA-Z]+$//; s/[;,\s{}\[\]\(\)]+/ /g;
return unless /^\s*(?:\d+(?:\.\d+)?\s?)*$/;
my @nums = split ' ', $_;

View File

@ -2,10 +2,11 @@ package DDG::Goodie::Coin;
use DDG::Goodie;
triggers start => 'flip', 'toss', 'coin';
triggers start => 'flip', 'toss', 'coin', 'heads';
primary_example_queries 'flip a coin', 'toss a coin';
secondary_example_queries 'flip 4 coins';
secondary_example_queries 'flip 4 coins', 'heads or tails';
description 'flip a coin';
name 'Coin Flip';
code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Coin.pm';
@ -14,23 +15,24 @@ category 'random';
attribution github => [ 'http://github.com/mattlehning', 'mattlehning' ];
handle query_lc => sub {
return unless my ($a, $n) = $_ =~ /^((?:flip|toss) a coin|(?:flip|toss) (\d{0,2}) coins?)$/;
my $flips;
if ($_ =~ /^(heads or tails[ ]?[\?]?)|((flip|toss) a coin)$/) {
$flips = 1;
}
elsif ($_ =~ /^(?:flip|toss) (\d{0,2}) coins?$/) {
$flips = $1;
}
return unless ($flips);
my @output;
my @ht = ("heads", "tails");
my $flips = 1;
my $flip;
my $b = "flip a coin";
my $c = "toss a coin";
my $count;
$n = 1 if ($a eq $b||$a eq $c);
if($n >= 1) {
for ($count = 1; $count <= $n; $count++) {
$flip = $ht[int rand @ht];
push @output, $flip;
}
for (1..$flips) {
my $flip = $ht[int rand @ht];
push @output, $flip;
}
return join(', ', @output) . ' (random)' if @output;
};

54
lib/DDG/Goodie/Dessert.pm Normal file
View File

@ -0,0 +1,54 @@
package DDG::Goodie::Dessert;
use DDG::Goodie;
sub itemify{
my $i = rand scalar @_;
my $dessert = $_[$i];
$dessert =~ s/\s/+/g;
return "<a href='http://duckduckgo.com/?q=$dessert+recipe'>$_[$i]</a>";
};
my %desserts = (
a => ['Apple Turnover'],
b => ['Banana Split', 'Biscuits'],
c => ['Cherry Pie', 'Cupcake', 'Chocolate'],
d => ['Donut'],
e => ['Eclair'],
f => ['Froyo', 'Fudge'],
g => ['Gingerbread'],
h => ['Honeycomb'],
i => ['Ice Cream Sandwich', 'Ice Cream'],
j => ['Jam Rolly Polly','Jelly Bean','Jelly'],
k => ['Key Lime Pie'],
l => ['Lollipop','Liqourice'],
m => ['Macaroons','Meringues','Marshmallow','Muffin'],
n => ['Nougat','Nutella'],
o => ['Oatmeal Pie','Oreos'],
p => ['Profiteroles','Pop Tart'],
q => ['Quiche'],
r => ['Rocky Road','Red Velvet Cake','Ruhbarb and Custard'],
s => ['Sundae','Strudel','Strawberries and Cream','Souffle'],
t => ['Tiramisu','Trifle','Twinkies','Taffy','Toffee'],
u => ['Unicorn Cake','Upside-down cake'],
v => ['Vanilla Swirl'],
w => ['Waffles','Watermelon','White Chocolate'],
x => ['Xmas Cake'],
z => ['Zepolle','Zucchini Pie'],
);
triggers start => 'dessert', 'desserts', 'a dessert';
handle remainder => sub{
if(lc $_ =~ m/^(?:that )?(?:start|beginn?)s?(?:ing)? ?(?:with)? (?:the letter )?([a-zA-Z])$/i){
my $in = lc $1;
my $items = $desserts{lc $in};
my $output = itemify(@{$items}) . " is a dessert that begins with the letter " . uc $in . '.';
return $output;
}
return;
};
zci is_cached => 0;
1;

View File

@ -32,7 +32,7 @@ sub get_info {
sub line {
my($num) = @_;
chomp $num;
return "<td>$num</td><td>".(get_info($num) or return)."</td>";
return "<td>$num</td><td>&nbsp;".(get_info($num) or return)."</td>";
}
sub single_format {
@ -91,7 +91,7 @@ handle remainder => sub {
$out_html =~ s/\[\[(.+?)\]\]/<a href="\/?q=$1">$1<\/a>/g;
$out =~ s/\[\[.+?\|(.+?)\]\]/$1/g;
$out =~ s/\[\[(.+?)\]\]/$1/g;
return ($multi) ? "" : $out, html => ($multi) ? "<table>$out_html</table>" : $out_html;
return ($multi) ? "" : $out, html => ($multi) ? "<table cellpadding=1>$out_html</table>" : $out_html;
};
1;

View File

@ -0,0 +1,51 @@
package DDG::Goodie::EmailValidator;
# ABSTRACT: Checks given email address
use DDG::Goodie;
use Email::Valid;
topics 'sysadmin';
category 'computing_info';
zci is_cached => 0;
triggers start => 'validate';
primary_example_queries 'validate foo@example.com';
attribution github => ['https://github.com/stelim', 'Stefan Limbacher'],
twitter => ['http://twitter.com/stefanlimbacher', 'Stefan Limbacher'];
my $message_part = {
tldcheck => 'top-level domain',
fqdn => 'fully qualified domain name',
localpart => 'localpart',
address_too_long => 'address length',
};
handle remainder => sub {
return if !$_;
$_ =~ /\b([^\s]+@[^\s]+)\b/g ;
my $address = $1;
return if !$address;
my $email_valid = Email::Valid->new(
-tldcheck => 1,
);
# Danger: address returns possible modified string!
my $result = $email_valid->address($address);
if (! $result) {
my $message = "$address is invalid. Please check the " . $message_part->{$email_valid->details} . "."
if defined $message_part->{$email_valid->details};
return $message || "E-mail address $address is not valid. ${\$email_valid->details} (see also: RFC 822)";
}
return "$result seems to be valid.";
};
1;

View File

@ -36,7 +36,7 @@ our @category_column = (
# Titles of tables and the symbols to explain
our %categories = (
'Anchors' => [
'^', '\A', '$', '\Z', '\b', '\B', '\<' , '\>'
'^', '\A', '$', '\Z', '\b', '\B', '\<', '\>'
],
'Character Classes' => [
'\c', '\s', '\S', '\d', '\D', '\w', '\W', '\x', '\O'
@ -71,32 +71,32 @@ our %categories = (
# Symbols and their explanation/description
our %syntax_map = (
'.' => 'Any character except newline (\n)',
'(a|b)' => 'a or b',
'(...)' => 'Group',
'.' => 'Any character except newline (\n)',
'(a|b)' => 'a or b',
'(...)' => 'Group',
'(?:...)' => 'Passive (non-capturing) group',
'[abc]' => 'Single character (a or b or c)',
'[abc]' => 'Single character (a or b or c)',
'[^abc]' => 'Single character (not a or b or c)',
'[a-q]' => 'Single character range (a or b ... or q)',
'[A-Z]' => 'Single character range (A or B ... or Z)',
'[0-9]' => 'Single digit from 0 to 9',
'^' => "Start of string or line",
'\A' => "Start of string",
'$' => "End of string or line",
'\Z' => "End of string",
'\b' => 'Word boundary',
'\B' => 'Not word boundary',
'\<' => 'Start of word',
'\>' => 'End of word',
'\c' => 'Control character',
'\s' => 'Whitespace',
'\S' => 'Not Whitespace',
'\d' => 'Digit',
'\D' => 'Not digit',
'\w' => 'Word',
'\W' => 'Not Word',
'\x' => 'Hexadecimal digit',
'\O' => 'Octal Digit',
'[a-q]' => 'Single character range (a or b ... or q)',
'[A-Z]' => 'Single character range (A or B ... or Z)',
'[0-9]' => 'Single digit from 0 to 9',
'^' => "Start of string or line",
'\A' => "Start of string",
'$' => "End of string or line",
'\Z' => "End of string",
'\b' => 'Word boundary',
'\B' => 'Not word boundary',
'\<' => 'Start of word',
'\>' => 'End of word',
'\c' => 'Control character',
'\s' => 'Whitespace',
'\S' => 'Not Whitespace',
'\d' => 'Digit',
'\D' => 'Not digit',
'\w' => 'Word',
'\W' => 'Not Word',
'\x' => 'Hexadecimal digit',
'\O' => 'Octal Digit',
'[:upper:]' => 'Uppercase letters [A-Z]',
'[:lower:]' => 'Lowercase letters [a-z]',
'[:alpha:]' => 'All letters [A-Za-z]',
@ -111,119 +111,122 @@ our %syntax_map = (
'[:graph:]' => 'Printed characters [\x21-\x7E]',
'[:print:]' => 'Printed characters and spaces [\x20-\x7E]',
'[:word:]' => 'Digits, letters and underscore [A-Za-z0-9_]',
'?=' => 'Lookahead assertion',
'?!' => 'Negative lookahead',
'?<=' => 'Lookbehind assertion',
'?=' => 'Lookahead assertion',
'?!' => 'Negative lookahead',
'?<=' => 'Lookbehind assertion',
'?!= or ?<!' => 'Negative lookbehind',
'?>' => 'Once-only Subexpression',
'?()' => 'Condition [if then]',
'?()|' => 'Condition [if then else]',
'?#' => 'Comment',
'*' => '0 or more',
'+' => '1 or more',
'?' => '0 or 1 (optional)',
'{3}' => 'Exactly 3',
'{3,}' => '3 or more',
'{2,5}' => '2, 3, 4 or 5',
'\\' => 'Escape following character',
'\Q' => 'Begin literal sequence',
'\E' => 'End literal sequence',
'\n' => 'New line',
'\r' => 'Carriage return',
'\t' => 'Tab',
'\v' => 'Vertical tab',
'\f' => 'Form feed',
'\ooo' => 'Octal character ooo',
'\xhh' => 'Hex character hh',
'//g' => 'Global Match (all occurrences)',
'//i' => 'Case-insensitive',
'//m' => 'Multiple line',
'//s' => 'Treat string as single line',
'//x' => 'Allow comments and whitespace',
'//e' => 'Evaluate replacement',
'//U' => 'Ungreedy pattern',
'$n' => 'n-th non-passive group',
'$2' => '"xyz" in /^(abc(xyz))$/',
'$1' => '"xyz" in /^(?:abc)(xyz)$/',
'$`' => 'Before matched string',
q{$'} => 'After matched string',
'$+' => 'Last matched string',
'$&' => 'Entire matched string',
'?>' => 'Once-only Subexpression',
'?()' => 'Condition [if then]',
'?()|' => 'Condition [if then else]',
'?#' => 'Comment',
'*' => '0 or more',
'+' => '1 or more',
'?' => '0 or 1 (optional)',
'{3}' => 'Exactly 3',
'{3,}' => '3 or more',
'{2,5}' => '2, 3, 4 or 5',
'\\' => 'Escape following character',
'\Q' => 'Begin literal sequence',
'\E' => 'End literal sequence',
'\n' => 'New line',
'\r' => 'Carriage return',
'\t' => 'Tab',
'\v' => 'Vertical tab',
'\f' => 'Form feed',
'\ooo' => 'Octal character ooo',
'\xhh' => 'Hex character hh',
'//g' => 'Global Match (all occurrences)',
'//i' => 'Case-insensitive',
'//m' => 'Multiple line',
'//s' => 'Treat string as single line',
'//x' => 'Allow comments and whitespace',
'//e' => 'Evaluate replacement',
'//U' => 'Ungreedy pattern',
'$n' => 'n-th non-passive group',
'$2' => '"xyz" in /^(abc(xyz))$/',
'$1' => '"xyz" in /^(?:abc)(xyz)$/',
'$`' => 'Before matched string',
q{$'} => 'After matched string',
'$+' => 'Last matched string',
'$&' => 'Entire matched string',
);
handle remainder => sub {
#if the user has requested information on a specific thing
if (length $_ > 0)
{
my $syntax_key = $_;
#let the user provide a number for {3}
if ($_ =~ /\{([0-9]+)\}/)
{
return "$_ - Exactly $1 occurrences", html => "<code> " . encode_entities($_) . " </code> - Exactly " . encode_entities($_) . " occurrences";
}
#let the user provide numbers for {3,} and {3,5}
elsif ($_ =~ /\{([0-9]+),([0-9]+)?\}/)
{
if ($2) {
return unless ($1 < $2);
return "$_ - Between $1 and $2 occurrences", html => "<code> " . encode_entities($_) . " </code> - Between $1 and $2 occurrences";
}
return "$_ - $1 or more", html => "<code> " . encode_entities($_) . " </code> - $1 or more occurrences";
}
# If the user has requested information on a specific pattern.
if (length $_ > 0) {
my $syntax_key = $_;
return unless $syntax_map{$syntax_key};
my $text_output = "$_ - $syntax_map{$syntax_key}";
my $html_output = "<code> " . encode_entities($_) . " </code> - " . encode_entities($syntax_map{$syntax_key});
return $text_output, html => $html_output;
# Let the user provide a number for the {n} pattern, e.g., {5} would say "Exactly 5 occurrences".
if ($_ =~ /\{([0-9]+)\}/) {
return answer => "$_ - Exactly $1 occurrences",
html => "<code>" . encode_entities($_) . "</code> - Exactly " . encode_entities($_) . " occurrences";
}
# Let the user provide numbers for {n,} and {n,m}, e.g., {4,} would say "4 or more occurrences".
elsif ($_ =~ /\{([0-9]+),([0-9]+)?\}/) {
if ($2) {
return unless ($1 < $2);
return answer => "$_ - Between $1 and $2 occurrences",
html => "<code>" . encode_entities($_) . "</code> - Between $1 and $2 occurrences";
}
return answer => "$_ - $1 or more",
html => "<code> " . encode_entities($_) . " </code> - $1 or more occurrences";
}
# Check our map if it's in our list of regex patterns.
return unless $syntax_map{$syntax_key};
#otherwise display the complete tabular output, into n columns in the order specified
my $text_output = "$_ - $syntax_map{$syntax_key}";
my $html_output = "<code> " . encode_entities($_) . " </code> - " . encode_entities($syntax_map{$syntax_key});
return answer => $text_output, html => $html_output;
}
my $text_output = '';
# Otherwise display the complete tabular output, into n columns in the order specified.
#style assigned to the outside wrapper div (around all content)
my $div_wrapper_style = 'max-height: 45ex; overflow-y: scroll; overflow-x: hidden';
my $text_output = '';
#style assigned to the wrapper column divs
my $div_column_style = 'width: 48%; display: inline-block; vertical-align: top;';
# Style assigned to the outside wrapper div (around all content).
my $div_wrapper_style = 'max-height: 45ex; overflow-y: scroll; overflow-x: hidden';
#style assigned to each table of results (Anchors, Quantifiers etc)
my $table_style = 'width: 100%; margin-bottom: 1ex;';
# Style assigned to the wrapper column divs
my $div_column_style = 'width: 48%; display: inline-block; vertical-align: top;';
# Style assigned to each table of results (Anchors, Quantifiers etc)
my $table_style = 'width: 100%; margin-bottom: 1ex;';
#content of the div column wrapper
my @html_columns = ();
# Content of the div column wrapper.
my @html_columns = ();
for(my $column = 0; $column < scalar(@category_column); ++$column)
{
for my $category ( @{$category_column[$column]} )
{
my $new_table = "<table style='$table_style'>
<caption><b> $category </b></caption>";
$text_output .= "$category\n";
for my $syntax_object ( @{$categories{$category}} )
{
$new_table .= " <tr>
<td><code> " . encode_entities($syntax_object) . " </code></td>
<td> " . encode_entities($syntax_map{$syntax_object}) . " </td>
</tr>" . "\n";
$text_output .= "\t$syntax_object - $syntax_map{$syntax_object} \n";
}
$text_output .= "\n";
$new_table .= "</table>" . "\n";
$html_columns[$column] .= "\n" . $new_table;
}
# Add a helper function for adding the <td> tag.
sub add_table_data {
my ($text, $is_code) = @_;
if($is_code) {
return "<td><code>" . encode_entities($text) . "</code></td>";
}
return "<td>" . encode_entities($text) . "</tb>";
}
for(my $column = 0; $column < scalar(@category_column); ++$column) {
for my $category (@{$category_column[$column]}) {
my $new_table = "<table style='$table_style'><b>$category</b>";
$text_output .= "$category\n";
for my $syntax_object (@{$categories{$category}}) {
$new_table .= "<tr>" . add_table_data($syntax_object, 1) . add_table_data($syntax_map{$syntax_object}, 0) . "</tr>\n";
$text_output .= "\t$syntax_object - $syntax_map{$syntax_object}\n";
}
$text_output .= "\n";
$new_table .= "</table>\n";
$html_columns[$column] .= $new_table;
}
}
my $html_output = "<div style='$div_wrapper_style'><div style='$div_column_style'>";
$html_output .= join ("</div><div style='$div_column_style'>", @html_columns);
$html_output .= "</div></div>";
return $text_output, html => $html_output;
my $html_output = "<div style='$div_wrapper_style'><div style='$div_column_style'>";
$html_output .= join ("</div><div style='$div_column_style'>", @html_columns);
$html_output .= "</div></div>";
return answer => $text_output, html => $html_output;
};
1;
1;

View File

@ -1,44 +0,0 @@
package DDG::Goodie::SharkWeek;
use DDG::Goodie;
use JSON;
use DateTime;
zci answer_type => 'schedule';
primary_example_queries 'shark week schedule';
secondary_example_queries 'shark week';
description 'see the schedule for shark week';
name 'Calculator';
code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Calculator.pm';
category 'entertainment';
topics 'entertainment';
attribution web => [ 'https://www.duckduckgo.com', 'DuckDuckGo' ],
github => [ 'https://github.com/duckduckgo', 'duckduckgo' ],
twitter => ['http://twitter.com/duckduckgo', 'duckduckgo' ];
triggers start => 'shark';
my $schedule = decode_json(scalar share('shark.json')->slurp);
handle query_lc => sub {
return unless $_ =~ /^shark week(?: schedule|)$/;
my $dt = DateTime->today();
my $key = $dt->day_name.' '.$dt->month_name . ' '.$dt->day;
my @episodes = @{$schedule->{$key}};
# return scalar(@episodes);
my $html = "<ul>";
my $txt = "$key Schedule\n";
foreach my $e (@episodes) {
my $time = $e->{'time'};
my $title = $e->{'title'};
my $description = $e->{'description'};
$html .= "<li>$time - $title</li>";
$txt .= "$time | $title\n";
}
$html .= "</ul>";
return $txt, html => $html, heading => "$key Schedule";
};
1;

View File

@ -0,0 +1,64 @@
package DDG::Goodie::Shortcut;
# ABSTRACT: Display keyboard shortcut for an action.
use DDG::Goodie;
triggers any => 'shortcut','keyboard shortcut', 'key combination';
zci answer_type => 'shortcut';
primary_example_queries 'windows show desktop shortcut';
secondary_example_queries 'ubuntu shortcut new folder';
description 'Keyboard shortcuts';
name 'Shortcut';
topics 'computing';
category 'computing_info';
attribution github => ['https://github.com/dariog88a','dariog88a'],
email => [ 'mailto:dariog88@gmail.com', 'dariog88' ],
twitter => ['http://twitter.com/dariog88','dariog88'];
my @shortcuts = share('shortcuts.csv')->slurp(iomode => '<:encoding(UTF-8)');
handle remainder_lc => sub {
#keep only letters and spaces (remove versioning)
s/[^a-z ]//gi;
#replace all OS words with starting char
s/windows|win|xp|vista|seven|eight/W/gi;
s/mac|os[ ]*x/M/gi;
s/linux|ubuntu|debian|fedora|kde|gnome/L/gi;
#get OS char (if any)
my $search = $_;
$search =~ /(W|M|L)/;
my $os = $1; #save OS char
$search =~ tr/[WML]//d; #remove all OS chars from search
$search =~ tr/ / /s; #leave just one blank between words
$search =~ s/^\s+|\s+$//g; #trim
if(!$os) {$os='';} #line added to avoid error, remove when UA detection added.
my $line;
foreach (@shortcuts) {
if($_ =~ /^$search/i) { #matches only the start
$line = $_;
$line =~ s/\R//g; #remove carriage return
last;
}
}
return if !$line;
my @columns = split('\|',$line);
my $answer = 'The shortcut for ' . $columns[0];
my %systems = (W=>'Windows',M=>'Mac OS',L=>'KDE/GNOME');
my %keys = (W => $columns[1], M => $columns[2], L => $columns[3]);
return if !$keys{$os};
if ($os) { $answer .= ' in ' . $systems{$os} . ' is ' . $keys{$os}; }
my $source = '<br/><a href="https://en.wikipedia.org/wiki/Table_of_keyboard_shortcuts">More at Wikipedia</a>';
return $answer, html => "$answer $source";
};
1;

View File

@ -7,7 +7,7 @@ use warnings;
use DDG::Goodie;
# TODO: This (sh|c)ould be re-written to be more precise
triggers query => qr`^([0-9]{1,3}\.){3}([0-9]{1,3})[\s/](([1-3]?[0-9])|(([0-9]{1,3}\.){3}([0-9]{1,3})))$`;
triggers query => qr#^([0-9]{1,3}\.){3}([0-9]{1,3})[\s/](([1-3]?[0-9])|(([0-9]{1,3}\.){3}([0-9]{1,3})))$#;
zci answer_type => "subnet_info";
zci is_cached => 1;
@ -20,78 +20,110 @@ category 'computing_tools';
topics 'sysadmin';
handle query => sub {
sub int_to_str($) {
my ($ip) = @_;
return sprintf "%u.%u.%u.%u", ($ip>>24&0xff),($ip>>16&0xff),($ip>>8&0xff),($ip&0xff);
}
sub ip_to_int(@) {
return (int($_[0])<<24) + (int($_[1])<<16) + (int($_[2])<<8) + (int($_[3]));
}
# Convert an integer into an IP address.
sub int_to_str {
my ($ip) = @_;
sprintf "%u.%u.%u.%u", $ip >> 24 & 0xff, $ip >> 16 & 0xff, $ip >> 8 & 0xff, $ip & 0xff;
}
my ($input) = @_;
my ($address,$cidr) = split qr`[\s/]`, $input;
my @octlets = split /\./,$address;
for (@octlets) {
return if int($_)>255;
}
# Convert an IP address into an integer.
sub ip_to_int {
(int($_[0]) << 24) + (int($_[1]) << 16) + (int($_[2]) << 8) + int($_[3]);
}
my $address_raw = ip_to_int(@octlets);
my $wildcard_mask = 0;
my $mask = 0;
my ($input) = @_;
my ($address, $cidr) = split qr`[\s/]`, $input;
my @octlets = split /\./, $address;
for (@octlets) {
return if int($_) > 255;
}
# Convert CIDR & Subnets
if ($cidr =~ /^[0-9]+$/) {
return if ($cidr>32 || $cidr<1);
$wildcard_mask = 2**(32-$cidr)-1;
$mask = 0xffffffff ^ $wildcard_mask;
}
elsif ($cidr =~ /([0-9]{1,3}\.){3}([0-9]{1,3})/) {
my @cidr_octlets = split /\./,$cidr;
for(@cidr_octlets) {
return if int($_)>255;
}
$mask = ip_to_int(@cidr_octlets);
my $mask_binary = sprintf("%b",$mask);
return unless ($mask_binary =~ /^1+0*$/);
$wildcard_mask = 0xffffffff ^ $mask;
$cidr = ($mask_binary =~ tr/1//); #count number of 1's
}
else {
return;
}
my $host = $address_raw & $wildcard_mask;
my $network = $address_raw & $mask;
my $start = $network+1;
my $end = $network+($wildcard_mask-1);
my $broadcast = $network+$wildcard_mask;
my $host_count = 1+$end-$start;
my $class = "A";
$class = "E (reserved)" if (($network>>28 & 0x0F) == 0x0F);
$class = "D (multicast)" if (($network>>28 & 0x0F) == 0x0E);
$class = "C" if (($network>>29 & 0x07) == 0x06);
$class = "B" if (($network>>30 & 0x03) == 0x02);
my $which_specified = "Host #".($host);
$which_specified = "Network" if ($host==0);
$which_specified = "Broadcast" if ($host==$host_count+1);
$which_specified = "Point-To-Point (".int_to_str($end).", ".int_to_str($start).")" if ($cidr==31);
$which_specified = "Host Only" if ($cidr==32);
my $output_str = "Network: ".int_to_str($network)."/$cidr,".
" Netmask: ".int_to_str($mask).",".
" $which_specified specified,".
" Class: $class";
$output_str .= ", Host Address Range: ".int_to_str($start)."-".int_to_str($end).",".
" $host_count Usable Addresses,".
" Broadcast: ".int_to_str($broadcast)
unless($cidr > 30);
return $output_str;
my $address_raw = ip_to_int(@octlets);
my $wildcard_mask = 0;
my $mask = 0;
# Convert CIDR & Subnets
if ($cidr =~ /^[0-9]+$/) {
return if ($cidr > 32 || $cidr < 1);
$wildcard_mask = 2**(32-$cidr) - 1;
# Flip the bits.
$mask = 0xffffffff ^ $wildcard_mask;
} elsif ($cidr =~ /([0-9]{1,3}\.){3}([0-9]{1,3})/) {
my @cidr_octlets = split /\./, $cidr;
# An octlet cannot be over 255.
for(@cidr_octlets) {
return if int($_) > 255;
}
$mask = ip_to_int(@cidr_octlets);
# Convert the integer into its binary representation.
my $mask_binary = sprintf("%b", $mask);
# The mask cannot have alternating 1s and 0s.
return unless ($mask_binary =~ /^1+0*$/);
# Flip the bits.
$wildcard_mask = 0xffffffff ^ $mask;
# Count the number of 1s.
$cidr = ($mask_binary =~ tr/1//);
} else {
return;
}
my $host = $address_raw & $wildcard_mask;
my $network = $address_raw & $mask;
my $start = $network + 1;
my $end = $network + ($wildcard_mask - 1);
my $broadcast = $network + $wildcard_mask;
my $host_count = 1 + $end - $start;
# Check the class type of the IP address.
my $class = "A";
$class = "E (reserved)" if (($network >> 28 & 0x0F) == 0x0F);
$class = "D (multicast)" if (($network >> 28 & 0x0F) == 0x0E);
$class = "C" if (($network >> 29 & 0x07) == 0x06);
$class = "B" if (($network >> 30 & 0x03) == 0x02);
my $which_specified = "Host #".($host);
$which_specified = "Network" if ($host == 0);
$which_specified = "Broadcast" if ($host == $host_count+1);
$which_specified = "Point-To-Point (".int_to_str($end).", ".int_to_str($start).")" if ($cidr == 31);
$which_specified = "Host Only" if ($cidr == 32);
sub to_html {
my $results = "";
foreach my $result (@_) {
$results .= "<div><i>$result->[0]: </i>$result->[1]</div>";
}
return $results;
}
sub to_text {
my $results = "";
foreach my $result (@_) {
$results .= "$result->[0]: $result->[1]\n";
}
return $results;
}
# We're putting them into an array because we want the output to be sorted.
my @output = (
["Network", int_to_str($network) . "/$cidr (Class $class)"],
["Netmask", int_to_str($mask)],
["Specified", "$which_specified"],
);
unless($cidr > 30) {
push @output, (["Host Address Range", int_to_str($start) . "-" . int_to_str($end) . " ($host_count hosts)"],
["Broadcast", int_to_str($broadcast)]);
}
return answer => to_text(@output), html => to_html(@output);
};
1;
1;

View File

@ -5,8 +5,8 @@ use DDG::Goodie;
zci is_cached => 1;
zci answer_type => "ups";
primary_example_queries '1Z0884XV0399906189';
secondary_example_queries 'ups 1Z0884XV0399906189';
primary_example_queries '1Z2807700371226497';
secondary_example_queries 'ups 1Z2807700371226497';
description 'Track a UPS package';
icon_url "/i/www.ups.com.ico";
name 'UPS';
@ -110,4 +110,4 @@ handle query_nowhitespace_nodash => sub {
return;
};
1;
1;

View File

@ -1,326 +0,0 @@
862=>NJ, US
863=>FL, US
864=>SC, US
865=>TN, US
867=>Yukon, NW Terr., Nunavut, CANADA
868=>Trinidad and Tobago, TRINIDAD AND TOBAGO
869=>St. Kitts and Nevis, ST. KITTS AND NEVIS
870=>AR, US
876=>Jamaica, JAMAICA
878=>PA, US
901=>TN, US
902=>Nova Scotia, Prince Edward Island, CANADA
903=>TX, US
904=>FL, US
905=>Ontario, CANADA
906=>MI, US
907=>AK, US
908=>NJ, US
909=>CA, US
910=>NC, US
912=>GA, US
913=>KS, US
914=>NY, US
915=>TX, US
916=>CA, US
917=>NY, US
918=>OK, US
919=>NC, US
920=>WI, US
925=>CA, US
928=>AZ, US
931=>TN, US
936=>TX, US
937=>OH, US
939=>Puerto Rico, US
940=>TX, US
941=>FL, US
947=>MI, US
949=>CA, US
951=>CA, US
952=>MN, US
954=>FL, US
956=>TX, US
970=>CO, US
971=>OR, US
972=>TX, US
973=>NJ, US
978=>MA, US
979=>TX, US
980=>NC, US
985=>LA, US
989=>MI, US
682=>TX, US
684=>AS, US
701=>ND, US
702=>NV, US
703=>VA, US
704=>NC, US
705=>Ontario, CANADA
706=>GA, US
707=>CA, US
708=>IL, US
709=>Newfoundland, CANADA
710=>US, US
712=>IA, US
713=>TX, US
714=>CA, US
715=>WI, US
716=>NY, US
717=>PA, US
718=>NY, US
719=>CO, US
720=>CO, US
724=>PA, US
727=>FL, US
731=>TN, US
732=>NJ, US
734=>MI, US
740=>OH, US
754=>FL, US
757=>VA, US
758=>St. Lucia, ST. LUCIA
760=>CA, US
762=>GA, US
763=>MN, US
765=>IN, US
767=>Dominica, DOMINICA
769=>MS, US
770=>GA, US
772=>FL, US
773=>IL, US
774=>MA, US
775=>NV, US
778=>British Columbia, CANADA
779=>IL, US
780=>Alberta, CANADA
781=>MA, US
784=>St. Vincent and the Grenadines, ST. VINCENT & GRENADINES
785=>KS, US
786=>FL, US
787=>Puerto Rico, US
801=>UT, US
802=>VT, US
803=>SC, US
804=>VA, US
805=>CA, US
806=>TX, US
807=>Ontario, CANADA
808=>HI, US
809=>the Dominican Republic, DOMINICAN REPUBLIC
810=>MI, US
812=>IN, US
813=>FL, US
814=>PA, US
815=>IL, US
816=>MO, US
817=>TX, US
818=>CA, US
819=>Quebec, CANADA
828=>NC, US
829=>the Dominican Republic, DOMINICAN REPUBLIC
830=>TX, US
831=>CA, US
832=>TX, US
843=>SC, US
845=>NY, US
847=>IL, US
848=>NJ, US
850=>FL, US
856=>NJ, US
857=>MA, US
858=>CA, US
859=>KY, US
860=>CT, US
574=>IN, US
575=>NM, US
580=>OK, US
585=>NY, US
586=>MI, US
601=>MS, US
602=>AZ, US
603=>NH, US
604=>British Columbia, CANADA
605=>SD, US
606=>KY, US
607=>NY, US
608=>WI, US
609=>NJ, US
610=>PA, US
201=>NJ, US
202=>DC, US
203=>CT, US
204=>Manitoba, CANADA
205=>AL, US
206=>WA, US
207=>ME, US
208=>ID, US
209=>CA, US
210=>TX, US
212=>NY, US
213=>CA, US
214=>TX, US
215=>PA, US
216=>OH, US
217=>IL, US
218=>MN, US
219=>IN, US
224=>IL, US
225=>LA, US
226=>Ontario, CANADA
228=>MS, US
229=>GA, US
231=>MI, US
234=>OH, US
239=>FL, US
240=>MD, US
242=>the Bahamas, BAHAMAS
246=>Barbados, BARBADOS
248=>MI, US
250=>British Columbia, CANADA
251=>AL, US
252=>NC, US
253=>WA, US
254=>TX, US
256=>AL, US
260=>IN, US
262=>WI, US
264=>Anguilla, ANGUILLA
267=>PA, US
268=>Antigua and Barbuda, ANTIGUA/BARBUDA
269=>MI, US
270=>KY, US
276=>VA, US
281=>TX, US
284=>the British Virgin Islands, BRITISH VIRGIN ISLANDS
289=>Ontario, CANADA
301=>MD, US
302=>DE, US
303=>CO, US
304=>WV, US
305=>FL, US
306=>Saskatchewan, CANADA
307=>WY, US
308=>NE, US
309=>IL, US
310=>CA, US
312=>IL, US
313=>MI, US
314=>MO, US
315=>NY, US
316=>KS, US
317=>IN, US
318=>LA, US
319=>IA, US
320=>MN, US
321=>FL, US
323=>CA, US
325=>TX, US
330=>OH, US
331=>IL, US
334=>AL, US
336=>NC, US
337=>LA, US
339=>MA, US
340=>the US Virgin Islands, US
345=>the Cayman Islands, CAYMAN ISLANDS
347=>NY, US
351=>MA, US
352=>FL, US
360=>WA, US
361=>TX, US
386=>FL, US
401=>RI, US
402=>NE, US
403=>Alberta, CANADA
404=>GA, US
405=>OK, US
406=>MT, US
407=>FL, US
408=>CA, US
409=>TX, US
410=>MD, US
412=>PA, US
413=>MA, US
414=>WI, US
415=>CA, US
416=>Ontario, CANADA
417=>MO, US
418=>Quebec, CANADA
419=>OH, US
423=>TN, US
424=>CA, US
425=>WA, US
430=>TX, US
432=>TX, US
434=>VA, US
435=>UT, US
438=>Quebec, CANADA
440=>OH, US
441=>Bermuda, BERMUDA
443=>MD, US
450=>Quebec, CANADA
469=>TX, US
473=>Grenada, GRENADA
478=>GA, US
479=>AR, US
480=>AZ, US
484=>PA, US
501=>AR, US
502=>KY, US
503=>OR, US
504=>LA, US
505=>NM, US
506=>New Brunswick, CANADA
507=>MN, US
508=>MA, US
509=>WA, US
510=>CA, US
512=>TX, US
513=>OH, US
514=>Quebec, CANADA
515=>IA, US
516=>NY, US
517=>MI, US
518=>NY, US
519=>Ontario, CANADA
520=>AZ, US
530=>CA, US
540=>VA, US
541=>OR, US
551=>NJ, US
559=>CA, US
561=>FL, US
562=>CA, US
563=>IA, US
567=>OH, US
570=>PA, US
571=>VA, US
573=>MO, US
612=>MN, US
613=>Ontario, CANADA
614=>OH, US
615=>TN, US
616=>MI, US
617=>MA, US
618=>IL, US
619=>CA, US
620=>KS, US
623=>AZ, US
626=>CA, US
630=>IL, US
631=>NY, US
636=>MO, US
641=>IA, US
646=>NY, US
647=>Ontario, CANADA
649=>the Turks and Caicos Islands, TURKS & CAICOS ISLANDS
650=>CA, US
651=>MN, US
660=>MO, US
661=>CA, US
662=>MS, US
664=>Montserrat, MONTSERRAT
671=>GU, US
678=>GA, US
959=>CT, US

View File

@ -1,51 +0,0 @@
AL=>Alabama
AK=>Alaska
AZ=>Arizona
AR=>Arkansas
CA=>California
CO=>Colorado
CT=>Connecticut
DE=>Delaware
DC=>District of Columbia
FL=>Florida
GA=>Georgia
HI=>Hawaii
ID=>Idaho
IL=>Illinois
IN=>Indiana
IA=>Iowa
KS=>Kansas
KY=>Kentucky
LA=>Louisiana
ME=>Maine
MD=>Maryland
MA=>Massachusetts
MI=>Michigan
MN=>Minnesota
MS=>Mississippi
MO=>Missouri
MT=>Montana
NE=>Nebraska
NV=>Nevada
NH=>New Hampshire
NJ=>New Jersey
NM=>New Mexico
NY=>New York
NC=>North Carolina
ND=>North Dakota
OH=>Ohio
OK=>Oklahoma
OR=>Oregon
PA=>Pennsylvania
RI=>Rhode Island
SC=>South Carolina
SD=>South Dakota
TN=>Tennessee
TX=>Texas
UT=>Utah
VT=>Vermont
VA=>Virginia
WA=>Washington
WV=>West Virginia
WI=>Wisconsin
WY=>Wyoming

File diff suppressed because one or more lines are too long

View File

@ -1,4 +0,0 @@
Monday August 5
Sharkbite Summer 3:00 PM The bite-by-bite account of America's notorious "Summer of the Shark" in 2001. Were the Ocean's apex predators really taking back America's shores?
Sharkbite Beach 4:00 PM In the summer of 2008, panic gripped the Pacific coast in the wake of 4 horrific shark attacks. Sharkbite Beach reveals the dramatic stories of survival and searches for clues that might explain why sharks turned on humans with such fury.
Rogue Sharks 5:00 PM The existence of man eating 'rogue' sharks has been hotly debated since the 1950s. This film unravels the truth behind the theory by analyzing some of the most notorious attacks from the last century and consulting the leading experts on shark biology.

View File

@ -0,0 +1,78 @@
File menu|Alt+F, or F10 then F|Ctrl+F2, then F (requires full keyboard access active, using System Preferences > Keyboard > Keyboard Shortcuts > Full Keyboard Access > All Controls. Alternatively use Ctrl+F1 to toggle this setting.)|Alt+F
Edit menu|Alt+E|Ctrl+F2, then E|Alt+E
View menu|Alt+V|Ctrl+F2, then V|Alt+V
Undo|Ctrl+Z, or Alt+←Backspace|⌘Cmd+Z|Ctrl+Z
Redo|Ctrl+Y|⇧Shift+⌘Cmd+Z|⇧Shift+Ctrl+Z, or Ctrl+Y
Cut|Ctrl+X, or ⇧Shift+Del|⌘Cmd+X|Ctrl+X
Copy|Ctrl+C, or Ctrl+Ins|⌘Cmd+C|Ctrl+C
Paste|Ctrl+V, or ⇧Shift+Ins|⌘Cmd+V|Ctrl+V
Paste special|Ctrl+Alt+V||Ctrl+⇧Shift+V
Select all|Ctrl+A|⌘Cmd+A|Ctrl+A
New folder|Ctrl+⇧Shift+N|⇧Shift+⌘Cmd+N|Ctrl+⇧Shift+N
Applications menu|⊞Win or Ctrl+Esc||Alt + "n" e.g. for _File_ Alt + F
Lock desktop|⊞Win+L|Ctrl+⇧Shift+Eject or MBR Ctrl+⇧Shift+Pwr (If "Require password after sleep or screen saver" is enabled in "System Preferences — Security & Privacy")|Ctrl+Alt+L
Show desktop|⊞Win+D or ⊞Win+M (then use ⊞Win+⇧Shift+M to bring back all windows)|F11|Ctrl+Alt+D
Log out user||⇧Shift+⌘Cmd+Q|Ctrl+Alt+Delete
Switch user|⊞Win+L||
Task manager|Ctrl+⇧Shift+Esc or Ctrl+Alt+Delete|Alt+⌘Cmd+Esc|Ctrl+Esc
Rename object|F2|↵Enter|F2
Open file or program|↵Enter|⌘Cmd+O|↵Enter
Switch window (next/previous)|Alt+Tab↹ / ⇧Shift+Alt+Tab↹|⌘Cmd+Tab↹ / ⇧Shift+⌘Cmd+Tab↹|Alt+Tab↹ / Alt+⇧Shift+Tab↹
Switch window without dialog (next/previous)|Alt+Esc / ⇧Shift+Alt+Esc|⌘Cmd+` / ⌘Cmd+~ Only works within single Applications|
Run application|⊞Win, enter executable name or ⊞Win+R, enter executable name|⌘Cmd+Space, enter executable name|Alt+F2, enter executable name
Search|⊞Win, enter search or ⊞Win+F|⌘Cmd+Space / Alt+F |
Save screenshot of entire screen as file|Windows+Print Screen|⇧Shift+⌘Cmd+3|Print Screen set the name and click "Save".
Copy screenshot of entire screen to clipboard|Print Screen or Ctrl+Print Screen|Ctrl+⇧Shift+⌘Cmd+3|Print Screen click "Copy to Clipboard".
Save screenshot of window as file||⇧Shift+⌘Cmd+4 then Space|Alt+Print Screen set the name and click "Save". GNOME
Copy screenshot of window to clipboard|Alt+Print Screen|Ctrl+⇧Shift+⌘Cmd+4 then Space|Alt+Print Screen click "Copy to Clipboard". GNOME
Delete char to the right of cursor|Del or Fn+←Backspace|Del, or Ctrl+d, or Fn+←Backspace |
Delete word to the right of cursor|Ctrl+Del|⌥Opt+Del or ⌥Opt+Fn+←Backspace|Ctrl+Del
Delete word to the left of cursor|Ctrl+←Backspace|⌥Opt+←Backspace|Ctrl+←Backspace
Start of line|Home, or Fn+←|⌘Cmd+← or Ctrl+A|Home
End of line|End, or Fn+→|⌘Cmd+→ or Ctrl+E|End
Start of document|Ctrl + Home|⌘Cmd+↑|Ctrl + Home
End of document|Ctrl + End|⌘Cmd+↓|Ctrl + End
Previous word|Ctrl+←|⌥Opt+←|Ctrl+←
Next word|Ctrl+→|⌥Opt+→|Ctrl+→
Previous line|↑|↑, or Ctrl+p|↑
Next line|↓|↓, or Ctrl+n|↓
Previous line break (paragraph)|Ctrl+↑|⌥Opt+↑|Ctrl+↑ (kword or GNOME)
Next line break|Ctrl+↓|⌥Opt+↓|Ctrl+↓ (kword or GNOME)
Move the cursor down the length of the viewport|Page Down|Fn+↓|Page Down
Move the cursor up the length of the viewport|Page Up|Fn+↑|Page Up
Find|Ctrl+F|⌘Cmd+F, ⌘Cmd+E (Search with current selection)|Ctrl+F, Ctrl+K (GNOME; interactive search)
Next search result|F3|⌘Cmd+G|Ctrl+G (GNOME) or F3 (KDE)
Previous search result|⇧Shift+F3|⇧Shift+⌘Cmd+G|⇧Shift+Ctrl+G (GNOME) or ⇧Shift+F3 (KDE)
Search and replace|Ctrl+H|⌘Cmd+F|Ctrl+H (GNOME) or Ctrl+R (KDE)
Bold|Ctrl+B|⌘Cmd+B|Ctrl+B
Underline|Ctrl+U|⌘Cmd+U|Ctrl+U
Italic|Ctrl+I|⌘Cmd+I|Ctrl+I
Uppercase|⇧Shift+F3|⌥Opt+⌘Cmd+C|⇧Shift+F3
Lowercase|⇧Shift+F3|⌥Opt+⌘Cmd+C|⇧Shift+F3
Superscript|Ctrl+⇧Shift++|Ctrl+⌘Cmd++ (Pages and Adobe Applications only?)|Ctrl+⇧Shift+P
Subscript|Ctrl+=|Ctrl+⌘Cmd+- (Pages and Adobe Applications only?)|Ctrl+⇧Shift+B
Previous location in history|Alt+← or ←Backspace|⌘Cmd+ ⌘Cmd+←|Alt+←
Next location in history|Alt+→ or ⇧Shift+←Backspace (web browser only)|⌘Cmd+] or ⌘Cmd+→|Alt+→
Go up one level in the navigation hierarchy|Alt+↑(Vista, 7 or 8 only) or ←Backspace(Windows Explorer)|⌘Cmd+↑|Alt+↑
Startup page|Alt+Home|⌘Cmd+Home|Ctrl+Home (KDE) / Alt+Home (GNOME)
Bookmarks menu|Ctrl+B|⌘Cmd+B (Firefox)|Alt+B
URL Shortcuts (Adds www. + .com)|Ctrl+↵Enter|⌘Cmd+↵Enter (Firefox) or Ctrl+↵Enter (Chrome)|Ctrl+↵Enter
URL Shortcuts (Adds www. + .org)|Ctrl+⇧Shift+↵Enter|⇧Shift+⌘Cmd+↵Enter (Firefox)|Ctrl+⇧Shift+↵Enter
URL Shortcuts (Adds www. + .net)|⇧Shift +↵Enter|⇧Shift +↵Enter (Firefox)|⇧Shift +↵Enter
Bookmark page|Ctrl+D|⌘Cmd+D|Ctrl+B / Ctrl+D
Manage bookmarks|Ctrl+B|⌘Cmd+⌥Opt+B (Chrome/Safari) or ⌘Cmd+⇧Shift+B (Firefox)|Ctrl+⇧Shift+R / Ctrl+B
Address bar|Ctrl+L or F6 or Alt+D|⌘Cmd+L|Ctrl+L or Alt+D or F6
Search bar|Ctrl+E|⌘Cmd+E (Opera) or ⌘Cmd+K (Firefox) or ⌥Opt+⌘Cmd+F (Safari)|Ctrl+K
Refresh a webpage|F5 or Ctrl+R|⌘Cmd+R|F5 or Ctrl+R
New window|Ctrl+N|⌘Cmd+N (Chrome)|Ctrl+N
Zoom in|Ctrl++|⌘Cmd++|Ctrl++
Zoom out|Ctrl+-|⌘Cmd+-|Ctrl+-
Zoom 100%|Ctrl+0|⌘Cmd+0|Ctrl+0
New tab|Ctrl+T|⌘Cmd+T|Ctrl+⇧Shift+N or Ctrl+⇧Shift+T or Ctrl+T
Close tab|Ctrl+W|⌘Cmd+W|Ctrl+W or Ctrl+F4
Close other tabs||⌘Cmd+⌥Opt+W (Safari)|
Next tab|Ctrl+Tab↹|Control+Tab↹ or ⌘Cmd+⇧Shift+→ (Safari)|Ctrl+PageDown or Ctrl+Tab↹ or Ctrl+.
Previous tab|Ctrl+⇧Shift+Tab↹|⇧Shift+Control+Tab↹ or ⌘Cmd+⇧Shift+← (Safari)|Ctrl+PageUp or Ctrl+⇧Shift+Tab↹ or Ctrl+,
Go to tab-n|Ctrl+n (Chrome/Firefox)|⌘Cmd+n (Chrome)|Alt+n (Chrome/Firefox) or Ctrl+n (Chrome)
Reopen closed tab|Ctrl+⇧Shift+T|⌘Cmd+⇧Shift+T (Firefox/Opera/Chrome)|Ctrl+⇧Shift+T (Firefox/Opera/Chrome)
Reopen closed window|Ctrl+⇧Shift+N (Firefox)| |
Can't render this file because it contains an unexpected character in line 12 and column 45.

View File

@ -18,6 +18,8 @@ ddg_goodie_test(
'toss a coin' => test_zci(qr/(heads|tails) \(random\)/),
'toss 1 coin' => test_zci(qr/(heads|tails) \(random\)/),
'toss 2 coins' => test_zci(qr/(heads|tails), (heads|tails) \(random\)/),
'heads or tails' => test_zci(qr/(heads|tails) \(random\)/),
'heads or tails?' => test_zci(qr/(heads|tails) \(random\)/),
);
done_testing;

25
t/Dessert.t Normal file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use DDG::Test::Goodie;
zci answer_type => 'dessert';
zci is_cached => 0;
ddg_goodie_test(
[qw(
DDG::Goodie::Dessert
)],
'desserts beginning with a' => test_zci( qr/(.*?) is a dessert that begins with the letter A.$/ ),
'dessert start with a' => test_zci( qr/(.*?) is a dessert that begins with the letter A.$/ ),
'desserts starting with a' => test_zci( qr/(.*?) is a dessert that begins with the letter A$./ ),
'dessert starts with a' => test_zci( qr/(.*?) is a dessert that begins with the letter A.$/ ),
'desserts beginning with A' => test_zci( qr/(.*?) is a dessert that begins with the letter A.$/ ),
'desserts beginning with z' => test_zci( qr/(.*?) is a dessert that begins with the letter Z.$/ ),
'a dessert that begins with the letter a' => test_zci( qr/(.*?) is a dessert that begins with the letter A.$/ ),
);
done_testing;

View File

@ -14,10 +14,10 @@ ddg_goodie_test(
)],
'dewey 123' => test_zci("123 is determinism and indeterminism in the Dewey Decimal System.", html => "123 is <a href=\"/?q=determinism\">determinism</a> and <a href=\"/?q=indeterminism\">indeterminism</a> in the Dewey Decimal System."),
'646 dewey decimal system' => test_zci("646 is sewing, clothing, personal living in the Dewey Decimal System.", html => "646 is <a href=\"/?q=sewing\">sewing</a>, <a href=\"/?q=clothing\">clothing</a>, personal living in the Dewey Decimal System."),
'dewey decimal system 640s' => test_zci("", html => '<table><tr><td>641</td><td><a href="/?q=Food">Food</a> & <a href="/?q=drink">drink</a></td></tr><tr><td>642</td><td><a href="/?q=Meal">Meal</a>s & table service</td></tr><tr><td>643</td><td><a href="/?q=House">Housing</a> & household equipment</td></tr><tr><td>644</td><td><a href="/?q=Household">Household</a> utilities</td></tr><tr><td>645</td><td><a href="/?q=Furniture">Household furnishings</a></td></tr><tr><td>646</td><td><a href="/?q=Sewing">Sewing</a>, <a href="/?q=clothing">clothing</a>, personal living</td></tr><tr><td>647</td><td><a href="/?q=Household management">Management of public household</a>s</td></tr><tr><td>648</td><td><a href="/?q=Household chore">Housekeeping</a></td></tr><tr><td>649</td><td><a href="/?q=Child rearing">Child rearing</a> & <a href="/?q=home care">home care</a> of sick</td></tr></table>'),
'dewey decimal system 640s' => test_zci("", html => '<table cellpadding=1><tr><td>641</td><td>&nbsp;<a href="/?q=Food">Food</a> & <a href="/?q=drink">drink</a></td></tr><tr><td>642</td><td>&nbsp;<a href="/?q=Meal">Meal</a>s & table service</td></tr><tr><td>643</td><td>&nbsp;<a href="/?q=House">Housing</a> & household equipment</td></tr><tr><td>644</td><td>&nbsp;<a href="/?q=Household">Household</a> utilities</td></tr><tr><td>645</td><td>&nbsp;<a href="/?q=Furniture">Household furnishings</a></td></tr><tr><td>646</td><td>&nbsp;<a href="/?q=Sewing">Sewing</a>, <a href="/?q=clothing">clothing</a>, personal living</td></tr><tr><td>647</td><td>&nbsp;<a href="/?q=Household management">Management of public household</a>s</td></tr><tr><td>648</td><td>&nbsp;<a href="/?q=Household chore">Housekeeping</a></td></tr><tr><td>649</td><td>&nbsp;<a href="/?q=Child rearing">Child rearing</a> & <a href="/?q=home care">home care</a> of sick</td></tr></table>'),
'#1 in the dewey decimal system' => test_zci("001 is knowledge in the Dewey Decimal System.", html => '001 is <a href="/?q=outline of knowledge">knowledge</a> in the Dewey Decimal System.'),
'dewey decimal system naturalism' => test_zci("146 is naturalism and related systems in the Dewey Decimal System.", html => '146 is <a href="/?q=naturalism (philosophy)">naturalism</a> and related systems in the Dewey Decimal System.'),
'etymology in the dewey decimal system' => test_zci("", html => qr{^<table>.*</table>$}),
'etymology in the dewey decimal system' => test_zci("", html => qr{^<table cellpadding=1>.*</table>$}),
);
done_testing;

26
t/EmailValidator.t Normal file
View File

@ -0,0 +1,26 @@
#! /usr/bin/env perl
use strict;
use warnings;
use Test::More;
use DDG::Test::Goodie;
zci answer_type => 'emailvalidator';
zci is_cached => 0;
ddg_goodie_test(
[
'DDG::Goodie::EmailValidator'
],
'validate foo' => undef,
'validate my email foo@example.com' => test_zci (qr/seems to be valid/),
'validate my email foo+abc@example.com' => test_zci (qr/seems to be valid/),
'validate my email foo.bar@example.com' => test_zci (qr/seems to be valid/),
'validate user@exampleaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com' => test_zci (qr/Please check the address/),
'validate foo@example.com' => test_zci (qr/seems to be valid/),
'validate customer/department=shipping@example.com' => test_zci (qr/seems to be valid/),
'validate foo@!!!.com' => test_zci(qr/Please check the fully qualified domain name/),
'validate foo@example.xyz' => test_zci(qr/Please check the top-level domain/),
);
done_testing;

View File

@ -30,7 +30,7 @@ ddg_goodie_test(
html => 'Default login for the BELKIN F5D6130:<br><i>Username</i>: (none)<br><i>Password</i>: password'
),
# You should include more test cases here. Try to think of ways that your
# plugin might break, and add them here to ensure they won't. Here are a
# instant answer might break, and add them here to ensure they won't. Here are a
# few others that were thought of for this goodie.
'Belkin f5d6130 password default' =>
test_zci('Default login for the BELKIN F5D6130: Username: (none) Password: password',

28
t/Shortcut.t Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
use Test::More;
use DDG::Test::Goodie;
zci answer_type => 'shortcut';
my $start = 'The shortcut for ';
my $first = 'Show desktop in Windows is ⊞Win+D or ⊞Win+M (then use ⊞Win+⇧Shift+M to bring back all windows)';
my $second = 'New folder in KDE/GNOME is Ctrl+⇧Shift+N';
my $third = 'Redo in Mac OS is ⇧Shift+⌘Cmd+Z';
my $fourth = 'Paste special in KDE/GNOME is Ctrl+⇧Shift+V';
my $br = ' <br/>';
my $link = '<a href="https://en.wikipedia.org/wiki/Table_of_keyboard_shortcuts">More at Wikipedia</a>';
ddg_goodie_test(
[qw( DDG::Goodie::Shortcut
)],
'windows show desktop shortcut' => test_zci($start . $first, html => $start . $first . $br . $link),
'ubuntu shortcut new folder' => test_zci($start . $second, html => $start . $second . $br . $link),
'redo shortcut mac' => test_zci($start . $third, html => $start . $third . $br . $link),
'paste special shortcut' => undef #test_zci($start . $fourth, html => $start . $fourth . $br . $link)
);
done_testing;

View File

@ -14,17 +14,18 @@ ddg_goodie_test(
# This is the name of the goodie that will be loaded to test.
'DDG::Goodie::SubnetCalc'
],
"10.0.0.0/24" => test_zci("Network: 10.0.0.0/24, Netmask: 255.255.255.0, Network specified, Class: A, Host Address Range: 10.0.0.1-10.0.0.254, 254 Usable Addresses, Broadcast: 10.0.0.255"),
"192.168.0.0/24" => test_zci("Network: 192.168.0.0/24, Netmask: 255.255.255.0, Network specified, Class: C, Host Address Range: 192.168.0.1-192.168.0.254, 254 Usable Addresses, Broadcast: 192.168.0.255"),
"8.8.8.8 255.255.224.0" => test_zci("Network: 8.8.0.0/19, Netmask: 255.255.224.0, Host #2056 specified, Class: A, Host Address Range: 8.8.0.1-8.8.31.254, 8190 Usable Addresses, Broadcast: 8.8.31.255"),
"4.4.4.255/24" => test_zci("Network: 4.4.4.0/24, Netmask: 255.255.255.0, Broadcast specified, Class: A, Host Address Range: 4.4.4.1-4.4.4.254, 254 Usable Addresses, Broadcast: 4.4.4.255"),
"42.24.42.24/17" => test_zci("Network: 42.24.0.0/17, Netmask: 255.255.128.0, Host #10776 specified, Class: A, Host Address Range: 42.24.0.1-42.24.127.254, 32766 Usable Addresses, Broadcast: 42.24.127.255"),
"172.32.1.3/31" => test_zci("Network: 172.32.1.2/31, Netmask: 255.255.255.254, Point-To-Point (172.32.1.2, 172.32.1.3) specified, Class: B"),
"10.255.255.16/32" => test_zci("Network: 10.255.255.16/32, Netmask: 255.255.255.255, Host Only specified, Class: A"),
"10.1.2.3/255.0.0.0" => test_zci("Network: 10.0.0.0/8, Netmask: 255.0.0.0, Host #66051 specified, Class: A, Host Address Range: 10.0.0.1-10.255.255.254, 16777214 Usable Addresses, Broadcast: 10.255.255.255"),
"192.168.16.1 23" => test_zci("Network: 192.168.16.0/23, Netmask: 255.255.254.0, Host #1 specified, Class: C, Host Address Range: 192.168.16.1-192.168.17.254, 510 Usable Addresses, Broadcast: 192.168.17.255"),
"224.241.221.2/23" => test_zci("Network: 224.241.220.0/23, Netmask: 255.255.254.0, Host #258 specified, Class: D (multicast), Host Address Range: 224.241.220.1-224.241.221.254, 510 Usable Addresses, Broadcast: 224.241.221.255"),
"241.1.1.254/32" => test_zci("Network: 241.1.1.254/32, Netmask: 255.255.255.255, Host Only specified, Class: E (reserved)")
"10.0.0.0/24" => test_zci(
"Network: 10.0.0.0/24 (Class A)\nNetmask: 255.255.255.0\nSpecified: Network\nHost Address Range: 10.0.0.1-10.0.0.254 (254 hosts)\nBroadcast: 10.0.0.255\n",
html => "<div><i>Network: </i>10.0.0.0/24 (Class A)</div><div><i>Netmask: </i>255.255.255.0</div><div><i>Specified: </i>Network</div><div><i>Host Address Range: </i>10.0.0.1-10.0.0.254 (254 hosts)</div><div><i>Broadcast: </i>10.0.0.255</div>",
),
"192.168.0.0/24" => test_zci(
"Network: 192.168.0.0/24 (Class C)\nNetmask: 255.255.255.0\nSpecified: Network\nHost Address Range: 192.168.0.1-192.168.0.254 (254 hosts)\nBroadcast: 192.168.0.255\n",
html => "<div><i>Network: </i>192.168.0.0/24 (Class C)</div><div><i>Netmask: </i>255.255.255.0</div><div><i>Specified: </i>Network</div><div><i>Host Address Range: </i>192.168.0.1-192.168.0.254 (254 hosts)</div><div><i>Broadcast: </i>192.168.0.255</div>",
),
"8.8.8.8 255.255.224.0" => test_zci(
"Network: 8.8.0.0/19 (Class A)\nNetmask: 255.255.224.0\nSpecified: Host #2056\nHost Address Range: 8.8.0.1-8.8.31.254 (8190 hosts)\nBroadcast: 8.8.31.255\n",
html => "<div><i>Network: </i>8.8.0.0/19 (Class A)</div><div><i>Netmask: </i>255.255.224.0</div><div><i>Specified: </i>Host #2056</div><div><i>Host Address Range: </i>8.8.0.1-8.8.31.254 (8190 hosts)</div><div><i>Broadcast: </i>8.8.31.255</div>",
),
);
done_testing;
done_testing;

View File

@ -0,0 +1,34 @@
package DDG::Goodie::<: $ia_name :>;
# ABSTRACT: Write and abstract here
# Start at https://dukgo.com/duckduckhack/goodie_overview if you are new
# to instant answer development
use DDG::Goodie;
#Attribution
primary_example_queries "first example query", "second example query";
secondary_example_queries "optional -- demonstrate any additional triggers";
description "Succinct explanation of what this instant answer does";
name "<: $ia_name :>";
icon_url "";
source "";
code_url "https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/<: $ia_name :>.pm";
category "";
topics "";
attribution github => ["https://github.com/", ""],
twitter => ["https://twitter.com/", ""];
# Triggers
triggers any => "triggerWord", "trigger phrase";
# Handle statement
handle remainder => sub {
# optional - regex guard
# return unless qr/^\w+/;
return $_ if $_;
return;
};
1;

15
template/t/Example.t Normal file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use DDG::Test::Goodie;
ddg_goodie_test(
[qw(
DDG::Goodie::<: $ia_name :>
)],
'example query' => test_zci('query')
);
done_testing;