├── .gitignore
├── duckduckhack
├── assets
│ ├── map.png
│ ├── artist.png
│ ├── coffee.png
│ ├── movies.png
│ ├── icon_tile.png
│ ├── ddg_request.png
│ ├── goodie_guid.png
│ ├── longhis_maui.png
│ ├── recipes_item.png
│ ├── seafood_maui.png
│ ├── coffee_recipes.png
│ ├── diagrams
│ │ ├── icon.png
│ │ ├── infobox.png
│ │ ├── metabar.png
│ │ ├── record.png
│ │ ├── answerbar.png
│ │ ├── base_item.png
│ │ ├── sourcelogo.png
│ │ ├── text_item.png
│ │ ├── ud_infobox.png
│ │ ├── base_detail.png
│ │ ├── metabar_item.png
│ │ ├── mtg_infobox.png
│ │ ├── products_item.png
│ │ ├── text_detail.png
│ │ ├── products_detail.png
│ │ ├── base_item_complex.png
│ │ ├── basic_image_item.png
│ │ ├── basic_info_detail.png
│ │ ├── instant_answer_ui.png
│ │ ├── base_detail_complex.png
│ │ ├── metabar_description.png
│ │ ├── products_item_detail.png
│ │ ├── basic_info_detail_w_aux.png
│ │ └── flip_text_goodie_diagram.png
│ ├── drinks-infobox.png
│ ├── better_than_links.png
│ ├── coffee_definition.png
│ ├── flip_text_goodie.png
│ ├── github_duckduckgo.png
│ ├── goodie_calculator.png
│ ├── goodie_url_decode.png
│ ├── products_detail.png
│ ├── tile_comparison.png
│ ├── tmux_cheat_sheet.png
│ ├── vim_cheat_sheet.png
│ ├── zekiel_isawesome.png
│ ├── amazon_pogs_detail.png
│ ├── app_search_example.png
│ ├── filter_ia_directory.png
│ ├── coffee_recipes_detail.png
│ ├── fathead_readme_example.png
│ ├── garlic_steak_recipes.png
│ ├── goodie_readme_example.png
│ ├── minimal_vertical_space.png
│ ├── spice_readme_example.png
│ ├── template_groups
│ │ ├── movies.png
│ │ ├── bbc_schedule.png
│ │ ├── bitcoin_price.png
│ │ ├── gandhi_quote.png
│ │ ├── gravatar_matt.png
│ │ ├── parking_panda.png
│ │ ├── whois_results.png
│ │ ├── buy_batman_lego.png
│ │ ├── define_indelible.png
│ │ ├── green_day_band.png
│ │ ├── cpan_app_cpanminus.png
│ │ ├── github_duckduckgo.png
│ │ ├── local_results_back.png
│ │ ├── local_results_map.png
│ │ ├── octopart_1770019-2.png
│ │ ├── reddit_duckduckgo.png
│ │ ├── flight_tracking_apps.png
│ │ ├── local_results_detail.png
│ │ ├── local_results_front.png
│ │ ├── lord_of_the_rings_movie.png
│ │ ├── alternative_to_photoshop.png
│ │ └── what_rhymes_with_awesome.png
│ ├── amazon_pogs_item_detail.png
│ ├── instant_answer_flowchart.png
│ ├── longtail_readme_example.png
│ ├── cheatsheet-template-types.png
│ ├── screencast_environment-setup.jpg
│ ├── screencast_multiple-endpoints.jpg
│ └── variant_diagrams
│ │ ├── tile_variant.png
│ │ ├── iconbadge_variant.png
│ │ ├── iconimage_variant.png
│ │ ├── tiletitle_variant.png
│ │ ├── tilefooter_variant.png
│ │ ├── tilerating_variant.png
│ │ └── tilesnippet_variant.png
├── longtail
│ ├── longtail_basic_tutorial.md
│ └── longtail_overview.md
├── resources
│ ├── common_pitfalls.md
│ ├── video-tutorials.md
│ ├── code_styleguide.md
│ └── faq.md
├── spice
│ ├── spice_perl_api.md
│ ├── spice_attributes.md
│ ├── spice_advanced_frontend.md
│ ├── spice_displaying.md
│ ├── spice_triggers.md
│ ├── spice_overview.md
│ └── spice_advanced_backend.md
├── getting-started
│ ├── determine_your_instant_answer_type.md
│ ├── ddh-intro.md
│ ├── contributing.md
│ └── setup_dev_environment.md
├── submitting-your-instant-answer
│ ├── preparing_for_a_pull_request.md
│ ├── metadata.md
│ └── submission_and_review.md
├── instant-answer-display
│ ├── design_styleguide.md
│ ├── subtemplates.md
│ ├── handlebars_helpers.md
│ └── templates_overview.md
├── testing
│ ├── testing_html.md
│ ├── testing_triggers.md
│ ├── testing_location_language_apis.md
│ └── test_files.md
├── goodie
│ ├── goodie_triggers.md
│ ├── goodie_overview.md
│ ├── goodie_helpers.md
│ ├── goodie_advanced_handle_functions.md
│ └── goodie_basic_tutorial.md
├── advanced
│ └── language_and_location_apis.md
├── ddh-prev-next.json
├── ddh-index.md
└── fathead
│ └── fathead_overview.md
├── duckpan
├── assets
│ ├── codio_fork.png
│ ├── codio_server.png
│ ├── dependency.png
│ ├── codio_success.png
│ ├── codio_terminal.png
│ └── codio_fork_both.png
└── duckpan-overview.md
├── README.md
├── CONTRIBUTING.md
└── templates
├── pull_request_template.md
└── CONTRIBUTING.md
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sw*
2 | *~
3 |
--------------------------------------------------------------------------------
/duckduckhack/assets/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/map.png
--------------------------------------------------------------------------------
/duckduckhack/assets/artist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/artist.png
--------------------------------------------------------------------------------
/duckduckhack/assets/coffee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/coffee.png
--------------------------------------------------------------------------------
/duckduckhack/assets/movies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/movies.png
--------------------------------------------------------------------------------
/duckpan/assets/codio_fork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckpan/assets/codio_fork.png
--------------------------------------------------------------------------------
/duckpan/assets/codio_server.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckpan/assets/codio_server.png
--------------------------------------------------------------------------------
/duckpan/assets/dependency.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckpan/assets/dependency.png
--------------------------------------------------------------------------------
/duckduckhack/assets/icon_tile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/icon_tile.png
--------------------------------------------------------------------------------
/duckpan/assets/codio_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckpan/assets/codio_success.png
--------------------------------------------------------------------------------
/duckpan/assets/codio_terminal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckpan/assets/codio_terminal.png
--------------------------------------------------------------------------------
/duckduckhack/assets/ddg_request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/ddg_request.png
--------------------------------------------------------------------------------
/duckduckhack/assets/goodie_guid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/goodie_guid.png
--------------------------------------------------------------------------------
/duckduckhack/assets/longhis_maui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/longhis_maui.png
--------------------------------------------------------------------------------
/duckduckhack/assets/recipes_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/recipes_item.png
--------------------------------------------------------------------------------
/duckduckhack/assets/seafood_maui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/seafood_maui.png
--------------------------------------------------------------------------------
/duckpan/assets/codio_fork_both.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckpan/assets/codio_fork_both.png
--------------------------------------------------------------------------------
/duckduckhack/assets/coffee_recipes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/coffee_recipes.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/icon.png
--------------------------------------------------------------------------------
/duckduckhack/assets/drinks-infobox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/drinks-infobox.png
--------------------------------------------------------------------------------
/duckduckhack/assets/better_than_links.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/better_than_links.png
--------------------------------------------------------------------------------
/duckduckhack/assets/coffee_definition.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/coffee_definition.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/infobox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/infobox.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/metabar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/metabar.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/record.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/record.png
--------------------------------------------------------------------------------
/duckduckhack/assets/flip_text_goodie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/flip_text_goodie.png
--------------------------------------------------------------------------------
/duckduckhack/assets/github_duckduckgo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/github_duckduckgo.png
--------------------------------------------------------------------------------
/duckduckhack/assets/goodie_calculator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/goodie_calculator.png
--------------------------------------------------------------------------------
/duckduckhack/assets/goodie_url_decode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/goodie_url_decode.png
--------------------------------------------------------------------------------
/duckduckhack/assets/products_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/products_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/tile_comparison.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/tile_comparison.png
--------------------------------------------------------------------------------
/duckduckhack/assets/tmux_cheat_sheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/tmux_cheat_sheet.png
--------------------------------------------------------------------------------
/duckduckhack/assets/vim_cheat_sheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/vim_cheat_sheet.png
--------------------------------------------------------------------------------
/duckduckhack/assets/zekiel_isawesome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/zekiel_isawesome.png
--------------------------------------------------------------------------------
/duckduckhack/assets/amazon_pogs_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/amazon_pogs_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/app_search_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/app_search_example.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/answerbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/answerbar.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/base_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/base_item.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/sourcelogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/sourcelogo.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/text_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/text_item.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/ud_infobox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/ud_infobox.png
--------------------------------------------------------------------------------
/duckduckhack/assets/filter_ia_directory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/filter_ia_directory.png
--------------------------------------------------------------------------------
/duckduckhack/assets/coffee_recipes_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/coffee_recipes_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/base_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/base_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/metabar_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/metabar_item.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/mtg_infobox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/mtg_infobox.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/products_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/products_item.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/text_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/text_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/fathead_readme_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/fathead_readme_example.png
--------------------------------------------------------------------------------
/duckduckhack/assets/garlic_steak_recipes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/garlic_steak_recipes.png
--------------------------------------------------------------------------------
/duckduckhack/assets/goodie_readme_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/goodie_readme_example.png
--------------------------------------------------------------------------------
/duckduckhack/assets/minimal_vertical_space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/minimal_vertical_space.png
--------------------------------------------------------------------------------
/duckduckhack/assets/spice_readme_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/spice_readme_example.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/movies.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/movies.png
--------------------------------------------------------------------------------
/duckduckhack/assets/amazon_pogs_item_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/amazon_pogs_item_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/products_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/products_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/instant_answer_flowchart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/instant_answer_flowchart.png
--------------------------------------------------------------------------------
/duckduckhack/assets/longtail_readme_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/longtail_readme_example.png
--------------------------------------------------------------------------------
/duckduckhack/assets/cheatsheet-template-types.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/cheatsheet-template-types.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/base_item_complex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/base_item_complex.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/basic_image_item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/basic_image_item.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/basic_info_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/basic_info_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/instant_answer_ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/instant_answer_ui.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/base_detail_complex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/base_detail_complex.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/metabar_description.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/metabar_description.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/products_item_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/products_item_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/screencast_environment-setup.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/screencast_environment-setup.jpg
--------------------------------------------------------------------------------
/duckduckhack/assets/screencast_multiple-endpoints.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/screencast_multiple-endpoints.jpg
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/bbc_schedule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/bbc_schedule.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/bitcoin_price.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/bitcoin_price.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/gandhi_quote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/gandhi_quote.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/gravatar_matt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/gravatar_matt.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/parking_panda.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/parking_panda.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/whois_results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/whois_results.png
--------------------------------------------------------------------------------
/duckduckhack/assets/variant_diagrams/tile_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/variant_diagrams/tile_variant.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/basic_info_detail_w_aux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/basic_info_detail_w_aux.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/buy_batman_lego.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/buy_batman_lego.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/define_indelible.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/define_indelible.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/green_day_band.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/green_day_band.png
--------------------------------------------------------------------------------
/duckduckhack/assets/diagrams/flip_text_goodie_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/diagrams/flip_text_goodie_diagram.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/cpan_app_cpanminus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/cpan_app_cpanminus.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/github_duckduckgo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/github_duckduckgo.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/local_results_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/local_results_back.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/local_results_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/local_results_map.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/octopart_1770019-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/octopart_1770019-2.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/reddit_duckduckgo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/reddit_duckduckgo.png
--------------------------------------------------------------------------------
/duckduckhack/assets/variant_diagrams/iconbadge_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/variant_diagrams/iconbadge_variant.png
--------------------------------------------------------------------------------
/duckduckhack/assets/variant_diagrams/iconimage_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/variant_diagrams/iconimage_variant.png
--------------------------------------------------------------------------------
/duckduckhack/assets/variant_diagrams/tiletitle_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/variant_diagrams/tiletitle_variant.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/flight_tracking_apps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/flight_tracking_apps.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/local_results_detail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/local_results_detail.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/local_results_front.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/local_results_front.png
--------------------------------------------------------------------------------
/duckduckhack/assets/variant_diagrams/tilefooter_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/variant_diagrams/tilefooter_variant.png
--------------------------------------------------------------------------------
/duckduckhack/assets/variant_diagrams/tilerating_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/variant_diagrams/tilerating_variant.png
--------------------------------------------------------------------------------
/duckduckhack/assets/variant_diagrams/tilesnippet_variant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/variant_diagrams/tilesnippet_variant.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/lord_of_the_rings_movie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/lord_of_the_rings_movie.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/alternative_to_photoshop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/alternative_to_photoshop.png
--------------------------------------------------------------------------------
/duckduckhack/assets/template_groups/what_rhymes_with_awesome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckduckgo/duckduckgo-documentation/HEAD/duckduckhack/assets/template_groups/what_rhymes_with_awesome.png
--------------------------------------------------------------------------------
/duckduckhack/longtail/longtail_basic_tutorial.md:
--------------------------------------------------------------------------------
1 | # Longtail Basic Tutorial
2 |
3 | (This section is coming soon! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
--------------------------------------------------------------------------------
/duckduckhack/resources/common_pitfalls.md:
--------------------------------------------------------------------------------
1 | # Common Pitfalls
2 |
3 | (This section is coming soon! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
4 |
5 | ### Defining Perl Variables and Functions
6 |
7 | - inside vs outside the `handle` function
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # We Have Moved!
2 |
3 | These are the **old docs**, and are outdated.
4 |
5 | The new documentation can be read [here](http://docs.duckduckhack.com) and the repository is hosted [here](https://github.com/duckduckgo/duckduckhack-docs).
6 |
7 | Any feedback, thoughts, or pull requests about the new docs are welcome, **please** let us know at open@duckduckgo.com
8 |
9 |
--------------------------------------------------------------------------------
/duckduckhack/spice/spice_perl_api.md:
--------------------------------------------------------------------------------
1 | # Spice Perl API Reference
2 |
3 | (This section is coming soon! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
4 |
5 | ### share()
6 |
7 | (Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
8 |
--------------------------------------------------------------------------------
/duckduckhack/resources/video-tutorials.md:
--------------------------------------------------------------------------------
1 | # Video Tutorials
2 |
3 | We have some video tutorials (screencasts) which accompany our DuckDuckHack documentation.
4 |
5 | ## Setting up your environment
6 |
7 | Watch a visual guide to setting up GitHub and Codio, the easiest way to start making DuckDuckGo Instant Answers.
8 |
9 | [Watch video on Vimeo](https://vimeo.com/132712266)
10 |
11 | 
12 |
13 | ## Multiple API endpoints
14 |
15 | Learn how to handle multiple API endpoints when developing a DuckDuckGo Instant Answer.
16 |
17 | [Watch video on Vimeo](https://vimeo.com/137152536)
18 |
19 | 
20 |
21 |
22 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to DuckDuckGo-Documentation
2 |
3 | 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.
4 |
5 | ## Getting Started
6 |
7 | - Make sure you have a [GitHub account](https://github.com/signup/free)
8 |
9 | If submitting a **bug/suggestion**:
10 | - Check if a GitHub issue already exists for the given bug/suggestion
11 | - If one doesn't exist, create a GitHub issue in the DuckDuckGo-Documentation repository
12 | - Clearly describe the bug/improvement, including steps to reproduce when it is a bug
13 | - If one already exists, please add any additional comments you have regarding the matter
14 |
15 | If submitting a **pull request** (bugfix/addition):
16 | - Fork the DuckDuckGo-Documentation repository on GitHub
17 |
18 | ## Making Changes
19 |
20 | - Before making any changes, refer to the [DuckDuckHack Styleguide](https://dukgo.com/duckduckhack/code_styleguide) to ensure your changes are made in the correct fashion
21 | - Make sure your commits are of a reasonable size. They shouldn't be too big (or too small)
22 | - Make sure your commit messages effectively explain what changes have been made, and please identify which Instant Answer or file has been modified:
23 |
24 | ```
25 | CONTRIBUTING.md - Added the example commit message because it was missing
26 | ```
27 |
28 | ## Submitting Changes
29 |
30 | - Push your changes to your fork of the repository
31 | - Submit a pull request to the DuckDuckGo-Documentation repository
32 | * Make sure to use the DuckDuckGo-Documentation repository's Pull Request template
33 |
--------------------------------------------------------------------------------
/duckduckhack/getting-started/determine_your_instant_answer_type.md:
--------------------------------------------------------------------------------
1 | # Determine Your Instant Answer Type
2 |
3 | The first step to planning your Instant Answer is deciding what type it is. Instant Answer type depends on how the result is obtained.
4 |
5 | Most Instant Answers rely on some type of data source (e.g. database, text file, API) to provide their answer. Others however, are able to provide their answer through the use of pure code, like a pre-existing Perl package on CPAN or simply a script you write (e.g. a string manipulation function).
6 |
7 | **Before you start coding, let us know your plans, and what Instant Answer type you'd like to use.** By involving us early we can provide guidance and potentially save you a lot of time and effort. Email us at [open@duckduckgo.com](mailto:open@duckduckgo.com) with what idea you're working on and how you're thinking of going about it.
8 |
9 | The following flowchart will help you to think about what type of Instant Answer you'll be creating, which is based on your Instant Answer's data source:
10 |
11 | 
12 |
13 |
14 |
15 | If you were able to determine your Instant Answer type, then you're ready to [setup your development environment](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/getting-started/setup_dev_environment.md)!
16 |
17 | ------
18 |
19 | If the right Instant Answer type is still not obvious, don't worry, the DuckDuckGo Community is here for you! Please visit our [Instant Answer Ideas Forum](https://dukgo.com/ideas) and post a new thread for your Instant Answer. Be sure to describe the Instant Answer you have in mind, and don't forget to indicate where you think the data should come from. Someone from the community or the DuckDuckGo staff will be able to help you determine the best course of action for you.
20 |
--------------------------------------------------------------------------------
/duckduckhack/getting-started/ddh-intro.md:
--------------------------------------------------------------------------------
1 | # We Have Moved!
2 |
3 | These are the **old docs**, and are outdated.
4 |
5 | The new documentation can be read [here](http://docs.duckduckhack.com) and the repository is hosted [here](https://github.com/duckduckgo/duckduckhack-docs).
6 |
7 | Any feedback, thoughts, or pull requests about the new docs are welcome, **please** let us know at open@duckduckgo.com
8 |
9 | # Welcome to DuckDuckHack
10 |
11 | We are a community of DuckDuckGo users who help improve the search engine with, "Instant Answers". To get started, please [request an invite to our Slack team](mailto:QuackSlack@duckduckgo.com?subject=AddMe). You may join multiple Slack channels to discuss your Instant Answer ideas with others who may have the same interests!
12 |
13 | - [Request Slack invite](mailto:QuackSlack@duckduckgo.com?subject=AddMe)
14 |
15 | You may also wish to join our DuckDuckHack Dev's email list (low traffic):
16 |
17 | - [DuckDuckHack developer mailing list](https://www.listbox.com/subscribe/?list_id=197814)
18 |
19 |
20 | ## What are Instant Answers?
21 |
22 | Instant Answers help you find what you're looking for in few or zero clicks. They're placed above ads and regular search results, and they're created/maintained by you (the community). Some Instant Answers are built from pure code and others require external sources (API requests), databases, or key-value stores. The possibilities are endless but the point is to provide a perfect result for every search.
23 |
24 | 
25 |
26 | In the above example, [Quixey](http://quixey.com/) was a source that our own DuckDuckHack Community suggested for mobile app search. Now, any time someone searches for apps on DuckDuckGo, we request information directly from Quixey to help answer the search.
27 |
28 | To see just how simple it is to contribute an Instant Answer, check out David Farrell's PerlTricks post: [Writing DuckDuckGo plugins just got easier](http://perltricks.com/article/189/2015/8/22/Writing-DuckDuckGo-plugins-just-got-easier).
29 |
30 | In these docs, we'll show you how to build Instant Answers that can do this and more. Start by reading about [ways to contribute](https://duck.co/duckduckhack/contributing).
31 |
--------------------------------------------------------------------------------
/duckduckhack/spice/spice_attributes.md:
--------------------------------------------------------------------------------
1 | # Spice Attributes (Perl)
2 |
3 | ## Spice `to`
4 |
5 | This attribute defines the API endpoint for your Instant Answer. E.g.
6 |
7 | ```perl
8 | spice to => 'http://example.com/search/$1?loc=$2';
9 | ```
10 |
11 | A GET request will be made to this URL to retrieve data. The **$1** and **$2** in the URL are values captured from the regular expression defined by `spice from`, which has a default value of `(.*)`. See the full documentation of `spice from` below for more information.
12 |
13 | ## Spice `from`
14 |
15 | The `spice from` attribute defines a regular expression which groups data returned from the `handle` function. All parameters returned from the `handle` function in a Spice are converted into strings and joined with a `/`. Here's an example:
16 |
17 | ```perl
18 | handle remainder => sub {
19 | # Produces the string "foo/bar/baz"
20 | return "foo", "bar", "baz";
21 | }
22 |
23 | # Captures three groups separated by a forward slash
24 | spice from => '(.*)/(.*)/(.*)';
25 | ```
26 |
27 | In the above example, the values returned from `handle` are passed to `spice from` as "foo/bar/baz", which then matches the regex and passes the parameters to `spice to`, where `$1 = "foo"`, `$2 = "bar"`, and `$3 = "baz"`. `spice to` then uses these parameters to handle the API request.
28 |
29 | By default, `spice from` has a value of `(.*)`, which sends all parameters from the `handle` function to `spice to` in a single group, **$1**.
30 |
31 | ## Spice `wrap_jsonp_callback`
32 |
33 | If the API used for your Instant Answer does not support JSONP (ie. it doesn't provide a URI parameter to indicate the callback function to be used on the API response), set `wrap_jsonp_callback` to true and the API response will automatically be wrapped in the appropriate function call for your Instant Answer.
34 |
35 | ## Spice `proxy_cache_valid `
36 |
37 | (Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
38 |
39 | ## Spice `is_unsafe`
40 |
41 | If your Instant Answer has the potential to return unsafe results (eg. contains vulgar words, crude humour) the `is_unsafe` flag must be set to true. Any Instant Answers that have `is_unsafe` set to true can only be seen when a user has safe-search turned off, or when they add the phrase `!safeoff` to their query (eg. "automeme !safeoff").
42 |
--------------------------------------------------------------------------------
/duckduckhack/submitting-your-instant-answer/preparing_for_a_pull_request.md:
--------------------------------------------------------------------------------
1 | # Preparing for Pull Request
2 |
3 | The culmination of your contribution comes in the form of a pull request to the Github repository for your Instant Answer type.
4 |
5 | Before proceeding, make sure you've done the following steps.
6 |
7 | - [Contacted us](mailto:open@duckduckgo.com) to let us know what you're working on
8 |
9 | By involving us, we can provide guidance and potentially save you a lot of time and effort. Email us at [open@duckduckgo.com](mailto:open@duckduckgo.com) with what idea you're working on and how you're thinking of going about it.
10 |
11 | - Determined your Instant Answer type (we will have helped you determine this, in addition to this [helpful guide](https://duck.co/duckduckhack/determine_your_instant_answer_type))
12 | - Forked the [correct repository](https://duck.co/duckduckhack/setup_dev_environment) on Github
13 | - Written and committed the code for your Instant Answer
14 | - Make sure you comment your code well so that it's easier for other people to maintain.
15 | - [Manually tested](https://duck.co/duckduckhack/testing_triggers) your Instant Answer
16 | - Written a comprehensive automatic [test file](https://duck.co/duckduckhack/test_files) for your Instant Answer
17 | - Manually verified that everything works.
18 | - Make sure your [tab name](https://duck.co/duckduckhack/display_reference#codenamecode-emstringem-required) is well-chosen and consistent with the guidelines
19 | - If you wrote custom CSS, did you namespace the CSS? Every Instant Answer should be contained in a `
` with a unique id. This id should be used to target your styles and avoid overwriting any global styles.
20 | - Confirmed the Instant Answer adheres to the [code style guide](https://duck.co/duckduckhack/code_styleguide)
21 | - Added yourself to the attribution (if updating an existing Instant Answer).
22 | - Can this Instant Answer return unsafe content (bad words, etc.)
23 | - Did you set `is_unsafe` to true?
24 | - Can this Instant Answer return an HTML response?
25 | - Have you guaranteed that the response does not contain unsanitized user-supplied strings (e.g., the query string) which could lead to [cross-site scripting attacks](https://duckduckgo.com/Cross-site_scripting?ia=about)?
26 |
27 | ## Proceed to Adding Metadata
28 |
29 | Checked everything off the list? Congratulations - you are now ready to [add metadata](https://duck.co/duckduckhack/metadata) to your Instant Answer which will help us to understand it a little better.
--------------------------------------------------------------------------------
/duckduckhack/spice/spice_advanced_frontend.md:
--------------------------------------------------------------------------------
1 | # Advanced Spice Frontend
2 |
3 | ## Accessing the query remainder
4 |
5 | It's possible to get the user's full original query with `DDG.get_query()`, but often you may only need a specific part of it.
6 |
7 | For example, let's look at the [Hacker News IA](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/HackerNews.pm).
8 |
9 | If a user searches for something like "hacker news oculus rift", you may want to ignore the trigger words ("hacker news") and only retrieve what the user was searching for ("oculus rift").
10 |
11 | You could replace those trigger words manually, but it's better not to have a duplicate list of trigger words between your backend and frontend code. Luckily there's a way to get the user's query as processed by the backend code.
12 |
13 | ```javascript
14 | var script = $('[src*="/js/spice/hacker_news/"]')[0],
15 | source = $(script).attr("src"),
16 | query = source.match(/hacker_news\/([^\/]+)/)[1],
17 | decodedQuery = decodeURIComponent(query);
18 |
19 | console.log(decodedQuery); // "oculus rift"
20 | ```
21 |
22 | Here's what this snippet does:
23 |
24 | ```
25 | var script = $('[src*="/js/spice/hacker_news/"]')[0],
26 | source = $(script).attr("src"),
27 | ```
28 |
29 | The JSONP response from the Spice query will be retrieved as a script with a source of `/js/spice/hacker_news/oculus%20rift`. The first part of this (`/js/spice/hacker_news/`) will always be the same for our Spice, so we can use jQuery to get access to our `script` tag, and get its full `src` attribute.
30 |
31 | At this point the `source` variable contains `/js/spice/hacker_news/oculus%20rift`.
32 |
33 | ```
34 | query = source.match(/hacker_news\/([^\/]+)/)[1],
35 | decodedQuery = decodeURIComponent(query);
36 | ```
37 |
38 | Then we use regular expressions to get anything after `/hacker_news/`, and run it against `decodeURIComponent()` to remove all URL encoded characters.
39 |
40 | If you're returning multiple values in your backend `handle` function, you may need some more logic. For instance:
41 |
42 | ```
43 | // our JSONP response has src like "/js/spice/example_answer/term1/term2"
44 |
45 | var matches = source.match(/example_answer\/([^\/]+)\/([^\/]+)/),
46 | partOne = matches[1], // equals "term1"
47 | partTwo = matches[2]; // equals "term2"
48 | ```
49 |
50 | (More for this section is coming soon! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
51 |
--------------------------------------------------------------------------------
/duckpan/duckpan-overview.md:
--------------------------------------------------------------------------------
1 | DuckPAN is an application built to provide developers a testing environment for the ZeroClickInfo Plugins. It allows users to test plugin triggers, and lets you preview their visual design.
2 |
3 | ## Using DuckPAN
4 |
5 | ### Help
6 |
7 | ```shell
8 | duckpan
9 | ```
10 |
11 | or
12 |
13 | ```shell
14 | duckpan help
15 | ```
16 |
17 | or
18 |
19 | ```shell
20 | man duckpan
21 | ```
22 |
23 | Prints out the DuckPAN man page
24 |
25 | ### Install Commands
26 |
27 | ```shell
28 | duckpan installdeps
29 | ```
30 |
31 | Install all requirements of the specific DuckDuckHack project (if
32 | possible), like zeroclickinfo-spice, zeroclickinfo-goodie, duckduckgo
33 | or community-platform
34 |
35 | ```shell
36 | duckpan roadrunner
37 | ```
38 |
39 | Same as `installdeps`, but avoids testing anything. Useful for speed, but
40 | not recommended unless you know what you are doing.
41 |
42 | ```shell
43 | duckpan check
44 | ```
45 |
46 | Check if you fulfill all requirements for the development
47 | environment (this is run automatically during setup)
48 |
49 | ```shell
50 | duckpan reinstall
51 | ```
52 |
53 | Force installation of the latest released versions of DuckPAN and DDG
54 |
55 | ### Instant Answer Testing
56 |
57 | ```shell
58 | duckpan query
59 | ```
60 |
61 | Test Goodie and Spice triggers interactively on the command line
62 |
63 |
64 | ```shell
65 | duckpan server [--verbose] [--no-cache] [--port ]
66 | ```
67 |
68 | Test Goodie and Spice Instant Answers on a local web server (for design/layout purposes)
69 |
70 | Options:
71 |
72 | - `--verbose` to provide more details
73 | - `--no-cache` to prevent DuckPAN's cache from being used (this forces the requested files to be pushed into the cache)
74 | - `--port` to specify which port DuckPAN's server should run on (defaults to 5000)
75 |
76 | ### Advanced Features
77 |
78 | ```shell
79 | duckpan env
80 | ```
81 |
82 | View env commands and also shows the env variables currently stored in ~/.duckpan/env.ini
83 |
84 | ```shell
85 | duckpan env
86 | ```
87 |
88 | Add an environment variable that duckpan will remember. Useful for
89 | spice API keys. Variables are stored in ~/.duckpan/env.ini
90 |
91 | ```shell
92 | duckpan env
93 | ```
94 |
95 | Retrieve the matching key for a given env variable.
96 |
97 | ```shell
98 | duckpan env rm
99 | ```
100 |
101 | Remove an environment variable from duckpan
102 |
103 | ```shell
104 | duckpan release
105 | ```
106 |
107 | Release the project of the current directory to DuckPAN
108 |
--------------------------------------------------------------------------------
/templates/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Instant Answer Pull Request Template
2 |
3 | We ask that you please use this template when submitting an Instant Answer pull request so we can better understand your changes and help you along when necessary.
4 |
5 | ## About Your Instant Answer
6 |
7 | **What does your Instant Answer do?**
8 |
9 |
10 | **What problem does your Instant Answer solve (Why is it better than organic links)?**
11 |
12 |
13 | **What is the data source for your Instant Answer? (Provide a link if possible)**
14 |
15 |
16 | **Why did you choose this data source?**
17 |
18 |
19 | **Are there any other alternative (better) data sources?**
20 |
21 |
22 | **What are some example queries that trigger this Instant Answer?**
23 |
24 |
25 | **Which communities will this Instant Answer be especially useful for? (gamers, book lovers, etc)**
26 |
27 |
28 | **Is this Instant Answer connected to a DuckDuckHack [Instant Answer idea](https://duck.co/ideas)?**
29 |
30 |
31 | **Which existing Instant Answers will this one supersede/overlap with?**
32 |
33 |
34 | **Are you having any problems? Do you need our help with anything?**
35 |
36 |
37 | **What does the Instant Answer look like? (Provide a screenshot for new or updated Instant Answers)**
38 |
39 | ## For First Time Contributors
40 |
41 | **What types of Instant Answers are you interested in contributing to in the future? (e.g. Cryptography, Video Game, Food, Sports, etc.)**
42 |
43 | **Where did you find out about DuckDuckHack?**
44 |
45 |
46 | ## Final Checklist
47 | Please place an 'X' where appropriate.
48 |
49 | ```
50 | [] Added metadata and attribution information
51 | [] Wrote test file and added to t/ directory
52 | [] Verified that Instant Answer adheres to design guidelines (https://duck.co/duckduckhack/design_styleguide)
53 | [] Verified that Instant Answer adheres to code styleguide (https://duck.co/duckduckhack/code_styleguide)
54 | [] Tested cross-browser compatibility
55 |
56 | Please let us know which browsers/devices you've tested on:
57 | - Windows 8
58 | [] Google Chrome
59 | [] Firefox
60 | [] Opera
61 | [] IE 10
62 |
63 | - Windows 7
64 | [] Google Chrome
65 | [] Firefox
66 | [] Opera
67 | [] IE 9
68 | [] IE 10
69 |
70 | - Mac OSX
71 | [] Google Chrome
72 | [] Firefox
73 | [] Opera
74 | [] Safari
75 |
76 | - iOS (iPhone)
77 | [] Safari Mobile
78 | [] Google Chrome
79 | [] Opera
80 |
81 | - iOS (iPad)
82 | [] Safari Mobile
83 | [] Google Chrome
84 | [] Opera
85 |
86 | - Android
87 | [] Firefox
88 | [] Native Browser
89 | [] Google Chrome
90 | [] Opera
91 | ```
92 |
--------------------------------------------------------------------------------
/duckduckhack/instant-answer-display/design_styleguide.md:
--------------------------------------------------------------------------------
1 | # Instant Answer Design Style Guide
2 |
3 | Being an open-source project with many contributors from all over the world, we strive for all our Instant Answers to appear aesthetically consistent.
4 |
5 | This means we maintain certain visual aspects across all of our Instant Answers such as the fonts and colors used, as well as the layout and placement of common elements. This helps instill a feeling of familiarity in our users when they come across new Instant Answers and improves usability and comfort with the interface.
6 |
7 | The most current design guide for all of DuckDuckGo, including Instant Answers, can be found at the [Official DuckDuckGo Style Guide](https://duckduckgo.com/styleguide).
8 |
9 | This section explains how the style guide affects the creation of a new Instant Answer.
10 |
11 | ---
12 |
13 | ## Templates
14 |
15 | Nearly all Instant Answers use [templates](https://duck.co/duckduckhack/templates_overview) as the easiest way to maintain consistency and, most importantly, maintainability over time.
16 |
17 | Templates abstract away nearly all design concerns. They allow developers to focus on their Instant Answer's results rather than deal with browser compatibility, responsiveness, fonts, colors, or CSS in general.
18 |
19 | To learn about the wide variety of built-in templates, start with the [Templates Overview](https://duck.co/duckduckhack/templates_overview).
20 |
21 | ## Built-In Style Elements
22 |
23 | Thanks to the use of templates, directly writing HTML is uncommon. However, some Instant Answers will use custom templates. This is usually in the form of [sub-templates](https://duck.co/duckduckhack/templates_overview), and in rare cases, the [`base` template group](https://duck.co/duckduckhack/template_groups#base-template-group).
24 |
25 | ## Built-In Style Elements
26 |
27 | When writing custom HTML, you can directly apply the built-in style resources documented in the [DuckDuckGo Style Guide](https://duckduckgo.com/styleguide) in your HTML. Using the built-in elements allows Instant Answers to automatically stay up-to-date with any DuckDuckGo style changes.
28 |
29 | Applying style guide elements is straightforward. For example, to [style text](https://duckduckgo.com/styleguide#txt-n-color) as a large heading, simply use that class:
30 |
31 | ```html
32 |
Your Heading
33 | ```
34 |
35 | To use an [icon](https://duckduckgo.com/styleguide#icons), add a class with the icon name:
36 |
37 | ```html
38 |
39 | ```
40 |
41 | To set built-in images such as flags, make a JavaScript call to obtain the image URL and pass it to your template as data:
42 |
43 | ```javascript
44 | DDG.settings.region.getLargeIconURL("CA");
45 | ```
46 |
47 | ## Giving Credit
48 |
49 | Instant Answers are meant to first and foremost provide users with value in an accessible way, while providing credit to the original source. Every Instant Answer template provides the display of a ["More at..."](https://duck.co/duckduckhack/display_reference#codemetacode-emobjectem-required) link, which serves as a consistent place for users to see the data source.
50 |
51 | Using Instant Answers for other goals, such as excessive self-promotion or inserting advertisements, particularly at the expense of usability, consistency, or usefulness - is not in line with the spirit of the community.
52 |
--------------------------------------------------------------------------------
/duckduckhack/testing/testing_html.md:
--------------------------------------------------------------------------------
1 | ## Testing HTML
2 |
3 | You should have already tested your triggers by following the [Testing triggers](https://duck.co/duckduckhack/testing_triggers) section. Now that you're confident your triggers are functioning properly, follow these steps to see how it looks on a live server!
4 |
5 |
6 |
7 | 1. Enter the root directory of your forked Instant Answer repository:
8 |
9 | Log in to Codio and visit the dashboard. In the menu, click Codio > [Dashboard](https://codio.com/home/projects)
10 |
11 | Click on the **DuckDuckHack project**, which you previously forked and cloned.
12 |
13 | Next, open a terminal window if it's not already open. (Tools > Terminal).
14 |
15 | At the command prompt, change into your repository directory, for example:
16 |
17 | ```shell
18 | cd zeroclickinfo-goodies
19 | ```
20 |
21 | The command line prompt will now indicate the repository and branch you are in, for example:
22 |
23 | ```shell
24 | [ codio@border-carlo workspace zeroclickinfo-goodies {master}]$
25 | ```
26 |
27 | 2. Type **`duckpan server`** and press "**Enter**". The Terminal should print some text and let you know that the server is listening on port 5000.
28 |
29 | ```shell
30 | Starting up webserver...
31 |
32 | You can stop the webserver with Ctrl-C
33 |
34 | HTTP::Server::PSGI: Accepting connections at http://0:5000/
35 | ```
36 |
37 | 3. Click the "**DuckPAN Server**" button at the top of the screen. A new browser tab should open and you should see the DuckDuckGo Homepage.
38 |
39 | You should now be able to search and see live Instant Answer results. The server runs code from our site which should make it look very much like the real DuckDuckGo.
40 |
41 | 4. Search.
42 |
43 | Having already tested your triggers, you should be able to construct a query to hit that trigger and see your newly defined result. Information about the processing of your requests is printed to the terminal where you started the server. Any external API calls will be highlighted if supported by your terminal.
44 |
45 | 5. Debug.
46 |
47 | If your search doesn't hit an Instant Answer, there will be an error message displayed on the page: "Sorry, no hit for your Instant Answer."
48 |
49 | If the trigger is hit but you do not see something displayed on the screen, a number of things could be wrong:
50 |
51 | - You have a JavaScript error of some kind. Internally, we like to use the JavaScript console in [Firebug](http://getfirebug.com/) to get more details.
52 |
53 | - An external API was not called correctly. You should examine the Web server output to make sure the correct API is being called. If it's not you will need to revise your [Spice handle function](https://duck.co/duckduckhack/spice_basic_tutorial#define-the-handle-function).
54 |
55 | - An external API did not return anything. Firebug is a great help here, as well. You should be able to see the external call in your browser and examine the response.
56 |
57 | 6. Tweak the display.
58 |
59 | Once all of the processing is working properly, you will probably want to adjust your callback function to get the display just right. The [Display reference](https://duck.co/duckduckhack/display_reference) section has some pointers to help you along.
60 |
61 | 7. Document.
62 |
63 | Please document your code as appropriate using in-line comments.
64 |
--------------------------------------------------------------------------------
/duckduckhack/longtail/longtail_overview.md:
--------------------------------------------------------------------------------
1 | # Longtail Instant Answers
2 |
3 | **If you have questions, [request an invite to our Slack team](mailto:QuackSlack@duckduckgo.com?subject=AddMe) and we'll be happy to chat!**
4 |
5 | Longtails are database-backed, full text search, Instant Answers. For every query DuckDuckGo receives, each Longtail's database of articles is searched and any matching articles are used to display a paragraph of text, highlighting the portion of the article which matches the query. Developing a Longtail Instant Answer entails writing a program that generates an XML data file. This XML file describes each article, as well as some other important information discussed below. The program may be written in Perl, Python, JavaScript, or Ruby, and if necessary, will be run periodically to keep the database current.
6 |
7 | ## Structure
8 |
9 | Longtails consist of two primary files. The first is a metadata file that describes the Instant Answer you are building. Its structure is identical to the Fathead metadata file, described [here](https://github.com/duckduckgo/zeroclickinfo-fathead#meta-file). The second, which can be generated using a language of your choosing, contains the data set in a format ready for us to deploy:
10 |
11 | ```XML
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 1
34 |
35 |
36 |
37 |
38 |
39 | ```
40 |
41 | (This section is still growing! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
42 |
--------------------------------------------------------------------------------
/duckduckhack/spice/spice_displaying.md:
--------------------------------------------------------------------------------
1 | # Adding Your Spice to the DuckDuckGo AnswerBar
2 |
3 | Once your Instant Answer has been triggered, and the API request has returned a response to the client, the final step is to display your results onscreen.
4 |
5 | 
6 |
7 | ## Contents of the Spice Frontend Callback
8 |
9 | The Spice frontend callback function, [covered in the Spice Basic Tutorial](https://duck.co/duckduckhack/spice_basic_tutorial#npm-spice-frontend-javascript), contains the code which displays your Spice.
10 |
11 | The most important part of this callback, and often the only part, is calling [`Spice.add()`](#codespiceaddcode-overview). This function is powerful and gives you a lot of control over your results' appearance, context, and user interactions.
12 |
13 | ## Available Options
14 |
15 | The properties you can pass to the `Spice.add()` function are documented in the [Instant Answer Display Reference](https://duck.co/duckduckhack/display_reference). This document provides an in-depth overview of all that `Spice.add()` allows you to do.
16 |
17 | In some scenarios, you may also want to handle the AnswerBar's events (for example, to stop media playing when the user hides your Instant Answer). These [events](https://duck.co/duckduckhack/display_reference#events) are covered at the end of the reference.
18 |
19 | ## Calling `Spice.add()`
20 |
21 | The following is a code summary of how the options covered in the [Instant Answer Display Reference](https://duck.co/duckduckhack/display_reference) are passed to `Spice.add()`
22 |
23 | ```javascript
24 | Spice.add({
25 |
26 | // Required properties:
27 |
28 | id: String,
29 | name: String,
30 | data: Array or Object (in the case of a single item),
31 |
32 | meta: {
33 | searchTerm: String,
34 | itemType: String,
35 |
36 | primaryText: String,
37 | secondaryText: String,
38 |
39 | sourceName: String,
40 | sourceLogo: String,
41 | sourceUrl: String (url),
42 | sourceIcon: Boolean,
43 | sourceIconUrl: String (url),
44 |
45 | snippetChars: Integer
46 | },
47 |
48 | templates: {
49 | group: String,
50 |
51 | item: String|Function,
52 | item_custom: String|Function,
53 | item_mobile: String|Function,
54 |
55 | detail: String|Function,
56 | detail_custom: String|Function,
57 | detail_mobile: String|Function,
58 | item_detail: String|Function,
59 |
60 | options: Object
61 |
62 | variants: Object
63 |
64 | elClass: Object
65 | },
66 |
67 | // Optional properties:
68 |
69 | normalize: Function,
70 |
71 | relevancy: {
72 | type: String,
73 | skip_words: [, String],
74 | primary: [, Object],
75 | dup: String,
76 | },
77 |
78 | view: String,
79 | model: String,
80 |
81 | sort_fields: Object,
82 | sort_default: String|Object,
83 |
84 | onItemSelected: Function,
85 | onItemUnselect: Function,
86 | onShow: Function,
87 | onHide: Function
88 |
89 | });
90 | ```
91 |
92 | For more information on each property and its usage, visit the [Instant Answer Display Reference](https://duck.co/duckduckhack/display_reference).
--------------------------------------------------------------------------------
/duckduckhack/goodie/goodie_triggers.md:
--------------------------------------------------------------------------------
1 | # Triggers
2 |
3 | There are two types of triggers, **words** and **regex**. We insist that you use word triggers whenever possible as they are simpler and faster.
4 |
5 | ## Word Triggers
6 |
7 | ### Usage
8 |
9 | ```perl
10 | triggers =>
11 | ```
12 |
13 |
14 |
15 | #### Examples
16 |
17 | ```perl
18 | triggers start => "trigger my instant answer", "trigger myIA", "myIA";
19 | ```
20 |
21 | or
22 |
23 | ```perl
24 | @triggers = qw(these are separate triggers for my instant answer);
25 | triggers any => @triggers;
26 | ```
27 |
28 | or
29 |
30 | ```perl
31 | triggers start => "starting phrase of query";
32 | triggers end => "ending phrase of query";
33 | ```
34 |
35 | ### Trigger Locations
36 |
37 | - `start` — Word exists at the start of the query
38 | - `end` — Word exists at the end of the query
39 | - `startend` — Word is at the beginning or end of the query
40 | - `any` — Word is anywhere in the query
41 |
42 | **Note:** You can combine several trigger statements if, for example, you want certain words or phrases to be **startend** but others to be **start**. The [Average Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Average.pm#L5) demonstrates the usage of multiple Word trigger statements.
43 |
44 | ## Regex Triggers
45 |
46 | ### Usage
47 |
48 | ```perl
49 | triggers =>
50 | ```
51 |
52 |
53 |
54 | #### Examples
55 |
56 | ```perl
57 | triggers query_lc => qr/trigger (?:my|your|our) instant answer/;
58 | ```
59 |
60 | or
61 |
62 | ```perl
63 | my $regex = qr/^this is an? instant answer regexp$/;
64 | triggers query_raw => $regex;
65 | ```
66 |
67 | #### Query Formats
68 |
69 | - `query_raw` — The query in its original form, with whitespace and case preserved
70 | - `query` — Uniformly whitespaced version of `query_raw`
71 | - `query_lc` — Lowercase version of `query`
72 | - `query_nowhitespace` — `query` with all whitespace removed
73 | - `query_clean` — `query_lc`, but with whitespace and non-alphanumeric ascii removed
74 |
75 | **Note:** You **cannot** combine the use of **Regex Triggers** with **Word Triggers**.
76 |
77 | ## Regex Guards
78 |
79 | 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.
80 |
81 | A good example of this is the Base64 goodie. In this case we want to trigger on queries with the form "base64 encode/decode \". 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:
82 |
83 | ```perl
84 | triggers startend => "base64";
85 |
86 | handle remainder => sub {
87 | return unless $_ =~ /^(encode|decode|)\s*(.*)$/i;
88 | ```
89 |
90 | ## Triggers in Multiple Languages
91 |
92 | 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.**
--------------------------------------------------------------------------------
/duckduckhack/goodie/goodie_overview.md:
--------------------------------------------------------------------------------
1 | ## Goodie Instant Answers
2 |
3 | **If you have questions, [request an invite to our Slack team](mailto:QuackSlack@duckduckgo.com?subject=AddMe) and we'll be happy to chat!**
4 |
5 | Goodies are pure-code Instant Answers. They are essentially a Perl function that is evaluated on our servers, and do not make external HTTP requests to other services.
6 |
7 | Goodies can be extremely simple, such as the [Uppercase](https://duckduckgo.com/?q=uppercase+duckduckgo+instant+answers) Goodie, which simply uses the perl `uc` function to uppercase a string.
8 |
9 | Goodies can also be extremely complex and powerful such as the [Calculator](https://duckduckgo.com/?q=%28879+*+14%29+%2F+12) or [Timezone Converter](https://duckduckgo.com/?q=4pm+EST+to+GMT) Goodies. Contributors have used Goodies to do additional cool things like [generate passwords](https://duckduckgo.com/?q=password+15+strong&ia=answer) and [create QR codes](https://duckduckgo.com/?q=qr+duckduckhack.com&ia=answer).
10 |
11 | ### Goodie Quick Start
12 |
13 | If you're new to DuckDuckHack or Perl, writing a simple Goodie Instant Answer is probably the quickest and easiest way to get started with DuckDuckHack. The Goodie [Quick Start Tutorial](https://duck.co/duckduckhack/goodie_quickstart) was created to help you dive right in.
14 |
15 | The [Goodie Quick Start](https://duck.co/duckduckhack/goodie_quickstart) is a hands-on, simple way to understand the Goodie framework, going from zero to a working Instant Answer. It's the best preparation for contributing to DuckDuckHack.
16 |
17 | ### Create a Goodie Cheat Sheet
18 |
19 | A popular use of Goodies is creating cheat sheet Instant Answers - for example, a cheat sheet for [vim](https://duckduckgo.com/?q=vim+cheat+sheet&ia=answer) or [tmux](https://duckduckgo.com/?q=tmux+cheat+sheet&ia=answer). We've made it exceptionally quick and easy to [contribute a Cheat Sheet](https://duck.co/duckduckhack/goodie_cheat_sheets) by adding a single file to the repository.
20 |
21 | 
22 |
23 | Goodie Cheat Sheets are the quickest way to make a live contribution, and a great place to get started. Learn more about [adding your Goodie Cheat Sheet](https://duck.co/duckduckhack/goodie_cheat_sheets).
24 |
25 | ## Important Goodie Criteria
26 |
27 | - Goodies ***cannot* make HTTP requests**. If it's better served by an external API, it should probably be a [Spice Instant Answer](https://duck.co/duckduckhack/spice_overview).
28 | - Goodies should return an answer in **less than 10ms**. Execution times between 10-50ms require review by the community. Goodies which run longer than 50ms will not be accepted.
29 | - Goodies should use **less than 1MB** in memory. Memory usage greater than 1MB will require review by the community.
30 |
31 | Most Goodies shouldn't have a problem, but if you think your idea might run into these constraints, we're happy to help you think through it. Feel free to email us at [open@duckduckgo.com](mailto:open@duckduckgo.com).
32 |
33 | ## Let Us Know What You're Working On
34 |
35 | **Before you start coding your new Instant Answer, let us know your plans.** By involving us early we can provide guidance and potentially save you a lot of time and effort.
36 |
37 | Email us at [open@duckduckgo.com](mailto:open@duckduckgo.com) with what idea you're working on and how you're thinking of going about it.
38 |
--------------------------------------------------------------------------------
/duckduckhack/testing/testing_triggers.md:
--------------------------------------------------------------------------------
1 | ## Testing
2 |
3 | Testing is crucial to ensuring a smooth integration process. This section of the documentation walks you through the process of testing everything that you've written so far. Don't forget to write your test files!
4 |
5 | ## Interactive Testing
6 |
7 | Interactive command-line testing is available using DuckPAN for **Goodie** and **Spice** Instant Answer types.
8 |
9 | This section assumes you've set up your development environment and worked through either the [Basic Goodie Tutorial](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_basic_tutorial.md) or the [Basic Spice Tutorial](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_basic_tutorial.md).
10 |
11 | 1. Enter the root directory of your forked Instant Answer repository:
12 |
13 | Log in to Codio and visit the dashboard. In the menu, click Codio > [Dashboard](https://codio.com/home/projects)
14 |
15 | Click on the **DuckDuckHack project**, which you previously forked and cloned.
16 |
17 | Next, open a terminal window if it's not already open. (Tools > Terminal).
18 |
19 | At the command prompt, change into your repository directory, for example:
20 |
21 | ```shell
22 | cd zeroclickinfo-goodies
23 | ```
24 |
25 | The command line prompt will now indicate the repository and branch you are in, for example:
26 |
27 | ```shell
28 | [ codio@border-carlo workspace zeroclickinfo-goodies {master}]$
29 | ```
30 |
31 | 2. Next, use the DuckPAN tool to test your triggers interactively:
32 |
33 | Type this command at the command line.
34 |
35 | ```shell
36 | duckpan query
37 | ```
38 |
39 | This command will present you with an interactive prompt.
40 |
41 | ```shell
42 | Loading Instant Answers...
43 |
44 | (Empty query for ending test)
45 | Query:
46 | ```
47 |
48 | *In some environments, the `duckpan query` command may print a long list of country aliases - that's perfectly fine. The end of the output will still display the `Query:` prompt.*
49 |
50 | **Now type in any query to see the response.**
51 |
52 | Typing a query here is just like using DuckDuckGo.com, except you're only viewing the ZeroClickInfo response, and in its raw form.
53 |
54 | In the following example, we've entered `chars this is a test` into the prompt and received the following response:
55 |
56 | ```shell
57 | Query: chars this is a test
58 |
59 | DDG::ZeroClickInfo {
60 | Parents WWW::DuckDuckGo::ZeroClickInfo
61 | Linear @ISA DDG::ZeroClickInfo, WWW::DuckDuckGo::ZeroClickInfo, Moo::Object
62 | public methods (3) : is_cached, new, ttl
63 | private methods (0)
64 | internals: {
65 | answer 14,
66 | answer_type "chars",
67 | is_cached 1
68 | }
69 | }
70 | ```
71 |
72 | There can be a lot of debugging output. Pay special attention to the **internals** section.
73 |
74 | ```shell
75 | internals: {
76 | answer 14,
77 | answer_type "chars",
78 | is_cached 1
79 | }
80 | ```
81 |
82 | Here you can see the answer returned, as well as any **zci** keywords (by default there will be an **answer\_type** and **is\_cached** value).
83 |
84 | A blank query will exit interactive mode.
85 |
86 | ```shell
87 | Query:
88 |
89 | \_o< Thanks for testing!
90 | ```
91 |
--------------------------------------------------------------------------------
/duckduckhack/testing/testing_location_language_apis.md:
--------------------------------------------------------------------------------
1 | ## Testing with the Location API
2 |
3 | To write a test for a location-aware Instant Answer, you'll need to pass the test function an extra parameter - a `DDG::Request` object, with the location specified. To do this, you'll need to `use DDG::Test::Location` and `use DDG::Request`. Here is a working annotated example excerpted from the [Spice::Snow](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/t/Snow.t) Instant Answer test file. The same process should be used for Goodies.
4 |
5 |
6 |
7 | Note that only a small set of locations are available to be simulated for testing. They are defined in [DDG::Test::Location.pm](https://github.com/duckduckgo/duckduckgo/blob/master/lib/DDG/Test/Location.pm#L18).
8 |
9 |
10 | ```perl
11 | #!/usr/bin/env perl
12 |
13 | use strict;
14 | use warnings;
15 | use Test::More;
16 | use DDG::Test::Spice;
17 |
18 | # These two modules are only necessary when testing with the Location API.
19 | use DDG::Test::Location;
20 | use DDG::Request;
21 |
22 | ddg_spice_test(
23 | [qw( DDG::Spice::Snow )],
24 | # This optional argument to ddg_spice_test is a DDG::Request object.
25 | # The object constructor takes two arguments of its own:
26 | # the query (usually specified in the test_zci),
27 | # and a location object - created by test_location (with a country code).
28 | DDG::Request->new(
29 | query_raw => "is it snowing?",
30 | location => test_location("de")
31 | ) => test_spice(
32 | '/js/spice/snow/'
33 | .'M%C3%B6nchengladbach%2C%20%20Nordrhein-Westfalen%2C%20%20Germany',
34 | call_type => 'include',
35 | caller => 'DDG::Spice::Snow',
36 | ),
37 | # The DDG::Request is used in place of a query string, and isn't necessary
38 | # to be used with every test passed to ddg_spice_test.
39 | 'is it snowing in new york?' => test_spice(
40 | '/js/spice/snow/new%20york',
41 | call_type => 'include',
42 | caller => 'DDG::Spice::Snow',
43 | )
44 | );
45 |
46 | done_testing;
47 | ```
48 |
49 | ## Testing with the Language API
50 |
51 | To write a test for a locale-aware Instant Answer, you'll need to pass the test function an extra parameter - a `DDG::Request` object, with the location specified. To do this, you'll need to `use DDG::Test::Language` and `use DDG::Request`. Here is a quick annotated example testing the language detect feature of the [Translate](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/Translate/Detect.pm) Instant Answer:
52 |
53 | ```perl
54 | #!/usr/bin/env perl
55 |
56 | use strict;
57 | use warnings;
58 | use Test::More;
59 | use DDG::Test::Spice;
60 |
61 | # These two modules are only necessary when testing with the Language API.
62 | use DDG::Test::Language;
63 | use DDG::Request;
64 |
65 | ddg_spice_test(
66 | ["DDG::Spice::Translate::Detect"],
67 | # This optional argument to ddg_spice_test is a DDG::Request oject.
68 | # The two arguments we pass to the constructor are:
69 | # the query we're testing against
70 | # language object, created by calling test_language with a country code
71 |
72 | # Note that the only supported values for test_language are:
73 | # "us" (US English), "de" (German) and "my" (Malay)
74 | DDG::Request->new(
75 | query_raw => "translate good",
76 | language => test_language("de"),
77 | ), test_spice(
78 | '/js/spice/translate/detect/good/de',
79 | caller => "DDG::Spice::Translate::Detect"
80 | )
81 | );
82 |
83 | done_testing;
84 | ```
85 |
--------------------------------------------------------------------------------
/duckduckhack/advanced/language_and_location_apis.md:
--------------------------------------------------------------------------------
1 | ## Language & Location APIs
2 |
3 | Some Instant Answers employ contextual data about the user's search to provide the most relevant results. For example, since weather conditions vary widely around the world, the [Is it snowing?](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/Snow.pm) Instant Answer requires the user's approximate location.
4 |
5 | The [core DDG library](https://github.com/duckduckgo/duckduckgo) provides Goodie and Spice Instant Answers with location and language APIs to provide simple, helpful and delightful results.
6 |
7 | ## Location API
8 |
9 | The [core DDG library](https://github.com/duckduckgo/duckduckgo) provides a Location API. Since Goodie and Spice Instant Answers inherit from this package, their `handle` functions have access to a `$loc` variable which refers to a [Location object](https://github.com/duckduckgo/duckduckgo/blob/master/lib/DDG/Location.pm).
10 |
11 | This Location object has a number of [useful attributes](https://github.com/duckduckgo/duckduckgo/blob/master/lib/DDG/Location.pm#L6) to help you provide relevant answers:
12 |
13 | ```perl
14 | my @geo_ip_record_attrs = qw( country_code country_code3 country_name region
15 | region_name city postal_code latitude longitude time_zone area_code
16 | continent_code metro_code );
17 | ```
18 |
19 | Example data from `$loc`:
20 |
21 | ```perl
22 | country_code => US
23 | country_code3 => USA
24 | country_name => United States
25 | region => PA
26 | region_name => Pennsylvania
27 | city => Phoenixville
28 | postal_code => 19460
29 | latitude => 40.1246
30 | longitude => -75.5385
31 | time_zone => America/New_York
32 | area_code => 610
33 | continent_code => NA
34 | metro_code => 504
35 | ```
36 |
37 | **Note:** When testing Instant Answers interactively with `duckpan`, the location will **always** point to "Phoenixville, Pennsylvania, United States":
38 |
39 | ```perl
40 | my $location = join(", ", $loc->city, $loc->region_name, $loc->country_name);
41 | # "Phoenixville, Pennsylvania, United States"
42 | ```
43 |
44 | For assistance with specifying the location to be used in automated testing, please refer to the [Location API testing guide](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/testing/testing_location_language_apis.md).
45 |
46 | Naturally, once your Instant Answer is live, `$loc` will refer to the appropriate location.
47 |
48 | ## Language API
49 |
50 | The [core DDG library](https://github.com/duckduckgo/duckduckgo) exposes a Language API which Goodie and Spice Instant Answers can access in their `handle` functions. The language data is contained in the `$lang` variable.
51 |
52 |
53 |
54 | `$lang` refers to a [Language object](https://github.com/duckduckgo/duckduckgo/blob/master/lib/DDG/Language.pm) with the following properties:
55 |
56 | ```perl
57 | my @language_attributes = qw( flagicon flag_url name_in_local rtl locale nplurals name_in_english);
58 | ```
59 |
60 | Example data from `$lang`:
61 |
62 | ```perl
63 | 'nplurals' => 2,
64 | 'name_in_local' => 'English of United States',
65 | 'rtl' => 0,
66 | 'flag_url' => 'https://duckduckgo.com/f2/us.png',
67 | 'name_in_english' => 'English of United States',
68 | 'locale' => 'en_US',
69 | 'flagicon' => 'us'
70 | ```
71 |
72 | **Note**: The user's locale does not imply their preferred language. It simply provides the locale based on the user's IP. Thus, the locale should not be used to determine the display language for an Instant Answer.
73 |
74 | When testing interactively with `duckpan`, the locale will always be set to `en_US`.
75 |
76 | It is possible to set different locales when running automated tests. Please refer to the [Language API testing guide](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/testing/testing_location_language_apis.md) for more information.
77 |
--------------------------------------------------------------------------------
/templates/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Please use this template as a starting point for any CONTRIBUTING.md's. Make sure to replace **"\"** with the correct repository name.
2 |
3 | ------
4 |
5 | # Contributing to the **\** repository
6 |
7 | 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.
8 |
9 | ## Getting Started
10 |
11 | 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.
12 |
13 | ## Submitting a **Bug** or **Suggestion**
14 |
15 | - Firstly, please make sure the bug is related to the **\** repository. If this bug is about the DuckDuckGo API, or the relevancy of our search results, please visit our feedback page at . If you're unsure, its best to use the feedback page (your message will be passed along to the correct people).
16 |
17 | - Check the **\** [issues](#link-to-issues) to see if an issue already exists for the given bug or suggestion
18 | - If one doesn't exist, create a GitHub issue in the **\** repository
19 | - Clearly describe the bug/improvement, including steps to reproduce when it is a bug
20 | - If one already exists, please add any additional comments you have regarding the matter
21 |
22 | If you're submitting a **pull request** (bugfix/addition):
23 | - Fork the **\** repository on GitHub
24 |
25 | ## Making Changes
26 |
27 | - Before making any changes, refer to the [DuckDuckHack Styleguide](https://dukgo.com/duckduckhack/code_styleguide) to ensure your changes are made in the correct fashion
28 | - Make sure your commits are of a reasonable size. They shouldn't be too big (or too small)
29 | - Make sure your commit messages effectively explain what changes have been made, and please identify which Instant Answer or file has been modified:
30 |
31 | ```shell
32 | CONTRIBUTING.md - Added the example commit message because it was missing
33 | ```
34 |
35 | is much better than:
36 |
37 | ```shell
38 |
39 | ```
40 |
41 | - Make sure you have added the necessary tests for your changes
42 | - Run `dzil test` (executes all tests in t/) to ensure nothing else was accidentally broken
43 | - If your change affects an Instant Answer, remember to add yourself to the Metadata attribution list in the appropriate `.pm` file
44 |
45 | ## Submitting Changes
46 |
47 | 1. Commit your changes.
48 |
49 | ```shell
50 | git commit -a -m "My first Instant Answer that does X is ready to go!"
51 | ```
52 |
53 | 2. Get your commit history [how you like it](http://book.git-scm.com/4_interactive_rebasing.html).
54 |
55 | ```shell
56 | git rebase -i origin/master
57 | ```
58 |
59 | or
60 |
61 | ```shell
62 | git pull --rebase origin/master
63 | ```
64 |
65 | 3. Push your forked repository back to GitHub.
66 |
67 | ```shell
68 | git push
69 | ```
70 |
71 | 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!
72 | Check out the [Metadata documentation](https://dukgo.com/duckduckhack/metadata) for detailed instructions on how to include your name and links.
73 |
74 | 5. Go into GitHub and submit a [pull request!](http://help.github.com/send-pull-requests/) to the **\** repository, making sure to use the **\** repository's **[Pull Request Template](#link-to-file)**. This will let us know about your changes and start the conversation about integrating it into the live code.
75 |
--------------------------------------------------------------------------------
/duckduckhack/spice/spice_triggers.md:
--------------------------------------------------------------------------------
1 | ## Triggers
2 |
3 | There are two types of triggers, **words** and **regex**. We insist that you use word triggers whenever possible as they are simpler and faster.
4 |
5 | [Word trigger example](http://duck.co/duckduckhack/spice_triggers#word-triggeres)
6 |
7 | ```perl
8 | triggers start => "trigger my instant answer", "trigger myIA", "myIA";
9 | ```
10 |
11 | [Trigger locations](http://duck.co/duckduckhack/spice_triggers#trigger-locations)
12 |
13 | - `start` — Word exists at the start of the query
14 | - `end` — Word exists at the end of the query
15 | - `startend` — Word is at the beginning or end of the query
16 | - `any` — Word is anywhere in the query
17 |
18 | ## Word Triggers
19 |
20 | ### Usage
21 |
22 | ```perl
23 | triggers =>
24 | ```
25 |
26 |
27 |
28 | #### Examples
29 |
30 | ```perl
31 | triggers start => "trigger my instant answer", "trigger myIA", "myIA";
32 | ```
33 |
34 | or
35 |
36 | ```perl
37 | @triggers = qw(these are separate triggers for my instant answer);
38 | triggers any => @triggers;
39 | ```
40 |
41 | or
42 |
43 | ```perl
44 | triggers start => "starting phrase of query";
45 | triggers end => "ending phrase of query";
46 | ```
47 |
48 | ## Trigger Locations
49 |
50 | - `start` — Word exists at the start of the query
51 | - `end` — Word exists at the end of the query
52 | - `startend` — Word is at the beginning or end of the query
53 | - `any` — Word is anywhere in the query
54 |
55 | **Note:** You can combine several trigger statements if, for example, you want certain words or phrases to be **startend** but others to be **start**. The [Average Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Average.pm#L5) demonstrates the usage of multiple Word trigger statements.
56 |
57 | ## Regex Triggers
58 |
59 | ### Usage
60 |
61 | ```perl
62 | triggers =>
63 | ```
64 |
65 |
66 |
67 | #### Examples
68 |
69 | ```perl
70 | triggers query_lc => qr/trigger (?:my|your|our) instant answer/;
71 | ```
72 |
73 | or
74 |
75 | ```perl
76 | my $regex = qr/^this is an? instant answer regexp$/;
77 | triggers query_raw => $regex;
78 | ```
79 |
80 | #### Query Formats
81 |
82 | - `query_raw` — The query in its original form, with whitespace and case preserved
83 | - `query` — Uniformly whitespaced version of `query_raw`
84 | - `query_lc` — Lowercase version of `query`
85 | - `query_nowhitespace` — `query` with all whitespace removed
86 | - `query_clean` — `query_lc`, but with whitespace and non-alphanumeric ascii removed
87 |
88 | **Note:** You **cannot** combine the use of **Regex Triggers** with **Word Triggers**.
89 |
90 | ## Regex Guards
91 |
92 | 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.
93 |
94 |
95 |
96 | A good example of this is the Base64 goodie. In this case we want to trigger on queries with the form "base64 encode/decode \". 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:
97 |
98 | ```perl
99 | triggers startend => "base64";
100 |
101 | handle remainder => sub {
102 | return unless $_ =~ /^(encode|decode|)\s*(.*)$/i;
103 |
104 | ```
105 |
106 | ## Triggers in Multiple Languages
107 |
108 | 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.**
--------------------------------------------------------------------------------
/duckduckhack/goodie/goodie_helpers.md:
--------------------------------------------------------------------------------
1 | # Goodie Helpers
2 |
3 | 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):
4 |
5 | ```perl
6 | with 'DDG::GoodieRole::RoleName';
7 | ```
8 |
9 |
10 | ## Numbers
11 |
12 | Often matching and outputting numbers intelligently is required, for this the NumberStyler role is ideal:
13 |
14 | ```perl
15 | with 'DDG::GoodieRole::NumberStyler';
16 | # get the regex for something that "looks like a number"
17 | my $number_re = number_style_regex();
18 | my $number_string =~ qr/($number_re)/;
19 |
20 | # get an object that can handle the number
21 | my $styler = number_style_for($number_string);
22 | return unless $styler; # might not be supported
23 |
24 | my $perl_number = $styler->for_computation($number_string);
25 | # now you can use $perl_number however you want
26 |
27 | $perl_number *= 2;
28 |
29 | # when you're ready for output simply use:
30 | $output = $styler->for_display($perl_number);
31 | ```
32 |
33 |
34 | To aid with ambiguity `number_style_for()` can also take an array to parse as a set:
35 |
36 | ```perl
37 | my @numbers = qw(123,450 543.43);
38 | my $styler = number_style_for(@numbers);
39 | ```
40 |
41 |
42 | ## Date Parsing
43 |
44 | Dates are especially complicated as different cultures use different formats; to this end we have the Date role, a simple usage of which is:
45 |
46 | ```perl
47 | with 'DDG::GoodieRole::Dates';
48 |
49 | # get the regex for something that "looks like a date string"; this doesn't mean it *is* a valid date
50 | my $datestring_regex = datestring_regex();
51 | my $probable_date = qr/($datestring_regex)/i;
52 |
53 | # returns a DateTime object or undef if the date is invalid
54 | my $parsed_date = parse_datestring_to_date($probable_date);
55 | return unless $parsed_date;
56 |
57 | # do something with $parsed_date
58 | $parsed_date->add( days => 1 );
59 |
60 | # output in the standard format
61 | $output = date_output_string($parsed_date);
62 | ```
63 |
64 |
65 | To aid in distinguishing ambiguous formats (such as 01/02/2003) multiple strings can be parsed collectively as one format like so:
66 |
67 | ```perl
68 | my @date_strings = qw(01/02/2001 02/13/2002);
69 |
70 | # by parsing as below, it will understand the user meant 2nd Jan 2001 and 13th Feb 2002
71 | my @date_objects = parse_all_datestrings_to_date(@date_strings);
72 | ```
73 |
74 |
75 | Also available for use are:
76 |
77 | * `full_month_regex()` - matches full month names, i.e. January
78 | * `short_month_regex()` - matches short month names. i.e. Feb
79 | * `month_regex()` - matches either short or full month names
80 | * `full_day_of_week_regex()` - matches full weekday i.e. Wednesday
81 | * `short_day_of_week_regex()` - matches short weekday i.e. Thu
82 | * `parse_descriptive_datestring_to_date()` - Takes a string like "next december" and produces the first of the month
83 | * `descriptive_datestring_regex()` - matches strings that can be parsed with `parse_descriptive_datestring_to_date()`
84 | * `parse_formatted_datestring_to_date()` - Takes a string in a variety of formats which can be recognized as exact dates
85 | * `formatted_datestring_regex()` - matches strings that can be parsed with `parse_formatted_datestring_to_date()`
86 | * `date_output_string()` - Takes a DateTime object (or a string which can be parsed into one) and returns a standard formatted output string or an empty string if it cannot be parsed.
87 |
88 | ## HTML Encoding
89 |
90 | In all situations when the query string is output as HTML, it ***must be encoded***; this is important for protection from [cross-site scripting attacks](https://duckduckgo.com/Cross-site_scripting?ia=about). There is a handy helper available for Goodies in the form of:
91 |
92 | ```perl
93 | # simple scalar:
94 | my $safe_to_output = html_enc($query_string);
95 |
96 | # also takes an array:
97 | my @safe_strings = html_enc(@unsafe_strings);
98 | ```
99 |
100 | ## URI Escaping
101 |
102 | It is also possible to URI escape ("percent-encode") strings in accordance with RFC 3986. The Goodie helper works like:
103 |
104 | ```perl
105 | # simple scalar:
106 | my $percent_encoded = uri_esc($uri);
107 |
108 | # also takes an array:
109 | my @percent_encodings = uri_esc(@uris);
110 | ```
111 |
--------------------------------------------------------------------------------
/duckduckhack/instant-answer-display/subtemplates.md:
--------------------------------------------------------------------------------
1 | # Using Sub-templates
2 |
3 | Many [templates](https://duck.co/duckduckhack/templates_reference) allow you to pass *sub-templates* to fill out particular features. For example, to render custom calls-to-action, render content, or decide how to display lists of values.
4 |
5 | The [templates reference](https://duck.co/duckduckhack/templates_reference) indicates which features can be passed a sub-template, and which can only be passed simple types.
6 |
7 | ## Specifying a Sub-template
8 |
9 | Sub-templates are specified when [displaying your Instant Answer](https://duck.co/duckduckhack/display_reference#codetemplatescode_emobjectem_required), under the `options` object of the [`templates` property](https://duck.co/duckduckhack/display_reference#codetemplatescode_emobjectem_required).
10 |
11 | - The **name** of the property is the template feature where you're inserting the sub-template.
12 | - The **value** is the reference to the template.
13 |
14 | For example, for the [Kwixer](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/share/spice/kwixer/kwixer.js) Instant Answer, the `buy` feature of the [`products_detail` template](https://duck.co/duckduckhack/templates_reference#codeproductsdetailcode-template) is set to the custom [`Spice.kwixer.buy` sub-template](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/share/spice/kwixer/buy.handlebars):
15 |
16 | ```javascript
17 | templates: {
18 | ...
19 | options: {
20 | ...
21 | buy: Spice.kwixer.buy
22 | }
23 | }
24 | ```
25 |
26 | *Note that built-in sub-templates are specified as string values, and custom sub-templates are directly referenced as a function. More on these differences below.*
27 |
28 | ### Built-In Sub-templates
29 |
30 | The Instant Answer framework provides several sub-templates which are available to use in particular templates. These are indicated, where relevant, in the [templates reference](https://duck.co/duckduckhack/templates_reference).
31 |
32 | For example, the [`list_detail` template](https://duck.co/duckduckhack/templates_reference#codelist_detailcode-template) works well when the built-in [`record` template](https://duck.co/duckduckhack/templates_reference#codelist_detailcode-template) is set as its `content` feature.
33 |
34 | **Built-in sub-templates are referenced using strings.** For example, the [WHOIS Instant Answer](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/share/spice/whois/whois.js) sets the `content` feature of the [`list_detail` template](https://duck.co/duckduckhack/templates_reference#codelist_detailcode-template) by naming it as a string:
35 |
36 | ```javascript
37 | templates:{
38 | ...
39 | options:{
40 | ...
41 | content: 'record' // a string, because the record template is built-in
42 | }
43 | }
44 | ```
45 |
46 | ### Custom Sub-templates
47 |
48 | Your Instant Answer can supply its own custom-made sub-templates.
49 |
50 | Custom handlebar sub-templates are placed in the `share/INSTANT_ANSWER_TYPE/INSTANT_ANSWER_NAME/` folder, right next to any JavaScript or CSS files. That way, they are accessible to be compiled in the frontend. For example, the path to the [Kwixer Instant Answer](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/share/spice/kwixer/kwixer.js) `buy.handlebars` template file is [`share/spice/kwixer/buy.handlebars`](https://github.com/duckduckgo/zeroclickinfo-spice/tree/master/share/spice/kwixer).
51 |
52 | **Custom sub-templates are set as function references.** Continuing our Kwixer example, the `buy.handlebars` sub-template is referenced in [kwixer.js](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/share/spice/kwixer/kwixer.js) like this:
53 |
54 | ```javascript
55 | templates: {
56 | ...
57 | options: {
58 | ...
59 | buy: Spice.kwixer.buy // a function reference
60 | }
61 | }
62 | ```
63 |
64 | Wondering why this is a variable path - and no '.handlebars' extension? That's because *handlebars* files are compiled into JavaScript functions so they can be used with data. Instead of referencing the file itself, we reference the resulting function. In this example, `share/spice/kwixer/buy.handlebars` is compiled and becomes available as `Spice.kwixer.buy`.
65 |
66 | ## Using Style Guide Elements
67 |
68 | ## Using Available Helpers
69 |
70 | There are a variety of helper functions available to you to make creating sub-templates easier. Learn more about [handlebars helpers](https://duck.co/duckduckhack/handlebars_helpers).
71 |
--------------------------------------------------------------------------------
/duckduckhack/goodie/goodie_advanced_handle_functions.md:
--------------------------------------------------------------------------------
1 | # Advanced Handle Functions
2 |
3 | ## Further Qualifying the Query
4 |
5 | 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.
6 |
7 | There are many techniques for doing this qualification. One of the most popular is to `return` as soon as a query can be disqualified.
8 |
9 | As an 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:
10 |
11 | ```perl
12 | handle remainder => sub {
13 | return unless /^([0-9]+)\s*(?:(?:in|as)\s+)?(hex|hexadecimal|octal|oct|binary|base\s*([0-9]+))$/;
14 | ...
15 | }
16 | ```
17 |
18 | ## Using Files in the Share Directory
19 |
20 | Goodies can use simple text or html input files for display or processing. These files can be read once and reused to answer many queries without cluttering up your source code.
21 |
22 | The `share` function gives each Instant Answer access to a subdirectory of the repository's `share` directory. The subdirectory for your Instant Answer is based on its Perl package name which is transformed from CamelCase to underscore_separated_words.
23 |
24 |
25 |
26 | For example the [Passphrase Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Passphrase.pm) uses the `share` directory to hold data for processing purposes:
27 |
28 | ```perl
29 | my @words = share('words.txt')->slurp;
30 | ```
31 |
32 | Here the `share` function grabs the `words.txt` file, found in `zeroclickinfo-goodies/share/goodie/passphrase/`. The returned object's `slurp` method is called which pushes each line of the file into the `@words` array.
33 |
34 | In another case, the [PrivateNetwork Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/PrivateNetwork.pm) uses its `share` directory to hold files for display purposes:
35 |
36 | ```perl
37 | my $text = scalar share('private_network.txt')->slurp,
38 | my $html = scalar share('private_network.html')->slurp;
39 |
40 | handle sub {
41 | $text, html => $html;
42 | };
43 | ```
44 |
45 | Here each file is grabbed from `share/goodie/private_network/` and `slurp`ed in a `scalar` context. This returns the entire file as a **string** and assigns it to the appropriate variable. In the `handle` function, `$text` and `$html` are returned to display as plain text or HTML Instant Answer.
46 |
47 | 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:
48 |
49 | ```perl
50 | my @shortcuts = share('shortcuts.csv')->slurp(iomode => '<:encoding(UTF-8)');
51 | ```
52 |
53 | 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.
54 |
55 | ## Generating Data Files
56 |
57 | 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.
58 |
59 | 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`.
60 |
61 | ## Stylesheets
62 |
63 | Goodies can load custom stylesheets by adding a `.css` file to their `share` directory, with a filename identical to the parent directory. Goodie stylesheets will be automatically included along with the Goodie's output when triggered. For example, the [RegexCheatSheet Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/RegexCheatSheet.pm) uses the directory `share/goodie/regex_cheat_sheet` which contains a [custom stylesheet](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/share/goodie/regex_cheat_sheet/regex_cheat_sheet.css).
64 |
65 | **Note:** Custom stylesheets should be used sparingly and only when absolutely necessary.
--------------------------------------------------------------------------------
/duckduckhack/spice/spice_overview.md:
--------------------------------------------------------------------------------
1 | ## Spice Overview
2 |
3 | **If you have questions, [request an invite to our Slack team](mailto:QuackSlack@duckduckgo.com?subject=AddMe) and we'll be happy to chat!**
4 |
5 | Spice Instant Answers are triggered by a backend Perl component that then calls the JSON API of an upstream service. The API response is wrapped in a JavaScript function call. You, the Instant Answer author, define this callback function and handle the API's response on the client side, generating the display from the data returned by the API.
6 |
7 | ## Spice API Criteria
8 |
9 | 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.
10 |
11 | First, the technical constraints:
12 |
13 | - 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.
14 | - APIs should respond to requests in **less than one second** (< 1s).
15 | - Avoid **static JSON files**. These often have large payloads and require heavy local processing. Not sure? [Talk to us about your idea](mailto:open@duckduckgo.com).
16 |
17 | Next, API reliability:
18 |
19 | - APIs used should be **reliable**. Pick sources that will be most likely be around and accurate for the foreseeable future.
20 | - APIs created by contributors solely for the purpose of an Instant Answer cannot be accepted.
21 |
22 | Finally, credibility:
23 |
24 | - 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.
25 | - APIs must have the appropriate permissions or rights to serve their information.
26 |
27 | If you're not sure about whether the API you'd like to use fits these criteria, we're happy to help figure it out. Email us over at [open@duckduckgo.com](mailto:open@duckduckgo.com).
28 |
29 | ## Spice Frontend
30 |
31 | The Spice frontend is the code that is triggered by the Perl backend for your spice Instant Answer. It mainly consists of a function (the Spice "callback" function) that takes a JSON formatted, API response as its input and uses the data to display a Spice result at the top of the DuckDuckGo search results page.
32 |
33 | ## Spice Templates
34 |
35 | In order to display the result, the Spice callback function needs to specify a template, which will determine how the result looks. There are several built-in templates to choose from and you are able to choose whichever template works best for the given data and desired output.
36 |
37 | ## Third-Party Libraries
38 |
39 | Aside from HTML and CSS, the Spice frontend also utilizes the following third-party libraries:
40 |
41 | - [jQuery](https://jquery.org) v1.10.2
42 | - and [Handlebars](http://handlebarsjs.com) v1.3.0
43 |
44 | If you're not already familiar with Handlebars, *please* read the [Handlebars documentation](http://handlebarsjs.com) before continuing on. Don't worry if you don't fully understand how to use Handlebars, the examples will explain everything. You should, at the very least, familiarize yourself with Handlebars concepts and terminology before moving on. It should only take a few minutes to read!
45 |
46 |
47 |
48 | Likewise, using jQuery is not required for making a Spice Instant Answer. But, it does offer certain benefits, such as cross-browser compatible implementations of various JavaScript functions. For example, jQuery's `$.each()` should be used in place of the native `Array.prototype.forEach()`, as it does **not** work in IE 6,7,8.
49 |
50 | Later, we will walk you through several examples, ranging from simple to complex, which will explain how to use templates and make your Instant Answers look awesome :)
51 |
52 | ## Spice Files
53 |
54 | A typical Spice Instant Answer requires several files to function properly.
55 | - The Perl files go in the **lib** directory: `lib/DDG/Spice/InstantAnswerName.pm`
56 | - The frontend files (JS, Handlebars, CSS) discussed later go in the **share** directory: `share/spice/instant_answer_name/`
57 |
58 | **\*\*Note** : The file and folder names must adhere to our naming conventions (covered later) in order for everything to function properly.
59 |
60 | ## Let Us Know What You're Working On
61 |
62 | **Before you start coding your new Instant Answer, let us know your plans.** By involving us early we can provide guidance and potentially save you a lot of time and effort.
63 |
64 | Email us at [open@duckduckgo.com](mailto:open@duckduckgo.com) with what idea you're working on and how you're thinking of going about it.
65 |
--------------------------------------------------------------------------------
/duckduckhack/getting-started/contributing.md:
--------------------------------------------------------------------------------
1 | # How Can I Contribute?
2 |
3 | There are several options for contributing to DuckDuckHack, explained below. If you have any questions at any point, feel free to ask on one of our community channels:
4 |
5 | - [Request invite to our Slack team](mailto:QuackSlack@duckduckgo.com?subject=AddMe)
6 | - [DuckDuckHack mailing list](https://duck.co/redir/?u=https%3A%2F%2Fwww.listbox.com%2Fsubscribe%2F%3Flist_id%3D197814)
7 | - Do not hesitate to email us directly at [open@duckduckgo.com](mailto:open@duckduckgo.com).
8 |
9 | ## New? Make Your First Contribution Today
10 |
11 | If this is your first time contributing to [DuckDuckHack](http://www.duckduckhack.com), you have two great ways to quickly make your first commit:
12 |
13 | **1. Make a [Cheat Sheet](https://duck.co/duckduckhack/goodie_cheat_sheets)**
14 |
15 | Cheat sheets are a super-easy way to contribute to the live DuckDuckGo AnswerBar very quickly, by editing a single file. Cheat sheets can be about anything, from Emacs and Vim to Game of Thrones house names or wine pairings.
16 |
17 | **2. Create a simple, complete "Hello World" Goodie with our [Quick Start Tutorial](https://duck.co/duckduckhack/goodie_quickstart)**
18 |
19 | This short tutorial will lead you through all the parts of building a full-loop Goodie. This is a perfect place to start if you have an idea for an original Instant Answer.
20 |
21 | ## Create a New Instant Answer
22 |
23 | Once you're comfortable with the workflow and how Goodies work, we're excited to have you create your own original Instant Answer:
24 |
25 | **1. Choose an idea**
26 |
27 | Bring your own idea, or check out the ideas forum - especially [top voted answer ideas](https://duck.co/ideas/status/3?table_lnKRpLENwO2NUmZUyukQpw_sort=votes).
28 |
29 | Think of the searches you do most often:
30 |
31 | - What has always frustrated you about the results?
32 | - What do you wish "just worked?"
33 | - Is there a website or source of data that would help answer most/all of those searches?
34 |
35 | For additional inspiration, we recommend browsing examples of [live Instant Answers](https://duck.co/ia).
36 |
37 | **2. Plan your implementation**
38 |
39 | The first step is to research and plan your Instant Answer. Consider [the best way to implement](https://duck.co/duckduckhack/determine_your_instant_answer_type) your idea, and review the [docs and guidelines](https://duck.co/duckduckhack/ddh-intro) that apply.
40 |
41 | **3. Involve us**
42 |
43 | Before you start coding, [let us know your plans](mailto:open@duckduckgo.com). By involving us early we can provide guidance and potentially save you a lot of time and effort. Email us at [open@duckduckgo.com](mailto:open@duckduckgo.com) with what idea you're working on and how you're thinking of going about it.
44 |
45 | In addition, we'll promptly set up a [central Instant Answer page](http://www.duck.co/ia) on the community platform so others can know you're working on it and how they can help you.
46 |
47 | This sample will help you craft your message:
48 |
49 | ```text
50 | To: open@duckduckgo.com
51 | Subject: Awesome Instant Answer Idea
52 |
53 | I'd like to make an Instant Answer to help people searching for !
54 | When someone searches for , it would be cool if they could see .
55 | I'm going to accomplish this with a type Instant Answer.
56 | This is the data source: .
57 | This is the related Duck.co idea: .
58 | This is my Github username: .
59 |
60 | Thanks!
61 |
62 | PS: DuckDuckGo is awesome!
63 | ```
64 |
65 | ## Improve an Existing Instant Answer
66 |
67 | Another great way to contribute is to improve an existing, live Instant Answer. It's a great way to get further acquainted with Instant Answers, as well as get implementation ideas. (Many contributors report completing their first fix within two hours of forking the repository!)
68 |
69 | **1. Choose a "low-hanging fruit"**
70 |
71 | We've made sure to identify these throughout our repositories for new contributors.
72 |
73 | - [Goodie Low Hanging Fruit](https://github.com/duckduckgo/zeroclickinfo-goodies/issues?q=is%3Aopen+is%3Aissue+label%3A%22Low-Hanging+Fruit%22) ([Goodie docs](https://duck.co/duckduckhack/goodie_overview))
74 | - [Spice Low Hanging Fruit](https://github.com/duckduckgo/zeroclickinfo-spice/issues?q=is%3Aopen+is%3Aissue+label%3A%22Low-Hanging+Fruit%22) ([Spice docs](https://duck.co/duckduckhack/spice_overview))
75 |
76 | **2. Dive in**
77 |
78 | Go ahead and comment on any issues you're interested in helping with. Let us know what you're thinking and if you'd like any help or guidance.
79 |
80 | As always, feel free to [ask us anything](mailto:open@duckduckgo.com), and don't forget the handy [Instant Answer documentation](https://duck.co/duckduckhack/ddh-intro).
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/duckduckhack/submitting-your-instant-answer/metadata.md:
--------------------------------------------------------------------------------
1 | # Instant Answer Metadata
2 |
3 | Including metadata helps us to categorize and describe your Instant Answer. This document explains the different types of metadata that you may add to the source code of your Instant Answer.
4 |
5 | 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:
6 |
7 | ```perl
8 |
9 | name "AlternativeTo";
10 | primary_example_queries "alternative to notepad";
11 | secondary_example_queries "alternative to photoshop for mac", "free alternative to spotify for windows";
12 | description "Find software alternatives";
13 | icon_url "/i/alternativeto.net.ico";
14 | source "AlternativeTo";
15 | code_url "https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/AlternativeTo.pm";
16 | topics "everyday", "programming";
17 | category "computing_tools";
18 | attribution github => ['https://github.com/Getty','Torsten Raudssus'],
19 | twitter => ['https://twitter.com/raudssus','Torsten Raudssus'];
20 | ```
21 |
22 | Metadata will be used in several places relating to your Instant Answer, including its [IA Page](https://duck.co/ia/view/alternative_to). Below is an explanation of each available property.
23 |
24 | ------
25 |
26 | ## name
27 |
28 | A unique name for this Instant Answer.
29 |
30 | While this can be arbitrary, it is considered good practice to have the chosen name be similar to the Perl package in which it is contained, e.g., DDG::Spice::RedditSubSearch.
31 |
32 | ```perl
33 | name "Subreddit Search";
34 | ```
35 |
36 | ## source
37 |
38 | The name of the data source used for your Instant Answer.
39 |
40 | ```perl
41 | source "Reddit";
42 | ```
43 |
44 | ## icon_url (optional)
45 |
46 | The favicon URL for the data source used.
47 |
48 | **Note:** The favicon is not always located at `http://domain/favicon.ico`. It is often given as an explicit URL in the HTML header as `x-icon`, `apple-touch-icon` or similar.
49 |
50 | Favicons can sometimes be found by searching for the data source on DuckDuckGo. If a favicon exists, we will display it beside any results from that domain. Feel free to use our link from there.
51 |
52 | ```perl
53 | icon_url "http://www.reddit.com/favicon.ico";
54 | ```
55 |
56 | or, for DuckDuckGo-sourced favicons,
57 |
58 | ```perl
59 | icon_url "/i/reddit.com.ico";
60 | ```
61 |
62 | ## description
63 |
64 | A succinct explanation of what the Instant Answer does. For clarity, *exclude* the source name if possible.
65 |
66 | ```perl
67 | description "Search for Subreddits";
68 | ```
69 |
70 | ## primary_example_queries
71 |
72 | Examples of the most common types of queries which will trigger the Instant Answer.
73 |
74 | ```perl
75 | primary_example_queries "/r/pizza", "subreddit nature";
76 | ```
77 |
78 | ## secondary_example_queries (optional)
79 |
80 | Examples of other, less common, trigger words or phrases for the Instant Answer, if applicable.
81 |
82 | ```perl
83 | secondary_example_queries "r/accounting";
84 | ```
85 |
86 | ## category
87 |
88 | The category into which your Instant Answer best fits.
89 |
90 |
91 |
92 | Supported categories include:
93 |
94 | - bang
95 | - calculations
96 | - cheat_sheets
97 | - computing_info
98 | - computing_tools
99 | - conversions
100 | - dates
101 | - entertainment
102 | - facts
103 | - finance
104 | - food
105 | - formulas
106 | - forums
107 | - geography
108 | - ids
109 | - language
110 | - location_aware
111 | - physical_properties
112 | - programming
113 | - q/a
114 | - random
115 | - reference
116 | - special
117 | - software
118 | - time_sensitive
119 | - transformations
120 |
121 | **Note:** Instant Answers may specify ***exactly one*** category.
122 |
123 | ```perl
124 | category "forums";
125 | ```
126 |
127 | ## topics
128 |
129 | A list of the topics to which your Instant Answer applies.
130 |
131 |
132 |
133 | Supported topics include:
134 |
135 | - everyday
136 | - economy\_and\_finance
137 | - computing
138 | - cryptography
139 | - entertainment
140 | - food_and_drink
141 | - gaming
142 | - geek
143 | - geography
144 | - math
145 | - music
146 | - programming
147 | - science
148 | - social
149 | - special_interest
150 | - sysadmin
151 | - travel
152 | - trivia
153 | - web_design
154 | - words\_and\_games
155 |
156 | **Note:** Instant Answers may specify ***multiple*** topics.
157 |
158 | ```perl
159 | topics "social", "entertainment", "special_interest";
160 | ```
161 |
162 | ## code_url
163 |
164 | URL for the Instant Answer code on github.
165 |
166 | ```perl
167 | code_url "https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/RedditSubSearch.pm";
168 | ```
169 |
170 | ## attribution
171 |
172 | Information about you, the author.
173 |
174 |
175 |
176 | Supported attribution sources include:
177 |
178 | - email
179 | - twitter
180 | - web
181 | - github
182 | - facebook
183 | - cpan
184 |
185 | **Note:** For each attribution type, you may provide either a single string or an array reference with two values.
186 |
187 | If a single string is given, it will be used to create a link to the defined profile and **also** serve as the **text** for the link.
188 |
189 | When an array reference is provided, the first element will be used to create the link while the second will be used as the text for the link.
190 |
191 | The same attribution type can appear multiple times if necessary, for example when there is more than one contibutor.
192 |
193 | ```perl
194 | attribution twitter => "mithrandiragain",
195 | github => ["MithrandirAgain", "Gary Herreman"],
196 | web => ['http://atomitware.tk/mith', 'MithrandirAgain'],
197 | github => ["jarmokivekas", "Jarmo Kivekas"];
198 | ```
199 |
--------------------------------------------------------------------------------
/duckduckhack/ddh-prev-next.json:
--------------------------------------------------------------------------------
1 | {
2 | "ddh-intro.md": {
3 | "prev": [],
4 | "next": ["contributing.md"]
5 | },
6 |
7 | "contributing.md": {
8 | "prev": ["ddh-intro.md"],
9 | "next": ["determine_your_instant_answer_type.md"]
10 | },
11 |
12 | "determine_your_instant_answer_type.md": {
13 | "prev": ["contributing.md"],
14 | "next": ["setup_dev_environment.md"]
15 | },
16 |
17 | "setup_dev_environment.md": {
18 | "prev": ["determine_your_instant_answer_type.md"],
19 | "next": ["goodie_overview.md", "spice_overview.md", "fathead_overview.md", "longtail_overview.md"]
20 | },
21 |
22 | "goodie_overview.md": {
23 | "prev": ["determine_your_instant_answer_type.md"],
24 | "next": ["goodie_quickstart.md"]
25 | },
26 |
27 | "goodie_quickstart.md": {
28 | "prev": ["goodie_overview.md"],
29 | "next": ["goodie_basic_tutorial.md"]
30 | },
31 |
32 | "goodie_basic_tutorial.md": {
33 | "prev": ["goodie_quickstart.md"],
34 | "next": ["goodie_triggers.md"]
35 | },
36 |
37 | "goodie_triggers.md": {
38 | "prev": ["goodie_basic_tutorial.md"],
39 | "next": ["goodie_advanced_handle_functions.md"]
40 | },
41 |
42 | "goodie_displaying.md": {
43 | "prev": ["goodie_triggers.md"],
44 | "next": ["goodie_advanced_handle_functions.md"]
45 | },
46 |
47 | "goodie_advanced_handle_functions.md": {
48 | "prev": ["goodie_triggers.md"],
49 | "next": ["goodie_helpers.md"]
50 | },
51 |
52 | "goodie_helpers.md": {
53 | "prev": ["goodie_advanced_handle_functions.md"],
54 | "next": ["goodie_cheat_sheets.md"]
55 | },
56 |
57 | "goodie_cheat_sheets.md": {
58 | "prev": ["goodie_helpers"],
59 | "next": []
60 | },
61 |
62 | "spice_overview.md": {
63 | "prev": ["determine_your_instant_answer_type.md"],
64 | "next": ["spice_basic_tutorial.md"]
65 | },
66 |
67 | "spice_basic_tutorial.md": {
68 | "prev": ["spice_overview.md"],
69 | "next": ["spice_triggers.md"]
70 | },
71 |
72 | "spice_triggers.md": {
73 | "prev": ["spice_basic_tutorial.md"],
74 | "next": ["spice_displaying.md"]
75 | },
76 |
77 | "spice_displaying.md": {
78 | "prev": ["spice_triggers.md"],
79 | "next": ["spice_frontend_walkthroughs.md"]
80 | },
81 |
82 | "spice_frontend_walkthroughs.md": {
83 | "prev": ["spice_displaying.md"],
84 | "next": ["spice_advanced_backend.md"]
85 | },
86 |
87 | "spice_advanced_backend.md": {
88 | "prev": ["spice_frontend_walkthroughs.md"],
89 | "next": ["spice_advanced_frontend.md"]
90 | },
91 |
92 | "spice_advanced_frontend.md": {
93 | "prev": ["spice_advanced_backend.md"],
94 | "next": ["spice_js_api.md"]
95 | },
96 |
97 | "spice_js_api.md": {
98 | "prev": ["spice_advanced_frontend.md"],
99 | "next": ["spice_perl_api.md"]
100 | },
101 |
102 | "spice_perl_api.md": {
103 | "prev": ["spice_js_api.md"],
104 | "next": ["spice_attributes.md"]
105 | },
106 |
107 | "spice_attributes.md": {
108 | "prev": ["spice_perl_api.md"],
109 | "next": ["testing_triggers.md"]
110 | },
111 |
112 | "fathead_overview.md": {
113 | "prev": ["determine_your_instant_answer_type.md"],
114 | "next": ["fathead_basic_tutorial.md"]
115 | },
116 |
117 | "fathead_basic_tutorial.md": {
118 | "prev": ["fathead_overview.md"],
119 | "next": ["testing_triggers.md"]
120 | },
121 |
122 | "longtail_overview.md": {
123 | "prev": ["determine_your_instant_answer_type.md"],
124 | "next": ["longtail_basic_tutorial.md"]
125 | },
126 |
127 | "longtail_basic_tutorial.md": {
128 | "prev": ["longtail_overview.md"],
129 | "next": []
130 | },
131 |
132 | "display_reference.md": {
133 | "prev": [],
134 | "next": ["templates_overview.md"]
135 | },
136 |
137 | "templates_overview.md": {
138 | "prev": ["display_reference.md"],
139 | "next": ["template_groups.md"]
140 | },
141 |
142 | "template_groups.md": {
143 | "prev": ["templates_overview.md"],
144 | "next": ["templates_reference.md"]
145 | },
146 |
147 | "templates_reference.md": {
148 | "prev": ["templates_overview.md"],
149 | "next": ["subtemplates.md"]
150 | },
151 |
152 | "subtemplates.md": {
153 | "prev": ["templates_reference.md"],
154 | "next": ["handlebars_helpers.md"]
155 | },
156 |
157 | "handlebars_helpers.md": {
158 | "prev": ["subtemplates.md"],
159 | "next": ["design_styleguide.md"]
160 | },
161 |
162 | "design_styleguide.md": {
163 | "prev": ["handlebars_helpers.md"],
164 | "next": [""]
165 | },
166 |
167 | "testing_triggers.md": {
168 | "prev": ["determine_your_instant_answer_type.md"],
169 | "next": ["testing_html.md"]
170 | },
171 |
172 | "testing_html.md": {
173 | "prev": ["testing_triggers.md"],
174 | "next": ["test_files.md"]
175 | },
176 |
177 | "test_files.md": {
178 | "prev": ["testing_html.md"],
179 | "next": ["testing_location_language_apis.md"]
180 | },
181 |
182 | "testing_location_language_apis.md": {
183 | "prev": ["test_files.md"],
184 | "next": []
185 | },
186 |
187 | "preparing_for_a_pull_request.md" : {
188 | "prev" : ["testing_location_language_apis.md"],
189 | "next" : ["metadata.md"]
190 | },
191 |
192 | "metadata.md": {
193 | "prev": ["preparing_for_a_pull_request.md"],
194 | "next": ["submission_and_review.md"]
195 | },
196 |
197 | "submission_and_review.md": {
198 | "prev": ["metadata.md"],
199 | "next": []
200 | },
201 |
202 | "language_and_location_apis.md": {
203 | "prev": [],
204 | "next": ["testing_location_language_apis.md"]
205 | },
206 |
207 | "other_development_environments.md": {
208 | "prev": [],
209 | "next": ["code_styleguide.md"]
210 | },
211 |
212 | "code_styleguide.md": {
213 | "prev": ["other_development_environments.md"],
214 | "next": ["common_pitfalls.md"]
215 | },
216 |
217 | "common_pitfalls.md": {
218 | "prev": ["code_styleguide.md"],
219 | "next": ["how_to_qa.md"]
220 | },
221 |
222 | "how_to_qa.md": {
223 | "prev": ["common_pitfalls.md"],
224 | "next": ["video-tutorials.md"]
225 | },
226 |
227 | "video-tutorials.md": {
228 | "prev": ["how_to_qa.md"],
229 | "next": ["faq.md"]
230 | },
231 |
232 | "faq.md": {
233 | "prev": ["video-tutorials.md"],
234 | "next": []
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/duckduckhack/ddh-index.md:
--------------------------------------------------------------------------------
1 | # DuckDuckHack Documentation Index
2 |
3 | - **Getting Started**
4 | - [Welcome!](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/getting-started/ddh-intro.md)
5 | - [How to Contribute](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/getting-started/contributing.md)
6 | - [Determine Your Instant Answer Type](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/getting-started/determine_your_instant_answer_type.md)
7 | - [Setup Your Development Environment](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/getting-started/setup_dev_environment.md)
8 |
9 | - **Goodie**
10 | - [Overview](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_overview.md)
11 | - [Quick Start](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_quickstart.md)
12 | - [Basic Tutorial](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_basic_tutorial.md)
13 | - [Triggers Overview](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_triggers.md)
14 | - [Goodie Display](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_displaying.md)
15 | - [Advanced Handle Functions](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_advanced_handle_functions.md)
16 | - [Helpers](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_helpers.md)
17 | - [Creating Cheat Sheets](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_cheat_sheets.md)
18 | - [FAQ](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/faq.md#goodie)
19 |
20 | - **Spice**
21 | - [Overview](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_overview.md)
22 | - [Basic Tutorial](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_basic_tutorial.md)
23 | - [Triggers Overview](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/spice_triggers.md)
24 | - [Spice Display](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_displaying.md)
25 | - [More Spice Tutorials](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_frontend_walkthroughs.md)
26 | - [Advanced Backend](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_advanced_backend.md)
27 | - [Advanced Frontend](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_advanced_frontend.md)
28 | - [JavaScript API Reference](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_js_api.md)
29 | - [Perl API Reference](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_perl_api.md)
30 | - [Spice Attributes](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_attributes.md)
31 | - [FAQ](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/faq.md#spice)
32 |
33 | - **Fathead**
34 | - [Overview](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/fathead/fathead_overview.md)
35 | - [Basic Tutorial](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/fathead/fathead_basic_tutorial.md)
36 | - [FAQ](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/faq.md#fathead)
37 |
38 | - **Longtail**
39 | - [Overview](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/longtail/longtail_overview.md)
40 | - [Basic Tutorial](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/longtail/longtail_basic_tutorial.md)
41 | - [FAQ](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/faq.md#longtail)
42 |
43 | - **Instant Answer Display**
44 | - [Display Reference](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/instant-answer-display/display_reference.md)
45 | - [Templates Overview](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/instant-answer-display/templates_overview.md)
46 | - [Template Groups](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/instant-answer-display/template_groups.md)
47 | - [Templates Reference](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/instant-answer-display/templates_reference.md)
48 | - [Sub-templates](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/instant-answer-display/subtemplates.md)
49 | - [Handlebars Helpers](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/instant-answer-display/handlebars_helpers.md)
50 | - [Design Styleguide](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/instant-answer-display/design_styleguide.md)
51 |
52 | - **Testing**
53 | - [Triggers](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/testing/testing_triggers.md)
54 | - [Display (HTML/testing/.md)](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/testing/testing_html.md)
55 | - [Test Files](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/testing/test_files.md)
56 | - [Testing with the Location & Language APIs](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/testing/testing_location_language_apis.md)
57 |
58 | - **Submitting Your Instant Answer**
59 | - [Preparing for a Pull Request](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/submitting-your-instant-answer/preparing_for_a_pull_request.md)
60 | - [Metadata](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/submitting-your-instant-answer/metadata.md)
61 | - [Submission and Review](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/submitting-your-instant-answer/submission_and_review.md)
62 |
63 | - **Advanced**
64 | - [Language & Location APIs](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/advanced/language_and_location_apis.md)
65 |
66 | - **Resources**
67 | - [Other Development Environments](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/other_development_environments.md)
68 | - [Code Styleguide](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/code_styleguide.md)
69 | - [Common Pitfalls](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/common_pitfalls.md)
70 | - [How to QA an Instant Answer](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/how_to_qa.md)
71 | - [Video Tutorials](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/video-tutorials.md)
72 | - [FAQ](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/resources/faq.md)
73 |
--------------------------------------------------------------------------------
/duckduckhack/fathead/fathead_overview.md:
--------------------------------------------------------------------------------
1 | # Fathead Instant Answers
2 |
3 | **If you have questions, [request an invite to our Slack team](mailto:QuackSlack@duckduckgo.com?subject=AddMe) and we'll be happy to chat!**
4 |
5 | Fatheads are key-value Instant Answers backed by a database. The keys of the database are typically words or phrases, and they are also used as the triggers for the Instant Answer. When a database key is queried, the corresponding row from the database is returned, which is typically a paragraph of text. Developing a Fathead Instant Answer entails writing a program that generates an **output.txt** file. This tab-delimited file indicates the keys and values for the database, as well as some other important information discussed below. The program may be written in Perl, Python, JavaScript, or Ruby, and if necessary, will be run periodically to keep the database current.
6 |
7 | The **output.txt** file that is generated will be consumed by the DuckDuckGo backend, cleaned up (details below) and then finally entered into an SQL database.
8 |
9 | ## Structure
10 |
11 | Each Fathead Instant Answer has its own directory, which looks like this:
12 |
13 | - ``lib/DDG/Fathead/FatheadName.pm`` – a Perl file that lists some meta information about the Instant Answer
14 |
15 | - ``share/fathead/fathead_name/fetch.sh`` – a shell script called to fetch the data.
16 |
17 | - ``share/fathead/fathead_name/download/`` – a directory to hold temp files created by fetch.sh
18 |
19 | - ``share/fathead/fathead_name/parse.xx`` – the script used to parse the data once it has been fetched. .xx can be .pl, .py, .rb, .js, etc. depending on what language you use.
20 |
21 | - ``share/fathead/fathead_name/parse.sh`` – a shell script wrapper around parse.xx
22 |
23 | - ``share/fathead/fathead_name/README.txt`` – Please include any dependencies here, or other special instructions for people trying to run it. Currently, Fathead Instant Answers require some hand work by DuckDuckGo staff during integration.
24 |
25 | - ``share/fathead/fathead_name/output.txt`` – the output file. It generally should **not** be committed to github, but may be committed if it is small (<1MB).
26 |
27 | - ``share/fathead/fathead_name/data.url`` – an optional pointer to a URL in the cloud somewhere, which contains the data to process.
28 |
29 |
30 | ## Data File Format
31 |
32 | Please name the output file output.txt (tab delimited) but do not store the data file(s) in the repository (as noted above) unless it is under 1MB.
33 |
34 | The output file needs to use UTF-8 encoding so we can process it. Please make sure you write your parse scripts accordingly or we'll probably run into some problems getting it integrated.
35 |
36 | The output format from `parse.xx` depends on the type of content. In any case, it should be a tab delimited file, with one line per entry. Usually there is no need for newline characters, but if there is a need for some reason, escape them with a backslash like `\\\n`. If you want a newline displayed, use ` `
37 |
38 | Every line in the output file must contain thirteen fields, separated by tabs. Some of the fields may be empty. The fields are as follows:
39 |
40 | 1. Full article title. Must be unique across the data set of this Instant Answer. *This field is required.* Examples: `Perl`
41 |
42 | 2. Type of article. `A` for actual articles, `D` for disambiguation pages, or `R` for redirects. *This field is required.*
43 |
44 | 3. *For redirects only.* An alias for a title such as a common misspelling or AKA. The format is the full title of the Redirect, e.g., DuckDuckGo. Examples: `Duck Duck Go -> DuckDuckGo`
45 |
46 | 4. *Ignore.*
47 |
48 | 5. Categories. An article can have multiple categories, and category pages will be created automatically. An example of a category page can be seen at [http://duckduckgo.com/c/Procedural_programming_languages](http://duckduckgo.com/c/Procedural_programming_languages). Multiple categories must be separated by an escaped newline, `\\n`. Categories should generally end with a plural noun. Examples: `Procedural programming languages\\n`
49 |
50 | 6. *Ignore.*
51 |
52 | 7. Related topics. These will be turned into links in the Zero-click Info box. Examples: `[[Perl Data Language]]`. If the link name is different, `[[Perl Data Language|PDL]]`.
53 |
54 | 8. *Ignore.*
55 |
56 | 9. External links. These will be displayed first when an article is shown. The canonical example is an official site, which looks like ``[$url Official site]\\n``. You can have several, separated by an escaped newline, though only a few will be used. You can also have before and after text or put multiple links in one. Examples: ``Before text [$url link text] after text [$url2 second link].\\n``
57 |
58 | 10. *For disambiguation pages only.* Content of disambiguation page. Should be a list, where each item is a link to a page followed by a one sentence description ending in a period. The items have to be separated by ``\n``. Examples: ``*[[Enum.value]], returns the value part of the Enum.\n*[[Pair.value]], returns the value part of the Pair.``
59 |
60 | 11. Image. You can reference an external image that we will download and reformat for display. Examples: ``[[Image:$url]]``
61 |
62 | 12. Abstract. This is the snippet info. It should generally be ONE readable sentence, ending in a period. Examples: ``Perl is a family of high-level, general-purpose, interpreted, dynamic programming languages.``
63 |
64 | 13. URL. This is the full URL for the source. If all the URLs are relative to the main domain, this can be relative to that domain. Examples: `http://www.perl.org`
65 |
66 |
67 |
68 | An example snippet from parse.xx written in [Perl](https://duckduckgo.com/Perl) may look like this:
69 |
70 | ```perl
71 |
72 | my $title = $line[0] || '';
73 | my $type = $line[1] || '';
74 | my $redirect = $line[2] || '';
75 | my $otheruses = $line[3] || '';
76 | my $categories = $line[4] || '';
77 | my $references = $line[5] || '';
78 | my $see_also = $line[6] || '';
79 | my $further_reading = $line[7] || '';
80 | my $external_links = $line[8] || '';
81 | my $disambiguation = $line[9] || '';
82 | my $images = $line[10] || '';
83 | my $abstract = $line[11] || '';
84 | my $source_url = $line[12] || '';
85 |
86 | print "$title\t$type\t\t\t$categories\t\t$see_also\t\t$external_links\t$disambiguation\t$images\t$abstract\t$source_url\n";
87 | ```
88 |
89 | There is a pre-process script that is run on this output, which:
90 |
91 | * Drops duplicates (on `$title`).
92 |
93 | * Reduces `$abstract` to one sentence.
94 |
95 | * Drops records that look like spam.
96 |
97 | * Normalizes spacing.
98 |
99 | * Makes sure the `$abstract` ends in a sentence.
100 |
101 |
102 | ## Code Blocks
103 |
104 | If you want to include a code snippet or another pre-formatted example in the abstract, like the [perl](https://duckduckgo.com/?q=perl+open) Fathead, wrap the code block like this:
105 |
106 | ```html
107 |
code block goes here
108 | ```
109 |
110 | For multiline code snippets, use only `\n` to separate lines:
111 |
112 | ```html
113 |
foo\nbar\nbaz
114 | ```
115 |
116 | ## Notes
117 |
118 | There should be no duplicates in the `$page` (first) variable. If you have multiple things named the same thing you have a number of options:
119 | - make disambiguation pages
120 | - put everything in one snippet
121 | - pick the most general one
122 |
--------------------------------------------------------------------------------
/duckduckhack/testing/test_files.md:
--------------------------------------------------------------------------------
1 | ## Test Files
2 | Good test files can help you quickly test code iterations. They also serve as a functional specification for your code. This specification helps everyone quickly understand and verify the expected behavior of the tested code, improving the quality of the feedback you receive and accelerating the review process.
3 |
4 |
5 |
6 | Every Instant Answer must include a test file in the `t` directory. The test files are run automatically before each release to ensure that all Instant Answers are functioning properly. Properly functioning Instant Answers:
7 |
8 | - ignore any unsuitable queries,
9 | - trigger on the expected queries, and
10 | - provide appropriate answers for the queries handled.
11 |
12 | At a minimum, your tests should cover all of your primary and secondary example queries. If possible, you should also include examples of similar queries on which your code does **not** trigger. If your answer depends on the user's location, please review the [Location API testing guide](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/testing/testing_language_location_apis.md) for help in developing your tests. If your answer depends on the time of day or year, please be sure that your tests will continue to pass no matter when they are run.
13 |
14 | ## Creating Test Files
15 |
16 | If you used `duckpan new` to start your project, a simple test file was automatically created for you. Otherwise, copying the test file from a similar Instant Answer is an easy way to get started. Either way, you are only a few well-placed edits away from a test file suitable for your Instant Answer.
17 |
18 | Your test file should have **the same name** as the package it is testing. For example, the code in `lib/DDG/Goodie/Fortune.pm` is tested by `t/Fortune.t`.
19 |
20 | The standard DuckPAN installation includes Goodie and Spice testing libraries (`DDG::Test::Goodie` and `DDG::Test::Spice`, respectively.) These libraries make it quick and easy to develop tests for your Instant Answer.
21 |
22 | ## Running Test Files
23 |
24 | Tests are run from the root of the repository using the `prove` command included in your Perl distribution. During development, you can quickly run a single test file to verify your changes:
25 |
26 | ```shell
27 | prove -Ilib t/TestName.t
28 | ```
29 |
30 |
31 |
32 | Or all of the tests in the repository's `t` directory:
33 |
34 | ```shell
35 | prove -Ilib t/
36 | ```
37 |
38 | To ensure that you have not inadvertently changed the behavior of other code, you should run the full test suite before submitting your Instant Answer. This is easily accomplished via `duckpan`:
39 |
40 | ```shell
41 | duckpan test
42 | ```
43 |
44 | ## Example Goodie Test File
45 |
46 | Below is the test file of the **RouterPasswords** Goodie, found at [`t/RouterPasswords.t`](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/t/RouterPasswords.t).
47 |
48 |
49 |
50 | ```perl
51 | #!/usr/bin/env perl
52 |
53 | use strict;
54 | use warnings;
55 |
56 | # These modules are necessary for the functions we'll be running.
57 | use Test::More;
58 | use DDG::Test::Goodie;
59 |
60 | # These zci attributes aren't necessary, but if you specify them inside your
61 | # goodie, you'll need to add matching values here to check against.
62 | zci answer_type => 'password';
63 | zci is_cached => 1;
64 |
65 | ddg_goodie_test(
66 | [
67 | # This is the name of the goodie that will be loaded to test.
68 | 'DDG::Goodie::RouterPasswords'
69 | ],
70 | # This is a sample query, just like the user will enter into the DuckDuckGo
71 | # search box.
72 | 'Belkin f5d6130' =>
73 | test_zci(
74 | # The first argument to test_zci is the plain text (default)
75 | # returned from a goodie. If your goodie also returns an HTML
76 | # version, you can pass that along explicitly as the second
77 | # argument. If your goodie is random, you can use regexps instead of
78 | # strings to match against.
79 | 'Default login for the BELKIN F5D6130: Username: (none) Password: password',
80 | html => 'Default login for the BELKIN F5D6130: Username: (none) Password: password'
81 | ),
82 | # You should include more test cases here. Try to think of ways that your
83 | # Instant Answer might break, and add them here to ensure they won't. Here are a
84 | # few others that were thought of for this goodie.
85 | 'Belkin f5d6130 password default' =>
86 | test_zci('Default login for the BELKIN F5D6130: Username: (none) Password: password',
87 | html => 'Default login for the BELKIN F5D6130: Username: (none) Password: password'),
88 | 'default password Belkin f5d6130' =>
89 | test_zci('Default login for the BELKIN F5D6130: Username: (none) Password: password',
90 | html => 'Default login for the BELKIN F5D6130: Username: (none) Password: password'),
91 | 'Belkin f5d6130 password' =>
92 | test_zci('Default login for the BELKIN F5D6130: Username: (none) Password: password',
93 | html => 'Default login for the BELKIN F5D6130: Username: (none) Password: password'),
94 | 'default BELKIN password f5d6130' =>
95 | test_zci('Default login for the BELKIN F5D6130: Username: (none) Password: password',
96 | html => 'Default login for the BELKIN F5D6130: Username: (none) Password: password'),
97 | 'password bELKIN default f5d6130' =>
98 | test_zci('Default login for the BELKIN F5D6130: Username: (none) Password: password',
99 | html => 'Default login for the BELKIN F5D6130: Username: (none) Password: password'),
100 | );
101 |
102 | # This function call is expected by Test::More. It makes sure the program
103 | # doesn't exit before all the tests have been run.
104 | done_testing;
105 | ```
106 |
107 | ## Example Spice Test File
108 |
109 | Below is the test file of the **Xkcd** Spice, found at [`t/Xkcd.t`](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/t/Xkcd.t).
110 |
111 |
112 |
113 | ```perl
114 | #!/usr/bin/env perl
115 |
116 | use strict;
117 | use warnings;
118 |
119 | # These modules are necessary for the functions we'll be running.
120 | use Test::More;
121 | use DDG::Test::Spice;
122 |
123 | ddg_spice_test(
124 | [
125 | # This is the name of the Spice will be loaded to test.
126 | 'DDG::Spice::Xkcd'
127 | ],
128 | # This is a sample query, just like the user will enter into the DuckDuckGo
129 | # search box.
130 | '619 xkcd' => test_spice(
131 | # The first argument is the Spice callback. It includes the javascript
132 | # endpoint and the argument list constructed by the Perl code. In this
133 | # case, the endpoint is '/js/spice/xkcd/', and the argument returned by
134 | # the Perl code is 619.
135 | '/js/spice/xkcd/619',
136 | # This is the Spice calltype. It's almost always set to 'include',
137 | # except for some special cases like FlashVersion which don't make a
138 | # normal API call.
139 | call_type => 'include',
140 | # This is the Spice that should be triggered by the query.
141 | caller => 'DDG::Spice::Xkcd',
142 | # This is the cache value to expect. It's only necessary if you specify
143 | # one in your Spice.
144 | is_cached => 0
145 | ),
146 | # You should include more test cases here. Try to think of ways that your
147 | # Instant Answer might break, and add them here to ensure they won't. Here are is
148 | # another that is tested for this Spice.
149 | 'xkcd' => test_spice(
150 | '/js/spice/xkcd/',
151 | call_type => 'include',
152 | caller => 'DDG::Spice::Xkcd',
153 | is_cached => 0
154 | ),
155 | );
156 |
157 | # This function call is expected by Test::More. It makes sure the program
158 | # doesn't exit before all the tests have been run.
159 | done_testing;
160 | ```
161 |
162 |
--------------------------------------------------------------------------------
/duckduckhack/spice/spice_advanced_backend.md:
--------------------------------------------------------------------------------
1 | ##Spice Handlers
2 |
3 | - [Multiple Placeholders in Spice To URL](http://duck.co/duckduckhack/spice_advanced_backend#Multiple-Placeholders-in-Spice-To-URL)
4 |
5 | - [Returning Multiple Values (to Spice From)](http://duck.co/duckduckhack/spice_advanced_backend#Returning-Multiple-Values-to-Spice-From)
6 |
7 | - [API Keys](http://duck.co/duckduckhack/spice_advanced_backend#api-keys)
8 |
9 | - [JSON -> JSONP](http://duck.co/duckduckhack/spice_advanced_backend#json-gt-jsonp)
10 |
11 | - [Pure JS functions](http://duck.co/duckduckhack/spice_advanced_backend#pure-js-functions)
12 |
13 | - [Caching API Responses](http://duck.co/duckduckhack/spice_advanced_backend#caching-api-responses)
14 |
15 | - [Caching API Calls](http://duck.co/duckduckhack/spice_advanced_backend#caching-api-calls)
16 |
17 | ## Multiple Placeholders in Spice To URL
18 |
19 | 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:
20 |
21 | ```perl
22 | spice from => '(?:([0-9]+)\-([0-9]+)|)';
23 | ```
24 |
25 | Whatever you return from the handle function gets sent to this **spice from** regexp, which then gets fed into the **spice to** API:
26 |
27 | For example, if your `handle` function looked like this:
28 |
29 | ```perl
30 | handle remainder => sub {
31 | ...
32 | if ( $foo ){
33 | my $minMax = "10-100"
34 | return $minMax;
35 | }
36 | return;
37 | }
38 | ```
39 |
40 |
41 |
42 | 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:
43 |
44 | ```perl
45 | spice to => 'http://api.wordnik.com/v4/words.json/randomWord?minLength=$1&maxLength=$2&api_key={{ENV{DDG_SPICE_WORDNIK_APIKEY}}}&callback={{callback}}';
46 | ```
47 |
48 | **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`.
49 |
50 | ## Returning Multiple Values (to Spice From)
51 |
52 | 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).
53 |
54 | ```perl
55 | return $prog, $platform, $license;
56 | ```
57 |
58 | In this case they are URL encoded and joined together with '/' chars, e.g., in this case **$prog/$platform/$license**. Then that full string is fed into the **spice from** regexp.
59 |
60 | ```perl
61 | spice from => '([^/]+)/?(?:([^/]+)/?(?:([^/]+)|)|)';
62 | ```
63 |
64 | ## API Keys
65 |
66 | Some APIs require API keys to function properly like in the [RandWord Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/RandWord.pm). You can insert an API key for testing in the callback function and replace it with a variable reference when submitting. The API key variable should be named using the provider name as a reference. As Wordnik is the API provider used for the [RandWord Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/RandWord.pm) we use `DDG_SPICE_WORDNIK_APIKEY` as the variable name.
67 |
68 | ```perl
69 | spice to => 'http://api.wordnik.com/v4/words.json/randomWord?minLength=$1&maxLength=$2&api_key={{ENV{DDG_SPICE_WORDNIK_APIKEY}}}&callback={{callback}}';
70 | ```
71 |
72 | You can set the variable when you start DuckPAN server like this:
73 |
74 | ```bash
75 | DDG_SPICE_WORDNIK_APIKEY=xyz duckpan server
76 | ```
77 |
78 | Alternatively you can save the API key variable in the `env.ini` file, which DuckPAN will load on start, using:
79 |
80 | ```bash
81 | duckpan env set DDG_SPICE_WORDNIK_APIKEY xyz
82 | ```
83 |
84 | ## JSON -> JSONP
85 |
86 | Some APIs don't do JSONP by default, i.e. don't have the ability to return the JSON object to a callback function. In this case, first you should try to contact the API provider and see if it can be added. Where it cannot, you can tell us to wrap the JSON object return in a callback function like in the [XKCD Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/Xkcd/Display.pm).
87 |
88 | ```perl
89 | spice wrap_jsonp_callback => 1;
90 | ```
91 |
92 | ## Pure JS functions
93 |
94 | 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).
95 |
96 | In cases like these you can define a **spice\_call\_type** as 'self' like this:
97 |
98 | ```perl
99 | spice call_type => 'self';
100 | ```
101 |
102 | Then in the handle function you can return call, e.g.:
103 |
104 | ```perl
105 | return $_ eq 'flash version' ? call : ();
106 | ```
107 |
108 | 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()**.
109 |
110 | ## Caching
111 |
112 | 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.
113 |
114 |
115 |
116 | ### Caching API Responses
117 |
118 | By default, we cache API responses for for **24 hours**. We use [nginx](https://duckduckgo.com/?q=nginx) and get this functionality by using the [proxy_cache_valid](http://wiki.nginx.org/HttpProxyModule#proxy_cache_valid) directive. You can override our default behavior by setting your own `spice proxy_cache_valid` directive like in the [RandWord Spice](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/RandWord.pm):
119 |
120 | ```perl
121 | spice proxy_cache_valid => "200 304 1d";
122 | ```
123 |
124 | This will cache any HTTP 200 and 304 responses for 1 day. You can also force API responses to **not** be cached like so:
125 |
126 | ```perl
127 | spice proxy_cache_valid => "418 1d";
128 | ```
129 |
130 | This is a special declaration that will only cache [418 HTTP](https://duckduckgo.com/?q=HTTP+418) return values for 1 day. Since regular return codes are [200](https://duckduckgo.com/?q=HTTP+200) and [304](https://duckduckgo.com/?q=HTTP+304), nothing will get cached.
131 |
132 | If you expect API response to change very frequently you should lower the caching time. As well, if your API is supposed to return random results (such as the RandWord spice) it makes sense to prevent all caching so every time the spice is trigger a new result will be returned.
133 |
134 | ### Caching API Calls
135 |
136 | When a Spice triggers, its Perl code is used to construct the URL for the API call. It's likely that a given query will always map to the same API call so by default we cache the API calls for a given query for **1 hour**:
137 |
138 | ```
139 | # This query will always make the same API call
140 | "random word" => http://api.wordnik.com/v4/words.json/randomWord
141 | ```
142 |
143 | Sometimes, a given query won't always require the same API call. This scenario generally arises when a Spice Instant Answer uses the Location API and uses it to append the user's location to the API call:
144 |
145 | ```
146 | # This query will NEVER make the same API call, because the location is dynamic
147 | "weather" => http://forecast.io/ddg?q=
148 | ```
149 |
150 | To **turn off** API Call caching, you must set `spice is_cached` to `0` as we do in the [Forecast](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/Forecast.pm) Instant Answer:
151 |
152 | ```perl
153 | spice is_cached => 0;
154 | ```
155 |
156 | This way, every time the Forecast Instant Answer is triggered, **Forecast.pm** will be run, so the correct URL will be built and the current user's location will be used for the API call.
157 |
--------------------------------------------------------------------------------
/duckduckhack/submitting-your-instant-answer/submission_and_review.md:
--------------------------------------------------------------------------------
1 | # Making a Pull Request
2 |
3 | Now that you have completed the [pull request checklist](https://duck.co/duckduckhack/preparing_for_a_pull_request) and added [Metadata](https://dukgo.com/duckduckhack/metadata) to your Instant Answer, you are ready to submit a pull request.
4 |
5 |
6 | ## Committing Your Changes
7 |
8 | The first step in submitting your changes is to commit your changes to your local repository. If you've already done this, you can skip to [submitting a pull request](#submitting-a-pull-request), below.
9 |
10 | Here is how to commit your code in the Codio environment:
11 |
12 | 1. Log in to [Codio](https://codio.com) and visit your [dashboard](https://codio.com/home/projects). (In the menu, click Codio > Dashboard)
13 |
14 | 2. Click on the **DuckDuckHack project**, which you previously forked and cloned.
15 |
16 | 3. Next, open a terminal window if it's not already open. (In the menu, click Tools > Terminal).
17 |
18 | 4. Enter the root directory of your forked Instant Answer repository. For example, for Goodies, enter the following into your terminal:
19 |
20 | ```shell
21 | cd zeroclickinfo-goodies
22 | ```
23 |
24 | Then press enter.
25 |
26 | 5. To add all new files to git, type **`git add .`**, then press enter.
27 |
28 | *This command tells the git repository to include and track changes to the files you've created. Even though the files were physically located in the repository, we need to explicitly tell git to track them.*
29 |
30 | 5. We are now ready to finally commit the changes. Type **`git commit -m "Description of your changes"`** and press **`Enter`**. Git should print some text confirming the changes that have been committed.
31 |
32 | ```
33 | [04:35 PM codio@buffalo-pixel zeroclickinfo-goodies {master}]$ git commit -m "Description of your changes"
34 | [master 6aeb841] Description of your changes
35 | 2 files changed, 56 insertions(+)
36 | create mode 100644 ...
37 | create mode 100644 ...
38 | ```
39 |
40 | 6. Now we'll upload the changes to *our* remote repository on GitHub. Once this step is done, we'll be ready to create a pull request back to the main, original DuckDuckGo repository.
41 |
42 | If you had created a branch for your current contribution then type **`git push origin branch_name`** and press **`Enter`**. If not type **`git push`** and press **`Enter`**. Enter your GitHub Username and password, press **`Enter`** after each. Git will print some text to the Terminal letting you know that your code has been pushed to GitHub.
43 |
44 | ```
45 | [04:35 PM codio@buffalo-pixel zeroclickinfo-goodies {master}]$ git push
46 | Username for 'https://github.com': GitHubUsername
47 | Password for 'https://GitHubUsername@github.com':
48 | Counting objects: 75, done.
49 | Delta compression using up to 4 threads.
50 | Compressing objects: 100% (60/60), done.
51 | Writing objects: 100% (75/75), 11.05 KiB | 0 bytes/s, done.
52 | Total 75 (delta 36), reused 0 (delta 0)
53 | To https://github.com/GitHubUsername/zeroclickinfo-goodies.git
54 | 138f5bc..c69c517 master -> master
55 | ```
56 |
57 |
58 |
59 | ## Submitting a Pull Request
60 |
61 | Clarity is super important in any open source project - especially one with lots of contributors. A pull request is a great, transparent way to review new changes.
62 |
63 | Here's how to submit a pull request to DuckDuckHack:
64 |
65 | 1. Open a **new browser tab** and go to your remote repository. For example, for Goodies: **`https://github.com/YOUR_GITHUB_USERNAME/zeroclickinfo-goodies`**.
66 |
67 | 2. Click the "**Pull Request**" button (grey text, middle of the screen).
68 |
69 | For advanced users, make sure you are on the correct branch where your changes are located.
70 |
71 | 3. Review the changes and click "**Create Pull Request**".
72 |
73 | Make sure there's only **one** Instant Answer per pull request.
74 |
75 | 4. Enter a title for your pull request:
76 |
77 | If your IA is new, use the format: "New {{IA NAME}} {{IA TYPE}}". For example:
78 |
79 | - "New Instagram Spice"
80 | - "New Firefox Cheat Sheet"
81 | - "New Color Hex Goodie"
82 |
83 | If you're submitting a fix, use the format: "{{IA NAME}}: Fixes {{ISSUE}}". For example:
84 |
85 | - "Forecast: Fixes #3434"
86 | - "Cheat Sheet: Fixes #4102"
87 |
88 | (Conveniently, this syntax will auto-close the Github issue when your pull request is merged.)
89 |
90 | 5. For new Instant Answers, copy the "Pull Request Template" for your type of Instant Answer from the links below. Paste it into the "Leave a Comment" text box, and answer the questions.
91 |
92 | - [Cheat Sheet Pull Request Template](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/pull_request_template_cheat_sheet.md)
93 | - [Goodie Pull Request Template](https://raw.githubusercontent.com/duckduckgo/zeroclickinfo-goodies/master/pull_request_template_goodie.md)
94 | - [Spice Pull Request Template](https://raw.githubusercontent.com/duckduckgo/zeroclickinfo-spice/master/pull_request_template_spice.md)
95 | - [Fathead Pull Request Template](https://raw.githubusercontent.com/duckduckgo/zeroclickinfo-fathead/master/pull_request_template_fathead.md)
96 | - [Longtail Pull Request Template](https://raw.githubusercontent.com/duckduckgo/zeroclickinfo-longtail/master/pull_request_template_longtail.md)
97 |
98 | 6. Add a screenshot of your Instant Answer to your answers:
99 |
100 | Go back to your Codio.com browser tab, and open the "Terminal" tab
101 |
102 | Type `duckpan server`, then press enter.
103 |
104 | Click the DuckPAN Server button at the top of Codio, and type in a sample search query that will trigger your Instant Answer.
105 |
106 | Save a screenshot on your computer.
107 |
108 | Go back to your GitHub.com browser tab.
109 |
110 | Drag-and-Drop your screen shot into the textbox. The picture will be uploaded and a link will be generated.
111 |
112 | 7. Finally, click **"Create Pull Request"**!
113 |
114 | Congratulations! You can now sit back and relax. A Community Leader or DDG staff member will review your Goodie in turn, give you any feedback (if necessary) and merge it in.
115 |
116 | Once it's merged, it will be deployed to the site and should be live within a few days. **We'll be sure to let you know once it's live!**
117 |
118 | *For more information on how to create a pull request, GitHub provides excellent [instructions](https://help.github.com/articles/creating-a-pull-request).*
119 |
120 | ## Review Process
121 |
122 | When you submit a pull request, a community leader will assign themselves to your pull request and work with you to get your Instant Answer live on DuckDuckGo.
123 |
124 | All comments and suggestions for your pull request should be discussed publicly in the pull request on Github, so that others can follow the progression. Of course, you can always contact anyone from the community or team if you have questions.
125 |
126 | In addition to the main [open@duckduckgo.com](mailto:open@duckduckgo.com) way to reach us, here are some community leaders who are available to help out:
127 |
128 |
129 |
130 | - [@bradcater](https://github.com/bradcater)
131 | - [@loganom](https://github.com/loganom)
132 | - [@mattr555](https://github.com/mattr555)
133 | - [@mintsoft](https://github.com/mintsoft)
134 | - [@TomBebbington](https://github.com/TomBebbington)
135 | - [@killerfish](https://github.com/killerfish)
136 | - [@MrChrisW](https://github.com/mrchrisw)
137 | - [@javathunderman](https://github.com/javathunderman)
138 |
139 | Here's how the whole process looks, after you submit your pull request:
140 |
141 | 1. A community leader (an experienced member of the community) will work with you on your pull request.
142 | - The community leader will ping [@abeyang](https://github.com/abeyang) (or [@chrismorast](https://github.com/chrismorast)) for any design/interaction feedback.
143 | - The community leader will test and give feedback about your code.
144 | - You discuss and incorporate any applicable feedback.
145 | 2. When the community leader feels that the Instant Answer is ready to go live, they ping [@jagtalon](https://github.com/jagtalon) so that he can set it up on a testing server.
146 | 3. Final review by the internal team.
147 | 4. Your pull request gets merged in and goes live!
148 |
149 | ## Thank you!
150 |
151 | We're excited to have you in our community and we can't wait to see your Instant Answer on DuckDuckGo.com. Your contributions are helping our search engine get better every day. We owe you our deepest gratitude.
152 |
--------------------------------------------------------------------------------
/duckduckhack/instant-answer-display/handlebars_helpers.md:
--------------------------------------------------------------------------------
1 | # Handlebars Helpers
2 |
3 | When creating [custom handlebars sub-templates](https://duck.co/duckduckhack/subtemplates) for your Instant Answer, you have access to a variety of built-in helper functions. In addition to the standard [handlebars helpers](http://handlebarsjs.com/#helpers), the following helpers are provided as part of the Instant Answer framework:
4 |
5 | - [`#concat`](#codeconcatcode): Concatenates all the elements in a collection
6 |
7 | - [`#condense`](#codecondensecode): Shortens a string
8 |
9 | - [`#stripHTML`](#codestriphtmlcode): Strips HTML tags/elements from text
10 |
11 | - [`#loop`](#codeloopcode): Counts from zero to the value of `context`
12 |
13 | - [`#each`](#codeeachcode): Extends Handlebars' built-in `{{each}}` lets you specify optional first and last indices
14 |
15 | - [`#keys`](#codekeyscode): Iterates over the properties of an object and provides a new object containing the "key" and "value"
16 |
17 | - [`include`](#codeincludecode): Loads the specified Handlebars template and applies it with the current context
18 |
19 | - [`plural`](#codepluralcode): Returns the value of `context` and appends the singular or plural form of the specified word
20 |
21 | - [`numFormat`](#codenumformatcode): Delimits a number or string with multiple numbers, using commas or given delimiter
22 |
23 | - [`imageProxy`](#codeimageproxycode): Rewrite a URL as a DuckDuckGo image redirect
24 |
25 | - [`ellipsis`](#codeellipsiscode): Shortens a string by removing words until string length is <= `limit` and appends an ellipsis ('...') to the output
26 |
27 | - [`trim`](#codetrimcode): Removes leading and trailing spaces from text
28 |
29 | ## `#concat`
30 |
31 | **Block Helper**
32 |
33 | Concatenates all the elements in a collection
34 |
35 | An optional item separator can be appended to
36 | each item and an optional conjunction can be
37 | used for the last item.
38 |
39 | Example:
40 |
41 | ```html
42 | {{#concat context sep="," conj="and"}}
43 | {{this}}
44 | {{/concat}}
45 | ```
46 |
47 | when `context` is:
48 | - `['a']` returns: `a`
49 | - `['a', 'b']` returns: `a and b`
50 | - `['a', 'b', 'c']` returns: `a, b and c`
51 |
52 | **Parameters**
53 |
54 | **sep**: *string*, **[optional]** Item separator. Default: `''`
55 |
56 | **conj**: *string*, **[optional]** Final separator, precedes last item. Default: `''`
57 |
58 |
59 | ## `#condense`
60 |
61 | **Block Helper**
62 |
63 | Shortens a string
64 |
65 | An optional maximum string length can be provided if preferred.
66 |
67 | Example:
68 |
69 | `{{condense myString maxlen="135" truncation="..."}}`
70 |
71 | This will output the value of `myString` up to a maximum of 135 characters
72 | (not including the length of the truncation string) and then append
73 | the truncation string to the output
74 |
75 | **Parameters**
76 |
77 | **maxlen**: *number*, **[optional]** Maximum allowed string length. Default: `10`
78 |
79 | **fuzz**: *number*, The allowable deviation from the maxlen, used to allow a sentence/word to complete if it is less than fuzz characters longer than the maxlen
80 |
81 | **{string**, truncation **[optional]** The truncation string. Default: `'...'`
82 |
83 |
84 | ## `#stripHTML`
85 |
86 | **Block Helper**
87 |
88 | Strips HTML tags/elements from text
89 |
90 | Example:
91 |
92 | `{{#stripHTML stringWithHTML}}Here is my string: {{this}}{{/stripHTML}}`
93 |
94 |
95 | ## `#loop`
96 |
97 | **Block Helper**
98 |
99 | Counts from zero to the value of `context` (assuming `context` is a **number**)
100 | applying the content of the block each time
101 |
102 | Note: A maximum of 100 loops is allowed.
103 |
104 | Example:
105 |
106 | ```html
107 | {{#loop star_rating}}
108 |
109 | {{/loop}}
110 | ```
111 |
112 |
113 | ## `#each`
114 |
115 | **Block Helper**
116 |
117 | Extends Handlebars' built-in `{{each}}`
118 | lets you specify optional inclusive first and last indices
119 | to iterate between
120 |
121 | Example:
122 |
123 | `{{#each myArray from="2" to="5"}} ... {{/each}}`
124 |
125 | This will limit the iteration to array indices 2, 3 and 4.
126 |
127 | If `to` is not given, defaults to array (or object) length:
128 |
129 | `{{#each myArray from="2"}} ... {{/each}}`
130 |
131 | will skip the first two items
132 |
133 | If `from` is not given, defaults to 0:
134 |
135 | `{{#each myArray to="5"}} ... {{/each}}`
136 |
137 | will only do the first five items
138 |
139 | **Parameters**
140 |
141 | **from**: *number*, **[optional]** Index to start from. Default: `0`
142 |
143 | **to**: *number*, **[optional]** Index to end on. Default: array/object length
144 |
145 |
146 | ## `#keys`
147 |
148 | **Block Helper**
149 |
150 | Iterates over the properties of an object and provides
151 | a new object containing the "key" and "value" for each
152 |
153 | Example:
154 |
155 | ```html
156 | {{#keys myObject}}
157 | {{key}} : {{value}}
158 | {{/keys}}
159 | ```
160 |
161 |
162 | ## `include`
163 |
164 | Loads the specified Handlebars template and applies it with
165 | the current context
166 |
167 | Note: There is no recursive cycle detection! **Be careful**.
168 |
169 | Example:
170 |
171 | `{{include ../myTemplate}}`
172 |
173 | Applies the template `myTemplate` using `this` as the data context
174 |
175 | `{{include ../myTemplate with="x"}}`
176 |
177 | Applies the template `myTemplate` using `this.x` as the data context.
178 | Identical to:
179 |
180 | `{{#with x}} {{include ../template}} {{/with}}`
181 |
182 | **Parameters**
183 |
184 | **with**: *string*, **[optional]** Context to use when including the template. Supports simple dot paths.
185 |
186 |
187 | ## `plural`
188 |
189 | Returns the value of `context` (assuming `context` is a **number**)
190 | and appends the singular or plural form of the specified word,
191 | depending on the value of `context`
192 |
193 | Example:
194 |
195 | `{plural star_rating singular="star" plural="stars"}}`
196 |
197 | Will produce:
198 | - `{{star_rating}} star` if the value of `star_rating` is `1`, or
199 | - `{{star_rating}} stars` if `star_rating` > `1`
200 |
201 | **Parameters**
202 |
203 | **singular**: *string*, Indicates the singular form to use
204 |
205 | **plural**: *string*, Indicates the plural form to use
206 |
207 | **delimiter**: *string*, **[optional]** Format the number with the `numFormat` helper
208 |
209 |
210 | ## `numFormat`
211 |
212 | Delimits a number or string with multiple numbers,
213 | using commas or given delimiter
214 |
215 | Note: This supports integers and decimal numbers.
216 |
217 | Credit: This function was borrowed from
218 | http://cwestblog.com/2011/06/23/javascript-add-commas-to-numbers/
219 |
220 | Example:
221 |
222 | ```html
223 | {{numFormat num}}
224 | {{numFormat num delimiter="." }}
225 | ```
226 |
227 | **Parameters**
228 |
229 | **delimiter**: *string*, **[optional]** The delimiter string. Default: `','`
230 |
231 | ## `imageProxy`
232 |
233 | Rewrite a URL as a DuckDuckGo image redirect
234 |
235 | Example:
236 |
237 | `{{imageProxy imageURL}}`
238 |
239 | produces: `/iu/?u={{imageURL}}`
240 |
241 |
242 | ## `trim`
243 |
244 | Removes leading and trailing spaces from text
245 |
246 | Example:
247 |
248 | `{{trim stringWithSpaces}}`
249 |
250 |
251 | ## `ellipsis`
252 |
253 | Shortens a string by removing words until string length is <= `limit` and
254 | appends an ellipsis ('...') to the output
255 |
256 | Note: It automatically appends any closing tag if one is missing.
257 |
258 | Example:
259 |
260 | `{{ellipsis title 50}}`
261 |
262 | **Parameters**
263 |
264 | **text**: *string*, text to shorten
265 |
266 | **limit**: *number*, maximum length of shortened string
267 |
268 | ## Creating Custom Helpers
269 |
270 | Of course, since we're using [Handlebars](http://handlebarsjs.com/), you can create your own helpers as well. Simply define your helper alongside your frontend callback. For example, see how the *Alternative To* Instant Answer defines the `AlternativeTo_getPlatform` helper in [`alternative_to.js`](https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/share/spice/alternative_to/alternative_to.js):
271 |
272 |
273 | ```javascript
274 | env.ddg_spice_alternative_to = function(api_result) {
275 | ...
276 | };
277 |
278 | Handlebars.registerHelper("AlternativeTo_getPlatform", function (platforms) {
279 | return (platforms.length > 1) ? "Multiplatform" : platforms[0];
280 | });
281 | ```
282 |
283 | This handlebars helper is very simple: it takes an array as input and depending on the length, returns either the first element in the array, or if more than one element exists, returns the string "Multiplatforms". You can learn more about helpers on the [Handlebars documentation](http://handlebarsjs.com/).
--------------------------------------------------------------------------------
/duckduckhack/instant-answer-display/templates_overview.md:
--------------------------------------------------------------------------------
1 | # Templates Overview
2 |
3 | When your Instant Answer returns its awesome and delightful result(s), the information is rendered at the top of the DuckDuckGo search results page. The way your results appear and behave is decided by the templates you choose.
4 |
5 | 
6 |
7 | ## Why Templates Are Great
8 |
9 | Templates save a lot of work: they allow contributors to focus on great results. Many Instant Answer frontends can be created entirely by setting various display options and item data, with little or no HTML/CSS coding.
10 |
11 | Additionally, Instant Answers that use templates are automatically compatible with future design improvements, with zero extra work.
12 |
13 | ## Template Groups
14 |
15 | Template groups are presets for all template settings; they abstract away all the settings described below. Template groups are the best - and strongly recommended - option for working with templates.
16 |
17 | Read more about [template groups](https://duck.co/duckduckhack/template_groups) and get help [choosing the best one](https://duck.co/duckduckhack/template_groups#picking-a-template-group) for your Instant Answer.
18 |
19 | ## How Templates Work
20 |
21 | Templates are handlebars files which render in the context of **one item** returned by the Instant Answer.
22 |
23 | The Instant Answer framework provides you with a wide choice of templates to use, as you will see below as well in the [reference](https://duck.co/duckduckhack/templates_reference).
24 |
25 | The built-in templates' options, variables, and [variants](https://duck.co/duckduckhack/templates_reference#variants) are documented in the [Templates Reference](https://duck.co/duckduckhack/templates_reference) section.
26 |
27 | ### Specifying `item` and `detail` Templates
28 |
29 | Instant Answers can return either a **single result** or **multiple results**. To provide the best experience, these two cases can be displayed with different templates.
30 |
31 | In your Instant Answer display options (for example, [Spice Display](https://duck.co/duckduckhack/spice_displaying) or [Goodie Display](https://duck.co/duckduckhack/goodie_displaying)), you can specify two separate templates:
32 |
33 | - `item` template (multiple results)
34 | - `detail` template (single results)
35 |
36 | Below is an example of multiple results being returned. Each result is displayed using the template specified for `item`:
37 |
38 | 
39 |
40 | Below is an example of the same Instant Answer returning a single result. This uses the template specified for `detail`:
41 |
42 | 
43 |
44 | ### Clicking on an Item
45 |
46 | In the case of multiple items, clicking on a single item will show the `detail` template below the items. This is the default behavior. To display a template other than the one used for `detail`, specify an `item_detail` template.
47 |
48 | This diagram shows what is displayed when an Instant Answer returns multiple items:
49 |
50 | ```
51 | INSTANT ANSWER RETURNS MULTIPLE ITEMS
52 |
53 | +--------------+--------------+--------------+--------------+--------------+--------------+---------------+
54 | | | | | | | | |
55 | | | | | | | | |
56 | | | | | | | | |
57 | | | | | | | | |
58 | | `item` | | | | | | |
59 | | template | | | | | | |
60 | | clicked | | | | | | |
61 | | | | | | | | |
62 | | | | | | | | |
63 | | | | | | | | |
64 | +--------------+--------------+--------------+--------------+--------------+--------------+---------------+
65 | | |
66 | | |
67 | | |
68 | | |
69 | | `detail` Template |
70 | | |
71 | | OR |
72 | | |
73 | | `item_detail` (when specified) |
74 | | |
75 | +---------------------------------------------------------------------------------------------------------+
76 | ```
77 |
78 | For example, the Amazon products search Instant Answer uses one template for single results (`detail`):
79 |
80 | 
81 |
82 | However, the Amazon Instant Answer displays a different template when multiple items are returned, and one is clicked (`item_detail`):
83 |
84 | 
85 |
86 | #### Disabling Detail Display on Click
87 |
88 | To disable the display of a detail template when an item is clicked, set `detail: false`. A side effect of this is that single results will be displayed as tiles.
89 |
90 | ### When Each Template Is Shown
91 |
92 | The Instant Answer framework automatically chooses which template to display based on how many results there are to show and user behavior. Here is the default logic for showing templates:
93 |
94 | ```
95 | Instant Answer result
96 | +
97 | |
98 | multiple results | single result
99 | |
100 | +---------+----------+
101 | | |
102 | | |
103 | | |
104 | +--------v--------+ +--------v---------+
105 | | | | |
106 | | `item` | | `detail` |
107 | | | | |
108 | +-------+---------+ +------------------+
109 | |
110 | | click an item
111 | |
112 | +-------v---------+
113 | | |
114 | | `detail` |
115 | | or |
116 | | `item_detail` |
117 | | (if specified) |
118 | | |
119 | +-----------------+
120 |
121 | ```
122 |
123 | Of course, you can specify template options to modify this; for example, you may want to prevent a particular template from appearing. For example, you might set `detail: false` to make sure your Instant Answer always displays results with the `item` template.
124 |
125 | ### Template Groups
126 |
127 | In practice, you will specify a template group. Template groups are presets which abstract the settings described above.
128 |
129 | **Template groups are the best - and strongly recommended - option for working with templates.** Read more about [template groups](https://duck.co/duckduckhack/template_groups) and get help [choosing the best one](https://duck.co/duckduckhack/template_groups#picking-a-template-group) for your Instant Answer.
130 |
131 |
--------------------------------------------------------------------------------
/duckduckhack/goodie/goodie_basic_tutorial.md:
--------------------------------------------------------------------------------
1 | ## Basic Goodie Tutorial
2 |
3 | **If you've already completed the [Quick Start](https://duck.co/duckduckhack/goodie_quickstart)**, you are well prepared for this section. Here you will learn more about all the things you can do with Goodie. While many of the steps will be familiar, we recommend starting from step one and creating a new Goodie from scratch.
4 |
5 | This tutorial will show you how to build a Goodie Instant Answer from scratch. If you've already completed the [Quick Start](https://duck.co/duckduckhack/goodie_quickstart), this tutorial is a great next step for getting more comfortable with creating Goodies.
6 |
7 | _Stuck on something? Got a question? Shoot us an email at **open@duckduckgo.com** and we'll jump at the chance to help._
8 |
9 | ## Let Us Know What You're Working On
10 |
11 | **Before you start coding your new Instant Answer, let us know your plans.** By involving us early we can provide guidance and potentially save you a lot of time and effort.
12 |
13 | Email us at [open@duckduckgo.com](mailto:open@duckduckgo.com) with what idea you're working on and how you're thinking of going about it.
14 |
15 | ## Automatically Generate Your Goodie Files
16 |
17 | The following tutorial will walk through each file and line of code necessary to build and test the example Goodie. However, for building your *own* Instant Answer, we've created a tool that **automatically creates the necessary boilerplate files**, with all of the correct naming conventions.
18 |
19 | The `duckpan new` tool will create the following Goodie files for you automatically, with the correct paths and naming conventions inside each file:
20 |
21 | - The backend Perl file with the right name, in the `DDG/Goodie/` directory
22 | - The test file, in the `t/` testing directory
23 |
24 | *Currently the `duckpan new` command does not automatically generate any [Goodie frontend files](https://duck.co/duckduckhack/goodie_displaying#setting-goodie-display-properties-in-the-frontend)*.
25 |
26 | This allows you to focus on what makes your Goodie unique. To use this tool, follow these instructions:
27 |
28 | 1. After [setting up your environment](https://duck.co/duckduckhack/setup_dev_environment), open your Terminal and enter the root directory of your local repository, `zeroclick-goodies\`.
29 | 2. At the command line, type `duckpan new` and hit enter.
30 | 3. When prompted, enter what you want to call your Goodie.
31 |
32 | *For example, `volume conversion`. (White spaces and character casing are automatically formatted.)*
33 |
34 | 4. You will see a list of the boilerplate files created for you, each with the proper naming conventions already done:
35 |
36 | ```
37 | [10:08 PM ... zeroclickinfo-goodies {master}]$ duckpan new
38 | Please enter a name for your Instant Answer : volume conversion
39 | Created file: lib/DDG/Goodie/VolumeConversion.pm
40 | Created file: t/VolumeConversion.t
41 | Successfully created Goodie: VolumeConversion
42 | ```
43 |
44 | Congratulations! You've breezed through a lot of typing, files, and naming conventions. In the following tutorial, we'll explain each line of code and how to customize it to your Instant Answer idea.
45 |
46 | ## The Chars Goodie
47 |
48 | In this tutorial, we'll be making a Goodie Instant Answer that checks the number of characters in a given search query. The end result, [chars.pm](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Chars.pm) works [like this](https://duckduckgo.com/?q=chars+How+many+characters+are+in+this+sentence%3F) and will contain the following:
49 |
50 | ```perl
51 | package DDG::Goodie::Chars;
52 | # ABSTRACT: Give the number of characters (length) of the query.
53 |
54 | use DDG::Goodie;
55 |
56 | triggers start => 'chars';
57 |
58 | handle remainder => sub {
59 | return 'Chars: ' . length $_ if $_;
60 | return;
61 | };
62 | 1;
63 | ```
64 |
65 | Let's go through the Chars Goodie line by line.
66 |
67 | ## Naming our Goodie Package
68 |
69 | To begin, open your favourite text editor like [gedit](http://projects.gnome.org/gedit/), notepad or [emacs](http://www.gnu.org/software/emacs/) and type the following:
70 |
71 | ```perl
72 | package DDG::Goodie::Chars;
73 | # ABSTRACT: Give the number of characters (length) of the query.
74 | ```
75 |
76 |
77 |
78 | Each Instant Answer is a [Perl package](https://duckduckgo.com/?q=perl+package), so we start by declaring the package namespace. For brand new development, you would change **Chars** to the name of the Instant Answer (written in [CamelCase](https://duckduckgo.com/?q=camelcase) format).
79 |
80 | The second line is a special comment line that is used for documentation purposes.
81 |
82 | ## Import the Goodie Class
83 |
84 | Next, type the following [use statement](https://duckduckgo.com/?q=perl+use) to import [the magic behind](https://github.com/duckduckgo/duckduckgo/tree/master/lib/DDG) our Instant Answer system.
85 |
86 | ```perl
87 | use DDG::Goodie;
88 | ```
89 |
90 | **Note:** Right after the above line, you should include any Perl modules that you'll be leveraging to help generate the answer. **Make sure** you add those modules to the `dist.ini` file in this repository. If you're not using any additional modules, carry on!
91 |
92 | ## Define the Trigger Word(s)
93 |
94 | On the next line, type:
95 |
96 | ```perl
97 | triggers start => 'chars';
98 | ```
99 |
100 | **triggers** are keywords/phrases that tell us when to make the Instant Answer run. When a particular *trigger word* (or phrase) appears in a search query, the DuckDuckGo engine knows that *triggering* the Instant Answer may *handle* the query.
101 |
102 | In this case there is one trigger word: "**chars**".
103 |
104 | Let's say someone searched "**chars this is a test**". **chars** is the *first* word, so it would trigger our Goodie because the **start** keyword says, "Make sure the *trigger word* is at the *start* of the query."
105 |
106 | There are several other keywords like **start** which will be covered shortly. The **=>** symbol is there to separate the trigger words from the keywords (for readability).
107 |
108 | ## Define the Handle Function
109 |
110 | Moving on, enter this on the next line:
111 |
112 | ```perl
113 | handle remainder => sub {
114 | ```
115 |
116 | Once triggers are specified, we define how to *handle* the query. `handle` is another keyword, similar to **triggers**.
117 |
118 | You can *handle* different parts of the search query, but the most common is the **remainder**, which refers to the remainder of the query, after the first matched trigger word/phrase has been removed.
119 |
120 |
121 |
122 | For example, if the query was "**chars this is a test**", the trigger would be *chars* and the remainder would be *this is a test*.
123 |
124 | Now let's add a few more lines to complete the handle function:
125 |
126 | ```perl
127 | handle remainder => sub {
128 | return 'Chars: ' . length $_ if $_;
129 | return;
130 | };
131 | ```
132 |
133 | This function (the part within the **{}**, after **sub**) is the most important part of the Goodie. It defines the Instant Answer that will be displayed at the top of the [search results page](https://duckduckgo.com/?q=chars+this+is+a+test).
134 |
135 | Whatever you are handling is passed to the function in the **$\_** variable ( **$\_** is a special default variable in Perl that is commonly used to store temporary values). For example, if you searched DuckDuckGo for *"chars this is a test"*, the value of **$\_** will be *"this is a test"*, i.e. the remainder.
136 |
137 | Let's take a closer look at the first line of the function:
138 |
139 | ```perl
140 | return 'Chars: ' . length $_ if $_;
141 | ```
142 |
143 | The heart of the function is just this one line. The **remainder** is in the **$\_** variable as discussed. If it is not blank ( **if $\_** ), we return the number of chars using Perl's built-in [length function](https://duckduckgo.com/?q=perl+length).
144 |
145 | Perl has a lot of built-in functions, as well as thousands of modules available [via CPAN](https://metacpan.org/). You can leverage these modules when making Goodies, similar to how the [Roman Goodie](https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/Roman.pm) uses the [Roman module](https://metacpan.org/module/Roman).
146 |
147 | If we are unable to provide a good Instant Answer, we simply **return nothing**. That's exactly what the second line in the function does.
148 |
149 | ```perl
150 | return;
151 | ```
152 |
153 | This line is only run if **$\_** contained nothing, because otherwise the line before it would return something and end the function execution.
154 |
155 |
156 | ## Return True at EOF
157 |
158 | Finally, all Perl packages that load correctly should [return a true value](http://stackoverflow.com/questions/5293246/why-the-1-at-the-end-of-each-perl-package) so add a 1 on the very last line, and make sure to also add a newline at the end of the file.
159 |
160 | ```perl
161 | 1;
162 |
163 | ```
164 |
165 | And that's it! At this point you have a working Goodie Instant Answer.
166 |
167 | ## Recap
168 | The Instant Answer system works like this at the highest level:
169 |
170 | - We break the query (search terms) down into separate words, which is a process that happens in the background.
171 |
172 | - We see if any of those words or groups of words are **triggers** for any Instant Answers. These **triggers** are defined by the developer when creating an Instant Answer. In the example we used above, the trigger word is "**chars**".
173 |
174 | - If a Goodie is triggered, we run its `handle` function.
175 |
176 | - If the Goodie's handle function outputs an Instant Answer via a **return** statement, we display it at the top of the SERP (search engine results pages).
177 |
--------------------------------------------------------------------------------
/duckduckhack/resources/code_styleguide.md:
--------------------------------------------------------------------------------
1 | # Code Style Guide
2 |
3 | As a largely open-source project, we like to keep our code as consistent as our Instant Answers. This means all code should be formatted the same way and should look and feel as though it has all been written by the same person.
4 |
5 | This document outlines some language specific guidelines for formatting your code and also highlights best practices, and things to avoid. In any large open-source project, maintainability is of utmost importance, so a style guide is necessary to help our contributors write clean, readable and maintainable code.
6 |
7 | ## General
8 |
9 | - **Indent with 4 spaces** (soft tabs)
10 |
11 | All DuckDuckHack code should be indented with four spaces. Be sure to configure your text editor to insert four spaces when you press the tab button - this is referred to as a "soft-tab". If you are correcting the indentation of a file, please submit that change in a separate pull request. It is important that code reviewers are able to easily differentiate between functional and stylistic changes.
12 |
13 | - **Document your code**
14 |
15 | Well-documented code helps others understand what you've written. It's likely that someone else will read your code and might even need to change it at some point in the future. Comments should primarily document the intent of the code. Reviewers are much more effective when they know exactly what you were trying to do. Meaningful variable names also help to document your intent.
16 |
17 | - **Writing meaningful commits**
18 |
19 | Commit messages should be concise and informative. If the specific commit fixes a bug on GitHub, note that by saying `fixes #123`, where `123` is the issue number. Doing this will automatically close the specified issue when your pull request is merged.
20 |
21 | Usually pull requests only deal with a single Instant Answer. If however your pull request modifies more than one Instant Answer, please preface your commit messages with the name of the IA modified by your commit:
22 |
23 | For example, if your pull request updates the Movies, InTheaters and Kwixer IA's:
24 |
25 | - Commit 1: `Movies: updated title font color to match mockup`.
26 | - Commit 2: `InTheaters: updated title text, typo fix`.
27 | - Commit 3: `Movies, InTheaters, Kwixer: change title to h5 tag`.
28 |
29 | ## JavaScript
30 |
31 | **We generally adhere to [Crockford's Code Conventions](http://javascript.crockford.com/code.html)**. Most importantly:
32 |
33 | - Use semicolons;
34 |
35 | - Use the ["One True Brace Style"](https://en.wikipedia.org/wiki/Indent_style#Variant:_1TBS) (opening brace on the same line)
36 |
37 | ```javascript
38 | // Bad
39 | if ( ... )
40 | {
41 | ...
42 | }
43 | else
44 | {
45 | ...
46 | }
47 |
48 | // Good
49 | if ( ... ) {
50 | ...
51 | } else {
52 | ...
53 | }
54 | ```
55 |
56 | - Use `{}` instead of `new Object()`, and `[]` instead of `new Array()`.
57 |
58 | ```javascript
59 | // Bad
60 | var obj = new Object();
61 | var arr = new Array();
62 |
63 | // Good
64 | var obj = {};
65 | var arr = [];
66 | ```
67 |
68 | - Use `===` instead of `==`, and `!==` instead of `!=`. [Why?](http://stackoverflow.com/a/359509/1998450)
69 |
70 | ```javascript
71 | // Bad
72 | if (foo == bar) { ... }
73 | if (foo != bar) { ... }
74 |
75 | // Good
76 | if (foo === bar) { ... }
77 | if (foo !== bar) { ... }
78 | ```
79 |
80 | - Declare variables with var, chaining multiple declarations -- one per line:
81 |
82 | ```javascript
83 |
84 | // Bad
85 | var foo = 1;
86 | var bar = true;
87 | var baz = "string";
88 |
89 | // good
90 | var foo = 1,
91 | bar = true,
92 | baz = "string";
93 |
94 | // when initializing undefined variables
95 | var foo, bar, baz;
96 | ```
97 |
98 | Note: We're using ECMAScript's [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FFunctions_and_function_scope%2FStrict_mode), so you'll *need* to declare every variable with `var`.
99 |
100 | - Avoid trailing commas
101 |
102 | We support all modern browsers, including IE 9, which breaks when it reaches a trailing comma in objects. It also treats trailing commas in arrays [differently than you might expect](http://www.akawebdesign.com/2011/06/23/the-curious-case-of-trailing-commas-in-ie/).
103 |
104 | ```javascript
105 | // Bad
106 | var foo = {
107 | a: 'b',
108 | c: 42, //<-- trailing comma
109 | };
110 |
111 | // Good
112 | var foo = {
113 | a: 'b',
114 | c: 42 //<-- no trailing comma
115 | };
116 | ```
117 |
118 | - Use [`$.map()`](http://api.jquery.com/jQuery.map/) and [`$.each()`](http://api.jquery.com/jQuery.each/) instead of `Array.prototype.map()` and `Array.prototype.forEach()`, again for IE support.
119 |
120 | - Avoid modifying object prototypes
121 |
122 | Do not modify the prototypes of objects which are defined outside of your code. For example, modifications to `Array.prototype` or `Spice` will affect the global scope and may cause problems. In general, we advocate the use of local, private functions instead.
123 |
124 | - Define default properties when the object is created:
125 |
126 | ```javascript
127 | // Bad
128 | var bar = {};
129 | bar.a = 'b';
130 | bar.c = 42;
131 |
132 | // Good
133 | var foo = {
134 | a: 'b',
135 | c: 42
136 | };
137 | ```
138 |
139 | - Store jQuery selectors:
140 |
141 | If you need to re-use a jQuery selector (e.g. `$('#myDiv')`), store it in a variable for speed and efficiency. Otherwise, jQuery will need to traverse the DOM each time you use the same selector.
142 |
143 | ```javascript
144 | // Bad
145 | // Traverse the DOM and find '#text_element'...
146 | $('#text_element').show();
147 | // ... now do all that work again!
148 | $('#text_element').html('abc');
149 |
150 | // Good
151 | // Traverse the DOM and find '#text_element', then store it in memory
152 | // Convention is to prefix variables with a '$' when they hold a jQuery object
153 | var $text_element = $('#text_element');
154 | $text_element.show();
155 | $text_element.html('abc');
156 |
157 | // Better
158 | // jQuery supports method chaining!
159 | $('#text_element').show().html('abc');
160 |
161 | ```
162 |
163 | ## Handlebars
164 |
165 | Handlebars templates and Handlebars helpers should be easy to read and understand. Please:
166 |
167 | - Put nested elements on new lines:
168 |
169 | ```html
170 |
171 |
187 | ```
188 |
189 | - Define helper functions with `Spice.registerHelper`, instead of `Handlebars.registerHelper`:
190 |
191 | ```javascript
192 | // Bad
193 | Handlebars.registerHelper("spice_name_do_something", function(){ ... });
194 |
195 | // Good
196 | Spice.registerHelper("spice_name_do_something", function(){ ... });
197 | ```
198 |
199 | - Namespace your helper functions:
200 |
201 | Handlebars helpers are all created in the same scope, so any two helpers with the same name will collide (we plan to fix this). This can be avoided by prepending your helpers with the name of your Spice IA.
202 |
203 | ```javascript
204 | // Bad
205 | Spice.registerHelper("do_something", function(){ ... });
206 |
207 | // Good
208 | Spice.registerHelper("spice_name_do_something", function(){ ... });
209 | ```
210 |
211 | ------
212 |
213 | The easiest way to verify your code meets our style guide is to test it with [JSHint](http://jshint.com/).
214 |
215 | ## CSS
216 |
217 | - All CSS should be "namespaced" with the container element.
218 |
219 | For Spices, use `.zci--spicename`, and for Goodies, use `.zci--answer`:
220 |
221 | ```css
222 | /* Stopwatch Spice */
223 | .zci--stopwatch .spice-pane {
224 | ...
225 | }
226 |
227 | /* Calendar Goodie */
228 | .zci--answer table.calendar {
229 | ...
230 | }
231 | ```
232 |
233 | - Put multiple selectors on new lines for each rule:
234 |
235 | ```css
236 | /* Bad */
237 | .zci--stopwatch .spice-pane, .zci--stopwatch .spice-pane-right {
238 | ...
239 | }
240 |
241 | /* Good */
242 | .zci--stopwatch .spice-pane,
243 | .zci--stopwatch .spice-pane-right {
244 | ...
245 | }
246 | ```
247 |
248 | - Avoid the use of vendor prefixes and experimental features. We strive for a uniform experience on all current browsers and your IA *must* work across them.
249 |
250 | When in doubt, [CanIUse](http://caniuse.com/) is a good resource for determining if prefixes are needed. We support IE 9+, and recent versions of Chrome, Firefox, Safari, and Opera.
251 |
252 | ```css
253 | /* Bad */
254 | .element {
255 | -webkit-border-radius: 45px;
256 | -o-border-radius: 45px;
257 | -moz-border-radius: 45px;
258 | -khtml-border-radius: 45px;
259 | border-radius: 45px;
260 | }
261 |
262 | /* Good */
263 | .element {
264 | border-radius: 45px;
265 | }
266 | ```
267 |
268 | - Avoid using inline CSS. Custom CSS should be placed in a file (`/share/{goodie,spice}/my_ia/my_ia.css`) to be automatically included in the Instant Answer response.
269 |
270 | ## Perl
271 |
272 | (This section is coming soon! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
273 |
--------------------------------------------------------------------------------
/duckduckhack/getting-started/setup_dev_environment.md:
--------------------------------------------------------------------------------
1 | # We Have Moved!
2 |
3 | These are the **old docs**, and are outdated.
4 |
5 | The new documentation can be read [here](http://docs.duckduckhack.com) and the repository is hosted [here](https://github.com/duckduckgo/duckduckhack-docs).
6 |
7 | Any feedback, thoughts, or pull requests about the new docs are welcome, **please** let us know at open@duckduckgo.com
8 |
9 | # Setting Up Your Development Environment
10 |
11 | In order to get moving with Instant Answer development, you'll need to setup your environment. At the very minimum, you will need a GitHub account and the DuckDuckHack developer tool, DuckPAN, to make and submit an Instant Answer. This guide will help you determine the best setup for you.
12 |
13 | Before moving forward, you **must** know which Instant Answer type you will be using. After this section, the documentation will be specific to each Instant Answer type.
14 |
15 | ## Before you start...
16 |
17 | We highly recommend that everyone uses Codio, a web-based IDE that simplifies the setup and development process greatly. If you prefer using a local text editor, that's alright, but using Codio is still beneficial because we already have the required software installed and ready to go. This page will show you how to set up Codio and then it's on to creating Instant Answers! You can also watch a [video screencast of this tutorial](https://vimeo.com/132712266).
18 |
19 | ### Alternative Development Environments
20 |
21 | Codio is the preferred choice of most DuckDuckHack contributors for its ease and speed. However, you may also [develop and test locally](https://duck.co/duckduckhack/other_development_environments), or install a [pre-configured virtual machine](https://duck.co/duckduckhack/other_development_environments). These options do require more time and effort than using Codio.
22 |
23 | ## Sign up for a GitHub Account
24 |
25 | *Already have a GitHub Account? Perfect, move on to [the next step](#sign-up-for-a-codio-account)!*
26 |
27 | If you're new to programming, GitHub is a well known, popular tool that many individuals and companies use to save their code. Many open-source projects (such as DuckDuckHack) are hosted on GitHub and anyone with an account can contribute. GitHub is a great tool that you will likely be using long after this tutorial. To get started, let's sign up!
28 |
29 | 1. Go to https://github.com/join and enter the required information, then click "**Create an Account**"
30 | 2. Click "**Finish Signup**" to continue with a **Free** GitHub account.
31 |
32 | **Congrats!** You now have a GitHub account.
33 |
34 |
35 | ## Sign up for a Codio Account
36 |
37 | Next, you'll need to get an account for Codio:
38 |
39 | *Already have a Codio Account? Perfect, move on to [the next step](#fork-the-duckduckhack-project-on-codio)!*
40 |
41 | 1. Go to https://codio.com and click "**Get Started**", at the top right corner.
42 | 2. Click "**Sign Up via GitHub**".
43 | 3. If you aren't already signed into GitHub, enter your GitHub login details and then click "**Sign In**".
44 | 4. Click "**Authorize application**" to continue.
45 | 5. In the new screen, enter the required details and click "**Create Account**".
46 |
47 | **Congrats!** You now have a Codio account. You'll notice that you didn't need to provide a password, that's because you've logged in to Codio using your GitHub account. As long as you can login to your GitHub account, you can also login to Codio. Now let's get started with setting up your Codio environment!
48 |
49 | ## Join the DuckDuckGo Organization
50 |
51 | 1. **After logging into Codio,** [click this link](https://codio.com/p/signup?orgToken=Ax-OB3tU4sdNAG8axJBYcjNqR04) and you'll be added to our organization, which gives you a professional Codio setup free of charge. You should see a confirmation message at the bottom of your Codio screen after clicking.
52 |
53 |
54 | ## Fork the DuckDuckHack Project on Codio
55 |
56 | 1. Go to https://codio.com/duckduckgo/duckduckhack and click "**Project**" at the top left corner.
57 | 2. In the drop-down, select the "**Fork**" option.
58 |
59 | 
60 |
61 | 3. In the pop-up window, select the "**Box & Project**" option and click "**Continue**".
62 |
63 | 
64 |
65 | 4. Wait a minute while the project forks...
66 | 5. You should now see a new window with three panes. It should say "**DuckDuckHack**" at the top of the left pane.
67 |
68 | **Congrats!** You've now successfully forked the DuckDuckHack environment. Now, let's grab the DuckDuckHack Goodie code (from GitHub.com) and start learning!
69 |
70 |
71 | ## Fork the correct DuckDuckHack repository on GitHub
72 |
73 | In order to test out and create your own Instant Answer, you'll need the open-source code that DuckDuckGo hosts on GitHub.com. We're now going to "fork" that code, so you'll have your own personal copy which you can modify.
74 |
75 | By now you should have [determined the Instant Answer type](https://duck.co/duckduckhack/determine_your_instant_answer_type) you're going to build.
76 |
77 | 1. Go to the Instant Answer repository homepage:
78 | - [Goodies](https://github.com/duckduckgo/zeroclickinfo-goodies) (for Cheat Sheets and Instant Answers that are pure code functions)
79 | - [Spice](https://github.com/duckduckgo/zeroclickinfo-spice) (for Instant Answers that will make API calls)
80 | - [Fathead](https://github.com/duckduckgo/zeroclickinfo-fathead) (for Instant Answers that use key->value based data)
81 | - [Longtail](https://github.com/duckduckgo/zeroclickinfo-longtail) (for Instant Answers that do full text search)
82 | 2. Do you see your user portrait or "**Sign up**" and "**Sign in**" buttons in the top right corner?
83 | - **User Portrait**? Perfect. Move on to the next step.
84 | - **Sign up/in Buttons**? Click "**Sign In**", then enter your details and click "**Sign In**".
85 | - **A portrait that's not mine**? Whoops! Click the portrait to see the username. If it's yours, you're good to go. If not, click Sign out, and then sign in with your username and password.
86 | 3. Click "**Fork**", near the top-right corner.
87 | 4. Wait while the repo forks...
88 | 5. You should see a page that looks nearly identical to the repo home page you were just on. The URL should be different though, it should look like **`https://github.com/yourGitHubUsername/zeroclickinfo-xxxxx`**. This is the URL for your personal copy of the DuckDuckHack code.
89 | 6. **Keep this URL handy, we'll be using it in a minute!**
90 |
91 |
92 | ## Clone your Repository onto your Codio Machine
93 |
94 | Now we need to "clone" the code from GitHub to your Codio box so you can see it, modify it and run it!
95 |
96 | 1. Go to the [Codio projects page](https://codio.com/home/projects).
97 | - See a "**Sign In**" screen? Use the "**Sign in via GitHub**" method like you did before (see Step #2 [here](#sign-up-for-a-codio-account)).
98 | 2. Click the "**DuckDuckHack**" project.
99 | 3. You should now see the three-pane window we previously saw. Press **Ctrl+Alt+R** (Cmd+Alt+R on a Mac), this will improve the layout a bit. (You can also click *View->Layouts->Default* from the command bar at the top).
100 | 4. Press **Shift+Alt+T** to open a new Terminal. (You can also click *Tools->Terminal* from the command bar at the top). You should see the right side pane change into a black command prompt.
101 | 5. Type **`git clone .git`** into the Terminal, replacing `` accordingly. It should look something like this for a Goodie:
102 |
103 | ```
104 | [04:30 PM codio@buffalo-pixel workspace {master}]$ git clone https://github.com/githubusername/zeroclickinfo-goodies.git
105 | ```
106 |
107 | _**If your Github password doesn't work**, you may need to enter a [Personal Access Token](https://github.com/settings/tokens) instead. Simply copy and paste your token from your [Github Settings](https://github.com/settings/tokens). (This happens if you have set up [Github's Two-Factor Authentication](https://github.com/blog/1614-two-factor-authentication) feature.)_
108 |
109 | 6. Press "**Enter**". You should see the Terminal print out some text that looks like this:
110 |
111 | ```
112 | [04:30 PM codio@buffalo-pixel workspace {master}]$ git clone https://github.com/githubusername/zeroclickinfo-goodies.git
113 | Cloning into 'zeroclickinfo-goodies'...
114 | remote: Counting objects: 18623, done.
115 | remote: Compressing objects: 100% (8083/8083), done.
116 | remote: Total 18623 (delta 8084), reused 18179 (delta 7868)
117 | Receiving objects: 100% (18623/18623), 5.50 MiB | 9.51 MiB/s, done.
118 | Resolving deltas: 100% (8084/8084), done.
119 | Checking connectivity... done.
120 | [04:30 PM codio@buffalo-pixel workspace {master}]$
121 | ```
122 |
123 | 7. The file tree on the left side should update. There should be a new "**zeroclickinfo-xxxxx**" directory, where "**xxxxx**" is whichever Instant Answer type you chose: Goodie, Spice, Fathead, or Longtail.
124 |
125 | 8. Change the current directory of the terminal by typing **`cd zeroclickinfo-xxxxx`**, where "**xxxxx**" is whichever Instant Answer type you chose: Goodie, Spice, Fathead, or Longtail.
126 |
127 | 9. [Optional, best practice] Create a new branch in your repository for this particular project. This lets you work on several ideas at one time and keep them separate. Create a new branch by typing **`git checkout -b branch_name`**. You can use any branch name you like. You must create a new branch for each of your contributions. You can switch between branches by using **`git checkout branch_name`**.
128 |
129 | **Congrats!** You've now cloned the DuckDuckHack code onto your Codio machine. You're now prepared to code your first Instant Answer!
130 |
131 | ## Start Coding!
132 |
133 | At this point, you're ready to start learning about the Instant Answer type you'll be using.
134 |
135 | - For **Goodies**, [start here](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_overview.md)
136 |
137 | - For **Spice**, [start here](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/spice/spice_overview.md)
138 |
139 | - For **Fathead**, [start here](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/fathead/fathead_overview.md)
140 |
141 | - For **Longtail**, [start here](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/longtail/longtail_overview.md)
142 |
--------------------------------------------------------------------------------
/duckduckhack/resources/faq.md:
--------------------------------------------------------------------------------
1 | # DuckDuckHack FAQ
2 |
3 | ## General FAQ
4 |
5 | ### Why should I make Instant Answers?
6 |
7 | We hope you will consider making DuckDuckGo Instant Answers to:
8 |
9 | - Improve results in areas you personally search and care about, e.g., [programming documentation](https://duckduckgo.com/?q=perl+split), [gaming](https://duckduckgo.com/?q=roll+3d12+%2B+4) or [entertainment](https://duckduckgo.com/?q=xkcd).
10 | - Increase usage of your own projects, e.g., data and [APIs](https://duckduckgo.com/?q=cost+of+living+nyc+philadelphia).
11 | - Attribution [on our site](https://duckduckgo.com/goodies.html) and [Twitter](https://twitter.com/duckduckhack) (working on more).
12 | - See your code live on a [growing](https://duckduckgo.com/traffic.html) search engine!
13 | - Learn something new.
14 |
15 | ### What if I'm not a coder at all?
16 |
17 | If you don't code at all, please check out our [Instant Answers Ideas Forum](https://duck.co/ideas) where you can suggest and comment on Instant Answer ideas. For instance, identifying the best sources to draw from is extremely important but developers may not know what they are. Similarly, you can submit [issues about current Instant Answers](https://github.com/duckduckgo/duckduckgo/issues?direction=desc&sort=created&state=open). Both of these activities are very valuable and will help direct community efforts.
18 |
19 | If you're a business and want your data to be utilized, adding your service to the [Instant Answers Ideas Forum](https://duck.co/ideas) is a great way for your API to get picked up by a developer and integrated into the search engine.
20 |
21 | ### Can you help me?
22 |
23 | Of course! Here are the easiest ways to contact someone who can help answer your questions:
24 |
25 | - Write us publicly on the [discussion list](https://www.listbox.com/subscribe/?list_id=197814).
26 | - Write us privately at open@duckduckgo.com.
27 |
28 | ### What if I don't know Perl?
29 |
30 | If you don't know Perl, that's OK! Some Instant Answer types ([Fathead](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/fathead/fathead_overview.md), [Longtail](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/longtail/longtail_overview.md)) don't require the use of Perl. Also, if you know PHP, Ruby, or Python you should be able to write a [Goodie](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/duckduckhack/goodie/goodie_overview.md) in Perl pretty easily using [this awesome cheat sheet](http://hyperpolyglot.org/scripting).
31 |
32 | ### Do you have any Instant Answer ideas?
33 |
34 | Yup! We maintain [a growing list](https://duck.co/ideas). There are also improvement ideas for [Goodies](https://github.com/duckduckgo/zeroclickinfo-goodies/issues), [Spice](https://github.com/duckduckgo/zeroclickinfo-spice/issues), [Fathead](https://github.com/duckduckgo/zeroclickinfo-fathead/issues) and [Longtail](https://github.com/duckduckgo/zeroclickinfo-longtail/issues).
35 |
36 | ### How do I note that I've started on something?
37 |
38 | In your initial pull request, please note the link on the [Ideas Forum](https://duck.co/ideas). We'll move it to the "in process" bucket for you.
39 |
40 | ### Where I can report Instant Answer bugs?
41 |
42 | Submit a GitHub issue in the [appropriate repository](http://github.com/duckduckgo).
43 |
44 | ### What if there are Instant Answer conflicts?
45 |
46 | Instant answer sources often compete to answer the same searches. In a lot of cases, the experience can be blended together so that the user is shown answers from more than one source. Our long-term vision for Instant Answers involves multiple sources used in that way.
47 |
48 | There are times, though, where one source does a drastically better job of answering a particular query set. In those cases, the source used for those queries should be the source most capable of delivering the best possible user experience. Our community evaluates those in a few ways:
49 |
50 | - Consistent performance (is the service reliable?)
51 | - Speed (does the service return results fast enough?)
52 | - Quality (does the service answer the queries better than any other service?)
53 |
54 | If you think you have a source that is better, let's talk about it on the [DuckDuckHack e-mail list](https://www.listbox.com/subscribe/?list_id=197814).
55 |
56 | ### Why isn't my Instant Answer in the [DuckDuckGo Instant Answers API](https://api.duckduckgo.com)?
57 |
58 | If your Instant Answer is spice or longtail, sometimes we can't expose it through the API for licensing reasons, but our over-arching goal is to make all of our Instant Answers available on their own.
59 |
60 | ### Can I add triggers for my language?
61 |
62 | 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.**
63 |
64 | ### Can I do something more complicated?
65 |
66 | Maybe. There are a bunch more internal interfaces we haven't exposed yet, and we'd love to hear your ideas to influence that roadmap.
67 |
68 | ### Can I create adult Instant Answers (i.e. NSFW)?
69 |
70 | No.
71 |
72 | ### What's the roadmap?
73 |
74 | Here's what we're working on (in roughly in this order):
75 |
76 | - better testing/file structure for spice Instant Answers.
77 | - better JS interface for spice Instant Answer callback functions.
78 | - better attribution.
79 | - embedding Instant Answers.
80 | - better testing/file structure for fathead Instant Answers.
81 | - more defined structure for longtail Instant Answers.
82 | - better testing for longtail Instant Answers.
83 |
84 | ### Are there other open source projects?
85 |
86 | Yes! Check out the other repositories in [our GitHub account](https://github.com/duckduckgo). You can email open@duckduckgo.com if you have any questions on those.
87 |
88 | ### Can I get the Instant Answers through an API?
89 |
90 | Yes! Check out the [DuckDuckGo API](https://api.duckduckgo.com). Our goal is to make as many Instant Answers as possible
91 | available through this interface. Fathead and goodie Instant Answers are automatically syndicated through the API, and Spice and Longtail are selectively (due to licensing complications) mixed in.
92 |
93 | ### Can I talk to you about a partnership idea?
94 |
95 | Sure -- check out [our partnerships page](https://duck.co/help/company/partnerships).
96 |
97 | ## Goodie FAQ
98 |
99 | ### Can Goodie Instant Answers make network requests?
100 |
101 | No. If you are trying to use an API, you should consider creating a Spice Instant Answer instead.
102 |
103 | ### Can Goodie Instant Answers include the user's query string?
104 |
105 | Yes. **However**, they must be handled *very* carefully. User-supplied strings create a lot of potential for [cross-site scripting attacks](https://duckduckgo.com/Cross-site_scripting?ia=about). While the platform attempts to mitigate these issues in pure ASCII responses, HTML responses should **never** include a raw query string. It is safest to return only data which is generated by your Goodie itself.
106 |
107 | ## Spice FAQ
108 |
109 | ### I want to use 'X' API, but it doesn't have an endpoint for 'Y'. What should I do?
110 |
111 | Email them! - If you explain what it's for, they might be willing to create and endpoint for you! If not, it's probably best to find another API.
112 |
113 | ### The API provides both HTTP and HTTPS endpoints; which should I use?
114 |
115 | We prefer to use **HTTP endpoints** because the reduced connection setup time allows us to provide faster answers to the user. Note that the end-user's query will still be secure in transit, because it is proxied ( e.g. https://duckduckgo.com/js/spice/movie/mib ) through an HTTPS connection to the DuckDuckGo servers.
116 |
117 | ### Can I use an API that returns XML?
118 |
119 | Sorry, but **not right now**. XML support is coming soon.
120 | **Note:** If an API supports both JSON and XML, we *strongly encourage* you to use **JSON**.
121 |
122 | ### Can I use an API that returns HTML or a String?
123 |
124 | Sorry, but **no**. We currently don't support HTML or plain text API's.
125 |
126 | ### Can I use the 'X', 'Y' or 'Z' JavaScript library?
127 |
128 | Probably not. Maybe, if it is very small, but we prefer that no third party, extra libraries are used. ***Please*** ask us first before writing an Instant Answer that is **dependent** on an extra library - we don't want you to waste your time and energy on something we can't accept!
129 |
130 | ### Can I use Coffeescript?
131 |
132 | No.
133 |
134 | ### What about...
135 |
136 | Nope. Just use JavaScript, please and thanks :)
137 |
138 | ## Fathead FAQ
139 |
140 | ### How can I test my output file?
141 |
142 | Unfortunately, there is no way for contributors to do so. But if you've gotten that far, we want to hear about it! Please open a pull request and we'll help you through the testing process.
143 |
144 | ### What can go in a result abstract?
145 |
146 | A result abstract can be either plain text (generally one readable sentence, ending in a period), or HTML. Special care needs to be taken when abstracts contain HTML. Please let us know ahead of time if you are planning to use HTML.
147 |
148 | (This section is still growing! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
149 |
150 | ## Longtail FAQ
151 |
152 | (This section is coming soon! Know what should go here? Then **please** [contribute to the documentation](https://github.com/duckduckgo/duckduckgo-documentation/blob/master/CONTRIBUTING.md)!)
153 |
154 | ## DuckPAN FAQ
155 |
156 | ### How do I install a missing Perl dependency?
157 |
158 | Any Perl module (.pm file) that has external Perl dependencies will load them with a `use` statement. Typically these statements are located near the top of the file. For example, the Factors Goodie (`lib/DDG/Goodie/Factors.pm`) loads the module `Math::Prime::Util`. If this is not installed on your system, DuckPAN will not be able to use the Factors Goodie and you will likely see an error or warning.
159 |
160 | In order to install any missing dependencies you can use cpan or cpanm like so:
161 |
162 | ```perl
163 | cpan install Math::Prime::Util
164 | # or
165 | cpanm Math::Prime::Util
166 | ```
167 |
168 | Alternatively, if you would like to install all the dependencies for the repo (e.g. zeroclickinfo-goodies), you can run `duckpan installdeps`. Please note that installing all the dependencies will take **several minutes** to install as there are many dependencies.
169 |
170 | 
171 |
--------------------------------------------------------------------------------