From e06f686cc83e191d93a730b95307d98af3cce44b Mon Sep 17 00:00:00 2001 From: Michael Joseph Date: Fri, 8 Nov 2019 14:41:27 -0500 Subject: [PATCH 01/71] bin/boilerplate/README.md: fix typo carpentries/styles#441 --- bin/boilerplate/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/boilerplate/README.md b/bin/boilerplate/README.md index ed47f43..060994a 100644 --- a/bin/boilerplate/README.md +++ b/bin/boilerplate/README.md @@ -17,7 +17,7 @@ Please see the current list of [issues][FIXME] for ideas for contributing to thi repository. For making your contribution, we use the GitHub flow, which is nicely explained in the chapter [Contributing to a Project](http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project) in Pro Git by Scott Chacon. -Look for the tag ![good_first_issue](https://img.shields.io/badge/-good%20first%20issue-gold.svg). This indicates that the mantainers will welcome a pull request fixing this issue. +Look for the tag ![good_first_issue](https://img.shields.io/badge/-good%20first%20issue-gold.svg). This indicates that the maintainers will welcome a pull request fixing this issue. ## Maintainer(s) From a966a6859ec2ef6c38337ac789a2f664a80afd0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Sat, 9 Nov 2019 00:50:32 +0100 Subject: [PATCH 02/71] Use Jekyll to generate the 'all-in-one' page (carpentries/styles#438) --- _includes/aio-script.md | 53 +++++++++----------------------- _includes/episode_keypoints.html | 9 +++++- _includes/episode_overview.html | 50 +++++++++++++++++++++++++++--- 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/_includes/aio-script.md b/_includes/aio-script.md index a81fbcd..d90e6d6 100644 --- a/_includes/aio-script.md +++ b/_includes/aio-script.md @@ -6,45 +6,20 @@ open an issue: https://github.com/carpentries/styles/issues/new {% include manual_episode_order.html %} - +{% for lesson_episode in lesson_episodes %} -{% comment %} Create an anchor for every episode. {% endcomment %} +{% if site.episode_order %} + {% assign e = site.episodes | where: "slug", lesson_episode | first %} +{% else %} + {% assign e = lesson_episode %} +{% endif %} -{% for lesson_episode in lesson_episodes %} - {% if site.episode_order %} - {% assign episode = site.episodes | where: "slug", lesson_episode | first %} - {% else %} - {% assign episode = lesson_episode %} - {% endif %} -
+

{{ e.title }}

+ +{% include episode_overview.html teaching_time=e.teaching exercise_time=e.exercises episode_questions=e.questions episode_objectives=e.objectives %} + +{{ e.content }} + +{% include episode_keypoints.html episode_keypoints=e.keypoints %} +
{% endfor %} diff --git a/_includes/episode_keypoints.html b/_includes/episode_keypoints.html index 2baa53e..5c283ea 100644 --- a/_includes/episode_keypoints.html +++ b/_includes/episode_keypoints.html @@ -1,10 +1,17 @@ {% comment %} Display key points for an episode. {% endcomment %} + +{% if page.keypoints == nil %} +{% assign episode_keypoints = include.episode_keypoints %} +{% else %} +{% assign episode_keypoints = page.keypoints %} +{% endif %} +

Key Points

    - {% for keypoint in page.keypoints %} + {% for keypoint in episode_keypoints %}
  • {{ keypoint|markdownify }}
  • {% endfor %}
diff --git a/_includes/episode_overview.html b/_includes/episode_overview.html index cb87e0f..c4a4d48 100644 --- a/_includes/episode_overview.html +++ b/_includes/episode_overview.html @@ -1,19 +1,59 @@ {% comment %} - Display an episode's timings and learning objectives. + Display episode's timings and learning objectives. + + Regarding the `if page.*** == nil` below: + all-in-one page combines all episodes into one. + It, therefore, does not define its own objectives, exercises, + and questions, which 'normal' episodes define in the front matter. + + To display episodes' teaching and exercise times, as well as episode + questions and objectives, we pass them as parameters to the Liquid's + `include` statement when we generate the page: + + {% include episode_overview.html teaching_time=e.teaching ... %} + + Here we obtain the information we need either from the episode itself or + from the parameters passed in. {% endcomment %} + +{% if page.teaching == nil %} +{% assign teaching_time = include.teaching_time %} +{% else %} +{% assign teaching_time = page.teaching %} +{% endif %} + +{% if page.exercises == nil %} +{% assign exercise_time = include.exercise_time %} +{% else %} +{% assign exercise_time = page.exercises %} +{% endif %} + +{% if page.questions == nil %} +{% assign episode_questions = include.episode_questions %} +{% else %} +{% assign episode_questions = page.questions %} +{% endif %} + +{% if page.objectives == nil %} +{% assign episode_objectives = include.episode_objectives %} +{% else %} +{% assign episode_objectives = page.objectives %} +{% endif %} + +

Overview

- Teaching: {{ page.teaching }} min + Teaching: {{ teaching_time }} min
- Exercises: {{ page.exercises }} min + Exercises: {{ exercise_time }} min
Questions
    - {% for question in page.questions %} + {% for question in episode_questions %}
  • {{ question|markdownify }}
  • {% endfor %}
@@ -26,7 +66,7 @@

Overview

Objectives
    - {% for objective in page.objectives %} + {% for objective in episode_objectives %}
  • {{ objective|markdownify }}
  • {% endfor %}
From 8ee9c2060b77256fd04e18fd73e74516677b2a78 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Mon, 11 Nov 2019 14:29:38 -0600 Subject: [PATCH 03/71] manual_episode_order.html: fix typo in a comment --- _includes/manual_episode_order.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/manual_episode_order.html b/_includes/manual_episode_order.html index 573ebde..7908627 100644 --- a/_includes/manual_episode_order.html +++ b/_includes/manual_episode_order.html @@ -35,7 +35,7 @@ as 'url' and 'title' and that are used in 'episode_navbar.html'. - When episode order is specified manualy, the 'lesson_episodes' + When episode order is specified manually, the 'lesson_episodes' variable contains a list of episode names ("slugs", to be precise; "slug" is the episode name without '.md'). Therefore, when we iterate over 'lesson_episodes' (in syllabus.html and navbar.html) , From 134f806afdecc93dc6ae571bd531ad6aea5f7f50 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Wed, 13 Nov 2019 14:45:35 -0600 Subject: [PATCH 04/71] Enable 'Sponsor' button on GitHub repos --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..2ee9d0e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [carpentries, swcarpentry, datacarpentry, librarycarpentry] +custom: ["https://carpentries.wedid.it"] From af588ebca75f69b45dba888b9a5f9433612bc84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Mon, 2 Dec 2019 12:48:29 -0500 Subject: [PATCH 05/71] remove Jekyll command markers from comment block fix carpentries/lesson-example#281 --- _includes/episode_overview.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/episode_overview.html b/_includes/episode_overview.html index c4a4d48..169ab26 100644 --- a/_includes/episode_overview.html +++ b/_includes/episode_overview.html @@ -10,7 +10,7 @@ questions and objectives, we pass them as parameters to the Liquid's `include` statement when we generate the page: - {% include episode_overview.html teaching_time=e.teaching ... %} + include episode_overview.html teaching_time=e.teaching ... Here we obtain the information we need either from the episode itself or from the parameters passed in. From 0cc96db78e050bdc29a5a068ce6d72c116343380 Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Tue, 3 Dec 2019 17:19:44 -0600 Subject: [PATCH 06/71] Forced re-encoding of text to UTF-8, to avoid issues on Windows --- bin/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/util.py b/bin/util.py index f9dc12f..084d5f4 100644 --- a/bin/util.py +++ b/bin/util.py @@ -118,6 +118,7 @@ def read_markdown(parser, path): cmd = 'ruby {0}'.format(parser) p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, close_fds=True, universal_newlines=True) + body = str(body.encode('utf-8')) stdout_data, stderr_data = p.communicate(body) doc = json.loads(stdout_data) From 85660470b8bc1928b941430b0667b24203cc3be8 Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Tue, 3 Dec 2019 17:20:12 -0600 Subject: [PATCH 07/71] Refactored paths to make use of OS agnostic methods --- bin/lesson_check.py | 56 ++++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/bin/lesson_check.py b/bin/lesson_check.py index 2597da5..f7e037a 100755 --- a/bin/lesson_check.py +++ b/bin/lesson_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python """ Check lesson files and their contents. @@ -29,19 +29,19 @@ # specially. This list must include all the Markdown files listed in the # 'bin/initialize' script. REQUIRED_FILES = { - '%/CODE_OF_CONDUCT.md': True, - '%/CONTRIBUTING.md': False, - '%/LICENSE.md': True, - '%/README.md': False, - '%/_extras/discuss.md': True, - '%/_extras/guide.md': True, - '%/index.md': True, - '%/reference.md': True, - '%/setup.md': True, + 'CODE_OF_CONDUCT.md': True, + 'CONTRIBUTING.md': False, + 'LICENSE.md': True, + 'README.md': False, + os.path.join('_extras', 'discuss.md'): True, + os.path.join('_extras', 'guide.md'): True, + 'index.md': True, + 'reference.md': True, + 'setup.md': True, } # Episode filename pattern. -P_EPISODE_FILENAME = re.compile(r'/_episodes/(\d\d)-[-\w]+.md$') +P_EPISODE_FILENAME = re.compile(r'(\d\d)-[-\w]+.md$') # Pattern to match lines ending with whitespace. P_TRAILING_WHITESPACE = re.compile(r'\s+$') @@ -117,7 +117,6 @@ def main(): check_config(args.reporter, args.source_dir) check_source_rmd(args.reporter, args.source_dir, args.parser) args.references = read_references(args.reporter, args.reference_path) - docs = read_all_markdown(args.source_dir, args.parser) check_fileset(args.source_dir, args.reporter, list(docs.keys())) check_unwanted_files(args.source_dir, args.reporter) @@ -157,7 +156,7 @@ def parse_args(): dest='trailing_whitespace', help='Check for trailing whitespace') parser.add_argument('--permissive', - default=False, + default=True, action="store_true", dest='permissive', help='Do not raise an error even if issues are detected') @@ -257,37 +256,56 @@ def read_all_markdown(source_dir, parser): {path : {'metadata':yaml, 'metadata_len':N, 'text':text, 'lines':[(i, line, len)], 'doc':doc}} """ + result = {} + for d in SOURCE_DIRS: + dpath = os.path.join(source_dir, d) + + pattern = os.path.join(dpath, '*.md') + for filename in glob.glob(pattern): + data = read_markdown(parser, filename) + if data: + result[filename] = data + + return result + all_dirs = [os.path.join(source_dir, d) for d in SOURCE_DIRS] + print(all_dirs) all_patterns = [os.path.join(d, '*.md') for d in all_dirs] + print(all_patterns) result = {} for pat in all_patterns: + print(pat) for filename in glob.glob(pat): data = read_markdown(parser, filename) if data: + print(filename) result[filename] = data - return result +# return result def check_fileset(source_dir, reporter, filenames_present): """Are all required files present? Are extraneous files present?""" # Check files with predictable names. - required = [p.replace('%', source_dir) for p in REQUIRED_FILES] + required = [os.path.join(source_dir, p) for p in REQUIRED_FILES] missing = set(required) - set(filenames_present) for m in missing: reporter.add(None, 'Missing required file {0}', m) # Check episode files' names. seen = [] - for filename in filenames_present: - if '_episodes' not in filename: + for filepath in filenames_present: + if '_episodes' not in filepath: continue - m = P_EPISODE_FILENAME.search(filename) + + # split path to check episode name + fname = os.path.basename(filepath) + m = P_EPISODE_FILENAME.search(fname) if m and m.group(1): seen.append(m.group(1)) else: reporter.add( - None, 'Episode {0} has badly-formatted filename', filename) + None, 'Episode {0} has badly-formatted filename', filepath) # Check for duplicate episode numbers. reporter.check(len(seen) == len(set(seen)), From d88b22af656c7d2c119bd7c4336136cc62d5bd5a Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Tue, 3 Dec 2019 17:20:32 -0600 Subject: [PATCH 08/71] Modified shebang to use python, not python3. --- bin/lesson_initialize.py | 2 +- bin/repo_check.py | 2 +- bin/test_lesson_check.py | 2 +- bin/workshop_check.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/lesson_initialize.py b/bin/lesson_initialize.py index 9ba8116..f798a6e 100755 --- a/bin/lesson_initialize.py +++ b/bin/lesson_initialize.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python """Initialize a newly-created repository.""" diff --git a/bin/repo_check.py b/bin/repo_check.py index af4b782..770ccbb 100755 --- a/bin/repo_check.py +++ b/bin/repo_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python """ Check repository settings. diff --git a/bin/test_lesson_check.py b/bin/test_lesson_check.py index 960059e..899d029 100755 --- a/bin/test_lesson_check.py +++ b/bin/test_lesson_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python import unittest diff --git a/bin/workshop_check.py b/bin/workshop_check.py index 0523d0c..c409b89 100755 --- a/bin/workshop_check.py +++ b/bin/workshop_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python '''Check that a workshop's index.html metadata is valid. See the docstrings on the checking functions for a summary of the checks. From 21a979bd3efbfeb5b4d54a316bcb3d419b1f7b23 Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Tue, 3 Dec 2019 17:23:09 -0600 Subject: [PATCH 09/71] Reverted change of permissiveness on lesson_check --- bin/lesson_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/lesson_check.py b/bin/lesson_check.py index f7e037a..887cfa3 100755 --- a/bin/lesson_check.py +++ b/bin/lesson_check.py @@ -156,7 +156,7 @@ def parse_args(): dest='trailing_whitespace', help='Check for trailing whitespace') parser.add_argument('--permissive', - default=True, + default=False, action="store_true", dest='permissive', help='Do not raise an error even if issues are detected') From 901c574eaed6e0779f99baadbf1ab8466c2fff4c Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Wed, 4 Dec 2019 14:15:05 -0600 Subject: [PATCH 10/71] Cleaned leftover debug code and old implementations. --- bin/lesson_check.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/bin/lesson_check.py b/bin/lesson_check.py index 887cfa3..bc585d2 100755 --- a/bin/lesson_check.py +++ b/bin/lesson_check.py @@ -117,6 +117,7 @@ def main(): check_config(args.reporter, args.source_dir) check_source_rmd(args.reporter, args.source_dir, args.parser) args.references = read_references(args.reporter, args.reference_path) + docs = read_all_markdown(args.source_dir, args.parser) check_fileset(args.source_dir, args.reporter, list(docs.keys())) check_unwanted_files(args.source_dir, args.reporter) @@ -268,20 +269,6 @@ def read_all_markdown(source_dir, parser): return result - all_dirs = [os.path.join(source_dir, d) for d in SOURCE_DIRS] - print(all_dirs) - all_patterns = [os.path.join(d, '*.md') for d in all_dirs] - print(all_patterns) - result = {} - for pat in all_patterns: - print(pat) - for filename in glob.glob(pat): - data = read_markdown(parser, filename) - if data: - print(filename) - result[filename] = data -# return result - def check_fileset(source_dir, reporter, filenames_present): """Are all required files present? Are extraneous files present?""" From 82dd7fbfdec9a99121b892667211b11e5b31b643 Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Wed, 4 Dec 2019 16:43:59 -0600 Subject: [PATCH 11/71] Added PYTHON variable to define executable to run python scripts --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index d291abe..8fc7d80 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ JEKYLL=jekyll JEKYLL_VERSION=3.8.5 PARSER=bin/markdown_ast.rb DST=_site +PYTHON=python3 # Controls .PHONY : commands clean files @@ -54,7 +55,7 @@ clean-rmd : ## workshop-check : check workshop homepage. workshop-check : - @bin/workshop_check.py . + ${PYTHON} bin/workshop_check.py . ## ---------------------------------------- ## Commands specific to lesson websites. @@ -93,15 +94,15 @@ _episodes/%.md: _episodes_rmd/%.Rmd ## lesson-check : validate lesson Markdown. lesson-check : lesson-fixme - @bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md + ${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md ## lesson-check-all : validate lesson Markdown, checking line lengths and trailing whitespace. lesson-check-all : - @bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md -l -w --permissive + ${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md -l -w --permissive ## unittest : run unit tests on checking tools. unittest : - @bin/test_lesson_check.py + ${PYTHON} bin/test_lesson_check.py ## lesson-files : show expected names of generated files for debugging. lesson-files : From c9add9b04978e7ba6b617d0572ab09426d6e9796 Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Wed, 4 Dec 2019 16:45:02 -0600 Subject: [PATCH 12/71] Reverted variable names --- bin/lesson_check.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/lesson_check.py b/bin/lesson_check.py index bc585d2..4a4af32 100755 --- a/bin/lesson_check.py +++ b/bin/lesson_check.py @@ -281,18 +281,18 @@ def check_fileset(source_dir, reporter, filenames_present): # Check episode files' names. seen = [] - for filepath in filenames_present: - if '_episodes' not in filepath: + for filename in filenames_present: + if '_episodes' not in filename: continue # split path to check episode name - fname = os.path.basename(filepath) - m = P_EPISODE_FILENAME.search(fname) + base_name = os.path.basename(filename) + m = P_EPISODE_FILENAME.search(base_name) if m and m.group(1): seen.append(m.group(1)) else: reporter.add( - None, 'Episode {0} has badly-formatted filename', filepath) + None, 'Episode {0} has badly-formatted filename', filename) # Check for duplicate episode numbers. reporter.check(len(seen) == len(set(seen)), From a2d1a1f28184982d145297fb0183b9571e75352a Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Wed, 4 Dec 2019 16:45:44 -0600 Subject: [PATCH 13/71] Removed shebang lines from Python scripts to avoid cross-OS problems --- bin/lesson_check.py | 2 -- bin/lesson_initialize.py | 2 -- bin/repo_check.py | 2 -- bin/test_lesson_check.py | 2 -- bin/workshop_check.py | 2 -- 5 files changed, 10 deletions(-) diff --git a/bin/lesson_check.py b/bin/lesson_check.py index 4a4af32..7d135dc 100755 --- a/bin/lesson_check.py +++ b/bin/lesson_check.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - """ Check lesson files and their contents. """ diff --git a/bin/lesson_initialize.py b/bin/lesson_initialize.py index f798a6e..5d0488d 100755 --- a/bin/lesson_initialize.py +++ b/bin/lesson_initialize.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - """Initialize a newly-created repository.""" diff --git a/bin/repo_check.py b/bin/repo_check.py index 770ccbb..51d2fe0 100755 --- a/bin/repo_check.py +++ b/bin/repo_check.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - """ Check repository settings. """ diff --git a/bin/test_lesson_check.py b/bin/test_lesson_check.py index 899d029..10048b1 100755 --- a/bin/test_lesson_check.py +++ b/bin/test_lesson_check.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest import lesson_check diff --git a/bin/workshop_check.py b/bin/workshop_check.py index c409b89..2caf560 100755 --- a/bin/workshop_check.py +++ b/bin/workshop_check.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - '''Check that a workshop's index.html metadata is valid. See the docstrings on the checking functions for a summary of the checks. ''' From cd41c7b84eac8058677df8c3406a26aa8e0c6249 Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Thu, 5 Dec 2019 06:47:00 -0600 Subject: [PATCH 14/71] Fixes encoding problem on Windows systems, with minimal changes to existing code. --- bin/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/util.py b/bin/util.py index 084d5f4..977c4e7 100644 --- a/bin/util.py +++ b/bin/util.py @@ -117,8 +117,8 @@ def read_markdown(parser, path): # Parse Markdown. cmd = 'ruby {0}'.format(parser) p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, - close_fds=True, universal_newlines=True) - body = str(body.encode('utf-8')) + close_fds=True, universal_newlines=True, encoding='utf-8') + stdout_data, stderr_data = p.communicate(body) doc = json.loads(stdout_data) From db22e7bfc719e0e5a3caa8e736b2518e218f0afe Mon Sep 17 00:00:00 2001 From: Joao Rodrigues Date: Thu, 5 Dec 2019 06:50:49 -0600 Subject: [PATCH 15/71] Silenced output of PYTHON calls --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 8fc7d80..89a3105 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ clean-rmd : ## workshop-check : check workshop homepage. workshop-check : - ${PYTHON} bin/workshop_check.py . + @${PYTHON} bin/workshop_check.py . ## ---------------------------------------- ## Commands specific to lesson websites. @@ -94,15 +94,15 @@ _episodes/%.md: _episodes_rmd/%.Rmd ## lesson-check : validate lesson Markdown. lesson-check : lesson-fixme - ${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md + @${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md ## lesson-check-all : validate lesson Markdown, checking line lengths and trailing whitespace. lesson-check-all : - ${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md -l -w --permissive + @${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md -l -w --permissive ## unittest : run unit tests on checking tools. unittest : - ${PYTHON} bin/test_lesson_check.py + @${PYTHON} bin/test_lesson_check.py ## lesson-files : show expected names of generated files for debugging. lesson-files : From 4381bcba70153a0ee0385ef440c7a6e2d7745536 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Thu, 5 Dec 2019 10:46:38 -0600 Subject: [PATCH 16/71] Makefile: detect Python 3 --- Makefile | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 89a3105..ecdb230 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,21 @@ JEKYLL=jekyll JEKYLL_VERSION=3.8.5 PARSER=bin/markdown_ast.rb DST=_site -PYTHON=python3 + +# Check Python 3 (https://stackoverflow.com/a/4933395) +ifneq (, $(shell which python3)) + PYTHON := python3 +else ifneq (, $(shell which python)) + PYTHON_VERSION_FULL := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) + PYTHON_VERSION_MAJOR := $(word 1,${PYTHON_VERSION_FULL}) + ifneq (3, ${PYTHON_VERSION_MAJOR}) + $(error "Your system does not appear to have Python 3 installed.") + endif + PYTHON := python +else + $(error "Your system does not appear to have any Python installed.") +endif + # Controls .PHONY : commands clean files From ff5f567173f6f504c4cc011b338bc4e941486f70 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Thu, 5 Dec 2019 10:49:09 -0600 Subject: [PATCH 17/71] util.py: remove empty line --- bin/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/util.py b/bin/util.py index 977c4e7..5a46cec 100644 --- a/bin/util.py +++ b/bin/util.py @@ -118,7 +118,6 @@ def read_markdown(parser, path): cmd = 'ruby {0}'.format(parser) p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, close_fds=True, universal_newlines=True, encoding='utf-8') - stdout_data, stderr_data = p.communicate(body) doc = json.loads(stdout_data) From a61b7f63ee2694b4ef7494f88bb864ab05576869 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Thu, 5 Dec 2019 13:36:50 -0600 Subject: [PATCH 18/71] Undo optimizations to read_all_markdown These will be submitted in a separate PR --- bin/lesson_check.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bin/lesson_check.py b/bin/lesson_check.py index 7d135dc..d9cc7a7 100755 --- a/bin/lesson_check.py +++ b/bin/lesson_check.py @@ -255,16 +255,14 @@ def read_all_markdown(source_dir, parser): {path : {'metadata':yaml, 'metadata_len':N, 'text':text, 'lines':[(i, line, len)], 'doc':doc}} """ + all_dirs = [os.path.join(source_dir, d) for d in SOURCE_DIRS] + all_patterns = [os.path.join(d, '*.md') for d in all_dirs] result = {} - for d in SOURCE_DIRS: - dpath = os.path.join(source_dir, d) - - pattern = os.path.join(dpath, '*.md') - for filename in glob.glob(pattern): + for pat in all_patterns: + for filename in glob.glob(pat): data = read_markdown(parser, filename) if data: result[filename] = data - return result From bab0fcab35a5e279a539d51b48abc24854deb98e Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Thu, 5 Dec 2019 13:37:44 -0600 Subject: [PATCH 19/71] Remove executable bits from Python scripts We can't use a single shebang: * on some platforms `python` may mean Python 2, on others - Python 3 * on some platforms `python3` does not exist at all Therefore, we're removing the shebangs altogether. --- bin/lesson_check.py | 0 bin/lesson_initialize.py | 0 bin/repo_check.py | 0 bin/test_lesson_check.py | 0 bin/workshop_check.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 bin/lesson_check.py mode change 100755 => 100644 bin/lesson_initialize.py mode change 100755 => 100644 bin/repo_check.py mode change 100755 => 100644 bin/test_lesson_check.py mode change 100755 => 100644 bin/workshop_check.py diff --git a/bin/lesson_check.py b/bin/lesson_check.py old mode 100755 new mode 100644 diff --git a/bin/lesson_initialize.py b/bin/lesson_initialize.py old mode 100755 new mode 100644 diff --git a/bin/repo_check.py b/bin/repo_check.py old mode 100755 new mode 100644 diff --git a/bin/test_lesson_check.py b/bin/test_lesson_check.py old mode 100755 new mode 100644 diff --git a/bin/workshop_check.py b/bin/workshop_check.py old mode 100755 new mode 100644 From bce2366e8f96bc043ff3a8f9a28ac666c701e7e2 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Thu, 5 Dec 2019 14:13:05 -0600 Subject: [PATCH 20/71] lesson_initialize: windows compatibility --- bin/lesson_initialize.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/lesson_initialize.py b/bin/lesson_initialize.py index 5d0488d..1ac8a23 100644 --- a/bin/lesson_initialize.py +++ b/bin/lesson_initialize.py @@ -12,11 +12,11 @@ 'CONTRIBUTING.md', 'README.md', '_config.yml', - '_episodes/01-introduction.md', - '_extras/about.md', - '_extras/discuss.md', - '_extras/figures.md', - '_extras/guide.md', + os.path.join('_episodes', '01-introduction.md'), + os.path.join('_extras', 'about.md'), + os.path.join('_extras', 'discuss.md'), + os.path.join('_extras', 'figures.md'), + os.path.join('_extras', 'guide.md'), 'index.md', 'reference.md', 'setup.md', @@ -39,7 +39,7 @@ def main(): # Create. for path in BOILERPLATE: shutil.copyfile( - "bin/boilerplate/{}".format(path), + os.path.join('bin', 'boilerplate', path) path ) From 1a0adfdeb4048bea419c1b0d3bc0bffd5bf89922 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Thu, 5 Dec 2019 15:20:52 -0600 Subject: [PATCH 21/71] lesson_check.py: Windows-compatible regular expression pattern --- bin/lesson_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/lesson_check.py b/bin/lesson_check.py index d9cc7a7..ee84d84 100644 --- a/bin/lesson_check.py +++ b/bin/lesson_check.py @@ -557,7 +557,7 @@ def __init__(self, args, filename, metadata, metadata_len, text, lines, doc): (re.compile(r'README\.md'), CheckNonJekyll), (re.compile(r'index\.md'), CheckIndex), (re.compile(r'reference\.md'), CheckReference), - (re.compile(r'_episodes/.*\.md'), CheckEpisode), + (re.compile(os.path.join('_episodes', '*\.md')), CheckEpisode), (re.compile(r'.*\.md'), CheckGeneric) ] From ec294aabfb5a26f14e2890e77662ba125eab7411 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Thu, 5 Dec 2019 15:36:51 -0600 Subject: [PATCH 22/71] repo_check.py: enforce utf-8 encoding ... for compatibility with Windows --- bin/repo_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/repo_check.py b/bin/repo_check.py index 51d2fe0..31651fd 100644 --- a/bin/repo_check.py +++ b/bin/repo_check.py @@ -102,7 +102,7 @@ def get_repo_url(repo_url): # Guess. cmd = 'git remote -v' p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, - close_fds=True, universal_newlines=True) + close_fds=True, universal_newlines=True, encoding='utf-8') stdout_data, stderr_data = p.communicate() stdout_data = stdout_data.split('\n') matches = [P_GIT_REMOTE.match(line) for line in stdout_data] From caf3b88f6baf62fca1cabacfe78931f5e0031f93 Mon Sep 17 00:00:00 2001 From: Sarah Brown Date: Fri, 6 Dec 2019 11:53:29 -0500 Subject: [PATCH 23/71] clarify comment on python check block --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ecdb230..dd47203 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ JEKYLL_VERSION=3.8.5 PARSER=bin/markdown_ast.rb DST=_site -# Check Python 3 (https://stackoverflow.com/a/4933395) +# Check Python 3 is installed and determine if it's called via python3 or python +# (https://stackoverflow.com/a/4933395) ifneq (, $(shell which python3)) PYTHON := python3 else ifneq (, $(shell which python)) From d454d5916a5271ec645b219fbdf6e925db187b9f Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 6 Dec 2019 13:31:19 -0600 Subject: [PATCH 24/71] Makefile: Windows does not like single quotes --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dd47203..a4268d7 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ all : commands ## commands : show all commands. commands : - @grep -h -E '^##' ${MAKEFILES} | sed -e 's/## //g' + @grep -h -E '^##' ${MAKEFILES} | sed -e "s/## //g" ## docker-serve : use docker to build the site docker-serve : From 41605eb72f086f2f31766e1ca96d43850f625c65 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 6 Dec 2019 13:31:55 -0600 Subject: [PATCH 25/71] test_lesson_check.py: skip unnecessary steps --- bin/test_lesson_check.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/test_lesson_check.py b/bin/test_lesson_check.py index 10048b1..0981720 100644 --- a/bin/test_lesson_check.py +++ b/bin/test_lesson_check.py @@ -10,10 +10,8 @@ def setUp(self): def test_file_list_has_expected_entries(self): # For first pass, simply assume that all required files are present - all_filenames = [filename.replace('%', '') - for filename in lesson_check.REQUIRED_FILES] - lesson_check.check_fileset('', self.reporter, all_filenames) + lesson_check.check_fileset('', self.reporter, lesson_check.REQUIRED_FILES) self.assertEqual(len(self.reporter.messages), 0) From 651af34cbeccbf8a159320a75ce43f30bf88a753 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 6 Dec 2019 13:43:11 -0600 Subject: [PATCH 26/71] Makefile: suppress error message on Windows --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a4268d7..4daaae6 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ DST=_site # Check Python 3 is installed and determine if it's called via python3 or python # (https://stackoverflow.com/a/4933395) -ifneq (, $(shell which python3)) +ifneq (, $(shell which python3 2>/dev/null)) PYTHON := python3 else ifneq (, $(shell which python)) PYTHON_VERSION_FULL := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) From 8eb0425e98fa8b42f3d628ab712e029c77a18a15 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 6 Dec 2019 14:20:31 -0600 Subject: [PATCH 27/71] fix typo in lesson_initialize.py --- bin/lesson_initialize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/lesson_initialize.py b/bin/lesson_initialize.py index 1ac8a23..2f7b8e6 100644 --- a/bin/lesson_initialize.py +++ b/bin/lesson_initialize.py @@ -39,7 +39,7 @@ def main(): # Create. for path in BOILERPLATE: shutil.copyfile( - os.path.join('bin', 'boilerplate', path) + os.path.join('bin', 'boilerplate', path), path ) From ecb16113fc647b59cb3ee4d66bfc717fdb755444 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 6 Dec 2019 15:11:48 -0600 Subject: [PATCH 28/71] Makefile: suppress another error message on Windows These '2>/dev/null' are important on Windows because without them a mere `make` stalls. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4daaae6..ba5080a 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ DST=_site # (https://stackoverflow.com/a/4933395) ifneq (, $(shell which python3 2>/dev/null)) PYTHON := python3 -else ifneq (, $(shell which python)) +else ifneq (, $(shell which python 2>/dev/null)) PYTHON_VERSION_FULL := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) PYTHON_VERSION_MAJOR := $(word 1,${PYTHON_VERSION_FULL}) ifneq (3, ${PYTHON_VERSION_MAJOR}) From e6622b88a854224eb6e6a6b118c000f0bcc12736 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Mon, 9 Dec 2019 16:45:16 -0600 Subject: [PATCH 29/71] Makefile: handle MS Store's Python 3 --- Makefile | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index ba5080a..a0cad9e 100644 --- a/Makefile +++ b/Makefile @@ -10,17 +10,25 @@ DST=_site # Check Python 3 is installed and determine if it's called via python3 or python # (https://stackoverflow.com/a/4933395) -ifneq (, $(shell which python3 2>/dev/null)) - PYTHON := python3 -else ifneq (, $(shell which python 2>/dev/null)) - PYTHON_VERSION_FULL := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) - PYTHON_VERSION_MAJOR := $(word 1,${PYTHON_VERSION_FULL}) - ifneq (3, ${PYTHON_VERSION_MAJOR}) - $(error "Your system does not appear to have Python 3 installed.") +PYTHON3_EXE := $(shell which python3 2>/dev/null) +ifneq (, $(PYTHON3_EXE)) + ifeq $(,findstring Microsoft/WindowsApps/python3,$(subst \,/,$(PYTHON3_EXE))) + PYTHON := python3 + endif +endif + +ifeq $(,$(PYTHON)) + PYTHON_EXE := $(shell which python 2>/dev/null) + ifneq (, $(PYTHON_EXE)) + PYTHON_VERSION_FULL := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) + PYTHON_VERSION_MAJOR := $(word 1,${PYTHON_VERSION_FULL}) + ifneq (3, ${PYTHON_VERSION_MAJOR}) + $(error "Your system does not appear to have Python 3 installed.") + endif + PYTHON := python + else + $(error "Your system does not appear to have any Python installed.") endif - PYTHON := python -else - $(error "Your system does not appear to have any Python installed.") endif From a732a2b2e6f9db3632d8c6a58eeb985b5fd12b26 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Mon, 9 Dec 2019 16:51:12 -0600 Subject: [PATCH 30/71] Makefile: fix syntax in conditional --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a0cad9e..f4f44d0 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ DST=_site # (https://stackoverflow.com/a/4933395) PYTHON3_EXE := $(shell which python3 2>/dev/null) ifneq (, $(PYTHON3_EXE)) - ifeq $(,findstring Microsoft/WindowsApps/python3,$(subst \,/,$(PYTHON3_EXE))) + ifeq $(,$(findstring Microsoft/WindowsApps/python3,$(subst \,/,$(PYTHON3_EXE)))) PYTHON := python3 endif endif From f1cb887d2083f05ae570cb44d7615c3b6cb9f913 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Mon, 9 Dec 2019 16:55:00 -0600 Subject: [PATCH 31/71] Makefile: fix two more syntax errors in conditionals --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f4f44d0..5ae969f 100644 --- a/Makefile +++ b/Makefile @@ -12,12 +12,12 @@ DST=_site # (https://stackoverflow.com/a/4933395) PYTHON3_EXE := $(shell which python3 2>/dev/null) ifneq (, $(PYTHON3_EXE)) - ifeq $(,$(findstring Microsoft/WindowsApps/python3,$(subst \,/,$(PYTHON3_EXE)))) + ifeq (,$(findstring Microsoft/WindowsApps/python3,$(subst \,/,$(PYTHON3_EXE)))) PYTHON := python3 endif endif -ifeq $(,$(PYTHON)) +ifeq (,$(PYTHON)) PYTHON_EXE := $(shell which python 2>/dev/null) ifneq (, $(PYTHON_EXE)) PYTHON_VERSION_FULL := $(wordlist 2,4,$(subst ., ,$(shell python --version 2>&1))) From 48dd39145c5819c28a0088eb29756533159732e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Wed, 11 Dec 2019 14:02:49 -0500 Subject: [PATCH 32/71] fix urls in _config.yml --- bin/boilerplate/_config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/boilerplate/_config.yml b/bin/boilerplate/_config.yml index c1e433e..fb6359c 100644 --- a/bin/boilerplate/_config.yml +++ b/bin/boilerplate/_config.yml @@ -32,11 +32,11 @@ repository: / email: "team@carpentries.org" # Sites. -amy_site: "https://amy.software-carpentry.org/workshops" +amy_site: "https://amy.carpentries.org/workshops" carpentries_github: "https://github.com/carpentries" carpentries_pages: "https://carpentries.github.io" carpentries_site: "https://carpentries.org/" -dc_site: "http://datacarpentry.org" +dc_site: "https://datacarpentry.org" example_repo: "https://github.com/carpentries/lesson-example" example_site: "https://carpentries.github.io/lesson-example" lc_site: "https://librarycarpentry.org/" From a56f2a08ca56307aaf0f2ab1ed45412dacd7ea1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Thu, 12 Sep 2019 16:41:02 +0200 Subject: [PATCH 33/71] use bundler to render lessons --- .gitignore | 2 +- Gemfile | 2 ++ Makefile | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 Gemfile diff --git a/.gitignore b/.gitignore index 27af20d..2776745 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,4 @@ _site .Rproj.user .Rhistory .RData - +Gemfile.lock \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..37f5eaa --- /dev/null +++ b/Gemfile @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gem 'github-pages', group: :jekyll_plugins diff --git a/Makefile b/Makefile index 5ae969f..5c9eba0 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,9 @@ # Settings MAKEFILES=Makefile $(wildcard *.mk) -JEKYLL=jekyll JEKYLL_VERSION=3.8.5 +JEKYLL=bundle update && bundle exec jekyll +JEKYLL_DOCKER=${JEKYLL} serve --host 0.0.0.0 PARSER=bin/markdown_ast.rb DST=_site @@ -43,7 +44,7 @@ commands : ## docker-serve : use docker to build the site docker-serve : - docker run --rm -it -v ${PWD}:/srv/jekyll -p 127.0.0.1:4000:4000 jekyll/jekyll:${JEKYLL_VERSION} make serve + docker run --rm -it -v ${PWD}:/srv/jekyll -p 4000:4000 jekyll/jekyll:${JEKYLL_VERSION} ${JEKYLL_DOCKER} ## serve : run a local server. serve : lesson-md From 0b6797efdc994f0e6cbaff5e36b4a80366ab43ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Wed, 11 Dec 2019 14:59:47 -0500 Subject: [PATCH 34/71] install gems locally --- .gitignore | 1 + Makefile | 2 +- bin/boilerplate/_config.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2776745..2f3299e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ _site .Rproj.user .Rhistory .RData +.vendor/ Gemfile.lock \ No newline at end of file diff --git a/Makefile b/Makefile index 5c9eba0..124e397 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ # Settings MAKEFILES=Makefile $(wildcard *.mk) JEKYLL_VERSION=3.8.5 -JEKYLL=bundle update && bundle exec jekyll JEKYLL_DOCKER=${JEKYLL} serve --host 0.0.0.0 +JEKYLL=bundle install --path .vendor/bundle && bundle update && bundle exec jekyll PARSER=bin/markdown_ast.rb DST=_site diff --git a/bin/boilerplate/_config.yml b/bin/boilerplate/_config.yml index fb6359c..a1b32fe 100644 --- a/bin/boilerplate/_config.yml +++ b/bin/boilerplate/_config.yml @@ -91,6 +91,7 @@ exclude: - Makefile - bin/ - .Rproj.user/ + - .vendor/ # Turn on built-in syntax highlighting. highlighter: rouge From 116d5b92846b72eb74af032846ad08a7f5616c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Wed, 11 Dec 2019 15:06:25 -0500 Subject: [PATCH 35/71] refactor use of docker Co-authored-by: Allen Lee --- .gitignore | 1 + Makefile | 7 +++++-- bin/boilerplate/_config.yml | 1 + bin/run-make-docker-serve.sh | 10 ++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) create mode 100755 bin/run-make-docker-serve.sh diff --git a/.gitignore b/.gitignore index 2f3299e..1aec1b6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ _site .Rhistory .RData .vendor/ +.docker-vendor/ Gemfile.lock \ No newline at end of file diff --git a/Makefile b/Makefile index 124e397..1fdc5d2 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ # Settings MAKEFILES=Makefile $(wildcard *.mk) JEKYLL_VERSION=3.8.5 -JEKYLL_DOCKER=${JEKYLL} serve --host 0.0.0.0 JEKYLL=bundle install --path .vendor/bundle && bundle update && bundle exec jekyll PARSER=bin/markdown_ast.rb DST=_site @@ -44,7 +43,11 @@ commands : ## docker-serve : use docker to build the site docker-serve : - docker run --rm -it -v ${PWD}:/srv/jekyll -p 4000:4000 jekyll/jekyll:${JEKYLL_VERSION} ${JEKYLL_DOCKER} + docker run --rm -it --volume ${PWD}:/srv/jekyll \ + --volume=${PWD}/.docker-vendor/bundle:/usr/local/bundle \ + -p 127.0.0.1:4000:4000 \ + jekyll/jekyll:${JEKYLL_VERSION} \ + bin/run-make-docker-serve.sh ## serve : run a local server. serve : lesson-md diff --git a/bin/boilerplate/_config.yml b/bin/boilerplate/_config.yml index a1b32fe..f5067e5 100644 --- a/bin/boilerplate/_config.yml +++ b/bin/boilerplate/_config.yml @@ -92,6 +92,7 @@ exclude: - bin/ - .Rproj.user/ - .vendor/ + - .docker-vendor/ # Turn on built-in syntax highlighting. highlighter: rouge diff --git a/bin/run-make-docker-serve.sh b/bin/run-make-docker-serve.sh new file mode 100755 index 0000000..1e09178 --- /dev/null +++ b/bin/run-make-docker-serve.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -o errexit +set -o pipefail +set -o nounset + + +bundle install +bundle update +exec bundle exec jekyll serve --host 0.0.0.0 From fade440e042c04c61004e0499fb42972bc89ba51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Fri, 13 Dec 2019 12:09:40 -0500 Subject: [PATCH 36/71] add @maxim-belkin suggestions --- Gemfile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Gemfile b/Gemfile index 37f5eaa..1ece4c0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,2 +1,10 @@ +# frozen_string_literal: true + source 'https://rubygems.org' + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +# Synchronize with https://pages.github.com/versions +ruby '>=2.5.3' + gem 'github-pages', group: :jekyll_plugins From aaab128d7c2609a86c57c2891a0a03bc870a1cd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Fri, 13 Dec 2019 15:50:42 -0500 Subject: [PATCH 37/71] add .bundle to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1aec1b6..a27efc9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ _site .Rproj.user .Rhistory .RData +.bundle/ .vendor/ .docker-vendor/ Gemfile.lock \ No newline at end of file From 38c1c0c457fba5ab71d08f9072b803eb2af84155 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 13 Dec 2019 11:48:58 -0600 Subject: [PATCH 38/71] Makefile: Specify shell. Don't include commands.mk --- Makefile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 1fdc5d2..14a53a2 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,6 @@ +# Use /bin/bash instead of /bin/sh +export SHELL = /bin/bash + ## ======================================== ## Commands for both workshop and lesson websites. @@ -142,8 +145,3 @@ lesson-files : lesson-fixme : @fgrep -i -n FIXME ${MARKDOWN_SRC} || true -#------------------------------------------------------------------------------- -# Include extra commands if available. -#------------------------------------------------------------------------------- - --include commands.mk From a435fcd371d20b2ea26cc646fbef3c8ee45a1718 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 13 Dec 2019 12:12:16 -0600 Subject: [PATCH 39/71] Makefile: use Python to execute repo_check.py --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 14a53a2..b878885 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ site : lesson-md # repo-check : check repository settings. repo-check : - @bin/repo_check.py -s . + @${PYTHON} bin/repo_check.py -s . ## clean : clean up junk files. clean : From e986d1a3e304dfd6b172282cd0eeeb78fe19ce7a Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 13 Dec 2019 16:30:00 -0600 Subject: [PATCH 40/71] Makefile: improve commands target and commands categories (#450) * Makefile: improve commands target and commands categories * replace 'files' with 'website' --- Makefile | 67 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/Makefile b/Makefile index b878885..c2b1853 100644 --- a/Makefile +++ b/Makefile @@ -37,34 +37,34 @@ endif # Controls .PHONY : commands clean files -.NOTPARALLEL: -all : commands -## commands : show all commands. -commands : - @grep -h -E '^##' ${MAKEFILES} | sed -e "s/## //g" +# Default target +.DEFAULT_GOAL := commands -## docker-serve : use docker to build the site -docker-serve : - docker run --rm -it --volume ${PWD}:/srv/jekyll \ - --volume=${PWD}/.docker-vendor/bundle:/usr/local/bundle \ - -p 127.0.0.1:4000:4000 \ - jekyll/jekyll:${JEKYLL_VERSION} \ - bin/run-make-docker-serve.sh +## I. Commands for both workshop and lesson websites +## ================================================= -## serve : run a local server. +## * serve : render website and run a local server serve : lesson-md ${JEKYLL} serve -## site : build files but do not run a server. +## * site : build website but do not run a server site : lesson-md ${JEKYLL} build -# repo-check : check repository settings. +## * docker-serve : use Docker to serve the site +docker-serve : + docker run --rm -it --volume ${PWD}:/srv/jekyll \ + --volume=${PWD}/.docker-vendor/bundle:/usr/local/bundle \ + -p 127.0.0.1:4000:4000 \ + jekyll/jekyll:${JEKYLL_VERSION} \ + bin/run-make-docker-serve.sh + +## * repo-check : check repository settings repo-check : @${PYTHON} bin/repo_check.py -s . -## clean : clean up junk files. +## * clean : clean up junk files clean : @rm -rf ${DST} @rm -rf .sass-cache @@ -73,22 +73,26 @@ clean : @find . -name '*~' -exec rm {} \; @find . -name '*.pyc' -exec rm {} \; -## clean-rmd : clean intermediate R files (that need to be committed to the repo). +## * clean-rmd : clean intermediate R files (that need to be committed to the repo) clean-rmd : @rm -rf ${RMD_DST} @rm -rf fig/rmd-* -## ---------------------------------------- -## Commands specific to workshop websites. + +## +## II. Commands specific to workshop websites +## ================================================= .PHONY : workshop-check -## workshop-check : check workshop homepage. +## * workshop-check : check workshop homepage workshop-check : @${PYTHON} bin/workshop_check.py . -## ---------------------------------------- -## Commands specific to lesson websites. + +## +## III. Commands specific to lesson websites +## ================================================= .PHONY : lesson-check lesson-md lesson-files lesson-fixme @@ -116,32 +120,39 @@ HTML_DST = \ $(patsubst _extras/%.md,${DST}/%/index.html,$(sort $(wildcard _extras/*.md))) \ ${DST}/license/index.html -## lesson-md : convert Rmarkdown files to markdown +## * lesson-md : convert Rmarkdown files to markdown lesson-md : ${RMD_DST} _episodes/%.md: _episodes_rmd/%.Rmd @bin/knit_lessons.sh $< $@ -## lesson-check : validate lesson Markdown. +# * lesson-check : validate lesson Markdown lesson-check : lesson-fixme @${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md -## lesson-check-all : validate lesson Markdown, checking line lengths and trailing whitespace. +## * lesson-check-all : validate lesson Markdown, checking line lengths and trailing whitespace lesson-check-all : @${PYTHON} bin/lesson_check.py -s . -p ${PARSER} -r _includes/links.md -l -w --permissive -## unittest : run unit tests on checking tools. +## * unittest : run unit tests on checking tools unittest : @${PYTHON} bin/test_lesson_check.py -## lesson-files : show expected names of generated files for debugging. +## * lesson-files : show expected names of generated files for debugging lesson-files : @echo 'RMD_SRC:' ${RMD_SRC} @echo 'RMD_DST:' ${RMD_DST} @echo 'MARKDOWN_SRC:' ${MARKDOWN_SRC} @echo 'HTML_DST:' ${HTML_DST} -## lesson-fixme : show FIXME markers embedded in source files. +## * lesson-fixme : show FIXME markers embedded in source files lesson-fixme : @fgrep -i -n FIXME ${MARKDOWN_SRC} || true +## +## IV. Auxililary (plumbing) commands +## ================================================= + +## * commands : show all commands. +commands : + @sed -n -e '/^##/s|^##[[:space:]]*||p' $(MAKEFILE_LIST) From a0c0681d99259fba47b0abea36f178b876758130 Mon Sep 17 00:00:00 2001 From: Anthony Gitter Date: Mon, 16 Dec 2019 13:39:10 -0600 Subject: [PATCH 41/71] Update R install in .travis.yml (#430) * Update R install in .travis.yml See https://cran.r-project.org/bin/linux/ubuntu/README.html * update .travis.yml --- bin/boilerplate/.travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/boilerplate/.travis.yml b/bin/boilerplate/.travis.yml index 4f23be8..d91aaf4 100644 --- a/bin/boilerplate/.travis.yml +++ b/bin/boilerplate/.travis.yml @@ -1,3 +1,4 @@ +# Travis CI is only used to check the lesson and is not involved in its deployment dist: xenial # Ubuntu 16.04 (required for python 3.7) language: python python: 3.7 @@ -7,7 +8,7 @@ branches: - /.*/ before_install: - sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9 - - echo "deb https://cran.rstudio.com/bin/linux/ubuntu trusty/" | sudo tee -a /etc/apt/sources.list + - echo "deb https://cloud.r-project.org/bin/linux/ubuntu xenial-cran35/" | sudo tee -a /etc/apt/sources.list - sudo apt-get update -y - sudo apt-get install -y r-base - sudo Rscript -e "install.packages('knitr', repos = 'https://', dependencies = TRUE)" @@ -15,7 +16,7 @@ before_install: - sudo Rscript -e "install.packages('checkpoint', repos = 'https://cran.rstudio.com', dependencies = TRUE)" - sudo Rscript -e "install.packages('ggplot2', repos = 'https://cran.rstudio.com', dependencies = TRUE)" - rvm default - - gem install json kramdown jekyll + - gem install json kramdown jekyll bundler install: - pip install pyyaml script: From b5c28789c7480a9b84a4b534cc2f060e4a82968a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Wed, 18 Dec 2019 14:25:25 -0500 Subject: [PATCH 42/71] specify YAML loader Co-authored-by: Daniel McCloy c --- bin/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/util.py b/bin/util.py index 5a46cec..f1499ff 100644 --- a/bin/util.py +++ b/bin/util.py @@ -144,7 +144,7 @@ def split_metadata(path, text): metadata_raw = pieces[1] text = pieces[2] try: - metadata_yaml = yaml.load(metadata_raw, Loader=yaml.FullLoader) + metadata_yaml = yaml.load(metadata_raw, Loader=yaml.SafeLoader) except yaml.YAMLError as e: print('Unable to parse YAML header in {0}:\n{1}'.format( path, e), file=sys.stderr) @@ -161,7 +161,7 @@ def load_yaml(filename): try: with open(filename, 'r') as reader: - return yaml.load(reader, Loader=yaml.FullLoader) + return yaml.load(reader, Loader=yaml.SafeLoader) except (yaml.YAMLError, IOError) as e: print('Unable to load YAML file {0}:\n{1}'.format( filename, e), file=sys.stderr) From 2f07ce17b6e32174b689deac3fe1e6658499a4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Mon, 10 Feb 2020 09:35:22 -0500 Subject: [PATCH 43/71] add warning hook + CSS class for Rmd-based lessons (#455) --- assets/css/lesson.scss | 18 +++++++++++------- bin/chunk-options.R | 19 +++++++++++++------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/assets/css/lesson.scss b/assets/css/lesson.scss index cba7c42..472e287 100644 --- a/assets/css/lesson.scss +++ b/assets/css/lesson.scss @@ -10,6 +10,7 @@ $color-brand: #2b3990 !default; // code boxes $color-error: #bd2c00 !default; +$color-warning: #cda01d !default; $color-output: #303030 !default; $color-source: #360084 !default; @@ -36,9 +37,10 @@ $color-testimonial: #fc8dc1 !default; border-radius: 4px 0 0 4px; } -.error { @include cdSetup($color-error); } -.output { @include cdSetup($color-output); } -.source { @include cdSetup($color-source); } +.error { @include cdSetup($color-error); } +.warning { @include cdSetup($color-warning); } +.output { @include cdSetup($color-output); } +.source { @include cdSetup($color-source); } .bash, .language-bash { @include cdSetup($color-source); } .make, .language-make { @include cdSetup($color-source); } @@ -48,6 +50,7 @@ $color-testimonial: #fc8dc1 !default; .sql, .language-sql { @include cdSetup($color-source); } .error::before, +.warning:before, .output::before, .source::before, .bash::before, .language-bash::before, @@ -56,13 +59,14 @@ $color-testimonial: #fc8dc1 !default; .python::before, .language-python::before, .r::before, .language-r::before, .sql::before, .language-sql::before { - background-color: #f2eff6; - display: block; - font-weight: bold; - padding: 5px 10px; + background-color: #f2eff6; + display: block; + font-weight: bold; + padding: 5px 10px; } .error::before { background-color: #ffebe6; content: "Error"; } +.warning:before { background-color: #f8f4e8; content:" Warning"; } .output::before { background-color: #efefef; content: "Output"; } .source::before { content: "Code"; } .bash::before, .language-bash::before { content: "Bash"; } diff --git a/bin/chunk-options.R b/bin/chunk-options.R index b0559cb..8e0d62a 100644 --- a/bin/chunk-options.R +++ b/bin/chunk-options.R @@ -48,16 +48,23 @@ hook_in <- function(x, options) { hook_out <- function(x, options) { x <- gsub("\n$", "", x) stringr::str_c("\n\n~~~\n", - paste0(x, collapse="\n"), - "\n~~~\n{: .output}\n\n") + paste0(x, collapse="\n"), + "\n~~~\n{: .output}\n\n") } hook_error <- function(x, options) { x <- gsub("\n$", "", x) stringr::str_c("\n\n~~~\n", - paste0(x, collapse="\n"), - "\n~~~\n{: .error}\n\n") + paste0(x, collapse="\n"), + "\n~~~\n{: .error}\n\n") +} + +hook_warning <- function(x, options) { + x <- gsub("\n$", "", x) + stringr::str_c("\n\n~~~\n", + paste0(x, collapse = "\n"), + "\n~~~\n{: .warning}\n\n") } -knit_hooks$set(source = hook_in, output = hook_out, warning = hook_error, - error = hook_error, message = hook_out) +knit_hooks$set(source = hook_in, output = hook_out, warning = hook_warning, + error = hook_error, message = hook_out) From aaf5d76ce4a561bfdb03996bf4667e3030099f7f Mon Sep 17 00:00:00 2001 From: Katrin Leinweber <9948149+katrinleinweber@users.noreply.github.com> Date: Wed, 12 Feb 2020 17:00:11 +0100 Subject: [PATCH 44/71] Update PyPI link --- _includes/links.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/links.md b/_includes/links.md index 4a85ed4..abe6093 100644 --- a/_includes/links.md +++ b/_includes/links.md @@ -35,7 +35,7 @@ [pandoc]: https://pandoc.org/ [paper-now]: https://github.com/PeerJ/paper-now [python-gapminder]: https://swcarpentry.github.io/python-novice-gapminder/ -[pyyaml]: https://pypi.python.org/pypi/PyYAML +[pyyaml]: https://pypi.org/project/PyYAML/ [r-markdown]: https://rmarkdown.rstudio.com/ [rstudio]: https://www.rstudio.com/ [ruby-install-guide]: https://www.ruby-lang.org/en/downloads/ From bc5c9baa3358620cde9f9b30f8aecc37c90fe286 Mon Sep 17 00:00:00 2001 From: "Zhian N. Kamvar" Date: Thu, 28 May 2020 02:18:22 -0700 Subject: [PATCH 45/71] Use carpentries/lesson-docker for docker-serve make rule (#461) --- .gitignore | 3 ++- Makefile | 14 ++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index a27efc9..d717a12 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ _site .bundle/ .vendor/ .docker-vendor/ -Gemfile.lock \ No newline at end of file +Gemfile.lock +.*history diff --git a/Makefile b/Makefile index c2b1853..366840e 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,6 @@ export SHELL = /bin/bash # Settings MAKEFILES=Makefile $(wildcard *.mk) -JEKYLL_VERSION=3.8.5 JEKYLL=bundle install --path .vendor/bundle && bundle update && bundle exec jekyll PARSER=bin/markdown_ast.rb DST=_site @@ -54,11 +53,14 @@ site : lesson-md ## * docker-serve : use Docker to serve the site docker-serve : - docker run --rm -it --volume ${PWD}:/srv/jekyll \ - --volume=${PWD}/.docker-vendor/bundle:/usr/local/bundle \ - -p 127.0.0.1:4000:4000 \ - jekyll/jekyll:${JEKYLL_VERSION} \ - bin/run-make-docker-serve.sh + docker pull carpentries/lesson-docker:latest + docker run --rm -it \ + -v $${PWD}:/home/rstudio \ + -p 4000:4000 \ + -p 8787:8787 \ + -e USERID=$$(id -u) \ + -e GROUPID=$$(id -g) \ + carpentries/lesson-docker:latest ## * repo-check : check repository settings repo-check : From 4f78e1711735e3c6b8d45934e45ae99a958f2be9 Mon Sep 17 00:00:00 2001 From: "Zhian N. Kamvar" Date: Fri, 29 May 2020 06:01:17 -0700 Subject: [PATCH 46/71] Use renv (#462) --- bin/generate_md_episodes.R | 56 ++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/bin/generate_md_episodes.R b/bin/generate_md_episodes.R index 7f37a7b..7c137d7 100644 --- a/bin/generate_md_episodes.R +++ b/bin/generate_md_episodes.R @@ -1,20 +1,21 @@ generate_md_episodes <- function() { - library("methods") - - if (!require("remotes", quietly = TRUE)) { - install.packages("remotes", repos = c(CRAN = "https://cloud.r-project.org/")) + if (!requireNamespace("renv", quietly = TRUE)) { + install.packages("renv", repos = c(CRAN = "https://cloud.r-project.org/")) } - if (!require("requirements", quietly = TRUE)) { - remotes::install_github("hadley/requirements") + if (!requireNamespace("rprojroot", quietly = TRUE)) { + install.packages("rprojroot", repos = c(CRAN = "https://cloud.r-project.org/")) } + cfg <- rprojroot::has_file_pattern("^_config.y*ml$") + root <- rprojroot::find_root(cfg) + required_pkgs <- unique(c( ## Packages for episodes - requirements:::req_dir("_episodes_rmd"), + renv::dependencies(file.path(root, "_episodes_rmd"), progress = FALSE, error = "ignore")$Package, ## Pacakges for tools - requirements:::req_dir("bin") + renv::dependencies(file.path(root, "bin"), progress = FALSE, error = "ignore")$Package )) missing_pkgs <- setdiff(required_pkgs, rownames(installed.packages())) @@ -28,7 +29,8 @@ generate_md_episodes <- function() { if (require("knitr") && packageVersion("knitr") < '1.9.19') stop("knitr must be version 1.9.20 or higher") - ## get the Rmd file to process from the command line, and generate the path for their respective outputs + ## get the Rmd file to process from the command line, and generate the path + ## for their respective outputs args <- commandArgs(trailingOnly = TRUE) if (!identical(length(args), 2L)) { stop("input and output file must be passed to the script") @@ -40,20 +42,28 @@ generate_md_episodes <- function() { ## knit the Rmd into markdown knitr::knit(src_rmd, output = dest_md) - # Read the generated md files and add comments advising not to edit them - vapply(dest_md, function(y) { - con <- file(y) - mdfile <- readLines(con) - if (mdfile[1] != "---") - stop("Input file does not have a valid header") - mdfile <- append(mdfile, "# Please do not edit this file directly; it is auto generated.", after = 1) - mdfile <- append(mdfile, paste("# Instead, please edit", - basename(y), "in _episodes_rmd/"), after = 2) - writeLines(mdfile, con) - close(con) - return(paste("Warning added to YAML header of", y)) - }, - character(1)) + # Read the generated md files and add comments advising not to edit them + add_no_edit_comment <- function(y) { + con <- file(y) + mdfile <- readLines(con) + if (mdfile[1] != "---") + stop("Input file does not have a valid header") + mdfile <- append( + mdfile, + "# Please do not edit this file directly; it is auto generated.", + after = 1 + ) + mdfile <- append( + mdfile, + paste("# Instead, please edit", basename(y), "in _episodes_rmd/"), + after = 2 + ) + writeLines(mdfile, con) + close(con) + return(paste("Warning added to YAML header of", y)) + } + + vapply(dest_md, add_no_edit_comment, character(1)) } generate_md_episodes() From 0deede13a0dbf9a0a20ee9a080b81d60223a5f42 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Mon, 15 Jun 2020 09:13:24 -0500 Subject: [PATCH 47/71] Improve issue template (#463) Co-authored-by: Sarah Brown --- .github/ISSUE_TEMPLATE.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index ec2d4fe..077de4c 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,11 +1,21 @@ -Please delete this line and the text below before submitting your contribution. +
+Instructions ---- +Thanks for contributing! :heart: -Thanks for contributing! If this contribution is for instructor training, please send an email to checkout@carpentries.org with a link to this contribution so we can record your progress. You’ve completed your contribution step for instructor checkout just by submitting this contribution. +If this contribution is for instructor training, please email the link to this contribution to +checkout@carpentries.org so we can record your progress. You've completed your contribution +step for instructor checkout by submitting this contribution! If this issue is about a specific episode within a lesson, please provide its link or filename. -Please keep in mind that lesson maintainers are volunteers and it may be some time before they can respond to your contribution. Although not all contributions can be incorporated into the lesson materials, we appreciate your time and effort to improve the curriculum. If you have any questions about the lesson maintenance process or would like to volunteer your time as a contribution reviewer, please contact The Carpentries Team at team@carpentries.org. +Keep in mind that **lesson maintainers are volunteers** and it may take them some time to +respond to your contribution. Although not all contributions can be incorporated into the lesson +materials, we appreciate your time and effort to improve the curriculum. If you have any questions +about the lesson maintenance process or would like to volunteer your time as a contribution +reviewer, please contact The Carpentries Team at team@carpentries.org. ---- +You may delete these instructions from your comment. + +\- The Carpentries +
From 6f3004391a9e101285deef8879eb8ae6596a6a92 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Fri, 19 Jun 2020 07:58:25 -0500 Subject: [PATCH 48/71] lesson.scss: style tab panels on setup pages (#464) --- assets/css/lesson.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assets/css/lesson.scss b/assets/css/lesson.scss index 472e287..eccc530 100644 --- a/assets/css/lesson.scss +++ b/assets/css/lesson.scss @@ -76,6 +76,13 @@ $color-testimonial: #fc8dc1 !default; .r::before, .language-r::before { content: "R"; } .sql::before, .language-sql::before { content: "SQL"; } +// Tab panels are used on Setup pages to show instructions for different Operating Systems +.tab-pane { + border: solid 1px #ddd; // #ddd == @nav-tabs-active-link-hover-border-color + border-top: none; + padding: 20px 20px 10px 20px; + border-radius: 0 0 4px 4px; // 4px == @border-radius-base +} //---------------------------------------- // Specialized blockquote environments for learning objectives, callouts, etc. From 974ee95cd3b71a9be370e02a25d0f3e0be2e040c Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Mon, 22 Jun 2020 11:15:46 -0500 Subject: [PATCH 49/71] Improve pull request template (#465) --- .github/PULL_REQUEST_TEMPLATE.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d9eb8c5..07aadca 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,9 +1,19 @@ -Please delete this line and the text below before submitting your contribution. +
+Instructions ---- +Thanks for contributing! :heart: -Thanks for contributing! If this contribution is for instructor training, please send an email to checkout@carpentries.org with a link to this contribution so we can record your progress. You’ve completed your contribution step for instructor checkout just by submitting this contribution. +If this contribution is for instructor training, please email the link to this contribution to +checkout@carpentries.org so we can record your progress. You've completed your contribution +step for instructor checkout by submitting this contribution! -Please keep in mind that lesson maintainers are volunteers and it may be some time before they can respond to your contribution. Although not all contributions can be incorporated into the lesson materials, we appreciate your time and effort to improve the curriculum. If you have any questions about the lesson maintenance process or would like to volunteer your time as a contribution reviewer, please contact The Carpentries Team at team@carpentries.org. +Keep in mind that **lesson maintainers are volunteers** and it may take them some time to +respond to your contribution. Although not all contributions can be incorporated into the lesson +materials, we appreciate your time and effort to improve the curriculum. If you have any questions +about the lesson maintenance process or would like to volunteer your time as a contribution +reviewer, please contact The Carpentries Team at team@carpentries.org. ---- +You may delete these instructions from your comment. + +\- The Carpentries +
From 3847b97ab655f2f4b04e2676ac707cb1ac7b8639 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Mon, 29 Jun 2020 03:12:43 -0500 Subject: [PATCH 50/71] OS stripe color (#468) --- assets/css/lesson.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/assets/css/lesson.scss b/assets/css/lesson.scss index eccc530..53f158f 100644 --- a/assets/css/lesson.scss +++ b/assets/css/lesson.scss @@ -84,6 +84,18 @@ $color-testimonial: #fc8dc1 !default; border-radius: 0 0 4px 4px; // 4px == @border-radius-base } +// Stripe above tab panels where OS tabs are shown +ul.nav.nav-tabs { + background: #E1E1E1; + border-radius: 4px 4px 0 0; // 4px == @border-radius-base +} + +// This color provides better contrast ratio on most backgrounds used on Carpentries websites +// 9.24 on FFFFFF: https://webaim.org/resources/contrastchecker/?fcolor=204A6F&bcolor=FFFFFF&api (body) +// 8.78 on F9F9F9: https://webaim.org/resources/contrastchecker/?fcolor=204A6F&bcolor=F9F9F9&api (tables) +// 7.07 on E1E1E1: https://webaim.org/resources/contrastchecker/?fcolor=204A6F&bcolor=E1E1E1&api (tab panels) +a { color: #204A6F; } + //---------------------------------------- // Specialized blockquote environments for learning objectives, callouts, etc. //---------------------------------------- From a52f6c2db42fbb2d314163848dcee9e2b9b2e467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Michonneau?= Date: Mon, 29 Jun 2020 10:07:09 -0400 Subject: [PATCH 51/71] bump ruby version --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1ece4c0..fb25ae4 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,6 @@ source 'https://rubygems.org' git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } # Synchronize with https://pages.github.com/versions -ruby '>=2.5.3' +ruby '>=2.5.8' gem 'github-pages', group: :jekyll_plugins From 5d4aaa2fb38e78d161af6f84ed0fde3abed5c8b9 Mon Sep 17 00:00:00 2001 From: Maxim Belkin Date: Tue, 30 Jun 2020 05:31:19 -0500 Subject: [PATCH 52/71] Upgrade jQuery to 3.5.1 (#469) ``` cd assets/js wget https://code.jquery.com/jquery-3.5.1.min.js wget https://code.jquery.com/jquery-3.5.1.min.map mv -f jquery-3.5.1.min.js jquery.min.js mv -f jquery-3.5.1.min.map jquery.min.map ``` Fixes carpentries/styles#460 --- assets/js/jquery.min.js | 8 ++------ assets/js/jquery.min.map | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/assets/js/jquery.min.js b/assets/js/jquery.min.js index f364443..b061403 100644 --- a/assets/js/jquery.min.js +++ b/assets/js/jquery.min.js @@ -1,6 +1,2 @@ -/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1; - -return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/\s*$/g,ra={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?""!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("