diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..2cfde055 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 7dd3f632a4eafd7997d1360b239eebdc +tags: d77d1c0d9ca2f4c8421862c7c5a0d620 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/LICENSE/index.html b/LICENSE/index.html new file mode 100644 index 00000000..6d7b9391 --- /dev/null +++ b/LICENSE/index.html @@ -0,0 +1,503 @@ + + + + + + <no title> — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Attribution 4.0 International

+

=======================================================================

+

Creative Commons Corporation (“Creative Commons”) is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an “as-is” basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible.

+

Using Creative Commons Public Licenses

+

Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses.

+
 Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More considerations
+ for the public:
+wiki.creativecommons.org/Considerations_for_licensees
+
+
+

=======================================================================

+

Creative Commons Attribution 4.0 International Public License

+

By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License (“Public License”). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions.

+

Section 1 – Definitions.

+

a. Adapted Material means material subject to Copyright and Similar +Rights that is derived from or based upon the Licensed Material +and in which the Licensed Material is translated, altered, +arranged, transformed, or otherwise modified in a manner requiring +permission under the Copyright and Similar Rights held by the +Licensor. For purposes of this Public License, where the Licensed +Material is a musical work, performance, or sound recording, +Adapted Material is always produced where the Licensed Material is +synched in timed relation with a moving image.

+

b. Adapter’s License means the license You apply to Your Copyright +and Similar Rights in Your contributions to Adapted Material in +accordance with the terms and conditions of this Public License.

+

c. Copyright and Similar Rights means copyright and/or similar rights +closely related to copyright including, without limitation, +performance, broadcast, sound recording, and Sui Generis Database +Rights, without regard to how the rights are labeled or +categorized. For purposes of this Public License, the rights +specified in Section 2(b)(1)-(2) are not Copyright and Similar +Rights.

+

d. Effective Technological Measures means those measures that, in the +absence of proper authority, may not be circumvented under laws +fulfilling obligations under Article 11 of the WIPO Copyright +Treaty adopted on December 20, 1996, and/or similar international +agreements.

+

e. Exceptions and Limitations means fair use, fair dealing, and/or +any other exception or limitation to Copyright and Similar Rights +that applies to Your use of the Licensed Material.

+

f. Licensed Material means the artistic or literary work, database, +or other material to which the Licensor applied this Public +License.

+

g. Licensed Rights means the rights granted to You subject to the +terms and conditions of this Public License, which are limited to +all Copyright and Similar Rights that apply to Your use of the +Licensed Material and that the Licensor has authority to license.

+

h. Licensor means the individual(s) or entity(ies) granting rights +under this Public License.

+

i. Share means to provide material to the public by any means or +process that requires permission under the Licensed Rights, such +as reproduction, public display, public performance, distribution, +dissemination, communication, or importation, and to make material +available to the public including in ways that members of the +public may access the material from a place and at a time +individually chosen by them.

+

j. Sui Generis Database Rights means rights other than copyright +resulting from Directive 96/9/EC of the European Parliament and of +the Council of 11 March 1996 on the legal protection of databases, +as amended and/or succeeded, as well as other essentially +equivalent rights anywhere in the world.

+

k. You means the individual or entity exercising the Licensed Rights +under this Public License. Your has a corresponding meaning.

+

Section 2 – Scope.

+

a. License grant.

+
   1. Subject to the terms and conditions of this Public License,
+      the Licensor hereby grants You a worldwide, royalty-free,
+      non-sublicensable, non-exclusive, irrevocable license to
+      exercise the Licensed Rights in the Licensed Material to:
+
+        a. reproduce and Share the Licensed Material, in whole or
+           in part; and
+
+        b. produce, reproduce, and Share Adapted Material.
+
+   2. Exceptions and Limitations. For the avoidance of doubt, where
+      Exceptions and Limitations apply to Your use, this Public
+      License does not apply, and You do not need to comply with
+      its terms and conditions.
+
+   3. Term. The term of this Public License is specified in Section
+      6(a).
+
+   4. Media and formats; technical modifications allowed. The
+      Licensor authorizes You to exercise the Licensed Rights in
+      all media and formats whether now known or hereafter created,
+      and to make technical modifications necessary to do so. The
+      Licensor waives and/or agrees not to assert any right or
+      authority to forbid You from making technical modifications
+      necessary to exercise the Licensed Rights, including
+      technical modifications necessary to circumvent Effective
+      Technological Measures. For purposes of this Public License,
+      simply making modifications authorized by this Section 2(a)
+      (4) never produces Adapted Material.
+
+   5. Downstream recipients.
+
+        a. Offer from the Licensor -- Licensed Material. Every
+           recipient of the Licensed Material automatically
+           receives an offer from the Licensor to exercise the
+           Licensed Rights under the terms and conditions of this
+           Public License.
+
+        b. No downstream restrictions. You may not offer or impose
+           any additional or different terms or conditions on, or
+           apply any Effective Technological Measures to, the
+           Licensed Material if doing so restricts exercise of the
+           Licensed Rights by any recipient of the Licensed
+           Material.
+
+   6. No endorsement. Nothing in this Public License constitutes or
+      may be construed as permission to assert or imply that You
+      are, or that Your use of the Licensed Material is, connected
+      with, or sponsored, endorsed, or granted official status by,
+      the Licensor or others designated to receive attribution as
+      provided in Section 3(a)(1)(A)(i).
+
+
+

b. Other rights.

+
   1. Moral rights, such as the right of integrity, are not
+      licensed under this Public License, nor are publicity,
+      privacy, and/or other similar personality rights; however, to
+      the extent possible, the Licensor waives and/or agrees not to
+      assert any such rights held by the Licensor to the limited
+      extent necessary to allow You to exercise the Licensed
+      Rights, but not otherwise.
+
+   2. Patent and trademark rights are not licensed under this
+      Public License.
+
+   3. To the extent possible, the Licensor waives any right to
+      collect royalties from You for the exercise of the Licensed
+      Rights, whether directly or through a collecting society
+      under any voluntary or waivable statutory or compulsory
+      licensing scheme. In all other cases the Licensor expressly
+      reserves any right to collect such royalties.
+
+
+

Section 3 – License Conditions.

+

Your exercise of the Licensed Rights is expressly made subject to the +following conditions.

+

a. Attribution.

+
   1. If You Share the Licensed Material (including in modified
+      form), You must:
+
+        a. retain the following if it is supplied by the Licensor
+           with the Licensed Material:
+
+             i. identification of the creator(s) of the Licensed
+                Material and any others designated to receive
+                attribution, in any reasonable manner requested by
+                the Licensor (including by pseudonym if
+                designated);
+
+            ii. a copyright notice;
+
+           iii. a notice that refers to this Public License;
+
+            iv. a notice that refers to the disclaimer of
+                warranties;
+
+             v. a URI or hyperlink to the Licensed Material to the
+                extent reasonably practicable;
+
+        b. indicate if You modified the Licensed Material and
+           retain an indication of any previous modifications; and
+
+        c. indicate the Licensed Material is licensed under this
+           Public License, and include the text of, or the URI or
+           hyperlink to, this Public License.
+
+   2. You may satisfy the conditions in Section 3(a)(1) in any
+      reasonable manner based on the medium, means, and context in
+      which You Share the Licensed Material. For example, it may be
+      reasonable to satisfy the conditions by providing a URI or
+      hyperlink to a resource that includes the required
+      information.
+
+   3. If requested by the Licensor, You must remove any of the
+      information required by Section 3(a)(1)(A) to the extent
+      reasonably practicable.
+
+   4. If You Share Adapted Material You produce, the Adapter's
+      License You apply must not prevent recipients of the Adapted
+      Material from complying with this Public License.
+
+
+

Section 4 – Sui Generis Database Rights.

+

Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material:

+

a. for the avoidance of doubt, Section 2(a)(1) grants You the right +to extract, reuse, reproduce, and Share all or a substantial +portion of the contents of the database;

+

b. if You include all or a substantial portion of the database +contents in a database in which You have Sui Generis Database +Rights, then the database in which You have Sui Generis Database +Rights (but not its individual contents) is Adapted Material; and

+

c. You must comply with the conditions in Section 3(a) if You Share +all or a substantial portion of the contents of the database.

+

For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights.

+

Section 5 – Disclaimer of Warranties and Limitation of Liability.

+

a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE +EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS +AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF +ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, +IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, +WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, +ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT +KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT +ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.

+

b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE +TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, +NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, +INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, +COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR +USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR +DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR +IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.

+

c. The disclaimer of warranties and limitation of liability provided +above shall be interpreted in a manner that, to the extent +possible, most closely approximates an absolute disclaimer and +waiver of all liability.

+

Section 6 – Term and Termination.

+

a. This Public License applies for the term of the Copyright and +Similar Rights licensed here. However, if You fail to comply with +this Public License, then Your rights under this Public License +terminate automatically.

+

b. Where Your right to use the Licensed Material has terminated under +Section 6(a), it reinstates:

+
   1. automatically as of the date the violation is cured, provided
+      it is cured within 30 days of Your discovery of the
+      violation; or
+
+   2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+
+

c. For the avoidance of doubt, the Licensor may also offer the +Licensed Material under separate terms or conditions or stop +distributing the Licensed Material at any time; however, doing so +will not terminate this Public License.

+

d. Sections 1, 5, 6, 7, and 8 survive termination of this Public +License.

+

Section 7 – Other Terms and Conditions.

+

a. The Licensor shall not be bound by any additional or different +terms or conditions communicated by You unless expressly agreed.

+

b. Any arrangements, understandings, or agreements regarding the +Licensed Material not stated herein are separate from and +independent of the terms and conditions of this Public License.

+

Section 8 – Interpretation.

+

a. For the avoidance of doubt, this Public License does not, and +shall not be interpreted to, reduce, limit, restrict, or impose +conditions on any use of the Licensed Material that could lawfully +be made without permission under this Public License.

+

b. To the extent possible, if any provision of this Public License is +deemed unenforceable, it shall be automatically reformed to the +minimum extent necessary to make it enforceable. If the provision +cannot be reformed, it shall be severed from this Public License +without affecting the enforceability of the remaining terms and +conditions.

+

c. No term or condition of this Public License will be waived and no +failure to comply consented to unless expressly agreed to by the +Licensor.

+

d. Nothing in this Public License constitutes or may be interpreted +as a limitation upon, or waiver of, any privileges and immunities +that apply to the Licensor or You, including from the legal +processes of any jurisdiction or authority.

+

=======================================================================

+

Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark “Creative Commons” or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses.

+

Creative Commons may be contacted at creativecommons.org.

+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_builds/CodeRefineryManuals.epub b/_builds/CodeRefineryManuals.epub new file mode 100644 index 00000000..783f81d5 Binary files /dev/null and b/_builds/CodeRefineryManuals.epub differ diff --git a/_builds/CodeRefineryManuals.pdf b/_builds/CodeRefineryManuals.pdf new file mode 100644 index 00000000..97cf3ad8 Binary files /dev/null and b/_builds/CodeRefineryManuals.pdf differ diff --git a/_builds/singlehtml/.buildinfo b/_builds/singlehtml/.buildinfo new file mode 100644 index 00000000..6748630f --- /dev/null +++ b/_builds/singlehtml/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 7dd3f632a4eafd7997d1360b239eebdc +tags: 33eac41acc08762151beb8f3b7b86c8f diff --git a/_builds/singlehtml/_images/chat--join-stream.png b/_builds/singlehtml/_images/chat--join-stream.png new file mode 100644 index 00000000..ae277c6b Binary files /dev/null and b/_builds/singlehtml/_images/chat--join-stream.png differ diff --git a/_builds/singlehtml/_images/exercise_options.png b/_builds/singlehtml/_images/exercise_options.png new file mode 100644 index 00000000..e756d9e8 Binary files /dev/null and b/_builds/singlehtml/_images/exercise_options.png differ diff --git a/_builds/singlehtml/_images/hackmd--controls.png b/_builds/singlehtml/_images/hackmd--controls.png new file mode 100644 index 00000000..46a74c75 Binary files /dev/null and b/_builds/singlehtml/_images/hackmd--controls.png differ diff --git a/_builds/singlehtml/_images/hackmd--full-demo.png b/_builds/singlehtml/_images/hackmd--full-demo.png new file mode 100644 index 00000000..0988b6f2 Binary files /dev/null and b/_builds/singlehtml/_images/hackmd--full-demo.png differ diff --git a/_builds/singlehtml/_images/hackmd--questions2.png b/_builds/singlehtml/_images/hackmd--questions2.png new file mode 100644 index 00000000..a6091991 Binary files /dev/null and b/_builds/singlehtml/_images/hackmd--questions2.png differ diff --git a/_builds/singlehtml/_images/instructor.png b/_builds/singlehtml/_images/instructor.png new file mode 100644 index 00000000..718f2a89 Binary files /dev/null and b/_builds/singlehtml/_images/instructor.png differ diff --git a/_builds/singlehtml/_images/layout--learner-livestream-sidebyside-onebrowser.png b/_builds/singlehtml/_images/layout--learner-livestream-sidebyside-onebrowser.png new file mode 100644 index 00000000..1681abbf Binary files /dev/null and b/_builds/singlehtml/_images/layout--learner-livestream-sidebyside-onebrowser.png differ diff --git a/_builds/singlehtml/_images/learner-largescreen.png b/_builds/singlehtml/_images/learner-largescreen.png new file mode 100644 index 00000000..3b6d2cdd Binary files /dev/null and b/_builds/singlehtml/_images/learner-largescreen.png differ diff --git a/_builds/singlehtml/_images/learner-normal.png b/_builds/singlehtml/_images/learner-normal.png new file mode 100644 index 00000000..590135e5 Binary files /dev/null and b/_builds/singlehtml/_images/learner-normal.png differ diff --git a/_builds/singlehtml/_images/learner-small.png b/_builds/singlehtml/_images/learner-small.png new file mode 100644 index 00000000..5d5f4216 Binary files /dev/null and b/_builds/singlehtml/_images/learner-small.png differ diff --git a/_builds/singlehtml/_images/mooc-diagram.png b/_builds/singlehtml/_images/mooc-diagram.png new file mode 100644 index 00000000..2b0a98ba Binary files /dev/null and b/_builds/singlehtml/_images/mooc-diagram.png differ diff --git a/_builds/singlehtml/_images/obs--controls.png b/_builds/singlehtml/_images/obs--controls.png new file mode 100644 index 00000000..8e5b9668 Binary files /dev/null and b/_builds/singlehtml/_images/obs--controls.png differ diff --git a/_builds/singlehtml/_images/s10-kickstart-prompt-log.png b/_builds/singlehtml/_images/s10-kickstart-prompt-log.png new file mode 100644 index 00000000..415799fb Binary files /dev/null and b/_builds/singlehtml/_images/s10-kickstart-prompt-log.png differ diff --git a/_builds/singlehtml/_images/s5-shell-intro-dark.png b/_builds/singlehtml/_images/s5-shell-intro-dark.png new file mode 100644 index 00000000..a1aef3c5 Binary files /dev/null and b/_builds/singlehtml/_images/s5-shell-intro-dark.png differ diff --git a/_builds/singlehtml/_images/s8-modular-code-development.png b/_builds/singlehtml/_images/s8-modular-code-development.png new file mode 100644 index 00000000..5f4361cd Binary files /dev/null and b/_builds/singlehtml/_images/s8-modular-code-development.png differ diff --git a/_builds/singlehtml/_images/s9-git-intro.png b/_builds/singlehtml/_images/s9-git-intro.png new file mode 100644 index 00000000..2fc1fa67 Binary files /dev/null and b/_builds/singlehtml/_images/s9-git-intro.png differ diff --git a/_builds/singlehtml/_images/screenshare-fullhd.png b/_builds/singlehtml/_images/screenshare-fullhd.png new file mode 100644 index 00000000..eda9d42d Binary files /dev/null and b/_builds/singlehtml/_images/screenshare-fullhd.png differ diff --git a/_builds/singlehtml/_images/screenshare-jupyter.png b/_builds/singlehtml/_images/screenshare-jupyter.png new file mode 100644 index 00000000..1e7bb5cf Binary files /dev/null and b/_builds/singlehtml/_images/screenshare-jupyter.png differ diff --git a/_builds/singlehtml/_images/screenshare-rsh.png b/_builds/singlehtml/_images/screenshare-rsh.png new file mode 100644 index 00000000..1bbb1ccc Binary files /dev/null and b/_builds/singlehtml/_images/screenshare-rsh.png differ diff --git a/_builds/singlehtml/_images/screenshare-vertical.png b/_builds/singlehtml/_images/screenshare-vertical.png new file mode 100644 index 00000000..28e18b06 Binary files /dev/null and b/_builds/singlehtml/_images/screenshare-vertical.png differ diff --git a/_builds/singlehtml/_images/teach-teaching--screenshot.png b/_builds/singlehtml/_images/teach-teaching--screenshot.png new file mode 100644 index 00000000..75cdb8d0 Binary files /dev/null and b/_builds/singlehtml/_images/teach-teaching--screenshot.png differ diff --git a/_builds/singlehtml/_images/team_status.png b/_builds/singlehtml/_images/team_status.png new file mode 100644 index 00000000..c1862868 Binary files /dev/null and b/_builds/singlehtml/_images/team_status.png differ diff --git a/_builds/singlehtml/_images/zoom--learner-names.png b/_builds/singlehtml/_images/zoom--learner-names.png new file mode 100644 index 00000000..39356971 Binary files /dev/null and b/_builds/singlehtml/_images/zoom--learner-names.png differ diff --git a/_builds/singlehtml/_images/zoom--participants.png b/_builds/singlehtml/_images/zoom--participants.png new file mode 100644 index 00000000..580ba9ca Binary files /dev/null and b/_builds/singlehtml/_images/zoom--participants.png differ diff --git a/_builds/singlehtml/_images/zoom--reactions.png b/_builds/singlehtml/_images/zoom--reactions.png new file mode 100644 index 00000000..88ec071a Binary files /dev/null and b/_builds/singlehtml/_images/zoom--reactions.png differ diff --git a/_builds/singlehtml/_images/zoom--rename.png b/_builds/singlehtml/_images/zoom--rename.png new file mode 100644 index 00000000..c4042e23 Binary files /dev/null and b/_builds/singlehtml/_images/zoom--rename.png differ diff --git a/_builds/singlehtml/_images/zoom--settings-monitors-fullscreen.png b/_builds/singlehtml/_images/zoom--settings-monitors-fullscreen.png new file mode 100644 index 00000000..127689fe Binary files /dev/null and b/_builds/singlehtml/_images/zoom--settings-monitors-fullscreen.png differ diff --git a/_builds/singlehtml/_static/_sphinx_javascript_frameworks_compat.js b/_builds/singlehtml/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..8549469d --- /dev/null +++ b/_builds/singlehtml/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,134 @@ +/* + * _sphinx_javascript_frameworks_compat.js + * ~~~~~~~~~~ + * + * Compatability shim for jQuery and underscores.js. + * + * WILL BE REMOVED IN Sphinx 6.0 + * xref RemovedInSphinx60Warning + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_builds/singlehtml/_static/basic.css b/_builds/singlehtml/_static/basic.css new file mode 100644 index 00000000..eeb0519a --- /dev/null +++ b/_builds/singlehtml/_static/basic.css @@ -0,0 +1,899 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} +dl.field-list > dt:after { + content: ":"; +} + + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_builds/singlehtml/_static/coderefinery.ico b/_builds/singlehtml/_static/coderefinery.ico new file mode 100644 index 00000000..a2df0fb6 Binary files /dev/null and b/_builds/singlehtml/_static/coderefinery.ico differ diff --git a/_builds/singlehtml/_static/css/badge_only.css b/_builds/singlehtml/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/_builds/singlehtml/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.eot b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.svg b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.ttf b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.woff b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-bold-italic.woff b/_builds/singlehtml/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-bold-italic.woff2 b/_builds/singlehtml/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-bold.woff b/_builds/singlehtml/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-bold.woff differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-bold.woff2 b/_builds/singlehtml/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-bold.woff2 differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-normal-italic.woff b/_builds/singlehtml/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-normal-italic.woff2 b/_builds/singlehtml/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-normal.woff b/_builds/singlehtml/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-normal.woff differ diff --git a/_builds/singlehtml/_static/css/fonts/lato-normal.woff2 b/_builds/singlehtml/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/_builds/singlehtml/_static/css/fonts/lato-normal.woff2 differ diff --git a/_builds/singlehtml/_static/css/theme.css b/_builds/singlehtml/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/_builds/singlehtml/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_builds/singlehtml/_static/doctools.js b/_builds/singlehtml/_static/doctools.js new file mode 100644 index 00000000..527b876c --- /dev/null +++ b/_builds/singlehtml/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_builds/singlehtml/_static/documentation_options.js b/_builds/singlehtml/_static/documentation_options.js new file mode 100644 index 00000000..d353a877 --- /dev/null +++ b/_builds/singlehtml/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'singlehtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_builds/singlehtml/_static/file.png b/_builds/singlehtml/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_builds/singlehtml/_static/file.png differ diff --git a/_builds/singlehtml/_static/jquery-3.6.0.js b/_builds/singlehtml/_static/jquery-3.6.0.js new file mode 100644 index 00000000..fc6c299b --- /dev/null +++ b/_builds/singlehtml/_static/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CodeRefinery operation manuals

+

This site contains various manuals about CodeRefinery workshops and +teaching/lesson development in general.

+

These pages document past history, but they don’t dictate future. +They are a starting point: feel free to be adventurous.

+
+
+

Attending an livestream workshop

+

We are glad you would like to attend an livestream workshop. This page +will help you prepare and get the most out of the workshop and take +advantage of the diverse ways to attend.

+

Even though it’s a one-to-many livestream, the course is still +interactive. In fact, it’s more interactive, since everyone can Q&A +at the same time via HackMD. Since we can +record without privacy risk, you are better able to catch up and +review. Read on to learn more.

+
    +
  • You might register to Zoom breakout rooms, which are interactive.

  • +
  • HackMD allows you to ask questions anonymously - +even better than a normal workshop! Once we have a few tens of people in +any workshop, people don’t ask voice questions anyway.

  • +
  • In some workshops, you can register for breakout rooms to get +interactive assistance during the exercise/breakout sessions.

  • +
+
+

How it works

+
    +
  • You open the livestream in a web browser. This is the “TV”, it is +always on (but sometimes silent).

  • +
  • If you are part of an exercise/breakout group, be with them. The +stream will tell you when the exercise/collaboration times are, and +you go to there.

    +
      +
    • If you are attending Zoom exercise session, open this at the +beginning. Leave it minimized when it’s not active.

    • +
    • If you are with an in-person group, be together. When the stream +is quiet, you can interact freely.

    • +
    +
  • +
  • The livestream is a portrait screenshare, so that it will only take +up half of your screen (and the other half is for you to work). (If +you are in a physical meeting room with a projector or second +monitor, it can be half the livestream and half the HackMD - this +will make sense when you see it).

  • +
+
+_images/layout--learner-livestream-sidebyside-onebrowser.png +

Screen layout with livestream on one side and workshop on the other.

+
+
+
+

General prerequisites, software installation, etc.

+

Check your workshop page for the general setup specific to that +workshop.

+
    +
  • Often, there is something to install on your own computer. (We +usually ask you to set up your own computer, so you can continue +working independently later.)

  • +
  • There may be some basic skills, such as the command line shell, to +review in advance.

  • +
+

Do the installation and configuration in advance, and double check +it. Our instructions are standard enough that someone local should +be able to help you, if some central install help isn’t provided. The +livestream can’t wait for individual people (but a local group can +provide live support).

+
+
+

Take the workshop seriously

+

It’s easy to think “it’s just online, it’s easy to passively watch”. +And that is OK! We’d rather have someone watch in case it might be +useful, than exclude people who don’t have time. Our material is +available for later. In this case, please don’t register for our +Zoom/in-person sessions, since that can take a spot from others.

+

However, we design the workshops to be interactive, and there is a lot +of time scheduled for hands-on work and Q&A. Reading this page and +preparing will help you to make the most of it: don’t do multiple +meetings, reserve the entire timeslots on your calendar, attend +every session, do the preparation.

+
+
+

Social

+

Attend with someone! Register together and try to be in their same +group. You could even reserve a room and work together. This will +create a network of learning and practice that will last much longer.

+

If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills.

+
+
+

Workspace

+

Get a good, quiet workspace. Make sure it is comfortable enough to +stay at for a while.

+

An extra monitor is useful but not required, since there is a lot of +stuff to follow: the stream itself, the lesson webpage, and the window +where you are doing the assignment. You could also use a second +device to watch the stream. However, we do design things to fit on +one computer.

+

If you have registered to attend breakout rooms, you’ll be expected +to talk at some times and take part, not simply be +quiet and listen all the time. Try to be in a place where you can +speak without disturbing others. By the same token, you’ll be +listening for a long time, and your ears may get tired of headphones. +If you have good enough external speakers, be somewhere that you can +use them (perhaps only sometimes - when it doesn’t interfere with your +microphone.)

+

If you work in a large office, consider attending from home or in a +meeting room so that you can speak and listen more freely. If you +need and extra monitor or more comfortable seating space and don’t +have that at home, consider working at your office. Yes, these are +conflicting ideas, you need to find what works best for you.

+
+
+

Time management

+

Paying attention to something requires time, whether it is online or +in-person.

+

Don’t schedule overlapping meetings, reserve the entire timeslots, +minimize distractions. It’s easy to think you can do multiple things +at once when doing it online, but really it’s a trap.

+

Plan to join the stream 10 minutes early to get ready - we start with +icebreakers and discussion then.

+

There will be breaks, but even long ones go by very fast, and this +gives you limited time to make coffee, eat, etc. We try to limit +ourselves to half-days because of this, but consider preparing food, +coffee, etc. in advance.

+

Make sure you take the breaks, walk around some, etc.

+
+
+

Accessibility

+

We believe that livestream workshops offer a wide variety of tools +which are useful to allow everyone to succeed. Consider how you want +to attend to make it the best for you:

+
    +
  • Our material is provided in writing (lesson websites), by voice, and +by demo. You don’t have to strictly follow along at the speed we +teach.

  • +
  • We record videos and post the notes so you can review at your own +pace later on. Videos don’t include audience voice or video, so you +don’t have to be afraid to interact.

  • +
  • HackMD allows anyone to ask questions anonymously and +asynchronously, without interrupting others. On the other hand, +there are a lot of questions, so don’t watch too closely if it is +distracting. We continue answering questions for a little bit after +each day ends, so you can ask even if you can’t write the question +on time.

  • +
  • Lesson websites/HackMD use standard web technologies, so that +browser accessibility plugins can be used (for example making the +font more accessible, check browser extensions).

  • +
  • Twitch can be live-captioned using the Google Chrome browser. Our +videos on YouTube provide automatic captions immediately, since +videos are released immediately they don’t come too late for you. +Other standard browser extensions can also provide other video +accessibility services without asking us.

  • +
  • You can follow along without providing any personal data +(registration, Twitch works with cookies blocked) - though +registration helps our reporting.

  • +
+
+
+

Communication

+

Most communication goes through HackMD. Make sure +that you open it and try it out during the icebreakers - it will +become obvious then. There will be an absolute flood of information +there, so watch strategically and don’t let yourself get overloaded.

+

HackMD is much better than chat, since you can ask anonymously, you +can ask at the same time as others, and multiple people can +answer, and we fix it up and publish it at the end.

+
+
+

Final notes

+

Join the stream 10 minutes in advance. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start.

+

There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions.

+

Sign up on the notify me +list to hear +about what comes next.

+
+
+
+

Attending a Zoom workshop

+

We are glad you would like to attend an online workshop. This page +will help you mentally and physically prepare.

+

Our workshops are interactive and hands-on, and you will get the most +out of them if you can take part in all exercises, unlike a normal +academic lecture where you mainly listen. Thus, please read this and +come prepared!

+
+

General prerequisites, software installation, etc.

+

Check your workshop page for the general setup specific to that +workshop.

+
    +
  • Often, there is something to install. We usually ask you to install +things so that your computer is set up to do work later.

  • +
  • There may be some basic skills, such as the command line shell, to +review in advance.

  • +
+

Do the installation and configuration in advance, and double check +it. In real workshops, problems here slow us down a lot, and if +you don’t prepare, you will immediately fall behind. If there is a +pre-workshop session for installation, go there if needed.

+

If all else fails, join the workshop well in advance and ask +for help then. Usually, there will be enough time to get ready for +the day.

+
+
+

Take the workshop seriously

+

It’s easy to think “it’s just online, it’s easy to passively watch”. +However, for an interactive workshop you do need to take part to get +the most of out it, and our workshops are targeted to that. If you +read this page and the workshop prerequisites, you should be OK.

+

Don’t do multiple meetings, reserve the entire timeslots on your +calendar, attend every session, do the preparation.

+
+
+

Social

+

Attend with someone! Register together and try to be in their same +group. You could even reserve a room and work together. This will +create a network of learning and practice that will last much longer.

+

If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills.

+
+
+

Workspace

+

Get a good, quiet workspace. Make sure it is comfortable enough to +stay at for a while.

+

An extra monitor is useful but not required, since there is a lot of +stuff to follow: the stream itself, the lesson webpage, and the window +where you are doing the assignment. You could also use a second +device to watch the stream (but if you do, see the +Zoom page for info about screen sharing).

+

You’ll be expected to talk at some times and take part, not simply be +quiet and listen all the time. Try to be in a place where you can +speak without disturbing others. By the same token, you’ll be +listening for a long time, and your ears may get tired of headphones. +If you have good enough external speakers, be somewhere that you can +use them (perhaps only sometimes - when it doesn’t interfere with your +microphone.)

+

If you work in a large office, consider attending from home or in a +meeting room so that you can speak and listen more freely. If you +need and extra monitor or more comfortable seating space and don’t +have that at home, consider working at your office. Yes, these are +conflicting ideas, you need to find what works best for you.

+
+
+

Time management

+

Despite what most people think, attending things online can be harder +than in-person.

+

Don’t schedule overlapping meetings, reserve the entire timeslots, +minimze distractions. It’s easy to think you can do multiple things +at once when doing it online, but really it’s a trap.

+

Join the workshop 10 minutes early to get ready.

+

There will be breaks, but even long ones go by very fast, and this +gives you limited time to make coffee, eat, etc. We try to limit +ourselves to half-days because of this, but consider preparing food, +coffee, etc. in advance.

+

Make sure you take the breaks, walk around some, etc.

+
+
+

Live streaming

+

If the workshop is also streamed, see +Live streaming for how to attend that +way.

+
+
+

Final notes

+

Join the stream 10 minutes in advance. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start.

+

There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions.

+

Sign up on the notify me +list to hear +about what comes next.

+
+
+
+

Attending an in-person workshop

+

We are glad you would like to attend an in-person workshop. This page +will help you mentally and physically prepare.

+

Our workshops are interactive and hands-on, and you will get the most +out of them if you can take part in all exercises, unlike a normal +academic lecture where you mainly listen. Thus, please read this and +come prepared!

+
+

General prerequisites, software installation, etc.

+

Check your workshop page for the general setup specific to that +workshop.

+
    +
  • Often, there is something to install. We usually ask you to install +things so that your computer is set up to do work later.

  • +
  • There may be some basic skills, such as the command line shell, to +review in advance.

  • +
+

If all else fails, join the workshop well in advance and ask +for help then. Usually, there will be enough time to get ready for +the day.

+
+
+

Take the workshop seriously

+

It’s easy to think “it’s just a class, it’s easy to passively watch”. +However, for an interactive workshop you do need to take part to get +the most of out it, and our workshops are targeted to that. If you +read this page and the workshop prerequisites, you should be OK.

+
+
+

Social

+

Attend with someone! Register together and try to sit near them. +This will create a network of learning and practice that will last +much longer.

+

If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills.

+
+
+

Computer and equipment

+

Bring your laptop and charger, of course. If you use external mice, +etc, it would be good to bring them too. You’ll be on your device a +lot.

+

Usually, you’ll need to look at both the lesson webpage and the window +where you are doing the exercises at the same time. Consider how you +can arrange windows to do this best.

+
+
+

Time management

+

Try your very best to attend the whole workshops; at least don’t miss +the early sessions. Later sessions depend on earlier ones, and it’s +easy to get behind. Tell others this is important so that you can +free your schedule.

+

Arrive 10 minutes early to get ready.

+
+
+

Final notes

+

Arrive 10 minutes in advance to get set-up. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start.

+

There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions.

+

Sign up on the notify me +list to hear +about what comes next.

+
+
+
+

Zoom mechanics and controls

+
+

Basics

+
    +
  • Most Zoom controls are probably well known by now, but if not, view +Zoom’s basic +guide

  • +
  • Mute and unmute yourself from the buttons on bottom.

  • +
  • You can rename yourself from the participants list (hover over +your name.

  • +
  • We don’t use Zoom chat for typical questions: use HackMD instead.

    +
      +
    • Chat OK for administrative questions.

    • +
    +
  • +
  • When joining, please use the name you used to register for the +course.

  • +
  • In livestream workshops, there is nothing in the main room: that +is broadcasted via livestream in a separate browser window, and you +switch as needed.

  • +
+
+
+

Audio/video on or off?

+
    +
  • Main room: Stay muted, video off, unless you want to speak up.

  • +
  • Breakout rooms: Try to leave on for most interactive +atmosphere.

  • +
+
+
+

Workshops with teams: your name should indicate your breakout room

+

You will be told if this section is relevant to you.

+
    +
  • Have your breakout room number in your name:

    +
      +
    • (number) Your Name

    • +
    • (number,H) The Name for helpers

    • +
    +

    Names with breakout room numbers

    +
  • +
  • Rename yourself in a meeting by starting participants list:

    +

    participants list button at bottom

    +

    Rename is found if you hover your name and click “more”

    +

    participants list button at bottom

    +
  • +
+
+
+

Breakout rooms

+
    +
  • Click the “breakout rooms” button at bottom and you can join a +room.

  • +
  • You can click “Join” to join your breakout room by yourself.

    +
      +
    • If you are joined via web, make sure your name is correct (see +above) and use Zoom chat to ask host to assign you to the room.

    • +
    +
  • +
  • Return to main room: “Leave” button at bottom has an option for +“Return to main room”.

  • +
+
+
+

Reactions

+

We watch the participant list and can see these reactions (in the +application):

+

Zoom reactions via the bottom bar

+
    +
  • Task completed: Green check

  • +
  • Technical problem: Red X

  • +
  • Need more time: Slower “<<”

  • +
  • You can signal go faster and go slower

  • +
  • You can Raise your hand

  • +
+
+
+

Other settings

+

Other zoom settings

+
    +
  • Automatic fullscreen when screenshare starts can be turned off

  • +
  • Dual monitor mode makes separate windows for screenshare and participants

  • +
+
+
+

See also

+ +
+

This is licensed under CC-BY +and we encourage and appreciate reuse, modifications, and contributions.

+
+
+
+

Collaborative document mechanics and controls

+

Hackmd or HedgeDoc are real-time text editor online. We use it to:

+
    +
  • As a threaded chat, to answer questions and provide other information without +interrupting the main flow of the room.

  • +
  • provide everyone with a more equal opportunity to ask questions.

  • +
  • create notes which will be archived, for your later reference.

  • +
+

You do not need to login/create an account to be able to edit the document.

+
+

Basic controls

+
+_images/hackmd--controls.png +

This may look slightly different on mobile devices and small windows.

+
+
    +
  • At the top (left or right), you can switch between view, +edit, and split view and edit modes.

  • +
  • You write in markdown here. Don’t +worry about the syntax, just see what others do and try to be like +that! Someone will come and fix any problems there may be.

  • +
  • Please go back to view mode if you think you won’t edit for a +while - it will still live update.

  • +
+
+
+

Asking questions

+

Always ask questions and add new sections at the very bottom. +You can also answer and comment on older questions, too.

+
+_images/hackmd--questions2.png +

Questions and answers in bullet points

+
+

Since we plan to publish the questions and answers later as part +of the workshop page, we recommend to not use any names. You can indicate +your own name to make it easier to discuss more during the workshop but +then always use this form: [name=Myname]. This makes it easier for +us to automatically remove all names before publishing the notes.

+

Other hints:

+
    +
  • Use +1 to agree with a statement or question (we are more likely +to comment on it).

  • +
  • Please leave some blank lines at the bottom

  • +
  • NOTE: Please don’t “select all”, it highlights for everyone and adds a +risk of losing data (there are periodic backups, but not instant).

  • +
  • It can be quite demanding to follow the collaborative document closely. Keep an eye +on it, but consider how distracted you may get from the course. For +things beyond the scope of the course, we may come back and answer +later.

  • +
+
+
+

Don’t get overwhelmed

+

There can be a flood of information on the collaborative document. Scan for what is +important, then if you would like come back later. But it is +important to keep checking it.

+
+
+

Privacy

+
    +
  • Assume the collaborative document is public and published: you never +need to put your name there.

  • +
  • The collaborative document will be published on the website afterwards. We will +remove all non-instructors names, but it’s easier if you don’t add +it there in the first place.

  • +
  • Please keep the link private during the workshop, since since +security is “editable by those who have the link”.

  • +
  • You can use [name=YOURNAME], to name yourself. We will remove +all names (but not the comments) before archiving the notes (use +this format to make it easy for us).

  • +
+
+
+
+
+
+

Roles overview

+

CodeRefinery has been able to scale online workshops while maintaining +an interactive feeling. This page describes the roles that we use in our workshops.

+

Despite the many different roles documented here, in practice many +of them are occupied by the same people. +Best practices below tells more about what tends to happen. +One of the advantages of our large workshops is that we have many more +staff on hand (often 10-15), thus allowing much more specialization +than small workshop can have (thus, the large number of roles below). +Many of our instructors give feedback such as “this is so much easier: +we only show up and teach!”

+

A common pathway goes (Learner/team leader) → (Expert +helper/Instructor) → (More specialized roles). Note that thanks to +our team teaching or “co-teaching”, it is really easy to join as +an instructor!

+

You can also find the common tasks in checklist-format under each roles section in the Workshop playbook.

+
+

Workshop roles

+
+

Learner

+

Comes and learns.

+
    +
  • Does necessary preparation and attends the workshop

  • +
  • More info: Learners section

  • +
+
+
+

Team leader

+

Team leaders are only a small step above learners. They aren’t +expected to know everything, but mainly keep their breakout rooms on +track - they could even be a slightly more confident learner.

+
    +
  • Leads a breakout room

    +
      +
    • keeps on track

    • +
    • makes welcoming community

    • +
    • answers some questions

    • +
    • ask for more help when needed

    • +
    +
  • +
  • Attends a one-hour team leader preparation / onboarding session.

  • +
  • More info: Team leaders / Helpers / Exercise leaders

  • +
+
+
+

Instructor

+

Obviously, instructors teach. Uniquely in our system, they have a lot +of support and generally can focus on the teaching part.

+
    +
  • Prepares lesson and “just teaches” without worrying about other workshop matters

  • +
  • Team teaching, you are not alone

  • +
  • Attend instructor preparation calls

  • +
  • Usually receives one-on-one mentoring in advance

  • +
  • Other times during the workshop, usually serves as an expert helper

  • +
  • More info: Instructors

  • +
+
+
+

Expert helper

+

Expert helpers are generalists who don’t have other assigned roles. +Thanks to HackMD and breakout rooms, they have plenty to do.

+
    +
  • All-around generalist who assists wherever is needed

  • +
  • Answers questions in HackMD

  • +
  • Supports team leaders in breakout rooms: rotates between +breakout rooms and checks how things are going

  • +
  • Identifies important issues and raises them to the instructors, +“voice of the audience”

  • +
  • More info: Expert helpers

  • +
+
+
+

Behind the scenes

+
+
HackMD manager
+

The HackMD manager closely watches HackMD to keep it organized and by +reading it in detail, can serve as the “voice of the audience” to the +instructors.

+
    +
  • Ensures everything gets some answer quickly

    +
      +
    • Even if it is “will be answered later”

    • +
    • Can raise issues to instructors immediately if needed.

    • +
    • In general serves as the instructors’ “ear on the ground”

    • +
    +
  • +
  • Maintenance during the workshop

    +
      +
    • Copies old information to archive HackMD if too much traffic

    • +
    • Organizes sections and questions

    • +
    • Notes break and exercise times

    • +
    +
  • +
  • Processes and archives HackMD after the course.

  • +
  • More info: HackMD manager

  • +
+
+
+
Host
+

The Host serves as the manager of learners during the course.

+
    +
  • Learner Zoom meeting host (often). Often the registration +coordinator.

  • +
  • Helps learners with organizational issues during the course

    +
      +
    • Ensures that everyone is welcomed and knows what is going on

    • +
    • Assign learners to breakout rooms

    • +
    • Answers technical questions about the course itself

    • +
    +
  • +
  • Often the same person as the registration coordinator.

  • +
  • More info: Host

  • +
+
+
+
Director
+

The director manages the flow of the course: preparing and cueing +instructors, switching the livestream scenes, announcing schedule, +adjusting schedule as needed.

+
    +
  • Instructor Zoom meeting host (often). Often the instructor +coordinator.

  • +
  • Cues the sessions, makes sure they flow together well.

  • +
  • Adjusts the flow when things do not go according to schedule.

  • +
  • Has sufficient knowledge of the tech setup to do the scene +switching.

  • +
  • More info: Director

  • +
+
+
+
Broadcaster (livestream)
+

The broadcaster is responsible for the livestreaming tech.

+
    +
  • Only needed in livestream courses

  • +
  • Installs and manages OBS control for livestreams

    +
      +
    • Ideally is not teaching in the first session

    • +
    • Is around in case of problems, otherwise the director does most of +the scene switching.

    • +
    +
  • +
  • Makes sure videos get processed and to Youtube in a timely manner, +or at least saves them where someone else can do it.

  • +
  • More info: Broadcaster

  • +
+
+
+
Registration coordinator
+

Oversees registration and generally everything on the participant side.

+
    +
  • Communicate with participants

  • +
  • Organize installation help session

  • +
  • Contact person for learners

  • +
  • Collect feedback

  • +
  • Provide participation certificates

  • +
  • More info: Registration coordinator)

  • +
+
+
+
Instructor coordinator
+ +
+
+
Outreach and marketing coordinator
+
    +
  • Makes sure workshop gets advertised in different places

  • +
  • You can find a list of commonly advertised places in the bottom of the Workshop checklist template.

  • +
+
+
+
+

Team leader / Exercise coordinator

+
    +
  • Communicate with all team leaders, contact person for them

  • +
  • Makes sure all exercises are ready and commicated before and during the workshop

  • +
  • Organize the team leader onboarding session

  • +
  • Usually attends as an expert helper to generally be available and +support all leaders.

  • +
  • Collect feedback from team leaders

  • +
  • More info: Exercise coordinator

  • +
+
+
+

Video editor

+
    +
  • Watches videos and prepares for YouTube upload

  • +
  • Uses +ffmpeg-editlist +to process videos after the Broadcaster has made them available.

  • +
  • Work should be done the day/evening of of the course

  • +
+
+
+
+

Best practices

+

Roles that are often combined:

+
    +
  • Registration coordinator and Host

  • +
  • Instructor coordinator and Director

  • +
  • Expert helper and anything

  • +
  • Instructor and any other role (but not Host)

  • +
+

Roles that should not be combined:

+
    +
  • Registration coordinator and Instructor coordinator (these +two together tend to form the “core team”)

  • +
  • Broadcaster/Director and Instructor on the first sessions of each +day.

  • +
  • HackMD manager and other roles (so delegate HackMD while you do +something else! this is OK.)

  • +
  • Host and any active teaching (in big workshops at least - +learner management keeps you busy)

  • +
+

Other notes:

+
    +
  • HackMD manager can rotate between different people.

  • +
  • Expert helpers can replace team leaders if they cannot join the +full workshop

  • +
  • Coordinators delegate

  • +
+
+
+
+

Team leaders / Helpers / Exercise leaders

+

We use this page during team leader onboarding.

+

Thanks for being a team leader :heart:! +Without you, these large online workshops would not be possible.

+
+

TL;DR (Summary of this page)

+
    +
  • Everyone watches the CodeRefinery stream (how to attend via livestream)

  • +
  • Communication happens via collaborative document (Collaborative document mechanics)

  • +
  • Exercises can be done individually, in a pre-formed or ad-hoc team online or in person

  • +
  • Team leads are between the instructors and learners, please

    +
      +
    • Keep track of things like learner progress, instructions and time and report them via collaborative document

    • +
    • Be available for learners to ask their questions and lead discussions

    • +
    • If idle, check the collaborative document for open questions and answer them

    • +
    +
  • +
+

If you want to contact us before the workshop you can send an email to our general email address support@coderefinery.org or you can join the +CodeRefinery chat (we recommend the #workshops stream, +and if you can’t find it then #general is good).

+

If you have fun being a team leader for the workshop, please visit our +contributing page page, to find out about further +volunteering possibilities within CodeRefinery.

+
+
+

Code of Conduct

+

We follow a code of +conduct for all our +interactions before, during and after workshops, also for this session.

+

We’ve designed the workshop so that it is very hard for one person to +ruin it for everyone. Within your team, you will need to take on the +role of ensuring a good environment.

+

If you see anything that is not supporting an positive learning +environment, let us know!

+
    +
  • If it’s a general issue that can be mentioned publicly, write it +immediately in the collaborative document.

  • +
  • Send a message to support@coderefinery.org if it is private and can +be handled asynchronously.

  • +
+
+
+

CodeRefinery project

+

We teach all the essential tools which are usually skipped in +academic education so everyone can make full use of software, computing, and +data. We don’t just give courses, but we are a training network that you can +join to share the effort and bring better courses to your community.

+
+
+

..and you?

+

Shortly introduce yourself in the collaborative document of the onboarding session:

+
    +
  • Who are you?

  • +
  • What do you do?

  • +
  • Where are you connecting from?

  • +
+
+
+

What is needed to be a team leader?

+

Most importantly, you do not have to know everything (we don’t, either), but you are expected to:

+
    +
  • Have been to a CodeRefinery before and used git some since then, OR have some general experience with git (branching, +pull requests) and command line work, OR be able to generally follow +the path of the exercises that we have laid out.

  • +
  • Be present in your teams physical/virtual room at least during exercise sessions of the workshop.

  • +
  • Show a positive, motivating attitude to learners.

  • +
  • Keep exercises going and let us know when there are difficult questions!

  • +
+
+

If you aren’t sure if you can be a team leader: you probably can be one!

+
+
+
+

Who is joining this workshop?

+

Be aware of the different

+
    +
  • career stages (students, postdoc, researcher, professor, industry),

  • +
  • backgrounds (computer scientist, IT, domain scientist, coding beginners,…),

  • +
  • infrastructure (operating system, access restrictions, preferences on graphical vs command line interfaces, …) and

  • +
  • preferred programming languages (Python, R, Matlab, Julia, Fortran, …) of your learners.

  • +
+

There is also usually a great variety of pre- knowledge on the different topics of the workshop.

+

Overview from the pre-workshop survey

+
+
+

What will happen during workshop?

+

The workshop schedule on the main workshop page contains +links to lesson material, including lists of exercises.

+

The best analogy is watching a popular sporting event on TV. +There are periods of lots of activity, and clear periods of breaks where you +do your own thing.

+
    +
  • Everyone follows stream during lessons - lessons, demos, exercise +intros, going over solutions, etc.

  • +
  • For questions and instructions we use a collaborative document (more below).

  • +
  • Exercises during the lessons are done individually or in teams and there is many +ways to do this:

    +
      +
    • Watch and work alone

    • +
    • Watch together and interact during exercises/breaks (in-person or +online)

    • +
    • Reviewing/doing exercises later

    • +
    +
  • +
+
+_images/exercise_options.png +

Overview of the different options of doing the exercises individually or in a team.

+
+
+
+

Exercise sessions

+

We try our best to be very explicit about what is going on. +Your first goal should be to make sure the learners are engaged and no one is left behind.

+

The instructors should clearly tell which exercises and for how long (minimum 10-15 min); +if anything is unclear please ask via collaborative document, you are our safety net.

+

Make it easy for learners to ask for help:

+
    +
  • Make sure your group knows your name and that you are their team lead.

  • +
  • Always start by greeting people and ask how the lesson is going; report back if there is something instructors should be aware of.

  • +
  • Encourage your team to also put answered questions in the collaborative document, someone else might be wondering the same thing.

  • +
+

Want extra help?

+
    +
  • It is OK to not know something!

  • +
  • Use the collaborative document if there is questions that you cannot answer. +Our instructors and expert helpers are watching it and try to answer every question.

  • +
+

Major problems?

+
    +
  • Exercise time is limited, watch the time and keep things moving.

  • +
  • If some debugging takes to long, it’s reasonable to describe the problem in the +collaborative document. An expert helper may have seen the problem +before.

  • +
  • If any one problem takes too long, it’s OK to say “we don’t have +time, let’s come back”

  • +
+
+_images/team_status.png +

Example of collaborative document during an exercise session. a) clear description of +topics of the exercises. b) team status. c) as always, +questions at the bottom.

+
+
+
+

What can I do to prepare for the workshop?

+

As a team leader, we do not expect you to know all our CodeRefinery training material, but if you have time:

+
    +
  • Take a look at the exercises in advance of each day (the exact +plan is on the workshop page. Lessons have an “exercise list” page that shows everything), check that you understand the general point of each of them.

  • +
  • If you are interested, also read through the instructor guides for the lessons (there is a link at the top or sidebar of each lesson).

  • +
  • Use github issues on the lesson github page to point out issues with exercises and the materials

  • +
+
+
+

Any questions?

+
    +
  • Send us an email to support@coderefinery.org

  • +
  • If you want to, sign up for our Zulip chat to ask us anything, anytime. Use +#tools-workshop during the workshop itself (you need to join the stream, it is not default for new chat members).

  • +
  • During the workshop, please use the collaborative document.

  • +
+
+
+

Path ahead

+

Would you like to

+ +

See our website and Contributing to CodeRefinery. +Best way to get started is to join the Zulip chat.

+
+
+

Tips and Tricks

+

This section provides some tips and tricks for being a team leader. Be aware that there are different types of team leads (online/in-person/team of colleagues/team of strangers) and these tipps may not apply to evryone.

+
+

How to create a positive learning environment?

+

As a team leader, you have a crucial role during workshops:

+
    +
  • You are between the learners and the organizers and instructors, please use the collaborative document to communicate.

  • +
  • Encourage learners to learn from each other.

  • +
  • Acknowledge that some of the material can be difficult and that people in your team will +learn more working together.

  • +
  • Acknowledge when learners are confused and raise it to the instructors. +Understanding why learners are confused provides useful feedback for +instructors. You are our eyes and ears.

  • +
  • As we said, you don’t have to know everything, just like learners don’t +necessarily know everything (we don’t know everything, either). It’s more +important to be responsive and work together.

  • +
  • If you meet virtually: Turn on your camera, and encourage everyone else to do so as well. Have an introductory round in the first exercise session, to get to know your group. Whichever strategy you choose for your team, be present and encourage learners to ask questions.

  • +
  • In an in-person workshop: Stand up and walk around, try to make rounds by everyone. If you are +convenient, students will ask. If you are sitting in the back, student’s +won’t. Students rarely try to get your attention from across the room if you +don’t look ready.

  • +
+
+
+

Strategies for leading a team

+

There are several strategies you can use to run your team, no matter if you meet in a physical or virtual room (Physical room would need a larger screen for every one to see though):

+

Strategy 1:

+
    +
  • Everyone does the exercises themselves until someone has a question

  • +
  • Encourage learners to ask multiple times; if necessary share your/learners screen and discuss.

  • +
  • If everyone is active, this can be good, but there is a risk that the barrier for distrurbing the silence is too big.

  • +
+

Strategy 2:

+
    +
  • To start things off, team leader can share the screen.

  • +
  • Do not try to hide mistakes (they make good learning opportunities, “can you spot my mistake?”) and discuss your solutions.

  • +
  • It might be good to give learners some lead first, and use this only +if no one volunteers.

  • +
+

Strategy 2:

+
    +
  • Team leader asks someone to share the screen and go through the exercise.

  • +
  • You can encourage the others to guide the one who is sharing the +screen. Or let the person go on her/his own pace.

    +
      +
    • If no one dares at first, you can also start sharing your screen and let the room tell you what to write.

    • +
    • That way they see how it can go and the barrier shrinks.

    • +
    +
  • +
  • Try to alternate who is sharing the screen for each session.

  • +
  • When someone has an issue, it is a good idea to switch screen share to them +and maybe even continue from there

  • +
+

You don’t actually have to do the exercises. You could apply +lesson material to your own team’s work, review what was just said, +have a free-form discussion, etc. - if those are more valuable. You +can always come back to exercises later, or let learners do them as homework.

+
+
+

How to solve common problems in teams?

+
    +
  • One learner asks very many questions, ends up monopolizing all of +the time. Other learners are left without help, and the whole group +may not get the exercises done

    +
      +
    • Encourage them to ask in the collaborative document

    • +
    • It can be very hard to say “no”, but it’s more important to have +balance than answer every question you are asked. If you need +to say no, you can try things such as “I’m sorry, but in order +to finish we need to go on now. We can keep working on it +later - would you like to watch?”

    • +
    +
  • +
  • There is some sort of problem that ends up taking a lot of time

    +
      +
    • Work on it for a minute or two.

    • +
    • Encourage to describe the problem in the collaborative document. Our expert helpers may be able to help. +Nothing wrong with this, because there is no deadline or time limit.

    • +
    +
  • +
  • No one asks any questions

    +
      +
    • Make sure people know that you are there for them if they need help

      +
        +
      • Some exercises are easier than others and people really may not need any help with some of them

      • +
      • Remind that the recording can also be watched later, if people cannot keep up

      • +
      +
    • +
    • Use your time answering questions the collaborative document

    • +
    +
  • +
+
+
+

Please do not …

+
    +
  • Take over the learner’s keyboard (neither physically nor remotely). It is rarely a good idea to type anything +for your learners and it can be demotivating for the learner because it +implies you don’t think they can do it themselves or that you don’t want to +wait for them. It also wastes a valuable opportunity for them to develop muscle +memory and other skills that are essential for independent work. Instead, try +to have a sticky note pad and pen / use the collaborative document and write the commands that they should type.

  • +
  • Criticize certain programs, operating systems, or GUI applications, or +learners who use them. (Excel, Windows, etc.)

  • +
  • Talk contemptuously or with scorn about any tool. Regardless of its +shortcomings, many of your learners may be using that tool. Convincing +someone to change their practices is much harder when they think you disdain +them.

  • +
  • Dive into complex or detailed technical discussion with the one or two people +in the audience who have advanced knowledge and may not actually need to be +at the workshop.

  • +
  • Pretend to know more than you do. People will actually trust you more if you +are frank about the limitations of your knowledge, and will be more likely to +ask questions and seek help.

  • +
  • Use “just”, “easy”, or other demotivating words. These signal to the learner +that the instructor thinks their problem is trivial and by extension that +they therefore must be stupid for not being able to figure it out.

  • +
  • Feign surprise at learners not knowing something. Saying things like “I can’t +believe you don’t know X” or “You’ve never heard of Y?” signals to the +learner that they do not have some required pre-knowledge of the material you +are teaching, that they don’t belong at the workshop, and it may prevent them +from asking questions in the future.

  • +
+
+
+
+

Background

+

The following section provides some background on our workshop setup.

+
+

Hierarchical workshops to scale

+

Traditionally, a workshop has instructors and team leaders/helpers, but the +capacity is limited by instructors, so we are limited to ~30-40 people +at most. Then, we tried to scale to larger numbers: even up to and beyond 100 +people. For this, we have to rely on team leaders . A team leader does not have to be an expert in the +material, but should be able to keep things flowing.

+

Team leaders are an essential part of the CodeRefinery workshop team and +allow CodeRefinery to scale to many more people than we could otherwise handle. +Team leaders will guide their team through the course, keep +time, and let us know when more help/time is needed during the exercise sessions. +Instructors and expert helpers are always available via the collaborative document. It is very +likely that you’ll grow as a mentor and learn how to be a more efficient +teacher.

+
+
+

Teams

+

A team could be for example a +group of colleagues/friends where one of the team members has a bit of knowledge +on the tools presented in the workhop. This person can act as team leader +for the workshop, but may still learn a thing or two themselves. In that way +you can work with people you know and the barrier for asking questions and +discuss together may be a bit lower than in a group of strangers.

+

Sometimes we also allow learners to register as invidual learner with interest in being in a team. We then try to arrange those people in teams which stay together for all exercise sessions on all days and provide a zoom breakoutroom with a team/exercise leader. Since this is dependent on our team leader capacities, we cannot accept infinte amount of learners. +Being assigned a team as a learner allows people to form a bond and get the +rooms started sooner. We will try to keep you in the same team +room as long as we can, but we give no promises and will rearrange as +needed when people can’t attend.

+
+
+
+

See also

+ +
+
+
+

Instructors

+

Instructors are the ones who “lecture” in the workshops - but of +course there are many other roles which are helping with the teaching, +most notably team leaders and other helpers.

+

This page links guides on various aspects of being an instructor.

+

Join the #workshops stream in the coderefinery Zulip chat and see what workshops are planned. +Below a few things that might be of interest if you want to teach with us:

+
+
+

Instructor introduction

+

This page gives general instructor and expert helper introduction +material. These people are responsible for more than one breakout +room, and have to have an overview of more of the course. In short, +if you want to take the next step in CodeRefinery, this is the place +to start.

+
+

See also

+

Co-instructors for an intro for starting co-instructors.

+
+
+

How do you get started?

+

That’s what this page is about (well, and the instructor +training). We +believe that you best learn by working with others in practice, and +provide plenty of opportunities to do that.

+
+
+

Starting materials

+

Reading here: the other pages in the section, see sidebar.

+ +

Also read the team leader information

+ +

Reading elsewhere:

+ +
+
+

As an instructor

+

Most of our workshops are very collaborative arrangements: you are +rarely alone. This is one way of looking at it:

+
    +
  • Look at and revise the workshops before they teach, making small, +incremental improvements. But, you don’t have to (and in some +sense, it’s good if they stabilize some more).

  • +
  • Especially go over the examples when preparing.

  • +
  • Have a chat with someone else (probably another instructor or +expert helper) before teaching. We encourage this for +everyone, even experienced instructors, to better transfer knowledge +among each other and stay up to date with the latest developments.

  • +
  • Teach independently or co-teach. Ideally, co-teach the first +time(s). Really, we’d like to get to the point where we always +co-teach. Co-teaching doesn’t mean different people take different +lessons, but two people teach all parts of the same lesson by +turning it into a discussion between the two instructors. TODO: +produce information on this.

  • +
+
+
in the main session
+

As an instructor, when preparing your lesson you first need to decide how to balance between the +main room and breakout sessions.

+
    +
  • Clearly say when a learner watches, when they type along, when they should +work on something independently as an exercise.

  • +
  • CodeRefinery is traditionally a hands-on workshop, so breakout-room sessions should be a large part of the workshop.

  • +
  • We usually keep the main room mostly for general discussions. Small exercises or polls can also be done in the main room, for all hands-on exercises we divide the learners into breakout-rooms each with one team leader.

  • +
  • To give you an idea about how the work in the breakout rooms is going, monitor the hackmd closely and if time allows try to visit a few breakout rooms to see how it is going and if needed adjust the timing.

  • +
+
+
+
Preparing for the breakouts (in the main room)
+

As an instructor, you need to clearly define what the tasks of each +breakout session is (even if it is just “explore and discuss”). +Online courses need more “meta talk” about how you expect things +to go, since it’s not as easy to read the room or fill in expectations +later (distractions, hard to communicate to breakout rooms after +opened).

+
    +
  • Clearly say what the tasks of the breakout session will be.

  • +
  • Put that task and a link to the part of the lesson in the hackmd.

  • +
  • Clearly say how long each breakout session will be (make sure it’s +long enough and adjust during the exercise session if needed)

  • +
  • Clearly say if things in the future will depend on this exercise (is +someone completely lost if they don’t make it to the end. Halfway?)

  • +
  • Try to make breakout sessions longer:

    +
      +
    • imagine a 5 minute overhead for each session, getting people +there, deciding who does what, acquainted with what they need to +do, and debugging problems.

    • +
    • 10 minutes is quite short, 20 minutes is best.

    • +
    • Can you say less and let people discover it for themselves?

    • +
    +
  • +
+

As a team leader, if anything is unclear to you, it is very unclear to +others. Comment/Ask in the HackMD or speak up and ask!

+
+
+
+

Top issues new instructors face

+
+_images/s10-kickstart-prompt-log.png +

An example of a beautiful screenshare. Note the portrait orientation +(you have half the screen free for notes and HackMD, learners have +half the screen free to do their own work). The terminal is +dark-on-light, a minimal prompt, no other fancy shell distractions, +there is a shell history visible, and slightly distinct colors between +the web browser and the terminal.

+
+
    +
  • Breaks are not negotiable, minimum 10 minutes.

  • +
  • Breakout sessions too short. Make them as long as possible, don’t +expect to come back for new intro, then go back.

  • +
  • People will accomplish less than you expect. Expect learners to be 5 +times slower than you, at best!

  • +
  • All the other tools and stuff will go wrong. Try to not bring in a +dependency when you don’t need it.

  • +
  • Trying to accomplish too much: it’s OK to cut out and adapt to the +audience. Have a reserve session at the end you prepare, but are +ready to skip.

  • +
  • Not clearly separating (in the learner’s mind, by meta-talk), the +differences between demo, type-along, and +exercise/exercise-prep.

    +
      +
    • Demo and type-along are hard to do at the same time: they are very +different types of focus

    • +
    • Type-along and exercise of the same thing are not good to combine, +leads to duplication

    • +
    +
  • +
  • Explaining how, but not why.

  • +
  • Running out of time to making your environment match the +learner’s.

  • +
  • Running out of time to set up good screen sharing practices +(terminal history, portion of screen, remote history) in advance.

  • +
  • Assuming learners remember what they have already learned, or know +the prerequisites. Or have stuff installed and configured.

  • +
  • Not managing expectations: learners think that you will accomplish +everything, and feel sad when you don’t. Instead, say explicitly +what everyone should follow along, what you might want to watch, +what is only a demo.

  • +
  • Following the lesson as written at all costs.

  • +
+

For livestream courses:

+
    +
  • Worrying too much (forgetting that there is a co-teacher and break +time where you can discuss and plan your next step).

  • +
  • Speaking like learners should be able to speak up with voice, +instead of “answer in HackMD or discuss within your groups.”

  • +
  • Forgetting to save time for Q&A: there is more Q&A because of +HackMD. You might take a few minutes to screenshare HackMD and +after each exercise session, after each break, after each episode, +and at the end of each day.

  • +
  • “Stop screenshare” instead of letting the other person start and +take it from you. Or, the broadcaster switching the scene. Never +do “stop screenshare”.

  • +
  • Forgetting to screenshare the HackMD during Q&A time (this is the +most important way learners know it is active, and thus feel a +connection to the course).

  • +
  • Forgetting there are multiple ways to attend: not everyone is in a +breakout room, not everyone has helpers nearby. Instead, use +phrasing such as “for those of you in breakout rooms, go there now. +Everyone, remember to ask any questions in the HackMD, even if you +are alone.”

  • +
  • Planning to do a demo during team breakout sessions (teams will +still hear your voice, if they mute the stream it’s hard to bring +them back).

  • +
  • Sharing a fullscreen, not the 840x1080 portrait layout.

  • +
  • Showing non-creative-commons material on the stream.

  • +
+
+
+
+

Being an instructor in livestreamed CodeRefinery workshop

+
+

Basic setup

+

In a livestreamed CodeRefinery workshop, we have two types of learners: Active learners attending in Zoom and passive learners watching the stream. +Learners from both groups will watch the stream from their own browser and have the possibility to interact with the instructors and ask questions via HackMD +(a collaborative note taking tool: Collaborative document mechanics and controls). +Active, registered learners will additionally get interactive help in Zoom breakoutrooms during exercise sessions. +Learners on stream can either form private groups or do the exercises on their own. +Following our team teaching strategy, your are never alone as an instructor. While you are teaching, you can fully focus on the task at hand, your co-instructor will watch the chat and HackMD and relay all important information to you.

+
+
+

I am teaching in a workshop, what do I need to know/do?

+
    +
  • Attend the instructor onboarding session (Instructor introduction)

  • +
  • Make sure you have your tech setup for the course: Instructor technical setup, online

  • +
  • Consider joining the learners Zoom to help in breakoutrooms and answer questions in HackMD

  • +
  • When your teaching time approaches, join the instructors Zoom.

    +
      +
    • Stay muted and turn your video off until it is your turn to teach

    • +
    • Setup your windows that you want to share during teaching

    • +
    • When it is your turn to (co-)teach,

      +
        +
      • All co-instructors, turn on your video

      • +
      • Unmute yourself only when talking

      • +
      • Share only the important portion of your screen in vertical mode

      • +
      • If you need a reaction from learners, use HackMD

      • +
      • Co-Instructor watches HackMD and relays important information/questions

      • +
      • Exercises: clearly state which exercises should be done and at what time the teaching continues

      • +
      +
    • +
    +
  • +
  • After your lesson, consider joining learners Zoom

  • +
  • If you can, join after-course-day-hangout with other instructors

  • +
  • Give feedback on your teaching experience with CodeRefinery

  • +
+

We have also collected a lot of material around teaching which you are free to read:

+ +
+
+

Why team teaching?

+

-> see also Team teaching

+
    +
  • makes lesson more lively

  • +
  • less chance of forgetting something essential

  • +
  • one of the instructors can watch for good questions in HackMD and ask/answer them on stream

  • +
  • less stressful for the individual

  • +
  • easier to include new instructors

  • +
  • easier debugging, finding typos etc on stream

  • +
  • you are not alone

  • +
+
+
+

Why livestream?

+

A livestream workshop allows us to reach an unlimited number of people, at the cost of not being as interactive as in classroom/zoom room. +However, we have had great experiences with the following strategy:

+
    +
  • HackMD as collaborative note-taking tool allows learners to ask questions anonymously and everyone can answer these questions asynchronously.

  • +
  • Learners can register to join Zoom breakout rooms, which are interactive and team leaders can help with any questions during exercise sessions and breaks.

  • +
  • Learners can also form private breakout rooms or meet in person and watch the stream and do exercises together.

  • +
+

While the full livestream setup is a bit complicated, you as an instructor do not have to worry about anything but your teaching. +We have setup the whole system in a way that only active instructors are shown in stream, which makes video postproduction faster. +What makes our setup different from your ‘usual zoom class’ is that our instructors Zoom room that you are in while instructing is completely separate from the learners, while providing interaction possibility via HackMD.

+
+
+
+

Teaching via livestreaming

+

We’ve all done a lot of teaching via Zoom, but the CodeRefinery +livestream is a new concept. This introduces teachers/helpers to the +idea (and for a detailed reference, see CodeRefinery MOOC strategy).

+
+

Video

+

Watch a demo on YouTube: https://www.youtube.com/watch?v=WjmttAniZX8. +(When watching, also carefully read the video description/chapter +titles, which provide more the explanation of what is going on).

+
+

Compared to Zoom teaching:

+
    +
  • You are in a Zoom meeting with only instructors/staff

  • +
  • Someone (not you) captures this meeting and broadcasts it via +livestream to all the audience.

  • +
  • The audience can’t directly talk with you (but when there is a large +audience, who does anyway?). Instead, always say things like “What +do you think? Write in the HackMD. [proceed to screenshare it and +discuss answers]”

  • +
  • You don’t need to worry much about managing the audience. Others do +this and relay information as you need. You should pay more +attention to HackMD.

  • +
+
+

Basic meeting setup

+

There is an “instructor Zoom meeting”. There are no students here, +and everything can and will be captured, recorded, published, and +livestreamed.

+
    +
  • In the call are instructors, the Zoom host, and possibly some other +helpers who might occasionally comment.

  • +
  • The cameras of instructors are captured via Zoom gallery view. +This is show as both a “teacher view” as well as “overlay on +screenshare”.

  • +
  • If you have your camera off, you will not appear in the stream. +So turn your camera off when you are in the instructor meeting but +not presenting. Ask others, but in principle it is fine to join, +stay hidden, and interact when relevant.

  • +
  • During the breaks/exercise times, the livestream itself (via OBS) +gets muted and switched to another scene. So, you are free to +unmute, talk, and chat with other instructors. This is a great way +to relax and prepare for the next segments! This actually lowers +the pressure to pre-plan every part in advance.

  • +
  • By the same token, you can join the meeting during the previous +break to get all set up.

  • +
  • Zulipchat serves as the overall connection between the different +parts of the course and instructor backchannel. This is the least +important place for the current active instructor to watch (but +might be useful for a co-instructor or expert helper to occasionally +check).

  • +
+
+
+

Screensharing

+

You can share your screen normally via Zoom. The livestream is fixed +to an aspect ratio of 840 pixels wide × 1080 pixels high (this is so +that the learner has half of their screen available). You can not +do a full landscape live-coding follow-along screenshare (nor is this +good practice in other workshops).

+
    +
  • In Zoom, you can either share one window or Advanced → Share a +portion of the screen → move the overlay to a portrait view. Don’t +worry about making it exactly 840×1080, OBS automatically fits it +and we can adjust it during the setup time.

  • +
  • If you have a landscape presentation (as opposed to live coding), +just share your whole screen, and the OBS operator will scale things +properly if it doesn’t automatically work. Note that the 4:3 aspect +ratio is better than 16:9, but that usually has black bars on the +side. This can be removed via OBS.

  • +
  • Don’t stop screenshare unexpectedly - wait for the broadcaster to +switch to gallery view. If you stop screenshare unexpectedly, the +stream reverts to someone picture full-screen. Because of Zoom +“dual-monitor mode”, sharing screen does not prevent the gallery +from showing.

  • +
+
+
+

HackMD and audience feedback

+

HackMD (or similar document-based things) is our preferred +communication system. The biggest problem is that it is too useful, +and too many people ask questions, which will easily overload you. To +solve this, we have co-teachers (non-typer can watch HackMD), HackMD +helpers (watch and answer basic questions).

+

There are several general strategies:

+
    +
  • Occasionally screenshare the HackMD. This emphasizes to the +audience that questions there do get noticed.

  • +
  • Rely on other helpers to answer most questions.

  • +
  • During Q&A time, go to the HackMD and comment on the most important +questions.

  • +
  • Call on co-teachers, “do we have any good questions from HackMD?”

  • +
  • Co-teachers should be more than willing to interrupt with relevant +questions right away.

  • +
+

You can’t use Zoom polls and so on. Instead, use HackMD cleverly. +For example, below you see a poll (people add o to make a bar +graph), and a free response:

+
Have you used HackMD before?
+yes: oooooooo
+no:  oooo
+
+What do you like about it?
+- answer
+- answer
+- .
+- .
+- .
+
+
+
+
+
+

Team teaching

+

Listening to only one person talk can be boring. Listening to a discussion is +much less so. “Team teaching” can mean many things, but in this case we +are referring to two instructors are both actively +involved in lecturing at the same time, as some sort of conversation +between them. It is a form of co-teaching.

+

When it works well, it makes a lecture much more dynamic and +engaging, and reduces the load for each person to plan everything +because you can rely on two minds to do it live. +The difficulty is that you need to coordinate and it is our nature to +keep talking while teaching, making a conversation difficult.

+
+

See also

+

Demo of CodeRefinery livestream teaching. This shows a +demo of many parts of team teaching on a livestream - read the +video description for details.

+
+
+

Basics

+
+_images/teach-teaching--screenshot.png +

Demo of team teaching. Two people are speaking, in this case one +is typing and giving the small point of view, and one is explaining +the big point of view.

+
+

We can’t claim to know the best way to do this yet, but we have seen ways +that work and don’t work.

+

The basic idea is that you want to keep a constant conversation +going. This can be a mutual discussion, one person explaining big +concepts and one the details, one person asking +questions and the other answering, or some other combination. This +is different that two people teaching different sections.

+

There is less need for the instructors to prepare every single thing, +since you can rely +on the wisdom of the group to get you through areas you haven’t +perfectly prepared. In fact, this is good, because then your learners will +see things go slightly wrong and your live debugging. +Still it can be useful to agree with your co-instructor on the choreography +of your session (more about this below).

+
+

One of the most important principles of ship handling is that there +be no ambiguity as to who is controlling the movements of the +ship. One person gives orders to the ship’s engine, rudder, lines, +and ground tackle. This person is said to have the “conn.”

+

— James Alden Barber, 2005, “Introduction”, The Naval +Shiphandler’s Guide, p. 8. Mark B. Templeton, via wikipedia

+
+

As the quote says, in any large enough operation, multiple people are +involved, but responsibilities should be clear. At least, the team +should know who is pushing things forward (even if, to make it seem +live, they still discuss among each other anyway).

+

We propose two basic models, but of course there is a constant +continuum. +And in either model it can be good to switch roles every 20-30 minutes.

+
+
+

Model 1: Guide and demo-giver

+

One person serves the role of guide, explaining the big picture +and possibly even the examples. The demo-giver shows the typing +and does the examples, and could take the role of a learner who is +asking about what is going on, the person who actually explains the +details, or an occasional commenter. Anyway, the guide is the one +navigating through the course and bringing up material in a logical +order for the audience and “has the conn”.

+

Hands-on demos and exercises work especially well like this. Here, +the guide would follow the outline and serve as the director (see +below).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Guide

Demo-giver

Introduces most material

Goes through theory

Asks questions that a learner may ask

Introduces type-along

Explains steps of type-along

Types during type-along

Asks questions to Demo-giver during type-along

Explains details what they are typing and what happens

Looks at HackMD during type-along

Looks at HackMD during theory

Discusses during Q&A

Discusses during Q&A

+
+
+

Model 2: Presenter and interviewer

+

In this case, it is the presenter who is mostly explaining and +giving the demos, and generally trying to move the forward through the +material. The interviewer serves as a learner or spotter, fills +in gaps by asking relevant questions, and tries to comment to the +presenter when things are going off track. The interviewer “has the +conn”.

+

This is closer to normal teaching, so feels more natural to do. The +big disadvantage is that it’s the tendency of the presenter to keep +talking, and the tendency of the interviewer to be nice and not +interrupt. This negates most of the benefit you would hope to have, +but is much better than solo teaching.

+

Here, the presenter would follow the outline and serve as the +director (see below).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Presenter

Interviewer

Asks questions to presenter

Answers questions using their special knowledge

Follows up with learner questions

Pushes forward though the material

Asks questions that a learner may ask

Introduces type-along

Explains type-along and material

Explains type-along and material

Looks at HackMD when possible

Looks at HackMD most of the time

Discusses during Q&A

Discusses during Q&A

+
+
+

Hints

+

With more than one person, there is a risk of seeming uncoordinated +when the team doesn’t know who is supposed to move the lesson forward. +It’s not bad to have short discussions to decide what to do next, it +makes the show seem interactive. But if it happens too +much, it becomes noticeable. As quoted above, you could adopt a +principle which exists +in many domains: at any time, only one person is +in control. Implemented in team teaching, it becomes: you explicitly +know who is in control (the director). The director is +responsible for understanding the current situation and checking with other +instructors, but in when you just need to something and no one has +strong opinions, you don’t debate, the director decides. The main +difference of Model 1 and Model 2 above is “is the director the one +mainly explaining new material, or the one asking questions”. There +are also multiple layers of director: there may be the director for +the whole course, and the director/”conn” for the lesson.

+

We can’t tell you what works best for you. But the models above and +thinking about who the director is should let you have an efficient +discussion to decide your model. The need for a director is why we +don’t recommend fully equal co-teachers. Instead, divide the course +into parts and use the two models for each part.

+
    +
  • Of course, there are other roles in a workshop.

    +
      +
    • The HackMD watcher pays particular attention to the audience +questions. They might be a different person from the co-teachers +and they can interrupt anytime.

    • +
    • The Meeting host manages the meeting itself.

    • +
    • The Director could be completely separate from the people on +screen, and somehow sending signals to the teachers as needed. +But, unlike scripted media, the course reacts more to the audience +and it is better for the director to be in the lecture.

    • +
    +
  • +
  • If you ever go off-plan, that’s OK. You can discuss during the +lecture so the audience can know what you are doing and why. You +want to adjust to the audience more than you would in a solo +course. But at the same time, be wary of deviating too much from +the material that the watchers have, since it will be disorienting.

  • +
  • Two people works well. With three, it’s hard to allow everyone to +speak equally and people tend to jump on top of each other in the +gaps - or no one talks, to give others a chance to say something. +You could have particular segments where different pairs of +people adopt the main roles, and others speak up if they want. Or, +at that point, make it a panel discussion format (multiple +presenters and one interviewer)

  • +
  • Of course, it helps to have a good plan of what you are going to +do. But if only one person knows that plan, this strategy can still +work, especially if that person is the presenter in model 2.

  • +
  • The less preparation you have, the more useful it is to strictly +define the roles of each person (to ensure someone is in charge of +moving it forward).

  • +
+

Please send us more suggestions to add to this list.

+
+
+

Preparation

+

This is one proposed model for preparing for team teaching:

+
    +
  • Talk with your co-teacher. These hints assume a two-person team.

  • +
  • Decide what material will be covered, overall timing, strategy, etc.

  • +
  • Divide up the material. In each section, decide the model to use +and roles. If in doubt, starting with the guide/demo-giver division +with the stronger instructor as guide works well.

  • +
  • Decide who will be the director for each part. Perhaps a good idea +is to keep it consistent: the guide is always the director.

  • +
  • At least one person prepares the outline (the order of topics to be +presented, key questions to ask, etc.) - usually the guide or +interviewer. The guide or interviewer +should be comfortable with it (and could even do it mostly alone), +everyone can give comments and make sure to read it at least once.

  • +
  • Run as above.

  • +
  • You don’t need to plan every step in detail but it can be useful to prepare +the session together and step through the choreography (e.g. “now I will show +this and then give you the screen and then ask you to do this … you will +lead this 20 minute block and then I will lead that 20 minute block and +please ask me questions while I present X”).

  • +
+

Then, just go! Don’t worry if it’s not perfect, if either person +wonders what to do next, just pause some or ask the other. This +imperfection is what makes it more dynamic and exciting, and in almost +all cases the audience has been impressed with the co-teaching +strategy, even if it’s not perfect.

+
+
+
+

Lesson presentation hints

+

This is a checklist/hints on what to do when standing up and giving a +presentation. Also see Instructor technical setup.

+
+

Before each lesson

+
    +
  • Remember: sticky notes, water, extra whiteboard markers.

  • +
  • Make your text large enough to be seen in the back, then bigger. +Make your voice loud enough to be heard in the back, then louder.

  • +
  • As people are coming in, encourage them to sit next to someone with +a similar operating system - then, when helping each other, the +unimportant differences are minimized.

  • +
  • By the same token, don’t allow people to sit alone: ask everyone to +set next to at least one other person. That way, people can help +each other.

  • +
  • Have a pen and paper next to you. When you notice problems in the +material, write it down right away during breaks in the type-along +parts.

  • +
  • Set up feedback system (chat, questions, etc)

  • +
+
+
+

Starting off

+
    +
  • Don’t start off with tech details, say why this is important. Think +of what the emotional (“coolness”) appeal is and start off with +that.

  • +
  • Why will this be useful?

  • +
+
+
+

Team teaching

+
    +
  • Discuss with co-teachers and helpers about what each of you will do.

    +
      +
    • Hand signals for common situations: too fast/slow in general, +louder, time for a break, “good enough, move on”, “explain more +here”.

    • +
    +
  • +
  • It can be hard for one person to manage everything. How can +multiple instructors take part? Probably the most common ones are:

    +
      +
    • Teach teaching: alternating

      +
        +
      • Commander and navigator: conceptually divide roles of big +picture teaching and doing the details.

      • +
      • If “real” alternating, each section should be 10-15 min at +least, otherwise too much context switching is distracting.

      • +
      +
    • +
    • Teach and assist (master helper going around)

    • +
    • Teach and observe.

    • +
    • Asking directed questions to fill in gaps.

    • +
    +
  • +
  • Tell the students the way the teachers will work together, so that +it seems coordinated rather than someone is interrupting.

  • +
+
+
+

During the lessons

+
    +
  • Helpers can read the team leader guide. +Encourage helpers to stand and be +constantly walking around, people rarely flag helpers from across +the room.

  • +
  • Encourage the use of sticky notes (red=need help, green=I am done with the +solution). They can also be used for voting, e.g. red/green for two +answers of a multiple choice question.

  • +
  • Don’t touch the learner’s keyboard! This is very hard to do, since +it’s only natural to want to get things done quickly. The best idea +we have is to have a pen and sticky notes, when it’s hard to spell +out a command to type, write it instead.

  • +
  • If appropriate for your topic, create a cumulative +cheatsheet/diagram on the board as you are presenting.

  • +
  • Take advantage of the mistakes/typos you make when teaching! +When you do a mistake and get an error message and realize what you did wrong, +explain what happened since this can offer valuable insights to learners.

  • +
  • Ask “do you do X?” where X is what you are teaching. Instead, ask +“how do you do Y?”. The first question implies something you are +doing wrong, the second is open-ended.

  • +
+
+
+

Exercise sessions

+
    +
  • What to do during exercise sessions

  • +
  • never stop sharing screen, ask someone else to share instead.

  • +
  • Always go over the lesson with someone else the day before.

  • +
+
+
+

Try to stick to the material

+
    +
  • Don’t try to show everything, show less, but show it clearly.

  • +
  • Try not to completely deviate from the material. Ideally, rather influence the material before you teach. +Of course it is good to react to questions and to adapt the material to the audience, so sometimes an excursion can be very useful, +but make clear that you then deviate from the script +and be explicit about whether participants should follow what you do or only watch.

  • +
  • If you want to show some extra steps in the terminal, show them perhaps at the end of an exercise block to not +“mess up” the exercise half-way and change it with respect to the material.

  • +
  • It is good to mention an anecdote or two but be careful about mentioning too much new jargon which +only very few participants may relate to.

  • +
+
+
+

Wrap up

+
    +
  • Say what you taught and why.

  • +
  • Say what comes next. Say where to get that.

  • +
  • Update the instructor’s guide and file issues for any problems you +noticed.

  • +
  • Use the sticky notes to get good/bad feedback: have people write one +good and one to be improved thing, and leave the note on the door on +the way out.

  • +
  • Get instant feedback from your co-teachers and helpers (students +too, if they offer any).

    +
      +
    • Consider making notes on a 4-way diagram of +(content←→presentation) × (went well←→can be improved).

    • +
    +
  • +
+
+
+
+

Instructor technical setup

+
+

See also

+ +
+
+

Final checklist

+
    +
  • Have you moved your configurations away and done the course setup +instead (or left it unconfigured)?: .bashrc (or equivalent), +.gitconfig, .ssh, .conda, etc.

  • +
  • Are you using a software environment as described in the workshop +instructions (conda, virtualenv, etc). Is it clean and without +extra stuff installed?

  • +
  • Is your setup as boring-looking as possible, if you are teaching at +the beginning of the workshop? The first sessions aren’t the time +for distractions.

  • +
  • Is your terminal

    +
      +
    • Dark text on light background?

    • +
    • Do you know key-bindings to change the font size quickly?

    • +
    +
  • +
  • Do you have command history set up? If in doubt, use +prompt-log and tail the +output in a separate smaller window.

  • +
  • Do you have a clean web browser session (different profile for +demos)?

  • +
  • If you use an advanced shell, do you have a simpler shell (bash) set +up for the demos?

  • +
  • (if online) have you practiced Zoom screensharing “Share a portion +of the screen” in portrait-mode? See +Instructor technical setup, online.

  • +
  • (if online) have you checked your audio settings? Join a test +meeting with someone and understand your microphone sound +adjustments. Can you control it for the full range from very quiet +to very loud, so that you can make whatever adjustments needed? Is +your best microphone/headset ready? Audio quality and balance is +critical.

  • +
  • Have you shown your setup to someone else for feedback?

  • +
+
+

Appearance matters. When you look at other professionally made videos +online, they look good. As a presenter, you also need to work to make +your screen look pleasing to the eye. It also has to be similar to a +learner’s screen, so that they are not distracted with your different +configuration or appearance.

+
+

Simple or fancy screen?

+

As a teacher of tech, you also +need to make sure that your screen supports the learning process: +you have conflicting goals of:

+
    +
  • Making your screen look simple, to not distract from what you are +trying to teach, and

  • +
  • Showing more advanced setups, so that others can learn and improve.

  • +
+

In general, try to use a simpler arrangement at the beginning of +workshops. You, or other teachers, can begin showing more advanced +screen layouts once learners are able to see what is important and +what is extra.

+
+
+

Check with someone before you start teaching

+

Most importantly, get your setup done well in advance and show your +co-teachers for feedback. Feedback and time to improve is very +important to make things beautiful.

+
+
+

Clean your environment

+

Do you have fancy .bashrc, .gitconfig, etc files? Move them +away so that you are as plain and normal as possible - beyond +appearances, you don’t want to use any shortcuts that every learner +won’t have access to (telling learners to add some configuration won’t +work - some will miss it and be lost, or worse their system may have a +weird behavior in the future).

+

Relevant files that are sometimes a problem:

+
    +
  • .bashrc

  • +
  • .gitconfig

  • +
  • .ssh/config, .ssh/authorized_keys

  • +
  • .conda/*

  • +
  • Any config for any program you will be demonstrating

  • +
+
+
+

Arrange your windows well

+

This is mostly the topic of Instructor technical setup, online (our +recommendations for in-person window arrangements aren’t so +up-to-date, but the same principles apply but you have a widescreen +view).

+
    +
  • For online teaching, you will want to screenshare a portion of your +screen: half the screen in “portrait mode” so that the other half is +available. See Instructor technical setup, online.

  • +
+
+
+

Desktop environment

+
    +
  • Is your overall desktop environment “normal”-looking?

  • +
  • Do your window title bars take up lots of space? Is it possible to +reduce their size for the teaching - you want as much space for +large fonts as possible.

    +
      +
    • Since you will only be sharing a portion of the screen, or have a +lower-resolution projector, these title bars take up more space +relative to the content.

    • +
    +
  • +
  • Same for desktop menu bars, etc.

  • +
  • Do you need to go into light-mode theme? Dark text on light +background is much better than dark mode, so it is strongly +recommended to do this.

  • +
  • Can you easily resize your windows for adjusting during teaching?

  • +
+
+
+

Web browser

+
    +
  • Are you doing a lot in a web browser? Consider making a separate +profile that is just for demos.

  • +
  • Install whatever basic safety extensions / ad blockers are most +relevant, but keep it simple otherwise.

  • +
  • Can you turn off unneeded menu- and toolbars?

  • +
  • Does your web browser have a way to reduce its menu bars and other +decoration size?

    +
      +
    • Firefox-based browsers: go to about:config and set +layout.css.devPixelsPerPx to a value slightly smaller than one, +like 0.75. Be careful you don’t set it too small or large since +it might be hard to recover! When you set it to something smaller +than 1, all window decorations become smaller, and you compensate +by zooming in on the website more (you can set the default zoom to +be greater than 100% to compensate). Overall, you get more +information and less distraction.

    • +
    +
  • +
+
+
+

Terminal

+
+
Terminal color schemes
+
    +
  • Dark text on light background, not dark theme. Research and our +experience says that dark-text-on-light is better in some cases and +similar in others.

  • +
  • Make a dedicated “demos” profile in your terminal emulator, if +relevant. Or use a different terminal emulator just for demos.

  • +
  • You might want to make the background light grey, to avoid +over-saturating people’s eyes and provide some contrast to the pure +white web browser. (this was an accessibility recommendation when +looking for ideal color schemes)

  • +
  • Do you have any yellows or reds in your prompt or program outputs? +Adjust colors if possible.

  • +
  • Eliminate menu bars and any other decoration that uses valuable +screen space.

  • +
+
+
+
Clearing the terminal
+
    +
  • Don’t clear terminal often (or ever - un-learn CTRL-L if possible). +Learner’s can follow as fast as you! More people will wonder what +just got lost than are helped by seeing a blank screen. Push +ENTER a few times instead to add some white space.

  • +
+
+
+
Terminal size
+
    +
  • Font should be large (a separate history terminal can have a smaller +font).

  • +
  • Be prepared to resize the terminal and font as needed. Know and use +keyboard shortcuts for changing the font size when you need to show +more columns (it’s also OK if the terminal is wider than your screen +if most of the right side is not that important to see). You can +have a larger font normally, and make it smaller and the terminal +wider when you have long lines that learners need to see.

  • +
+
+
+
Prompt
+

Your prompt should be minimal: few distractions, and not take up many +columns of text.

+

Learners have to read your prompt quickly, understand what you +entered, copy it, all the while not being distracted by everything +else or your screen. Day 1 git-intro is not the time to have your +fancy git-bash prompt, instead show them how to use git to get that +information. Set an easily-viewable prompt.

+
    +
  • prompt-log (see the next section on command line history) does +this for you.

  • +
  • The minimum to do is is export PS1='\$ '.

  • +
  • Blank line between entries: export PS1='\n\$ '.

  • +
  • Have a space after the $ or % or whatever prompt character you +use.

  • +
  • Strongly consider the bash shell. This is what most new people will +use, and bash will be less confusing to them. (Later in workshops, +using other shells and being more adventurous is OK - learners will +know what is essential to the terminal and what is extra for your +environment).

  • +
+
+
+
Command line history
+

You need to find a way to show the recent commands you have entered, +outside of your main window, so that learners can see the recent +commands.

+

Consider prompt-log by rkdarst +(https://github.com/rkdarst/prompt-log/). It adds a interesting idea +that the command you enter is also in color and also provides +terminal history before the command returns (see below).

+

Arrange two terminals, so that there is the main work window and the +history window with a font smaller size - the history can be off to +the side.

+

See the following screenshot for an ideal arrangement:

+
+_images/s10-kickstart-prompt-log.png +

S10: HPC Kickstart course. Note the colors contrast of the +windows and colors of the prompt and text. The history is smaller and +doesn’t take up primary working space. The working directory is +in the window titlebar.

+
+ +
+
+
+
+

Instructor technical setup, online

+
+

See also

+

This is online-specific instructor tech setup. For general, see +Instructor technical setup which also applies here.

+
+

The information in this is currently specific to Zoom teaching and +livestream teaching.

+
+

Final checklist

+

See the list in Instructor technical setup, which includes points for +online.

+
+
+

Audio

+

Audio quality, and balance between instructors, is absolutely +critical to good online work, especially teaching. Consider the +following:

+
    +
  • Can you adjust your microphone volume from very low to +higher-than-needed? Make sure your dynamic range is larger than +“barely working”, so that you have some room to adjust for later.

  • +
  • Do you have a high-quality headset? A headset with microphone is +the most reliable, but if you can get a desktop setup working +well, that can be good too. Always have a high-quality headset for +backup anyway.

  • +
  • If you have a bluetooth headset, consider:

    +
      +
    • Bluetooth headsets have significant latency compared to wired or +purpose-built wireless protocols like gaming headsets have.

    • +
    • The microphone might not have enough bandwidth (if it’s part of +the same headset).

    • +
    • Bluetooth 5 is much better in both latency and quality.

    • +
    • Consider investing (or getting your work to invest in) some +high-quality headset or desktop audio gear.

    • +
    +
  • +
  • “Ducking” is when the first words are silenced/quieted by noise +cancellation, until it detects speaking. To avoid this, don’t use +“high” noise cancellation (as low as possible is better). If you +need high cancellation because of background noise, switch to your +headset.

  • +
+
+
+

Screen sharing

+

You have to assume the smallest screen from learners and plan for +that. You should share a portrait screen: either a portion of +your screen, or one window in portrait mode. See the examples below.

+
    +
  • Learners have a small screen, and need room for their own terminals +and web browser open, too. A big screen or multiple monitors is +the special case.

  • +
  • Sharing a 1920x1080 screen is not a good idea: you need to make all +the text size large so that learners can scale it down to have room +to do their work. Pixels are wasted. Instead, force yourself to +save space by using a normal font size but sharing less of your +screen.

  • +
  • Zoom now has a “share portion of screen” (Screen sharing → Advanced +→ Share a portion of the screen).

  • +
  • For livestreaming, our aspect ration is 840×1080 (portrait). +This is a bit less than half your screen. This is 43% of the width +of your screen and the full height, for a standard FullHD screen.

  • +
+

When streaming/recording: Never stop sharing a screen, ask someone +else to take it over. +There is a chance that the view goes to “gallery view” in the +recording or stream, which makes video editing harder or disrupts +learner privacy.

+
+
Screen share examples
+

These are layouts of the actual screen or portion of screen being +shared:

+
+_images/screenshare-fullhd.png +

S1: A FullHD 1920x1080 screen shared.

+
+
+_images/screenshare-vertical.png +

S2: A vertical screen layout shared. Note the extra shell history at the +top. The web browser is at the bottom, because the Zoom toolbar can +cover the bottom bit.

+
+
+_images/screenshare-jupyter.png +

S3: A sort-of GUI (Jupyter) shared vertically.

+
+
+_images/screenshare-rsh.png +

S4: This isn’t a screenshare from CodeRefinery, but may be instructive. +Note the horizontal layout and shell history at the bottom right.

+
+
+_images/s5-shell-intro-dark.png +

S5: Similar to above, but dark. Includes contents on the right.

+
+
+_images/s8-modular-code-development.png +

S8: Jupyter + terminal, including the fish shell and the +terminal history.

+
+
+_images/s9-git-intro.png +

S9: Similar to S8. Lesson + terminal, tmux plus terminal history +and dark background.

+
+
+_images/s10-kickstart-prompt-log.png +

S10: HPC Kickstart course. Note the colors contrast of the +windows and colors of the prompt and text. The history is smaller and +doesn’t take up primary working space. The working directory is +in the window titlebar.

+
+
+
+
Screen layout: learners
+

This is how learners can arrange their screen:

+
+_images/learner-largescreen.png +

L1: Learner with a large screen, Zoom in dual-monitor mode so that the +instructur pictures are not shown. Screenshare is on the left side, +HackMD at bottom left, terminal and web browser on the right.

+
+
+_images/learner-normal.png +

L2: A learner with a single large screen (Zoom in “single monitor mode”). +Instructor screen share at right, learner stuff at left.

+
+
+_images/learner-small.png +

L3: A learner with a particularly small screen. Instructur screenshare at +left, your windows at right.

+
+
+
+
+

Screen layout: instructors

+

This is what the instructor sees on their screen:

+
+_images/instructor.png +

I1: Vertical instructor setup. Zoom is sharing a portion of the left +side, the right side is free for following HackMD, chat, etc (but +don’t overload yourself).

+
+
+
+
+
+

Responsibilities of an instructor

+
    +
  • Review, triage, and work on lesson issues

  • +
  • Define exercises

  • +
  • Communicate exercise list to Exercise coordinator

  • +
  • Set up and test a quality screen share

  • +
  • Coordinate with co-instructor

  • +
  • Communicate software requirements to Instructor coordinator

  • +
  • Communicate timing adjustments to Instructor coordinator

  • +
  • After planning/editing the lesson: Do a dry run (prefereably with someone “new” to the topic)

  • +
+
+
+

From team leader/helper to more

+

Here is one possible pathway from learner to (whatever else). This is +an idea for a pathway but by no means a requirement - you can join +at whatever step you like, and steps don’t have to happen in order. +Maybe you are interested in some or the other. There are also roles +completely outside of this pathway.

+
    +
  • After being a learner, you come back as an team leader/helper.

  • +
  • When you have a solid understanding of all materials, you may join +as an expert helper.

  • +
  • You begin co-teaching episodes with someone else

    +
      +
    • We find that co-teaching is a good way to start. In this, there +are two people, one person assumes the big-picture discussion, and +the other the typing and explaining what they are doing. By +making the lesson a discussion instead of a lecture, it’s more +dynamic.

    • +
    +
  • +
  • Eventually, you get confident enough to teach yourself (though +really we should always be co-teaching…)

  • +
  • Somewhere in there (before or after instructor, depending on your +interests), you may want to try to be a HackMD helper or Zoom host. +These are more about coordinating all the other people involved in +the workshop.

  • +
+

Let’s emphasize again: this is one pathway, but you should do what you +want.

+
+
+
+

Co-instructors

+

Since we focus on Team teaching, almost everyone is a +co-instructor. But this page is focused on onboarding new +co-instructors in their first lessons, so focuses on explaining the +most common starting point.

+
+

Why co-teaching?

+
+_images/teach-teaching--screenshot.png +

Demo of team teaching. Two people are speaking, in this case one +is typing and giving the small point of view, and one is explaining +the big point of view.

+
+

The dream of interactive teaching is hard to achieve: most audiences +are very quiet and even if someone does speak up, it is a small +fraction of the audience. We have found a better way: Build the +interaction straight in to the course by co-teaching. Instead of +trying to have a conversation with students, we have a conversation +among co-instructors.

+

Co-teaching provides other benefits, such as easier preparation and +easier presentation.

+
+
+

How co-teaching works: guide and demo-giver

+

Main article: Team teaching.

+

We have developed several ways of team teaching, but for starters we +suggest the “guide and demo-giver” approach. The guide manages +the overall flow through the lesson. The demo-giver does the +typing during the demonstrations. So, for example:

+
    +
  • The guide introduces a type-along session and walks through the +steps while…

  • +
  • … the demo-giver does the typing in the screenshare

  • +
  • The guide and demo-giver ask each other about what is happening.

  • +
+

During other times, the demo-giver and guide ask each other questions +when the other is talking.

+
+
+

Preparing for your first time

+
+_images/s10-kickstart-prompt-log.png +

An example of a beautiful screenshare. Note the portrait orientation +(you have half the screen free for notes and HackMD, learners have +half the screen free to do their own work). The terminal is +dark-on-light, a minimal prompt, no other fancy shell distractions, +there is a shell history visible, and slightly distinct colors between +the web browser and the terminal.

+
+
    +
  • There is some generic technical setup for your own computer - make a +clean environment that matches learners, make a good prompt, and so +on. See Instructor technical setup and +Instructor technical setup, online.

  • +
  • Watch the Demo of CodeRefinery livestream teaching + (read the +description for an explanation).

  • +
  • Talk and plan with your co-instructors: decide which model of +co-teaching you will give.

  • +
  • Plan the material, try to go through all of the exercises and +type-along.

  • +
  • Do a run-through of the lesson, practicing what each person says. +This can be relatively quick (remember, most of the time in an +actual lesson is learners doing exercises alone).

    +
      +
    • Also check the technical setup - make sure that it looks good on +screen.

    • +
    +
  • +
+
+
+

Top issues new co-instructors face

+

See the instructor-intro for now.

+
+
+

See also

+ +
+
+
+

HackMD manager

+

We have one person who is a “HackMD helper”. This isn’t the only +person that should edit and answer, but one person shouldn’t have too +much else on their mind so can focus on it. They also make sure that +HackMD is updated with exercise, break, and other meta-information to +keep people on track.

+

Below, (*) = important.

+
+

Before the workshop

+
    +
  • Create a new hackmd for the workshop

  • +
  • make sure that editing is enabled for anyone without login

  • +
  • Add workshop information, links to the workshop page and material +and an example question and answer to the top of the hackmd (see below)

  • +
+
+
+

Most things to edit (everyone)

+

Make it easy to post after the course and consistent to follow:

+
    +
  • Tag all names with [name=XXX] (so they can be removed later), +remove other personal data or make it obvious.

  • +
  • Add in information on exercises (new section for them, link, end +time, what to accomplish)

  • +
  • Make a logical section structure (# for title, ## for sections, +### for episodes, etc. - or what makes sense)

  • +
+
+
+

General HackMD practices

+
+_images/hackmd--full-demo.png +

A live demo of HackMD during a Q&A time. The two instructors are +discussing some of the import answers. Multiple learners have asked +questions, multiple answers, and some remaining to be answered

+
+

Keep it formatted well:

+
    +
  • (*) Tag names you see with [name=XXX] so that we can remove it +later.

  • +
  • Heading level # is only the page title

  • +
  • Add a new ## heading when a new lesson or similar thing is +started (introduction, icebreaker, break between lessons, etc)

  • +
  • Add a new ### heading when a new episode, exercise, break +(within exercise session)

  • +
  • Ensure people are asking questions at the bottom, direct them there +if they aren’t.

  • +
  • (*) Ensure each question is a bullet point. Each answer or follow-up +should be a bullet point below.

    +
      +
    • Should you use more deeply nested bullet points, or have only one +level below the initial question? It depends on the context, but +if a conversation goes on too long, try not to let it go too +deep.

    • +
    +
  • +
+

Update with meta-talk, so that learners can follow along easily:

+
    +
  • Add Icebreaker and introductory material of the day. Try to talk to +people as they joined to get them to open HackMD and answer.

  • +
  • Anything important for following along should not be only said via +voice. It needs to be in the HackMD, too.

  • +
  • New lessons or episodes, with links to them.

  • +
  • For exercises, link to exercise and add the duration, end time, +goals. If these are unclear, bring it up to the instructor by voice.

  • +
  • Add a status display about breaks.

  • +
+

Screenshare it when necessary:

+
    +
  • During breaks and other times, share the HackMD (including the +notification about break, and when it ends).

  • +
  • It is nice if the arrangement allows some of the latest questions to +be seen, so people are reminded to ask there.

  • +
  • Someone else may do this, but should make sure it happens.

  • +
+

Answer questions

+
    +
  • If there is an question that should be answered by the instructor by +voice, bring it up (by voice) to the instructor immediately.

  • +
  • During breakout sessions, watch for HackMD notifications about +breakout rooms that need help +and direct someone to that room.

  • +
  • How soon do you answer questions? Two points of view:

    +
      +
    • Answer questions right away: can be really intense to follow.

    • +
    • Wait some so that we don’t overload learners: reduces the info +flow. But then do people need to check back more often.

    • +
    • You need to find your own balance. Maybe a quick answer right +away, and more detailed later. Or delay answers during the most +important parts of the lecture.

    • +
    +
  • +
  • Avoid wall-of-text answers. If reading an answer takes too long, it +puts the person (and other people who even try to read it) behind +even more by taking up valuable mental energy. If an answer needs a +wall of text, consider these alternatives:

    +
      +
    • Progressive bullet points getting more detailed (first ones +useful alone for basic cases)

    • +
    • Don’t be worried to say “don’t worry about this now, let’s talk +later.”

    • +
    • Figure out the root problem instead of answering every possible +interpretation

    • +
    • Declare it advanced and that you will come back later.

    • +
    +
  • +
+

Ensure it can be posted quickly:

+
    +
  • HackMD gets posted to the workshop webpage. For this, it needs some +minimal amount of formatting (it doesn’t need to be perfect, just +not horrible).

  • +
  • All names and private information needs to be stripped. This is why +you should rigorously tag all names with [name=XXX] so they can be +removed (see above).

    +
      +
    • Learner names can be completely removed. CR staff names can be +[name=CR] or something similar.

    • +
    • There may be other private URLs at the top or bottom.

    • +
    +
  • +
  • If possible, send the PR adding the HackMD to the workshop webpage +(though others can do this, too).

  • +
+
+
+

HackMD format example

+
# Workshop, day 1
+
+
+## Lesson name
+https://coderefinery.github.io/lesson/
+
+### Episode name
+https://coderefinery.github.io/01-episode/
+
+- This is a question
+  - Anwser
+  - More detailed answer
+- question
+  - answer
+
+### Exercises:
+https://link-to-exercise/.../.../#section
+20 minutes, until xx:45
+Try to accomplish all of points 1-3.  Parts 4-5 are optional.
+
+Breakout room status:
+- room 2, need help with Linux permissions
+- room 5, done
+
+### Break
+:::danger
+We are on a 10 minute break until xx:10
+:::
+
+
+## Lesson 2
+https://coderefinery.github.io/lesson-2/
+
+
+
+
+
+

Posting HackMD to website

+

HackMD should be posted sooner rather than later, and hopefully the +steps above will make it easy to do so quickly. You could wait a few +hours, to allow any remaining questions to be asked an answered.

+
    +
  • Download as markdown

  • +
  • Remove any private links at the top

  • +
  • Adjust headings so that they are reasonable

  • +
  • Look for private info and remove it

    +
      +
    • Search document for [name=???] (change to [name=staff] or +[name=learner])

    • +
    • Any names not tagged with [name=]

    • +
    • usernames in URLs

    • +
    • private links

    • +
    +
  • +
+
+
+
+

Expert helpers

+

We mainly have expert helpers for large workshops.

+
    +
  • As an expert helper, your main job is to move between different +groups and make sure that groups are doing well.

  • +
  • You might be summoned to a group whose helper needs extra help, or +take the place of a helper if a group doesn’t have one.

    +
      +
    • Watch HackMD/Zulip for this, though requests might come in from +other channels, too.

    • +
    +
  • +
  • No one is expected to know everything, but an expert helper should be +able to find a person who can answer, or confident enough to say +they should move on.

  • +
  • Make sure you have a new (newer than 15 october 2020) Zoom client, +so that you can join arbitrary breakout rooms.

    +
      +
    • If you don’t, then you have to ask to be put into some room, and +then you can swap to any other room.

    • +
    +
  • +
  • Report an overview of the pulse of the breakout rooms in zulipchat +(or hackmd). Is everyone behind? People finishing early? Big +differences between them? Questions which we should bring up in the +main room?

  • +
  • Monitor if any team leaders need extra help or training. Should we +improve our team leader training?

  • +
+
+

Tasks

+

There’s not much difference between a team leader and expert helper, but we +envision this role standing by and jumping into rooms when there’s a +difficult problem.

+
    +
  • Sometimes, you wait around for a problem that needs your attention. +But it’s better to be proactive and go into the rooms yourself and +check them out. Talk to the organizers/instructors to see which you +should do.

  • +
  • You aren’t assigned to particular breakout room, but you can +switch between them (but it’s not obvious how):

    +
      +
    • To do this, you do get assigned into one room initially. Join +that room. After you are in the room, click on “Breakout +Rooms”, and then Join to switch to a different room of your +choice.

    • +
    • You also always have the option “Leave breakout room” (if in a +room) or “Join your assigned room” (if in main room and assigned +one).

    • +
    +
  • +
  • Your role is to switch between breakout rooms and check up on them.

    +
      +
    • e.g. join room 1, take a look/ask how it is, then join room 2, +then 3, then back to 1, and repeat.

    • +
    • Of course, stay in one longer, if it’s needed.

    • +
    • Make a note of any important questions to be asked in the main +room afterwards.

    • +
    +
  • +
  • Try to divide up the breakout rooms between the staff, and try to +join and catch up with the same rooms (this promotes familiarity).

    +
      +
    • E.g. A rotates between rooms 1-3, B gets rooms 4-7, C gets rooms +8-11.

    • +
    +
  • +
  • Make sure to watch the HackMD for expert helper requests, this could help +you decide which room to jump to next. Comment when you are heading +there.

  • +
+

Concrete example for an expert helper’s time:

+
    +
  • I join breakout room 5 randomly. I spend 15 seconds watching, then +ask if things are going OK. If everything is good, I move on within +a minute since I am not needed (if there is a good break, I’ll ask +“everything OK? good, see you around.”). If there are questions +that I can help with, I answer them. If they seem to be struggling, +then I will make a note in the HackMD and stay a while longer and +watch/help.

  • +
+
+
+

Common issues and solutions

+
    +
  • A room is very slow, the person sharing the screen is working quite +slowly.

    +
      +
    • Kindly suggest that you or someone else take over and go through +it faster

    • +
    • Yes, this is hard to say nicely

    • +
    +
  • +
  • No one wants to take initiative and screen share

    +
      +
    • If you think everyone is confident enough, this can be OK

    • +
    • But especially at the beginning of the workshops, you can share +your own screen and go along with people.

    • +
    +
  • +
  • Someone is having trouble installing software

    +
      +
    • “Perhaps we can take a look at this after the workshop? We try +to make sure everything is installed beforehand, but “

    • +
    +
  • +
+

Other reference:

+ +
+
+
+

Host

+

WARNING: page out of date, this is also split to the director.

+
    +
  • Make all of other staff and expert helpers co-hosts.

  • +
  • Take attendance in spreadsheet, if we do that.

    +
      +
    • TODO: provide sample spreadsheet

    • +
    • It might be easiest to take attendance all at once, in the middle +of the session, after everyone has been assigned to breakout +rooms.

    • +
    +
  • +
+
+

Breakout rooms

+
    +
  • Rename people to include breakout room number (other co-hosts should +help and hopefully do most of this work too), though. (this is a +continuous process as people drop out and rejoin)

  • +
  • Assign people to breakout rooms (this is a continuous process)

  • +
  • Merge breakout rooms as necessary, to try to keep them balanced well

  • +
  • Constantly watch for new people joining, rename them, and assign +them to breakout rooms.

    +
      +
    • Note, you might have merged the room they were originally in, so +they might end up in an empty room!

    • +
    +
  • +
  • Plan for the future: how many helpers might be missing, which rooms +need to be merged. Can you keep the merging somewhat consistent +over time?

  • +
+
+
+

Recording

+

Recording workshops provides a way for learners to get an instant +review of what was covered, increasing learning. We don’t currently +intend for workshop recordings to be useful to new people learning +later, but they could be.

+
    +
  • Record the workshop or give permission for others to record.

    +
      +
    • If you are recording, you can’t leave and go to other rooms.

    • +
    • Perhaps a separate computer could record?

    • +
    +
  • +
  • spotlight speaker

  • +
  • dual monitor mode?

  • +
  • ensure that screen is always being shared?

  • +
  • stay in speaker view (not gallery view)

  • +
  • start and stop recording

  • +
  • rename recording immediately dayN-lessonname-zoom.mp4 and upload +to google drive.

  • +
+
+
+

Streaming

+

All of the steps needed to record mean that you can stream, too. In +fact, you could look at streaming as a side-effect of recording (or a +way to record).

+
    +
  • spotlight speaker

  • +
  • start streaming

  • +
  • dual monitor mode?

  • +
  • ensure that screen is always being shared?

  • +
  • stay in speaker view (not gallery view)

  • +
  • have stream feed open. If you see it change to gallery view, fix it +immediately.

  • +
  • stop streaming

  • +
  • download recording from twitch, rename to +dayN-lessonname-twitch.mp4 and upload to google drive.

  • +
+
+
+
+

Registration coordinator

+

The registration coordinator is responsible for the Indico registration page and the workshop homepage. +Usually the registration coordinator has the best position for sending emails. Drafting can be collaborated with outreach and marketing coordinator. +They keep and eye on the Helpdesk before, during and after every workshop and make sure everyone is registered and knows where to go. +After the workshop, they make sure the CodeRefinery webpage is up-to-date and all changes needed in the planning HackMD are ported to the template. +The registration coordinator also has the overview over statistics for reporting and adds those to the webpage after the workshop.

+
+
+

Exercise coordinator

+

Also called team leader coordinator.

+

The exercise coordinator makes sure that the hands-on idea of the workshop is preserved. They remind the instructors to check and report their exercises before the workshop. They are also the contact person for the team leaders and organize the team leader onboarding before the workshop.

+

If wished, they can also host the exercise Zoom room and support the registration coordinator with building the teams for the breakout rooms in Zoom.

+
+
+

Workshop marketing

+

The workshop marketing and outreach coordinator makes sure (by delegation) that the workshops are advertised in all known channels. +They also coordinate mass communications with all entities of the workshop.

+

Some thoughts on target groups that should be tried to be reached:

+
    +
  • Learners (many sub-categories with different time vs need trade-offs: students, junior researchers, senior researchers, lifelong learning) (join a workshop)

  • +
  • team leaders (bring your friends, join to learn more and lead groups)

  • +
  • Research leaders (people who can tell their students they need to attend CR)

  • +
  • University staff (Computing, open sci, etc.) (people who can serve as local organizers and serve as local helpers)

  • +
  • Potential instructors (teach, etc.)

  • +
  • High-level management (provide us funding)

  • +
+

You can find a list of commonly advertised places in the bottom of the Workshop checklist template.

+
+
+

Director

+

The director manages the flow of the course, and in particular the +flow when things do not go according to plan. During livestream +courses, the director also manages the stream scene/audio selection.

+
    +
  • Gives introductions and wrap-ups (to the days, sessions, and +instructors), or at least ensures they happen.

  • +
  • Ensures good flow of the course overall

    +
      +
    • Is aware enough of the schedule so that they can decisively adjust +it when needed.

    • +
    • Keeps time, ensures breaks

    • +
    • Actively discusses with the instructors about these practical +arrangements (e.g. negotiating best break times)

    • +
    +
  • +
  • (livestreaming) Flips the livestream scenes when necessary, cues +instructors.

  • +
+
+

Managing the schedule

+

The director manages the overall flow: making sure the instructors are +ready, icebreakers happen, transitions are smooth, people are +introduced, breaks happen, HackMD is shared at the appropriate times, +and so on.

+

During large courses, there are many different instructors and certain +exercises/lessons may randomly take longer (no matter how much +preparation there is). The audience expects this, and in practice +decisively accepting and adjusting the schedule (or deciding not to) +makes things smooth.

+

The Director is usually the instructor coordinator, so knows the +schedule well. The instructor should be empowered to decide (after +checking chat, HackMD, and other instructors) what to do, and can +directly announce the new schedule. This takes confidence, but don’t +worry: you have plenty of people to consult with, ask advice from +those around and then make your choice.

+

You should also make sure that HackMD is updated with breaks, +exercises, and so on. You will probably be the one sharing HackMD +during the breaks.

+
+
+

Switching scenes and audio

+

During a livestream course, various video inputs are mixed +(screenshare, instructor gallery, title card, HackMD) and +broadcasted. This gives one extra level of management that is needed: +yes, it is more overhead, but the advantages are that the instructors +can mute the livestream and have a private discussion. This is great +for breaks and exercise times, and really helps with the flow a lot.

+

So, for example:

+
    +
  • Start the course on the “title card”

  • +
  • Switch to gallery view for introduction

  • +
  • Switch to screenshare (and adjust PiP size) during teaching

  • +
  • Share HackMD during the break and then make PiP size zero

  • +
  • Repeat for next courses.

  • +
+

The available controls include:

+
    +
  • Audio: the audio capture can be turned on and off:

    +
      +
    • “Instructors”: the capture of the Zoom

    • +
    • “Mic”: this is the local microphone of the capture computer and +should not normally be adjusted.

    • +
    +
  • +
  • Scene selection: there is a button to select among these scenes

    +
      +
    • “Title card”: graphics used before learners arrive

    • +
    • “Gallery”: instructors

    • +
    • “Screenshare”: capture of the Zoom screenshare

    • +
    • “Hackmd”: just what it says

    • +
    +
  • +
+ +
    +
  • Picture in Picture display: adjust size and layout of this

    +
      +
    • The size can be adjusted to fit the screen

    • +
    • To turn it off, make the size zero

    • +
    • The cropping can be adjusted based on the number of people in +the Zoom display.

    • +
    +
  • +
+
+
+

OBS remote control via obs-tablet-remote

+

The broadcaster will provide you with a URL to go to the remote +control. TODO: picture

+

This is an example (note: it won’t work, because you don’t have OBS running):

+
    +
  • coderefinery.github.io/obs-tablet-remote/#!auto&host=HOST&port=4444&password=PASSWORD&config=https://raw.githubusercontent.com/coderefinery/obs-config/master/obs-tablet-remote-config.json

  • +
+

Go to this URL. It will prompt you for a password (or the broadcaster +might add the password to the URL already). The OBS remote control +will open with a pre-arranged configuration for your course, with +buttons corresponding to the controls you see above.

+
+
+

See also

+

(none yet)

+
+
+
+

Broadcaster

+

This page explains the setup and how-to guide for the OBS broadcaster. +This person manages the technical setup of OBS and thus +the streaming. This person often is, but does not have to be, the OBS +director [todo: link] who switches the scenes and manages the +broadcast after it has started.

+
+

Role of the broadcaster

+

As the broadcaster, you manage the OBS application that captures Zoom +and sends it to the world. This is different from:

+
    +
  • The Director manages the scenes and the overall flow of the +workshop (switches scenes, cues instructors when to start talking, +shares HackMD during the breaks). This person is often the +broadcaster, but for clarity we use more precise terms.

  • +
  • The Host is the interface between the instructors and the +audience: e.g. announcing instructors, keeping to the schedule, +etc.). They are very often the same as the Director.

  • +
  • The Instructors connect to Zoom and teach. If there is no +designated director, at least one instructor needs to know a bit +about that.

  • +
+

The broadcaster has a lot of preparation work to do the first time +they get set up (future courses aren’t so bad). They should expect +some panicked fixing of stuff right before each course starts. During +the courses themselves, the broadcaster is mainly sitting back making +sure nothing breaks.

+
+
+

Initial setup

+

Prerequisites:

+
    +
  • A somewhat powerful computer dedicated for broadcasting (not used +for teaching as an instructor, the broadcaster can use an +instructor computer, but that is much more complicated).

  • +
  • Stable internet connection (speed is not too important these days).

    +
      +
    • 20/5 download/upload Mbps is probably plenty good. 100/10 Mbps is +far more than is needed.

    • +
    • Wired connections, rather than wireless, are better (WiFi, +non-cellular uplink). However, you probably know your overall +stability the best: you want a continuous, smooth connection +without much jitter. +However, OBS settings can be tuned to have a larger buffer to +handle this.

    • +
    +
  • +
+

Software installation:

+
    +
  • Install OBS (Linux, Mac, Windows - +this is a mass market product so there is good support)

  • +
  • Install obs-websocket. This is also +fairly widespread, but slightly less so than OBS.

  • +
  • Zoom (but you likely already have that)

  • +
+

Zoom setup:

+
    +
  • Install Zoom. There’s not much you need to do differently.

  • +
  • Some Zoom settings:

    +
      +
    • General → Use dual monitors → yes. Despite the name, this gives +Zoom two windows: one for the gallery view, one for the +screenshare (or active speaker if there is no screenshare).

    • +
    • General → Enter full screen automatically when starting or joining +a meeting → false

    • +
    • Screen Share → Enter full screen when a participant shares screen +→ false (important)

    • +
    • Screen Share → Scale to fit shared content to Zoom window → true.

    • +
    +
  • +
+

OBS setup:

+
    +
  • Clone the obs-scenes repository. This contains some +pre-made scenes which will set your OBS up for teaching nicely.

  • +
  • Import the TeachingStreaming profile +(Profile → Import → obs-scenes/profiles/Teaching_Streaming). This contains things +like audio and encoder settings

    +
      +
    • TODO: this may need adjustment for your particular situation. At +least things like file paths will need to be adjusted. Look at +the obs-scenes readme for more information.

    • +
    • Most importantly, this sets it to 840 horizontal × 1080 vertical +(portrait mode).

    • +
    +
  • +
  • Import the Teaching_Streaming_ZoomCapture scene collection (Scene +Collection → Import → +obs-scenes/scenes/Teaching_Streaming_ZoomCapture).

  • +
  • You now need to configure some window captures, for example, you +need to tell OBS which window has the gallery of all instructors in +it. From the “Scenes”

    +
      +
    • Scene _GalleryCapture[hidden] → source ZoomMeeting-Gallery +right click → Properties → Window → select the Zoom gallery view +(for me it is titled “Zoom meeting”). TODO: adjust the size of +this window until it fits the pre-made scene [it looks nice and +large]

    • +
    • Scene _Screenshare-Zoom-Capture[hidden] → source +Zoom-SecondWindow right click → Properties → Window → select +the Zoom screenshare/active speaker window (for me it is titled +only “Zoom”). Adjust the size of this window until it nicely +fills the preview pane (the ideal size is 840×1080).

    • +
    • (optional) Scene _Hackmd-Capture[hidden]: similar, select the +shared HackMD

    • +
    • (optional) Scene _Broadcaster-Screen[hidden]: configure your +local desktop capture.

    • +
    +
  • +
  • Configure the audio

    +
      +
    • Settings → Audio → Desktop Audio → “Default” (or if you want, +select an explicit device). This is what will capture Zoom by +monitoring your speakers/headphones.

      +

      Note: prevent audio feedback! Be careful if you set this to +speakers, and you have a separate computer which you use for +teaching with a microphone that would hear those speakers: you +would get feedback.

      +
    • +
    • Settings → Audio → Mic/Aux Audio → “Default” (or whatever device +you want). This would capture that computer’s local microphone, +if you use it. (More likely, you would join the meeting as an +instructor, and thus use a separate computer to speak to people)

    • +
    • From the main OBS scene, rename the audio devices:

      +
        +
      • Bottom panel → Audio mixer → one of the devices → gear icon → +Rename →

        +
          +
        • Desktop capture to “Instructors”

        • +
        • Mic to “BroadcasterMic”

        • +
        +
      • +
      +
    • +
    +
  • +
  • Configure obs-websocket (set the listening socket + authentication).

    +
      +
    • Tools → Websocket server settings → {Enable websockets +server=true, Server port=(something), Enable authentication=true, +Password=something}. Share your IP address, server port, and +password with your other instructors.

    • +
    +
  • +
  • Allow outside connections. On of these two:

    +
      +
    • Use ngrok to forward the connection +(including SSL). Read more from the obs-websocket documentation: +https://github.com/obsproject/obs-websocket/blob/4.x-current/SSL-TUNNELLING.md +. Note that the free plan limits to 4 simultaneous connections +and the connection information will change every time you restart, +which is not great.

    • +
    • Configure your router/firewall to allow incoming connections to you +IP address, on the port configured above. (it is this external IP +address that you need to share with other instructors.

    • +
    +
  • +
  • Verify the obs-tablet-remote connection (see TODO director-setup).

  • +
+
+
+

Before each day

+
    +
  • Set Twitch stream data: stream title, stream description, channel +about page.

  • +
  • Configure and check streams

  • +
  • Test everything

  • +
  • Basic information private message:

    +
    * zoom info:
    +* zoom link:
    +* attendee hackmd:
    +* notes hackmd:
    +* live preview:
    +* control panel: http://rkd.zgib.net/obs-tablet-remote/#!auto&host=HOST&port=PORT&password=PASSWORD&config=https://raw.githubusercontent.com/coderefinery/obs-config/master/obs-tablet-remote-config.json
    +
    +
    +
  • +
+
+
+

Before each broadcast

+
    +
  • Ensure anything from the above is done (obs-tablet-remote +connection, scene layout, etc).

  • +
  • Ensure Zoom scenes are correctly captured, flip through them to +verify.

  • +
  • Wait for first instructors to join.

  • +
  • Zoom: Disable sound on participants joining

  • +
  • In zoom, right click on a participant without video and “Hide +non-video participants”. You may need three participants in order +to do this: if you have fewer, join through a browser or something.

  • +
  • Make other instructors co-hosts in the Zoom so that they can share +screen without the other person stopping.

  • +
  • Start recording / start streaming ~20-30 minutes in advance, with +audio muted and on the title card scene. Start recording at the +same time as streaming so you don’t forget it!

  • +
  • Hand it off to the director (possible yourself) to flip the audio +and scene once icebreakers start.

  • +
+
+
+

During the broadcast

+
    +
  • You can not share screen with Zoom (it messes up the windows: +screenshare becomes gallery, the old gallery window disappears).

    +
      +
    • Instead, there is a separate OBS scene for local screenshare.

    • +
    • But we recommend using a separate computer for broadcasting and +instructing, to avoid this problem.

    • +
    +
  • +
  • For the most part, the director does the scene switching (and you +might be the director)

  • +
  • You don’t need to always be in front of the broadcasting computer, +but be available in case there are emergencies.

  • +
+
+
+

Common problems

+
    +
  • Internet connection goes down

  • +
  • OBS crashes While this happens somewhat often during testing, +during live productions, when the settings are not being changed, it +has never been observed. Set all settings in advance, and maybe +quit and restart right before starting the broadcast.

  • +
  • Audio is capturing the wrong inputs, or audio quality is bad

    +

    So once when broadcasting, the audio quality was horrible. It +turned out that the sound system got confused and the desktop audio +capture (zoom capture) was actually capturing the microphone. This +was not reflected in the OBS settings.

    +

    To solve this, go to the OBS settings (you can adjust most, but not +all, settings while a stream/recording is ongoing). Flip the audio +devices to “disabled”, then back to what it should be (possibly you +need to save in between?).

    +

    It’s possible there are other times you need to adjust the audio.

    +
  • +
  • I have HackMD open in view mode (to share) and HackMD open in edit +mode (to edit), but OBS keeps switching to share the editable +one. OBS seems to go by window title. Try this: Use a different +browser, or run one of them in private mode (so that the title is +different).

  • +
+
+
+

See also

+
    +
  • There is plenty about OBS and streaming online, since it is a big +business now. You can find answers to most questions once you know +the basic theory.

  • +
+
+
+
+

Video editor

+

The video editor takes the raw recorded files from the broadcaster, +processes them, and uploads them to YouTube (or whatever).

+
+

Overall priorities

+
    +
  1. No learner (or anyone not staff) video, audio, names, etc. are +present in the recordings.

  2. +
  3. Good descriptions.

  4. +
  5. Removing breaks and other dead time.

  6. +
  7. Splitting videos into useful chunks (e.g. per-episode), perhaps +equal with the next one:

  8. +
  9. Good Table of Contents information so learners can jump to the +right spots (this also helps with “good description”.)

  10. +
+
+
+

Modern: livestream method

+

Modern livestream courses produce videos without any learners in +them. In this case, using +https://github.com/coderefinery/ffmpeg-editlist is sufficient. Look +at that repo for instructions. As an example, check out +https://github.com/AaltoSciComp/video-editlists-asc for some past +workshops. For example, kickstart-2022-winter.yaml is a +reasonable starting point to copy.

+

It’s our standard to have these videos on YouTube by the same evening +the course is held. It may be hard, but it’s better to reduce the +quality to make it happen quickly than wait a while to get it perfect +(otherwise it might not happen at all).

+
+
+

If the learner Zoom is recorded

+

If learners may be in the recordings, they need detailed checking +before they can be posted. See Video checking OLD for the +preparation work and Video editing OLD for the processing work.

+

In practice, if things are recorded this way, they are almost never +released because it is too much work and it never gets done.

+
+
+
+

Workshop organizers

+

Everyone can be part of the workshop organizing team. But we are mostly looking for help from the community for team leads, expert helpers and instructors. +If you want to help ‘in the background’, join the ´#workshops´ stream in the coderefinery Zulip chat and see what is planned. +There is a lot of roles to fill already before the actual workshop, as well as after:

+
+
+

Workshop requirements - in person

+

This checklist is for the pre-planning phase of in-person CodeRefinery +workshops: where you are deciding if you can host one and what room to +use. Let us know about the items on this list when you contact us.

+
+

Lecture room

+
    +
  • The room needs to be sufficiently large (a typical workshop is attended by +around 20 learners and 4 instructors).

  • +
  • There needs to be enough space for instructors to walk around and interact +with learners individually (a “flat” room is required).

  • +
  • Learners should face the same direction, and learners should be able to sit +side-by-side for pairwise work.

  • +
  • The room should preferably have windows, and be ventilated well enough so +that 20-30 people (and same amount of laptops) will not make it too warm.

  • +
  • A coffee room (or similar) should be located nearby for the coffee breaks.

  • +
  • Two overhead projectors are desirable, but if only one is available that will +work too.

  • +
  • The projector screen needs to be large, and the resolution of the projector +needs to be good.

  • +
  • Stable wireless connectivity for 20-30 people.

  • +
  • Sufficiently many electricity outlets so that all participants can charge +their laptops.

  • +
  • Standing board for instructor.

  • +
+
+
+

Helpers

+

CodeRefinery workshops are hands-on and interactive, and a lot of time is +spent on exercises where participants learn by doing. Participants +explore themselves, and that means they need guides to help them if +they get stuck.

+

We recommend that each site takes proactive steps to recruit at least +two helpers per workshop. We’ve noticed that helper diversity +promotes learning, so we recommend that organizers also make proactive +steps to have diverse helpers (male/female, international, etc.). +Local organizers should directly contact possible helpers and invite them.

+

Good candidates are people who have any of:

+
    +
  • have attended a previous CodeRefinery workshop

  • +
  • have a passion for teaching, scientific software development, open +source, open science, etc.

  • +
  • are research software engineers or hold a similar technical research position

  • +
  • have experience from teaching e.g. Software Carpentry workshops

  • +
  • want to experience CodeRefinery but already have a good idea of most basics

  • +
+
+
+

Other requirements

+

When we organize a workshop or event at a new site, we may need help with some local arrangements, +including:

+
    +
  • Booking a lecture room.

  • +
  • Ordering coffee and refreshments.

  • +
  • Advertise the workshop through local dissemination channels.

  • +
+
+
+

After the workshop

+

Would you like to become a helper, instructor, or partner +and make more workshops possible?

+
+
+
+

Organizing a CodeRefinery workshop

+

Anyone can organize a CodeRefinery workshop and teach the CodeRefinery lessons which are +licensed under CC-BY. +However, making it a successful workshop requires careful planning and preparation. Here we will go +through practical aspects of organizing a workshop.

+
+

Email templates

+

A collection of email templates:

+
+
+
Advertising workshop
+

Dear Professor X,

+

My name is NAME and I work as a XXX in YYY. I’m contacting you now to spread the word about a workshop which I am co-organizing in LOCATION together with the CodeRefinery project (http://coderefinery.org/) organized under the NeIC organization. I found your contact information via ZZZ…

+

CodeRefinery (http://coderefinery.org) aims to reach out to diverse academic communities which use and develop software in their research, and advocate more modern and efficient software development methods (such as collaborative distributed version control, automated testing, code documentation, managing code complexity, etc). CodeRefinery is not about efficient code, but rather efficient coding, and experience has shown that researchers have a lot to gain from our course material!

+

A CodeRefinery workshop is planned for LOCATION in CITY on DATE, see the website here: URL

+

The most natural audience for our workshops is PhD students and postdocs, but both more junior and senior people may find it valuable to attend.

+

On behalf of the CodeRefinery team, +NAME

+
+
+
Looking for helpers
+

This was part of a SNIC training newsletter. Saving it so that we can reuse +in future:

+
Engage as a tutor on the CodeRefinery online workshop, Nov 17-19 and 24-26,
+9:00-12:00
+
+Engage in the successful CodeRefinery workshop program, by becoming a tutor for
+the exercise sessions and discussion groups.  If you have been to a
+CodeRefinery workshop, you will have experienced  a very hands-on approach to
+training with frequent exercise sessions and group discussions.  In online
+workshops these sessions take place in breakout rooms with 5-7 participants and
+1-2 workshop tutors.  Tutors answer questions from the learners, guide them
+through the exercises and try to keep time.  If needed, tutors can call on
+experienced trainers in the background to help answer tricky questions.  The
+tutors are an important part of the CodeRefinery teaching concept and all the
+workshops to scale to many more people than the instructors could  otherwise
+manage!
+
+If you have previously attended a CodeRefinery workshop, and/or use some of the
+tools and methods covered in a workshop (Git, software testing, modern
+documentation platforms etc.), then please consider joining a CodeRefinery
+workshop as a tutor! Being a tutor is fun, it expands your network and develops
+your teaching and mentoring skills.  You always learn something new about a
+subject by teaching it!
+
+If you would like to help on the upcoming workshop in November, please sign up
+as a tutor on https://coderefinery.github.io/2020-11-17-online/.  If you would
+like to engage in later workshops, please register as a tutor on the notify-me
+form (https://indico.neic.no/event/135/surveys/36).
+
+
+
+
+
Notify-me announcement
+

Dear all,

+

You are receiving this email because you have previously signed up for the “notify-me” list to get updates +on upcoming online or in-person CodeRefinery workshops.

+

We now have the pleasure to announce that an [in-person/online] 3-day workshop will be held on LOCATION, on DATE. +Registration has just been opened, see the workshop webpage: +URL

+

If you want to attend, don’t wait too long to register since the number of seats is limited.

+

If you wish to unsubscribe from these announcements, please reply to this email.

+

Hope to see you there!

+

On behalf of the CodeRefinery team, +NAME

+
+
+
Post-workshop survey
+
+
First email
+
Subject:  [CodeRefinery] 5-minute post-workshop survey
+
+Dear CodeRefinery alumnus,
+
+We hope that you enjoyed participating in a CodeRefinery workshop last semester and that it was 
+beneficial for your work and research! We don’t keep an attendance list, so apologies to those 
+of you who couldn't make it to the workshop...
+
+Please help us to improve our course material and teaching methods by answering our very brief questionnaire at 
+https://indico.neic.no/event/109/
+about whether and how the CodeRefinery workshop affected how you develop code. 
+All information you provide will be useful. Your participation is extremely valuable 
+and will help us to develop the project further. The average time to fill the form is around 5 minutes.
+
+Would you be interested in being a helper or instructor in future workshops? It's a great way to continue 
+developing your skills and expanding your network! We're always interested in recruiting new helpers 
+and instructors. If this sounds interesting to you, please get in touch by writing to 
+support@coderefinery.org or join our chat: https://coderefinery.zulipchat.com
+
+On behalf of the CodeRefinery team,
+Thor 
+
+
+
+
+
Reminder 1 week after first email
+
Dear all,
+
+It's us, CodeRefinery, again. We just want to send this one reminder to kindly ask you to participate 
+in our 5-minute workshop-followup survey. To participate, please go to:  
+https://indico.neic.no/event/109/
+
+Sorry for spamming (particularly to those of you who already participated), this is the last 
+you'll hear from us regarding the survey!
+
+Cheers,
+Thor 
+
+
+
+
+
+
Practical info (online)
+

Dear all,

+

The online CodeRefinery workshop TITLE is approaching! It will take place on DATE at START - END in Zoom room ZOOMID. +On the first day, we also have an optional session starting half an hour before START where you can connect, +test your video client and iron out any technical issues (we recommend attending this if you haven’t used Zoom before).

+

If it turns out that you cannot attend, please let us know as soon as possible so that we can offer your seat to someone on the waiting list.

+

We will be using a Zoom room with ID ZOOMID. We recommend that you install the Zoom client (https://zoom.us/download). +In order to join the room you will need the password ZOOMPASSWORD. +You will be encouraged (but not forced) to use a webcam during the workshop. +If you don’t want the physical room you’re in to be visible on the webcam, Zoom allows users to set up a virtual background: +https://support.zoom.us/hc/en-us/articles/210707503-Virtual-Background +You might also be asked to share your screen during group exercises or in interactions with a workshop helper. +Remember to keep private information away from the screen you share!

+

You are expected to install some software on your computers before the workshop starts. +Please visit the workshop webpage WORKSHOPURL and go through each tool under “Software requirements”, +and install whatever you’re missing before the workshop starts. Note that you also need to create some accounts. +Note that each of these tools/accounts can easily be removed/deactivated after the workshop, if you so wish (see https://coderefinery.github.io/installation/accounts/).

+

Don’t hesitate to get in touch (support@coderefinery.org) if you run into any installation problems or have questions relating +to Zoom or other practical details. Note that we maintain a list of common installation issues that can occur at https://coderefinery.github.io/installation/troubleshooting/

+

If you haven’t already filled the pre-workshop survey, please do that soon since it helps us with workshop preparation. +You can find it at: SURVEYURL.

+

The workshop will be very focused on version control with Git. Some of you are already familiar with Git, but not all. +While we will be starting from the basics, we will be progressing quickly so it’s useful if you spend a few minutes to read up on the basic idea of Git. +For this purpose, we have prepared this “refresher” material: https://coderefinery.github.io/git-refresher/ +Note that this material also contains important Git configuration steps which all of you should go through before the workshop starts, to save valuable time during the workshop.

+

CodeRefinery strives to follow a Code of Conduct. Please have a look at +https://coderefinery.org/about/code-of-conduct/ so that we all are aware of how to treat each other respectfully.

+

Don’t hesitate to get in touch if you have any questions!

+

Best, +MYNAME

+
+
+
Practical info, in-person
+

Dear all,

+

The CodeRefinery CITY workshop on DATE is approaching! The location and schedule +is available on the workshop webpage: URL

+

If it turns out that you cannot attend, please let us know as soon as possible +so that we can offer your seat to someone on the waiting list.

+

You are expected to install some software on your laptops before the workshop +starts. Please visit the workshop webpage (URL) and go through each tool under +“Software requirements”, and install whatever you’re missing before the workshop +starts. Note that you also need a couple of accounts (GitHub and Read the Docs). +Note that each of these tools/accounts can easily be removed/deactivated after +the workshop, if you so wish (see https://coderefinery.github.io/installation/accounts/).

+

Don’t hesitate to get in touch (support@coderefinery.org) if you run into any +installation problems. We also maintain a list of common installation issues +that can occur at https://coderefinery.github.io/installation/troubleshooting/

+

If you haven’t already filled the pre-workshop survey, please do that soon since +it helps us with workshop preparation. You can find it at: URL

+

The workshop will have a strong focus on version control with Git. Some of you +are already somewhat familiar with Git, but not all. While we will be starting +from the basics, we will be progressing quickly so it’s useful if you spend +10-20 minutes to read up on the basic idea of Git. For this purpose, we have +prepared this “refresher” material: +https://coderefinery.github.io/git-refresher/

+

Please have a look at this material before the workshop starts. Note that it +also contains important Git configuration steps which all of you should go +through before the workshop starts, to save valuable time during the workshop.

+

CodeRefinery strives to follow a Code of Conduct. Please have a look at +https://coderefinery.org/about/code-of-conduct/ so that +we all are aware of how to treat each other respectfully.

+

Don’t hesitate to get in touch if you have any questions!

+

Best, +Thor

+
+
+
Waiting list
+

Dear NNN,

+

thank you for request about the course:

+

https://coderefinery.org/workshops/COURSE_HERE/ +The workshop is currently full but you are placed on the waiting list and I will inform you in case somebody else cancels and a seat frees up.

+

In case this is too uncertain for you and you make other plans, please let me know.

+

If you want to make sure to get a seat on the next workshop near you, please register on the “notify-me” list: https://coderefinery.org/workshops/upcoming/

+

We would love to give more courses and hope it works out for you.

+

Thank you in advance and best wishes, +CCCC

+
+
+

When adding new ones, add to an existing page (make a new section) +or. Try to avoid too much markdown formatting, so that a rendered +version can be copied to plain text email easily still.

+
+
+

Select a workshop coordinator

+

One or two persons coordinate the workshop preparation and debrief. This does +not mean that they do all the work - they are encouraged to delegate tasks - +but they make sure that nothing gets forgotten.

+
+
+

Other documents and references

+ +
+
+

Before the workshop

+
+
First steps
+ +
+
+
Lecture room
+
    +
  • Start looking for an appropriate lecture room early.

  • +
  • See this list of requirements for +the lecture room.

  • +
+
+
+
Set up workshop page
+
    +
  • Import the template at https://github.com/coderefinery/template-workshop-webpage to your username +or the coderefinery organization, and name it like “2019-10-16-somecity”.

  • +
  • Update the required fields in index.md and push the commits. +The page should now be served at username.github.io/2019-10-16-somecity/.

  • +
  • If the workshop will be customized to the needs of a particular audience, modify the schedule accordingly.

  • +
  • If the workshop should be listed on https://coderefinery.org:

    +
      +
    • (Fork and) clone https://github.com/coderefinery/coderefinery.org

    • +
    • Under coderefinery.org/_workshops/, add a file named like 2019-10-16-somecity.md which contains +the fields permalink, city and dates. For example:

      +
      ---
      +permalink: https://username.github.io/2019-10-16-city/
      +city: Somecity
      +dates: October 16-18, 2019
      +---
      +
      +
      +
    • +
    • send a pull request with your new file.

    • +
    +
  • +
  • Create a registration form following Indico event setup.

  • +
  • Open and test registration

  • +
+
+
+
Announcing the workshop
+
    +
  • Twitter

  • +
  • Email persons who registered to notify-me form

  • +
  • Use local mailing lists and all channels possible

  • +
+

For self-organized workshops:

+
    +
  • Write an email to support@coderefinery.org to get a pre-workshop survey link and registration form on +https://indico.neic.no

  • +
+
+
+
Distribute the work
+
    +
  • Make sure lessons are distributed

  • +
+
+
+
Preparing lessons
+
    +
  • Go through the lesson material you will be teaching and think about how you +intend to teach it, and how much time you will be spending on each episode.

  • +
  • Are there any unsolved issues that you can fix?

  • +
  • Go through the instructor guides of the lessons you will be teaching.

    +
      +
    • Review the intended learning outcomes, and try to keep these in mind while teaching.

    • +
    • Try to memorize the typical pitfalls and common questions.

    • +
    +
  • +
  • Go through the lesson presentation hints.

  • +
  • Go through the helping and teaching guide, +and request all helpers to go through it too.

  • +
+
+
+
Prepare practicals
+
    +
  • Order catering (coffee, tea, water, fruit, something sweet, etc.)

  • +
  • Organize sticky notes

  • +
  • Organize extension cables if needed

  • +
  • Organize alternative wireless for those without Eduroam (if any)

  • +
+
+
+
Communication with participants
+
    +
  • Send out practical information, including installation instructions, around 2 weeks ahead. +Here is a template.

  • +
  • Emphasize that all software should be installed before the workshop starts, and point out +the configuration problems and solutions.

  • +
  • Remind registered participants that they are either expected to show up or to cancel participation

  • +
  • Also ask those without Eduroam to speak up.

  • +
  • Maintain waiting list if needed

  • +
  • Make sure we have enough pre-survey answers

  • +
  • Close registration on the workshop page

  • +
+
+
+
1-2 weeks before the workshop
+
    +
  • Workshop coordinator organizes a call with all instructors and helpers to discuss the schedule to leave no doubts about timing. Also +discuss the survey results.

  • +
  • Point helpers (and instructors) to the tips for helpers.

  • +
+
+
+
Right before the workshop starts
+
    +
  • Prepare a shared Google doc or https://hackmd.io with global write permissions, +consider creating a memorable short-link (e.g. bit.ly)

  • +
+
+
+
+

Create exercise repositories

+
    +
  • The collaborative Git lesson requires exercise repositories to +be set up. For this follow the instructor guide in the lesson material.

  • +
+
+
+

Workshop preparation checklist

+
    +
  • This checklist can be set up as an issue under +https://github.com/coderefinery/coderefinery.org/ or on another +repository to keep track of the progress

    +
    - [ ] reserve dates
    +- [ ] decide workshop organizer
    +- [ ] (online) prepare Zoom link or (in-person) book lecture room
    +- [ ] announce (twitter, notify-me, mailing lists)
    +- [ ] team of instructors complete
    +- [ ] workshop website up
    +- [ ] lessons distributed
    +- [ ] prepare lessons
    +- [ ] create exercise repositories
    +- [ ] (in-person) prepare practicals (coffee/tea, sticky notes, extension cacles)
    +- [ ] (online) Zoom roles distributed
    +- [ ] registration open
    +- [ ] team of helpers complete
    +- [ ] registration closed
    +- [ ] enough pre-survey answers
    +- [ ] install instructions sent
    +- [ ] pre-workshop briefing held, helper training
    +- [ ] survey results shared with co-instructors/helpers
    +
    +
    +
  • +
+
+
+

As participants arrive

+
    +
  • Emphasize to participants that you need to sit with someone - don’t work alone.

  • +
  • Try to have participants sit next to someone with a similar operating +system if they have no preference, since they will face similar +problems.

  • +
+
+
+

Introduction talk

+
    +
  • See https://github.com/coderefinery/workshop-intro

  • +
  • Have a 10 minute ice-breaker session where participants and instructors introduce themselves +and either describe their research in 2-3 sentences or what they hope to get out of the workshop.

  • +
+
+
+

During workshop

+
    +
  • While teaching, keep these tips in mind

  • +
  • Don’t start off with tech details, say why this is important.

  • +
  • Try to stick to the material, +although some excursions are useful.

  • +
  • Keep up interactive feel by encouraging and asking questions

  • +
  • Keep time

  • +
  • For presentations which have shell commands, create a +cheatsheet/reference on the board in real time.

  • +
  • Remind participants about sticky notes.

  • +
  • Make sure we take regular breaks (at least a short break each hour)

  • +
  • Give participants some time to also experiment (do not rush the classroom through exercises)

  • +
  • Encourage optional feedback at the end of each day or end of each lesson +on sticky notes. Process the feedback immediately and adjust your teaching +(pace etc) accordingly

  • +
  • Create GitHub issues for points which are confusing or problematic

  • +
  • Take active part even in the lessons you’re not teaching, e.g. by asking +questions and (politely) interject with clarifications when you think +something is confusing to the learners

  • +
  • Wrap up, +say what you taught and why, and what comes next.

  • +
+
+
+

At the end of workshop

+ +
+
+

Post-workshop

+
    +
  • Process and distribute feedback to co-instructors and others (e.g. type up in shared document)

  • +
  • Debrief with instructors

  • +
  • Process certificate requests

  • +
+
+
+

Post-workshop survey

+

To measure the long-term impact of CodeRefinery workshops it’s useful to send out a +post-workshop survey. This survey can identify which topics taught in workshops are +particularly useful and which have less benefits for the participants.

+
+
+
+

Indico registration system

+

This describes the Indico registration system as used by +CodeRefinery. Indico is a open-source registration system suitable for large +scientific meetings. NeIC runs one at https://indico.neic.no which we +routinely use.

+
+
+

Indico event setup

+

We use the NeIC Indico service, https://indico.neic.no/, so you need to create +an account at https://indico.neic.no/login/.

+

Radovan is manager of the CodeRefinery category in +indico.neic.no and will need to grant you permissions to create event pages.

+

To create a new workshop page, it is easiest to clone a previous event. This +copies the registration form and metadata, but not the pre-workshop survey +which needs to be manually imported as a json file.

+
+
Step-by-step instructions:
+
+
Copy basics from latest event
+
    +
  • Visit https://indico.neic.no/, and click CodeRefinery which takes you to https://indico.neic.no/category/5/.

  • +
  • Click the latest workshop event. You might need to show “events in the future” to see the latest event.

  • +
  • Go to admin mode (click the pen symbol on top toolbar, “Switch to the management area of this event”).

  • +
  • Click the “Clone” button, and select “Clone Once”. Click “Next” button.

  • +
  • For “What should be cloned”, select +“Registration forms” (do not clone “ACLs and protection settings”). +Uncheck “Refresh user information”. Click “Next”.

  • +
  • Confirm category “CodeRefinery”, and click “Next”.

  • +
  • Select the start date and time of the workshop, click “Clone”.

  • +
  • You are now on the cloned event page (confirm that the event number changed), and you should start updating the information.

  • +
+
+
+
Update copied event information
+
    +
  • Adjust permissions so that only the workshop organizer(s)/coordinator(s) has/have access to the forms and data. +In order to have better control over who has access we do not copy “ACLs and protection settings” from older events.

  • +
  • Update the Title, Description, Date, Time, Room, Venue and Address fields by clicking the pen symbols on the right.

  • +
  • Click “Protection” and remove administrators who were copied from past event but should not have access to this event.

  • +
  • Click “Registration” from the left-hand menu, and confirm that there is one or two registration forms, probably with a wrong title.

  • +
  • Click the “Manage” button on the “List of registration forms”,

    +
      +
    • Click “Edit” on the “General settings”

    • +
    • Update the registration form name and both the fields “Contact info” and “List of recipients” with your own email address to get notifications on new registrations.

    • +
    • Waiting list:

    • +
    • Indico doesn’t have an actual waiting list functionality. To implement a waiting list, we use moderated registrations and confirm all registrations up to max capacity (eg. 40). Registrations after that up to maximum number of participants (eg. 60) are left unconfirmed and an email is sent manually from Indico to the registrant that they are on the waiting list. Now we have a waiting list of size 60 - 40 = 20.

    • +
    • Activate “Moderated” which will require each registration to be approved.

    • +
    • Set maximum number of participants (after which registration is closed), this should be room capacity + waiting list size. Click “Save”.

    • +
    • Then go back to “Manage” and verify and configure the “Registration Form”: +read all fields and check that nothing outdated has been cloned to this +event. Adapt the dates.

    • +
    +
  • +
+
+More information about the registration process +
    +
  • The Description field in the general settings should contain additional information about the registration process:

    +
    Welcome to the registration page for the Online CodeRefinery workshop March 22-24 and 29-31!
    +
    +To complete your registration, you need to:
    +
    +1) Enter your registration details by clicking the "Register now" button below.
    +2) Fill in the pre-workshop survey by clicking the "Fill out the survey" button below.
    +
    +Confirmation email
    +After filling out the registration form you will receive an automatic
    +confirmation email, but please note that all registrations go to a waiting
    +list first. Please contact to support@coderefinery.org if you don't receive
    +this confirmation email within a couple of days after signing-up. 
    +
    +Questions?
    +If you have any questions about your registration status, please write to support@coderefinery.org.
    +
    +Looking forward to seeing you at the workshop!
    +
    +
    +
  • +
+
+
+
+
Import survey
+
    +
  • Now click “Surveys” from the left hand menu. You will now import the standard pre-workshop survey from a json file.

  • +
  • Go to https://github.com/coderefinery/pre-workshop-survey and clone the repository.

  • +
  • Go back to the Indico Surveys page, and click “Create survey”

  • +
  • Name the survey “Pre-workshop survey”, enable the option “Anonymous submissions” and disable “Only logged-in users”. Click “Save”.

  • +
  • Back on the “Surveys” page, click “Manage” on the newly created “Pre-workshop-survey” survey.

  • +
  • It will say “Survey not ready”. Click “Prepare questionnaire”.

  • +
  • Click the “Import” button, click “Choose from your computer”, and find the file exported-survey.json” from the pre-workshop-survey repository you cloned. Click “Save”.

  • +
  • Go back to the survey page (click “Surveys” on the left), and click “Manage”. Click the “Open now” button to let the survey go live.

  • +
+
+
+
Open registration
+
    +
  • Go to the Registration page from the left-hand menu, and click “Manage”.

  • +
  • It will say “Registrations are not open yet”. Click “Start now” for both regular and staff registration forms to open for registrations.

  • +
  • Click the blue “Switch to display view” on the top left.

  • +
  • Confirm that both the “Surveys” and “Registration” links can be seen.

  • +
  • Click both links to do a test registration

  • +
  • Once you manage to test-register, update the workshop webpage, and announce via Twitter.

  • +
+
+
+
Exporting registrations
+
    +
  • Go to the Registration page from the left-hand menu, and click “Registrations” which +takes you to the list of registrations..

  • +
  • Click the check-box on the menu just above the list of registrations and select “All”.

  • +
  • Click on “Export” from the top menu, select “CSV” and choose a download directory.

  • +
  • You can use the read_csv.py to parse the CSV file and print +selected fields, e.g. email addresses to be used in sending out information to +participants.

  • +
+
+
+
+
+

Indico in-person workshop workflow

+
+
Flow
+
    +
  • People register

  • +
  • Confirm the people you want to accept.

  • +
+

TODO: Is there anything else to note?

+
+
+
+

Indico online workshop workflow

+

This describes the workflow in Indico online workshops

+
+
Basic types
+

Registration types = {Learner, team leader, Livestream only}

+
+
+
Flow
+
    +
  • People may register in any of the types.

  • +
  • When people get accepted to Type={Learner,team leader}, they are +confirmed using the Indico moderation “approve registrations” +feature. (These people then become State=Completed)

  • +
  • After soft deadline, accept the number of learners you think you can +handle (see above).

    +
      +
    • Non-accepted people are moved to Type=Livestream but this is +mainly to help them, people can still register.

    • +
    +
  • +
  • A new field “I confirm I can attend via Zoom” is made visible. +Everyone in State=Completed is expected to log in and click this +box.

    +
      +
    • Other non-accepted people

    • +
    +
  • +
  • Those who do not make Confirm=Yes are moved to Type=Livestream.

    +
      +
    • Note: any saving of the form, even by staff, will set +Confirm=No. So Confirm=No does not mean that they declined, +it could also be staff who saved the form.

    • +
    +
  • +
  • If there are remaining free spots, they are given to those who are +Type=Livestream Confirm=Yes.

  • +
  • Everyone else is set to Type=Livestream

  • +
  • The event registration form is edited, so that the number of +Type=Learner spots is set to the actual number registered. Then, +no one else can register as a learner.

    +
      +
    • This could be done a bit earlier in the process, but it prevents +even organizers from moving people between categories. Thus, it’s +slightly more convenient to leave it free than have to adjust the +registration form every time you need to switch someone to learner +(for example, registering on a team)

    • +
    +
  • +
+
+
+
Email filters
+

During registration

+
    +
  • People who want to in Zoom, State!=Withdrawn Type={Learner,Exercise Leader}

  • +
+

After confirmation

+
    +
  • People in Zoom, State!=Withdrawn Type={Learner,team leader}

  • +
  • PEople in livestream, State!=Withdrawn Type=Livestream

  • +
+
+
+
+

Indico hints

+
+
Emailing people
+
    +
  • Go to registration list

  • +
  • Filter people based on who you need

  • +
  • Select all (this selects only the visible people; you can confirm +this by looking at the names in the email box, though you can’t see +them all our count them)

  • +
  • Actions → Email

  • +
  • Compose your email (warning: it is easy to lose everything, there is +no saving)

  • +
  • Preview email to make sure it works

  • +
  • Ensure that it is sent from support@coderefinery.org

    +
      +
    • If you want a real test, you could register and send the first +draft to yourself (make sure you copy the full text first, +otherwise you lose the placeholders)

    • +
    +
  • +
  • Copy full text before you send the email, otherwise you lose the +form fields.

  • +
  • Click send

  • +
  • Don’t worry

  • +
+
+
+
+
+
+

Icebreakers

+

This is a list of possible icebreaker questions.

+

You should make it very clear that everyone should answer the +question, and thus it should be very broad. The point is to make sure +they know how to use the tools. Make sure that the question feels +inclusive - not just that people can answer, but that it doesn’t make +people feel they are far behind others.

+

If you ask people to add there name as part of an introduction, the +document becomes personal data and must be controlled more, and sets +you on a path to extensive editing before it can be released. Think +before you do this - maybe you just ask for information about +backgrounds without names.

+ +
+

Relevant to workshop

+

An icebreaker isn’t supposed to be relevant to the workshop, but it +could be useful some days or as a second question.

+
    +
  • What from this workshop are you going to use in the near future?

  • +
  • What was the most confusing thing from yesterday?

  • +
  • Have you already used what you have learned in the course during +your work? If so, what?

  • +
  • What is the most useful thing you know, that you wish someone had +just told you about computing when you first started it?

  • +
+
+
Adapted from pre-workshop survey
+
    +
  • What is the operating system that you will use during the course (on your laptop)?

    +
      +
    • macOS

    • +
    • Linux

    • +
    • Windows

    • +
    • Other

    • +
    +
  • +
  • Have you used version control? If yes, which?

    +
      +
    • I don’t know what it is

    • +
    • I haven’t used version control but I know what it is

    • +
    • I have used version control, but I don’t know which system

    • +
    • Git

    • +
    • Mercurial

    • +
    • Subversion

    • +
    • CVS

    • +
    • Perforce

    • +
    • Bazaar

    • +
    • Other

    • +
    +
  • +
  • Which programming languages are you using or will you use in your projects?

    +
      +
    • Matlab

    • +
    • R

    • +
    • Python

    • +
    • Perl

    • +
    • C

    • +
    • C++

    • +
    • Fortran 77

    • +
    • Fortran 90+

    • +
    • Julia

    • +
    • Haskell

    • +
    • Go

    • +
    • Rust

    • +
    • Other

    • +
    +
  • +
  • Are you using automated testing platforms (e.g. Travis CI, Jenkins or GitLab CI) in your programming project(s)?

    +
      +
    • No and I don’t know what it is

    • +
    • No but I know what it is

    • +
    • Yes

    • +
    +
  • +
  • Are you employing code review in your programming project(s)?

    +
      +
    • No and I don’t know what it is

    • +
    • No but I know what it is

    • +
    • Yes

    • +
    +
  • +
  • Are you using the Jupyter Notebooks in your programming project(s)?

    +
      +
    • No and I don’t know what it is

    • +
    • No but I know what it is

    • +
    • Yes

    • +
    +
  • +
  • Are you using a web-based repository for your code(s)? Which ones?

    +
      +
    • I’m not using a web-based repository

    • +
    • GitHub

    • +
    • GitLab

    • +
    • Bitbucket

    • +
    • Redmine

    • +
    • source.coderefinery.org

    • +
    • Other

    • +
    +
  • +
  • How would you describe your programming experience?

    +
      +
    • I have no programming experience

    • +
    • Basic understanding and experience, I have looked through code and made minor adjustments

    • +
    • I have written my own simple programs

    • +
    • I have written many small codes and/or contributed to large complex software

    • +
    • I am an expert

    • +
    +
  • +
  • How comfortable are you with the Unix/Linux command line working in a terminal window?

    +
      +
    • I know what most of the following commands do: cd, ls, cat, mv, rm, chmod, man, mkdir, cp, ssh

    • +
    • I do not know what most of these commands do

    • +
    +
  • +
  • Please mark the sessions that you are most interested in.

    +
      +
    • Introduction to version control

    • +
    • Documentation

    • +
    • Jupyter notebooks

    • +
    • Collaborative distributed version control

    • +
    • Managing complexity and modular code development

    • +
    • Automated testing

    • +
    • Git branch design

    • +
    • Software licensing

    • +
    • Reproducible research

    • +
    +
  • +
+
+
+
+

General questions

+
    +
  • What’s a good icebreaker question?

  • +
  • How is the weather where you live?

  • +
  • How are you doing?

  • +
  • Are you happy to continue this workshop for another week?

  • +
  • Is that an Iphone?

  • +
  • If you could have anything what you want for dinner today, what would it be?

  • +
  • What cool thing/tool have you discovered/learned the past days? +(independently of this course)

  • +
  • Is this course part of your work? Or do you spend free time on it?

  • +
  • Do you like olives?

  • +
  • Are you annoyed at the size of anaconda?

  • +
  • What’s your favourite pizza?

  • +
  • Do pineapples :pineaplle: belong on pizza?

  • +
  • What did you have for breakfast?

  • +
  • Do you like Python?

  • +
  • Where’s your favorite place to nap?

  • +
  • Do you use git or identify as one?

  • +
  • When and how did you learn to program?

  • +
+
+
+

Credits

+

Most of these questions came from a “What is an icebreaker” question +in the first Mega-CodeRefinery workshop.

+
+
+
+

Video checking OLD

+
+

Note

+

This is old information, these days we use ffmpeg-editlist and ensure +that no learners are in the videos in the first place.

+
+
+

See also

+

Video editing OLD tells how to edit yourself. This page +describes how to check a video for processing.

+
+

The purpose of this page is to give video processing volunteers a +starting point. CodeRefinery produces a lot of videos, and learner +privacy is important: we can’t post videos until they are checked. +These videos are mainly useful to the learners of the very workshop, +so we need them quickly (and for every workshop).

+
+

Overview

+
    +
  • Ask for the directory of videos. It is on Google Drive or something +similar, but is not public.

  • +
  • Look at the tracking issue. Find a unclaimed section of the course.

  • +
  • Watch the video.

    +
      +
    • Carefully look for any appearances of learner video within the +video.

    • +
    +
  • +
  • Copy the template below.

  • +
  • Fill out the template.

  • +
  • Paste the answers into an issue.

  • +
+
+
+

Segment report

+

Template:

+
* [ ] Title:
+* Filename:
+* Start:
+* End:
+* Segments to cut:
+* Audience visible:
+Other notes for channel description:
+
+
+

Example:

+
* Title: git-intro basics
+* Filename: day1-obs
+* Start: 25:13
+* End: 45:00
+* Segments to cut: 36:12 - 42:10
+* Audience visible:  none
+
+Other notes for channel description:
+
+In this first episode, we go over the basics of using git for a single
+local directory.
+https://coderefinery.github.io/git-intro/02-basics/
+
+
+

Why do we ask all this? It saves time for the person who has to +upload it to YouTube.

+
    +
  • Title: what would it be called? You don’t need to include the +workshop name, someone will add it.

  • +
  • Filename: you don’t need the full filename but indicate what +file you were searching (often we have a recording and backup +recording for each day)

  • +
  • Start, end: start time of the segment

  • +
  • Segments to cut: Segments which should be cut out. Don’t be +strict, it is better to get it out fast than cut out every 3-minute +break. But if there is a ~10 minute break or idle time, then we can +cut it.

  • +
  • Audience visible: Time periods where any audience (not including +staff).

  • +
  • Other notes for channel description: Describe the content of the +video, include any links. You can think what is useful for someone +to find this (but it doesn’t have to be perfect).

  • +
+
+
+

Other comments

+
    +
  • How small should segments be? First, it’s better for videos to exist +than be perfect, so the 3-hour segment is better than nothing. Short +lessons (1.5 hour) are probably fine to be at once, and long ones (git +intro/collab) could possibly be each episode separately. Discuss with +others to see what you would like.

  • +
  • Ideally, there are two videos from each day: one recorded by Twitch +(raw dump of the stream), and one recorded by OBS/Zoom (local +recording). The OBS/Zoom recording is preferable. You can tell +them apart via the filenames.

  • +
+
+
+
+

Video editing OLD

+
+

Note

+

This is old information, these days we use ffmpeg-editlist and ensure +that no learners are in the videos in the first place.

+
+
+

See also

+

Video checking OLD for how to check a video and give an +edit-list to someone else to do the editing.

+
+

The purpose of this page is to give video processing volunteers a +starting point. (It also has some hints for workshop organizers).

+

For some of our online lessons, we release videos on YouTube. This is +not necessarily for brand new people to watch and learn the material +(though they may), but especially for people who attended the workshop +to review what they saw. As such, it’s more important to get them +published fast, than make them perfect.

+
+

What we want

+

Our workshops consist of lectures, demo, and exercises in breakout +rooms. We record the main Zoom room, and also livestream the main +room via Twitch. We would like the video of the workshop to be +processed so that it can be released on YouTube. This should not be a +major production: it is more useful to those who want to review what +they saw in person, rather than a new person watching.

+

We will provide the following:

+
    +
  • Raw video files (probably two copies one recorded from Zoom and one +from Twitch - so there is a backup.)

  • +
  • List of lessons (= final videos) and which raw files contain them +and when.

  • +
  • List of instructors

  • +
+

We want out:

+
    +
  • One processed video file per lesson.

  • +
  • With irrelevant breaks removed.

  • +
  • Without any video from learners. We use Zoom so that learners +should not appear in the stream, but we can’t be sure it works so +this needs to be checked.

  • +
+

The rough process is:

+
    +
  • Load up the right video files in the editor.

  • +
  • Find the start of the lesson (hint: look for a change of +instructor - ask us if you need help!) and cut off the stuff before.

  • +
  • Watch through the videos. Most of the lecture parts are fairly +standard and can be fast-forwarded through (it’s rare for a +learner’s picture to appear here).

  • +
  • Cut out the idle time during breaks.

  • +
  • In exercise sessions, learners go to breakout rooms, which are not +recorded. This part can be cut out, but sometimes the instructor +stays in the main room to do the exercises for the stream.

  • +
  • Don’t be too precise. We aren’t trying to make a masterpiece to end +all masterpieces, but a something for those who were at the workshop +to refer back to. So:

    +
      +
    • Imprecise start/stop/break times are fine

    • +
    • Other random off-topic chat is fine

    • +
    • Voices of learners is fine and expected

    • +
    • Video of learners is not ok (really, this is the only +thing that needs care).

    • +
    +
  • +
+
+
+

Before/during/immediately after the workshop

+
    +
  • From day 1, advertise that “the workshop may be recorded and put on +YouTube. We will prevent any pictures and names from going there, +but your voice may be. Please don’t include your name in hackmd +unless you accept it may be published. We support your right to be +anonymous in this workshop.”

  • +
  • Same announcement at the start of the workshop.

  • +
  • Record in zoom. Note: when you start the recording, make sure that +someone is currently sharing the screen, and the screen is a good +size (e.g. normal Full HD, as opposed to some vertical shape). The +dimensions when the sharing first starts determines the dimensions +for the entire course.

  • +
  • Immediately after workshop, go to Twitch and download the raw +streamed version. You have to be logged in as the channel, then the +option is naturally provided to you.

  • +
  • Choose some standard, shared place and immediately upload videos +there. Recommended naming scheme:

    +
    day1-topic1-topic2-zoom.mp4
    +day1-topic1-topic2-twitch.mp4
    +
    +
    +
  • +
+
+
+

Processing

+

Processing principles:

+
    +
  • Remove any participant videos, if they accidentally make it into +the video file. This is really the only serious rule in the +processing, if we didn’t have to check this we could just upload the +raw ones and it would be good enough.

  • +
  • Create one final video per lesson in the workshop

  • +
  • Work incrementally, upload processed ones when you can, get quick +feedback.

  • +
+

If it’s not clear, the course organizers will provide a list of the +lessons (final outputs) and the respective inputs (which source files +go into it).

+

You can generally:

+
    +
  • Use some video editor

    +
      +
    • iMovie on Mac

    • +
    • OpenShot is a simple cross-platform editor (tutorial)

    • +
    • (please give more ideas here)

    • +
    +
  • +
  • (so far, this is not a general “how to edit video” guide… you will +need to find one for your editing program)

  • +
  • Create a new project for the output (e.g. the Jupyter lesson)

  • +
  • Import the raw video files which contain Jupyter (e.g. day 4). If +one lesson is split over multiple files, combine them.

  • +
  • Cut off the part before and after the lesson itself (saving +frequently). You’ll have to figure out the start and end times, +this may be hard when there are several files.

  • +
  • Begin watching the lesson. Look for the following things:

    +
      +
    • Break time? Exercise session with irrelevant stuff in the video? +Cut the time out.

    • +
    • Any non-instructors pictures in the stream? Cut it out. +Sometimes you might need to blank the picture while

    • +
    • Don’t be too perfectionist - the goal is to get something done, +not maek the perfect videos.

    • +
    +
  • +
  • Export the videos with a high quality, e.g. jupyter.mp4. It +will go to YouTube which will render lower resolutions, so you don’t +need to worry about this so much.

  • +
  • Upload the videos to the processed subdirectory of the google +drive. Do this immediately, video by video. It’s better to get +continuous feedback on this. You are done!

  • +
+
+
+

Publication

+

We upload them to YouTube (not that we agree with all the ethics of +YouTube, but it seems like the least bad and most useful of the +options).

+
    +
  • Preview the processed videos, do a quick check for any issues.

  • +
  • Upload to the channel. For one workshop, put all related videos +into a playlist. CC-BY license.

  • +
  • This is a prototype channel description you can copy:

    +
    git-intro 1/2, CodeRefinery 25.may-4.jun 2020 day 1
    +
    +Day 1: git-intro: LINK-TO-LESSON
    +
    +Part of a series of video recordings of the CodeRefinery workshop,
    +25.may-4.june.  CodeRefinery teaches intermediate software
    +development skills to researchers in the Nordics.
    +
    +Workshop page: LINK-TO-WORKSHOP
    +Q&A for day 1: LINK-TO-HACKMD
    +
    +(table of contents below)
    +
    +
    +
  • +
  • Create a table of contents (can be done later, after uploading). +This divides the videos into chapters, with clickable links in the +description and labels in the video’s time slider. In the bottom of +the description, put this text and it is automatically parsed:

    +
    00:15 Introduction
    +02:30 Motivation - https://coderefinery.github.io/git-intro/01-motivation/
    +17:17 Basics - https://coderefinery.github.io/git-intro/02-basics/
    +38:29 Staging - https://coderefinery.github.io/git-intro/04-staging-area/
    +...
    +
    +
    +

    You may want to ask someone for help with this, since it can take +some time to go through the videos.

    +

    Example with table of contents: https://youtu.be/r1tF2x5OLNA

    +
  • +
+
+
+
+
+
+

Workshop checklist template

+

This page is a checklist that we use when planning a CodeRefinery workshop +with 300 or more participants but may be useful in organizing other workshops as well.

+

Let’s keep this brief and copy-paste-able to HackMD/HedgeDoc for the actual planning.

+
+
+
+

CodeRefinery workshop YYYY-MM-DD

+

[toc]

+ +
+

Workshop roles

+
    +
  • Overview of the roles: https://coderefinery.github.io/manuals/roles-overview/

  • +
+

If you want to take part, add your name here, sign up in Indico and select “I +am interest in being a helper, co-instructor, or observer”, and you will be +contacted.

+
+

Instructors

+

(Description)

+

Two names per lesson, first is primary

+
    +
  • [ ] day 1 - git-intro: ???, ???

  • +
  • [ ] day 2 - git-intro: ???, ???

  • +
  • [ ] day 3 - git-collabiorative: ???, ???

  • +
  • [ ] day 4 - reproducible research: ???, ???

  • +
  • [ ] day 4 - social coding: ???, ???

  • +
  • [ ] day 5 - jupyter: ???, ???

  • +
  • [ ] day 5 - documentation: ???, ???

  • +
  • [ ] day 6 - testing: ???, ???

  • +
  • [ ] day 6 - modular code development: ???, ???

  • +
+
+
+

Expert helpers

+

(description)

+

If a central Zoom exercise room is provided: Help in our learner zoom, circle +around breakout rooms; there will probably be 2 or 3 rooms where we need to +provide the helper. Else: Help answering questions in Collaborative Q&A +document.

+
    +
  • [ ] day 1 - git-intro: ???, ???, …

  • +
  • [ ] day 2 - git-intro: ???, ???, …

  • +
  • [ ] day 3 - git-collab: ???, ???, …

  • +
  • [ ] day 4 - reproducible research: ???, ???, …

  • +
  • [ ] day 4 - social coding: ???, ???, …

  • +
  • [ ] day 5 - jupyter: ???, ???, …

  • +
  • [ ] day 5 - documentation: ???, ???, …

  • +
  • [ ] day 6 - testing: ???, ???, …

  • +
  • [ ] day 6 - modular code development: ???, ???, …

  • +
+
+
+

Managing collaborative document

+

(description)

+

Keep the document organized, check for unanswered questions, and archive notes each day.

+
    +
  • [ ] preparation before workshop:

  • +
  • [ ] day 1 - git-intro: ???, ???, …

  • +
  • [ ] day 2 - git-intro: ???, ???, …

  • +
  • [ ] day 3 - git-collab: ???, ???, …

  • +
  • [ ] day 4 - reproducible research: ???, ???, …

  • +
  • [ ] day 4 - social coding: ???, ???, …

  • +
  • [ ] day 5 - jupyter: ???, ???, …

  • +
  • [ ] day 5 - documentation: ???, ???, …

  • +
  • [ ] day 6 - testing: ???, ???, …

  • +
  • [ ] day 6 - modular code development: ???, ???, …

  • +
+
+
+
+

Workshop organization; roles “behind the scenes”

+

Organiser roles and their responsibilities. This does not mean that a person will do +everything that is part of their responsibility, but they will make sure that +their responsibilities are followed-up and not forgotten.

+
+

Event director

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • Before workshop

    +
      +
    • [ ] Create planning document by copying this template

    • +
    • [ ] Distribute roles using this document

      +
        +
      • [ ] Ask collaborators/stakeholders to pick roles

      • +
      +
    • +
    • [ ] Add all sessions to CodeRefinery calendar separately

    • +
    • [ ] Send calendar invite to all organizers, instructors, expert helpers, with all relevant links

    • +
    • [ ] Decide if certificates will be possible and what is needed for getting a certificate/credits (ask from partner universities)

    • +
    • [ ] Remind co-organizers to register

    • +
    • [ ] Send summary email to all co-organizers will all important links in one place

    • +
    +
  • +
  • After the workshop:

    + +
  • +
+
+
+

Registration coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+ +
+
Broadcaster
+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Prepare ice-breakers for each day

  • +
  • [ ] Create instructor Zoom and communicate it (with exercise coordinator and outreach and marketing coordinator)

  • +
  • [ ] Publish recordings (does not do all the work but coordinates it)

    +
      +
    • [ ] Prepare for upload (use ffmpeg-editlist and collaborate)

    • +
    • [ ] Upload videos and communicate (with outreach and marketing coordinator) +:::

    • +
    +
  • +
+
+
+
+

Instructor coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Confirm that each lesson and session has co-instructors

  • +
  • [ ] Schedule calls with each instructor pair to distill most important questions and tasks to them

    +
      +
    • [ ] Show where the detailed schedule is and recommend to move it to instructor guide

    • +
    • [ ] Discuss that the detailed schedule can and should be improved

    • +
    • [ ] Show where Q&A and feedback from past workshop can be found

    • +
    • [ ] Discuss plans for exercises: try 3 exercises each half-day, each not shorter than 20 mins

    • +
    • [ ] Ask them to check their lesson’s exercise list

    • +
    • [ ] Ask for any software requirements changes

    • +
    • [ ] Inform about audience (at the time of writing half of registrants prefer to follow on their own) - adapt exercise expectations to audience

    • +
    • [ ] Check/test for high-quality screen share

    • +
    • [ ] Discuss how we can give learners get a good experience

    • +
    +
  • +
  • [ ] Test software install instructions

  • +
  • [ ] List instructors on the website (with exercise coordinator)

  • +
  • [ ] Organize team leader on-boarding sessions (with exercise coordinator)

  • +
  • [ ] After the workshop copy detailed schedule to the individual lesson repos as issues +:::

  • +
+
+
+

Exercise and team leader coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • Before the workshop

    +
      +
    • [ ] Make sure exercise list is communicated (with outreach and marketing coordinator)

    • +
    • [ ] List all team leads (who consent to being listed) on the website (with instructor coordinator)

    • +
    • [ ] List expert helpers on the website (with instructor coordinator)

    • +
    • [ ] Organize staff & helpers on-boarding sessions (with instructor coordinator)

    • +
    • [ ] Send team leader onboarding summary email + save it to the website (with outreach and marketing coordinator)

    • +
    +
  • +
  • After the workshop

    +
      +
    • [ ] Organize a de-briefing call with team leads to learn about their experiences and suggestions

    • +
    • [ ] Help other roles in putting everybody who contributed and consents on the website as credit

    • +
    • [ ] After the workshop remove the exercise repositories

    • +
    • [ ] Help event director with post-workshop survey +:::

    • +
    +
  • +
+
+
+

Outreach and marketing coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Create/update advertising texts and relevant news on the workshop page

  • +
  • [ ] Newsletter

    +
      +
    • https://tinyletter.com/coderefinery/archive

    • +
    • draft: https://hackmd.io/@coderefinery/CRnewsletter_1_2023

    • +
    +
  • +
  • [ ] Advertising texts on the workshop page

    +
      +
    • https://coderefinery.github.io/2023-03-21-workshop/communication/

    • +
    • https://github.com/coderefinery/2023-03-21-workshop/tree/main/content/communication

    • +
    +
  • +
  • [ ] CodeRefinery Twitter

    +
      +
    • https://coderefinery.zulipchat.com/#narrow/stream/119815-general/topic/tweet-toot-suggestions

    • +
    +
  • +
  • [ ] CodeRefinery Mastodon

    +
      +
    • https://coderefinery.zulipchat.com/#narrow/stream/119815-general/topic/tweet-toot-suggestions

    • +
    +
  • +
  • [ ] CodeRefinery LinkedIn

    +
      +
    • https://www.linkedin.com/events/coderefineryworkshopmarch21-23a7031623728480272384/comments/

    • +
    +
  • +
  • [ ] CHCAA LinkedIn (Aarhus University)

  • +
  • [ ] Partner Twitter, retweet and own tweets

    +
      +
    • [ ] Aalto Scientific Computing

    • +
    +
  • +
  • [ ] Partner newsletters

    +
      +
    • [ ] Sigma2

    • +
    • [ ] SNIC/NAISS

    • +
    • [ ] ENCCS

    • +
    • [ ] CSC

    • +
    +
  • +
  • [ ] Partner websites training calendars

    +
      +
    • [ ] CSC

    • +
    • [ ] ENCCS

    • +
    • [ ] UiB

    • +
    • [ ] AU (Aarhus University)

    • +
    +
  • +
  • [ ] Partner and other email lists

    +
      +
    • [ ] Aalto STEM students

    • +
    • [ ] Aalto triton users

    • +
    • [ ] Delta doctoral network

    • +
    • [ ] UiB researcher

    • +
    • [ ] UiB HPC

    • +
    • [ ] NERSC Bergen

    • +
    • [ ] Bjerknes Bergen

    • +
    • [ ] University of Oslo computational biology

    • +
    • [ ] University of Oslo Phd and Postdocs

    • +
    • [ ] University of Oslo Dcince contact (?)

    • +
    • [ ] Research institutes in all countries

    • +
    +
  • +
  • [ ] Partner posters

    +
      +
    • [ ] Aalto (CS,U,NBE,PHYS,VAARE) +:::

    • +
    +
  • +
+
+
+

Certificate coordinator

+

https://coderefinery.github.io/2023-03-21-workshop/certificates/

+
    +
  • lead:

  • +
  • backup: ASC team (the process can be run by anyone and we are now using a ticketing system to track requests)

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Make sure that instructions on certificates are disseminated multiple times

    +
      +
    • [ ] Workshop page, emails

      +
      - Learner sends materials to scip _at_ aalto.fi. This opens a ticket in Aalto "esupport" system
      +- The person who generates the certificate verifies quickly that the tasks were completed.
      +- We then work with https://github.com/coderefinery/generate-certificates to generate PDF certificates
      +- Certificate is sent to the person and ticket is closed
      +- Aalto specific:
      +    - The local version of that repository is at /scratch/rse/generate-certificates/. The commands were slightly modified so that the default working directory is not the home folder
      +    - Aalto students can also obtain directly the 1 ECTS credit. See internal process at ASC pages.
      +
      +
      +
    • +
    +
  • +
+

:::

+
+
+
+
+
+
+

Online teaching

+

In 2020, we were forced to start teaching online. Is this good or +bad?

+

The promise of the Internet was that we could reach everyone in the +world. Instead, we immediately learned to hide or Zoom links from +anyone except the people who register in advance to hide from trolls. +We directly translate in-person to online, and wonder why we don’t +have as much engagement. It doesn’t have to be this way. +CodeRefinery has developed a vision of this teaching that can take the +best of both worlds.

+
+

Video: The future of teaching

+

“The future of teaching”, +https://www.youtube.com/watch?v=S9Jor12Cxdc (45:31) is a talk +describing many aspects of this strategy in a concise form.

+
+
+

What is different about online?

+

Online teaching requires a certain mindset.

+

First off, it is different, and different is not better or worse. +You must rethink your existing assumptions and design for the current world.

+

Some differences in mindset include:

+
    +
  • If the material is online, why pay attention now. Why not find +the same or similar material when you need it? If the course isn’t +online, still you realize you can do a web search and find something +equivalent later.

  • +
  • Why dedicate myself to this now? Why night attend a course +passively now, get the basics, and come back later when I need to +really understand something?

  • +
  • How to best use the tools? I might have only one screen to take the +course (and no projector to watch), but the instructor material is +also closer. Why type things myself, if my normal work is copying +from StackOverflow anyway?

  • +
  • Related to the above, you can’t use attendance as a proxy for +engagement. You have to actually engage people, or accept that +passive attendees are OK. Do you measure the benefit of people +watching the course later?

  • +
  • Everyone knows how to way of attending in-person courses. But there +are different ways to attend online courses, and you don’t get as +much feedback from others. You need to be explicit.

  • +
+

Once you learn to take advantage of online formats, you might never go +back!

+
+
+

Taxonomy of online teaching

+

This isn’t a strict division, but here is a rough vision of steps to +take, from simplest to more advanced.

+
+

(1) By yourself, in a meeting

+

It’s you and a group of students in a meeting (e.g. Zoom). This can +reach people, but it’s easy to lose the attention of attendees. +Because you need to avoid trolls and protect privacy, you may have a +private registration and you may not publish recordings. This gives +limited usefulness in the future.

+

Key aspects:

+ +
+
+

(2a) Group teaching, in a meeting

+

One of the advantages of online teaching is it doesn’t require +full-time physical attendance, so you can more easily bring in a +diverse set of helpers, which greatly reduces your load.

+ +

At the same time, you can start grouping learners together into small +groups. This is the equivalent of different tables in a physical +workshop.

+
    +
  • Zoom breakout rooms can group people together

  • +
  • You need to be explicit about how the groups work. Even in person, +many learners work independently even when forced into a group.

  • +
  • Add “team leaders” (helpers, former students) to guide each +group.

  • +
+
+
+

(2b) Higher production values

+

Now we reach the real promise of online teaching: by using streaming +platforms, you can reach everyone in the world. No registration is +needed and anyone can take part. The disadvantage is that you don’t +have close interaction with the learners (by design: removing these +close interactions how you can accept everyone).

+

This focuses on technical setup

+ +
+
+

(2c) Multiple ways of attending

+

One no longer has to limit yourself to interactive watching

+
    +
  • Streaming

  • +
  • Encourage in-person “watching parties”

  • +
  • Make videos available (Video editor)

  • +
  • Make videos available immediately, for catch-up purposes

  • +
+
+
+

(3) High-accessibly zen-level courses

+

Finally, we get to our final state: You can combine the contradictory +options: privacy for learners, but anyone can attend. Interactive +course, but people can refer to it later.

+

This is more a mindset thing, and combines everything from above.

+
+
+
+
+

CodeRefinery MOOC strategy

+

This page documents the CodeRefinery MOOC (massive open online course) strategy. It is not a real +MOOC (it’s not massive enough yet), but it does reach out from one to +many, and can scale to basically all the world.

+
+

Video: The future of teaching

+

“The future of teaching”, +https://www.youtube.com/watch?v=S9Jor12Cxdc (45:31) is a talk +describing many aspects of this strategy in a concise form.

+
+
+

Technical setup summary

+

We have a public broadcast, with goes out via a livestream. +Disconnected from this, people are watching the broadcast in a +separate Zoom meeting and doing exercises/breakouts there. Or, +people can watch via the livestream alone. Or there can be different +meetings. Or people could watch recorded videos later.

+

The mental model here is “Watching TV together”. We collectively watch +a show together. There are periodic intermissions where each watching +community discusses among themselves and works on the exercises. +Everyone feels they are a part of something big and that keeps people interested.

+

We have clear communication channels from learner→instructor +(HackMD), helpers→instructors (chat), instructors→learners +(livestream). Of course instructors can directly communicate with the audience +during their breaks.

+

The Director controls the stream and is responsible for keeping +things running smoothly.

+
+
+

Summary diagram

+
+_images/mooc-diagram.png +

The general presence and information flow within the MOOC strategy.

+
+
+
+

Instructors

+

There is an instructor Zoom meeting. This is broadcasted via +Twitch, using OBS (there is usually a separate director +or production manager for this, instructors don’t need to worry +themselves with this).

+

Compared to the classic style, advantages include:

+
    +
  • You are freed from student management, others help manage the +audience and convey these important parts to you.

  • +
  • Audio/video is muted during breaks, there is more opportunity to +discuss and plan what comes next with the instructors.

  • +
+

Disadvantages:

+
    +
  • You lose the direct access to all students (but how often would +someone speak up anyway?).

  • +
+

Instructors should keep in mind (many of these are not special to the +MOOC format, but are even more important):

+
    +
  • At all times you will have a director to help keep you on track: +just teach and watch chat (and HackMD when you have time, but others +do this and let you know).

  • +
  • You will have a private Zoom meeting with only instructors (and any +other key helpers who want to be there).

  • +
  • Share a vertical screen (840 × 1080 is our standard and your +maximum). This allows students +to keep half of their screen open for their own work.

  • +
  • HackMD is the main way of receiving questions from students (just +like in our current courses). The HackMD helper can be in the +main stream to immediately ask questions from the audience, or your +co-instructors could do this. Really, perhaps both.

  • +
  • During breaks and pauses, the livestream will be muted, so that +instructors (and helpers there) can talk without the audience +hearing. This greatly increases professionalism and makes it easier +to coordinate.

  • +
  • There is the standard text chat (Zulip) to use to communicate with +other helpers.

  • +
  • Of course, you can go join the student room during breaks, other +sessions, and so on.

  • +
  • Zoom polls won’t work, since the instructors and audience aren’t in +the same Zoom meeting. This is one reason we already use HackMD for +polls (though there are other options, such as presemo.aalto.fi, +which could work in even larger courses).

  • +
  • You will have more than just the registered students in another room +as an audience. Your audience includes students in the breakout +room meeting, livestream watchers, people in their own meetings with +a private team we don’t know about, people broadcasting it to +physical rooms, people watching recordings later, and who knows who +else.

    +
      +
    • Try to speak with awareness of this diverse audience. You don’t +need to change much, but go slowly and give plenty of time, and +you can say things like “If you are registered, … . If you are +on your own, … .”

    • +
    • Repeat back questions before answering them, so that people across +channels can follow. This is a usually good idea anyway, and also +it is natural when questions are coming through chat or notes.

    • +
    • Speak in terms of breaks and exercises sessions.

    • +
    • Speak in terms of relative times, since people will be in different +timezones. For example, say “We resume at +50 minutes past the hour” and write “xx:50”.

    • +
    • Realize there are different learning styles. Some people will +attempt all exercises. Some will passive watch and want demos.

    • +
    +
  • +
  • We propose this general model for each lecture-exercise cycle:

    +
      +
    • Give the lecture part

    • +
    • Introduce the exercises

    • +
    • Short break (~5 minutes). People attempting exercises themselves +go into their other meetings and work on it. The learners +attempting it themselves will mute the stream.

    • +
    • On-stream, do the exercise as a type-along or demo. This is useful +for some audience, and also is very useful in recordings.

    • +
    • At the designated time, the learners come back to the livestream. +Depending on what you want, you could use the outcome of the demo +to discuss what we learned, do a whole new demo (perhaps faster +this time), or you go on.

    • +
    +
  • +
  • You should also make it clear to the audience (mainly +helpers/team leaders) what the expectation for each exercise +session is. This should be written in the HackMD!

  • +
  • It is OK to decide you can’t make things perfect for every audience. +The rest will understand this if you make this explicit.

  • +
+
+
+

Director

+

You job is to be aware of everything going on, and when there is a +question like “Do we need more time?” or “what should we do now?”, you +can answer it. You can give people the pushes when they get slightly +off track (though others should always be willing to speak up when +this is needed, too). You maintain this awareness by watching as many +of the communication channels as you can.

+

Hint: find your computer’s detailed audio controls, so that you can +adjust volumes of multiple sources independently. This helps you be +in multiple meetings at once. (This may be useful for others that +want to attend multiple meetings.)

+
+
+

Expert helpers and other staff

+

As a helper, your job stays pretty much the same. There is more +emphasis on making sure that all questions and comments are in the +HackMD.

+

Some helpers can join the instructor meeting and directly relay +questions and thoughts, and in general provide the “voice of the +audience”. This is a logical role for the HackMD helper.

+
+
+

Audience and team leaders

+

The learners and team leaders focus on watching the material and +asking questions in HackMD, much as in a regular course.

+
+

In the main meeting with breakouts

+

Here, there is a meeting (e.g. Zoom) which has a lot of learners in +it. There are two options for lectures:

+
    +
  • Meeting host shares the livestream (video + audio)

  • +
  • Participants individually open the livestream and watch, and go back +to the meeting when it is time to do exercises.

  • +
+

All audience members ask questions and discuss in HackMD (just like in +regular workshops). The meeting chat is mainly used for +practicalities, and is not designed to be monitored by the audience.

+

The most significant risk here is that learners have to mute the +livestream (or turn it off) during the exercise sessions if there are +demos going on while they are doing exercises. This means we may have +trouble getting their attention.

+
+
+

Via livestream

+

Here, each audience member watches Twitch independently. During the +exercise sessions, they can work alone, watch the demos, or work with +their own self-organized teams.

+
+
+

Live

+

The stream is broadcast in the physical classroom or meeting room +where a class or team is located.

+
+
+

Recording

+

You can watch the recording, refer to the lesson page, and refer to +the archived HackMD notes afterwards.

+
+
+
+

Open issues

+
    +
  • It can require some cognitive effort to understand and keep track of +all of these different channels. But when we did it in +January/February, learners picked up quickly and there were few +complaints in the end.

  • +
  • HackMD spam: Lately, we have had one HackMD for all students +(registered or watching via the stream). There has yet to be any +spam or trolling problems, but it will happen if we get big enough. +We need a transition plan to private HackMD if needed. (Proposal: +have a backup HackMD. If spam starts, we email the new one and go +from there.

  • +
  • Chat/Q&A scaling: Will HackMD actually scale enough for us? What +alternatives do we have?

  • +
+
+
+

See also

+ +
+
+
+

Open Broadcaster Software theory

+

This page describes the theory around OBS. For practical steps to +run a course, see Broadcaster.

+

Open Broadcaster Software is an amazing open-source audio/video +production tool. It’s probably not professional grade, but is used in +serious events and will make a non-professional feel professional. +The main point is that, instead of being limited to what your meeting +software can do, you can:

+
    +
  • create more advanced mixes of screens/video/etc, without having to +do post-processing.

  • +
  • do more with the (local recording, streaming)

  • +
  • do this all better, for example, exclude the audience speaking from +the recording.

  • +
+

It is a GUI application, so is not that hard to figure out, but there are a +lot of initial concepts. This page isn’t a comprehensive tutorial, +but will introduce the basic concepts and what you can get out of it, +and you can either figure out the rest or read other tutorials.

+
+

Vision

+

When teaching online, we are usually limited by our online meeting +software. This forces us to make certain trade-offs to fit the +limitations of the software, so that we can’t reach our full +potential. By using more advanced technology, we can do more: have +interactive sessions while also recording and preserving privacy. For +more information, see the online teaching guide.

+
+
+

Basics

+ +
+

User interface basics

+

OBS is a graphical program. Once you start it up, you see various +user interface features:

+
+_images/obs--controls.png +

Basic OBS control layout

+
+

Of primary note are the following concepts:

+
+
Preview area

Shows what is currently being broadcasted or recorded, or will be +if you turn it on. There is also a separate “Studio mode” with a +preview area, and live area. The preview area is used to prepare +the stream, you can make it live when you want.

+
+
Scenes

A certain layout that can be broadcasted. On the lower left is +your scene collection, and you can add, delete, reorder, and rename +scenes. By clicking on a scene, you switch to it and it begins +broadcasting/recording.

+
+
Sources

An image source which can be composed together in a scene. Scenes +can be added, deleted, recorded. Via the preview area, sources can +be graphically moved around to your liking. There is a +comprehensive set of positional and image effect transforms you can +make.

+

Sources can have filters applied to them, which do some sort of +video transformation (for example, background removal). There are +also transformations, which affect the position in the scene. +Put together, you can do almost anything you would like.

+
+
Audio sources

You can take audio input from various sources: mainly, microphones +or as a monitor of a computer audio device (to, for example, play +sound). Audio sources are configured in settings, but can be +muted/have volume adjusted in the respective area of the screen.

+

Audio sources also have filters.

+
+
Control buttons

There are buttons to start/stop recording/streaming. The output +locations are configured in the settings.

+
+
+
+
+
+

Configuration

+

Here, we will go over the main parts of configuration. We won’t say +everything, since this is graphical program and you can mostly click +around and find your own customization you would like.

+

Because of the popularity of streaming, it is easy to find more +tutorials and recommendations for anything here. Add “streaming” or +“OBS” to your search.

+
+

Basic configuration

+

These options are found in the “Settings” dialog. These are just +generally suggested defaults and when you might want to tone them.

+
+
File → Settings → Stream

Here, you would configure the streaming service, if any.

+
+
File → Settings → Output

Here, you configure streaming/recording output parameters.

+

If you use Simple, you pretty much can’t go wrong. If you are +mainly screensharing and don’t have much action video, you can +make the bitrate much lower, for example 2500 Kbps. The slower +“encoder preset” is, the more CPU power that will be spent to get +that quality, so the less space it will use. The better your CPU +is, the slower you can make it; “fast” to “slow” are reasonable.

+

If you use advanced you have more options:

+

Streaming: Rate control=CBR, 2500 Kbps, other options don’t matter +so much, defaults should be fine. You can search for +recommendations online, but realize that most others stream +high-action games so their settings are much higher than you need.

+

Recording: Recording format, mp4 (mkv would be better, but we need +to check that it can be uploaded to common sites). Encoder=x264, +Rate control=CRF, CRF=22, Keyframe interval=auto, CPU +preset=medium (or slower, for better CPUs) +(slower=use more CPU to do better +encoding, either higher quality or lower bitrate. Veryfast–Slow +is a good range), +Profile=main, Tune=None

+
+
File → Settings → Video

Here, you set the base size of the picture you will be using. +You could do FullHD at 1920x1080, or HD at 1280x720. For vertical +recording, we recommend you do 840x1080. Use your chosen value +for both Base and Output resolutions. 30 FPS.

+

When setting your video size, traditionally people tell you to be +as large as possible (to attract viewers). However, this guide is +focused on teaching +and learning, and for that a) we want our content to be as +accessible as possible. There is no need for as many pixels as +possible, as we often say “present from your smallest screen”, and +you can do that by artificially restricting yourself. b) We have +found a vertical screen works well: a learner can have the +video/stream taking up half of their screen, and the other half +available for doing their own work.

+
+
+

Click around through the other menus in settings and see if there is +anything to configure to your own needs.

+
+
+

Scene configuration

+

After the above, you can set up scenes basically however you would +like. However, as a starting point I propose these scenes to get you +started (and I propose we standardize on these names, so that we +can make some uniform scripting tools):

+
    +
  • Title, the logos and titles of the event.

  • +
  • Gallery, a gallery of the people presenting (or the one). When +presenting from a Zoom meeting, this is a capture of the gallery +view in dual-monitor mode.

  • +
  • Local is a local screenshare, that you get by capturing your own +screen.

  • +
  • Remote is a screenshare by someone remote. If you are capturing +from a Zoom meeting, it is the capture of the second window of the +dual-monitor mode.

  • +
  • Notes is some HackMD or other material you might want to show +during discussion periods or breaks.

  • +
+

Common types of sources (scene elements) include:

+
    +
  • Static image (e.g. logo or background)

  • +
  • Desktop capture, for your local desktop. You can crop it (in the +source config) to share only a portion of your desktop.

  • +
  • Single-window capture. Note that this is smarter than Zoom, +since it can capture the full window even if is not on top.

  • +
  • Text (which works, but is not very powerful)

  • +
  • Solid colors

  • +
  • Other scenes. You can make one scene, then insert it into other +scenes to avoid duplication of scene elements scene elements.

  • +
+

The sources themselves can be moved around graphically, which is good for +setting things up. When there are more demanding needs, the source +transformation can be edited for more precise control (right click on +source in preview → edit transformation). There are +source filters, which can do video effects such as removing a color. +Some sources can be cropped in the source-specific config as well.

+
+
+

Audio configuration

+

Audio configuration is simpler than video configuration, since there +are fewer different sources. On the other hand, it is harder to +see what is going on (no preview) so it is harder to adjust it +perfectly, and easier to cause problems like loops.

+

The main concept is that your computer may have different input and +output sound devices (“cards”). For example, I can output sound from +some application on my monitor’s speakers, while sound from other +applications on the headphones at the same time. Find your computer’s +way to see and configure what is going on under the hood.

+

There are two types of audio inputs:

+
    +
  • Microphones, obviously recording from a microphone.

  • +
  • Monitors (as in, monitor a sound card), recording what is +currently being played on another +sound card. This is what is used to capture audio from a remote +meeting, such as Zoom.

  • +
+

You set the active audio input in the application settings. The +volumes of these can be independently adjusted - you want typical +volume to be in the yellow zone. Advice for various operating systems +include:

+
    +
  • Linux using PulseAudio: pavucontrol

  • +
  • Windows: ???

  • +
  • MacOS: ???

  • +
+

Under “advanced audio properties” (a menu item, also available from +the gear icon in the audio area) you have several more options.

+
    +
  • You can add various filters, such as noise reduction.

  • +
  • You can group audio sources into various audio tracks, and the +stream/recordings can use different tracks. For example, a person +may stream with music but leave that out of the recorded video. Or, +you might record a video with two different audio tracks, one just +the presenter and one with presenter + audience.

  • +
  • You can monitor the audio, which plays what is being recorded back +over the headphones and speakers for you to check. Make sure you +don’t make any loops!

  • +
+

Audio configuration is a big deal. You can look at thees other +guides:

+
    +
  • ???

  • +
+

High-quality audio is quite important. I’ve spent far too long +playing with it, and my conclusion is that I don’t know enough to make +it better than what I have now. I could use a better microphone, but +then I had to add noise reduction and the quality ended up the same as +a “worse” headset microphone that was close to my mouth that seemed to +have automatic noise reduction. Your environment (noise, amount of +echo) matters just as much as your microphone.

+

I propose a central recommendation: talk about audio quality. Start +meetings early and test it. Communicate about problems early, don’t +ignore and think it’s “good enough for now”.

+
+
+

Recording and streaming

+

Once you have done the above, you can record and stream by clicking +the buttons.

+

One piece of advice: always keep the recording going, and then +stop/restart it when you need to cut. It’s easier to delete the +unnecessary segments than realize you forgot to push “record”.

+
+
+

Projector and loopback output

+

Beyond recording and streaming, there are several more ways to use the +output that can feed into other applications.

+

With projectors you can display the scene locally on another +monitor or window.

+
    +
  • The fullscreen projector displays the scene to a monitor. As +the name says, this could be used to send it to an external +projector or capture card via HDMI. Or even preview locally, or +screenshared in an online meeting.

  • +
  • The windowed projector does similar, but makes a new window that +can be moved and resized. This can be captured as a single-window +screenshare in an online meeting.

  • +
+

The loopback output creates a virtual camera device. This +appears to other applications as a camera, just like the camera that +captures your video. +Other applications can use this as the input just like another +webcam. So, you could make a fancy scene that is used instead of your +normal camera’s picture. +Or, in Zoom you can share screen from “second camera” - +which would use this scene. (Note in Zoom it will interpret it as a +landscape picture, regardless of what aspect ration you actually use. +Thus, this isn’t very suitable for vertical screen sharing.)

+
+
+
+

Example configurations

+
+

Recording your own demo

+

Scenes: Title, Gallery, Local. Variable bitrate.

+
+
+

Online teaching event

+

Scenes:

+
    +
  • Title

  • +
  • Gallery - contains galleryCapture

  • +
  • Local - capture of your screen, when you need to teach. Has +galleryCapture in top-right corner

  • +
  • Remote: capture of Zoom second window (which has been +adjusted to be same resolution as your base canvas size). Also has +galleryCapture in top-right corner.

  • +
  • Notes: contains HackMD + galleryCapture

  • +
  • galleryCapture - contains the Zoom gallery capture. This gets +inserted into the other scenes above.

  • +
+

Audio:

+
    +
  • Microphone capture

  • +
  • Monitor of sound card which has the Zoom output

  • +
+

Outputs:

+
    +
  • Recorded locally. Start and restart recording after every +transition that you would want to publish separately. (Better to cut +more than less, to have logically organized shorter segments. Also, +always keep it recording, in case you forget to turn it back on!).

  • +
  • Stream to your preferred site.

  • +
  • Use windowed projector or Zoom capture to send the output directly +to a Zoom meeting. But, that requires careful audio routing.

  • +
+
+
+
+
+

Online training manual OLD

+
+

Note

+

This hasn’t been updated since we developed our MOOC strategy.

+
+

Also please read our lessons learned.

+

This manual covers general guidelines for conducting online +training as well as specific tips on using Zoom.

+
+

For the instructors

+

If you have an old spare laptop, connect to the call as a second “you” and you can +watch and verify your screensharing and fontsize to avoid “Am I sharing the screen? +Hopefully you see what I see.”

+
+
+

How to avoid “Zoom bombing”

+
    +
  • Either set a password or use waiting rooms

  • +
  • Share connection details only with participants and helpers, not on the web

  • +
  • Disable file transfer

  • +
  • Disable “Allow removed participants to rejoin”

  • +
+
+
+

Preparation

+
    +
  • Schedule the meeting/webinar in the online Zoom system

  • +
  • do not auto-mute participants’ microphones, as this also happens when you enter breakout rooms.

  • +
  • Decide roles:

    +
      +
    • Decide the Zoom host and co-hosts

    • +
    • Use panelists? (Zoom webinar feature)

    • +
    • Decide instructor and backup-instructor in case of network issues

    • +
    • Decide helpers. One helper should be responsible for monitoring +Zoom, i.e. the chat window, hand-raising and other feedback

    • +
    +
  • +
  • Co-hosts, breakout rooms and feedback controls need to be enabled (on +website) before the meeting starts. If options are reconfigured, the meeting +may need to be ended and restarted for them to take effect.

  • +
  • Create enough breakout rooms at the beginning since this cannot be easily changed during the meeting.

  • +
  • TODO: set up pre-lesson polling? (zoom feature) Maybe unnecessary in view of pre-workshop survey

  • +
  • Instructors and helpers should use a reliable camera and microphone. +Computer microphone might not be enough since audio quality will depend on +instructor’s head angle and proximity to screen.

  • +
  • Workshop owner creates a HackMD which will be used for collaborative note taking.

  • +
+
+
+

At the beginning of the session

+
    +
  • Allow time at the beginning of the session to debug video/audio and to +arrange windows. This takes few minutes so better do not start with teaching +from minute 1. Plan for an early 5-minute break to debug this.

  • +
  • We cannot assume that all Zoom participants have the same and up to date +client and some clients do not contain “sticky notes” feedback or a button to +raise hands so agree with participants on signals (e.g. typing \hand in the +chat window seems to be standard).-

  • +
  • We demonstrate how HackMD works and use it in an ice-breaker (roll call or asking a questions).

  • +
+
+
+

Recording of sessions

+

If you plan on recording and publishing the session, prepare in advance so that +you don’t have a difficult editing job later. +Make sure that you (or users) don’t show any personal or confidential information. +Think about what happens if users speak: do you ask for permission to publish +in advance (maybe encouraging people not to), or edit it out later (taking +your time later).

+

If you plan to record the session, make sure that everybody is aware that the +sessions is recorded, informed about how the recording will be used, and gives +consent to be recorded: +https://support.zoom.us/hc/en-us/articles/360026909191-Consent-to-be-Recorded

+

In Zoom it’s important to start recording in the form you want the video to be +in (e.g. start recording when screen is shared so that it stays there): +https://support.zoom.us/hc/en-us/articles/360025561091-Recording-layouts

+

Set screen background to black. We saw a glitch in Zoom which caused the +background image to flash above the screen, if it was pure black it would be +less distracting.

+
+
+

Zoom-specific installations instructions sent out before workshop/lesson

+
    +
  • Recommend to install Zoom app. Browser is possible but more limited

  • +
  • Test-launch zoom and test microphone, speaker and camera (lower left corner buttons)

  • +
  • Instruct participants to watch a zoom introduction (TODO: insert link), +and play around with zoom.us/test to get acquainted with interface.

  • +
  • Optional: set up virtual background

  • +
  • “During the workshop, you might be asked by a helper to share your screen. +Make sure to keep private information away from the screen you share.”

  • +
+
+

Contingency plans

+
    +
  • Be prepared for intermittent network problems.

  • +
  • There should be a backup instructor in case the main +instructors disconnects

  • +
  • Learners might occasionally experience lag and temporary +network hickups. This makes it particularly important to +speak slowly and repeat important topics.

  • +
+
+
+
+

Breakout rooms

+
    +
  • Breakout rooms can be used both by helpers to assist individual +learners during an exercise, or for multiple learners working on +a group exercise.

  • +
  • When creating groups, the host or co-hosts can choose automatic setup, +where only the number of groups is selected and the distribution into +groups is automatic, or manual setup where the host/co-hosts distribute +learners into groups.

  • +
  • Host needs to move helpers, co-hosts cannot enter rooms on their own.

  • +
  • Somebody asking for help gets assigned to a room together with a helper.

  • +
  • TODO: is it possible to create breakout room for only some participants, +leaving other learners unaffected? This is crucial for helping participants +during exercises who have raised their hand. Need to test this

  • +
  • Host and co-hosts can join any room and jump between rooms. This should be +used during collaborative exercises to see how the exercise is progressing +or participate in the group work.

  • +
  • When a collaborative exercise is about to end, the host/co-hosts can +broadcast a message into all groups.

  • +
  • When the host/co-hosts end a breakout room session, participants in groups +have 60 seconds to finish before the session terminates.

  • +
+
+
+

Exercises

+
    +
  • Just like in a regular workshop, demonstrations and type-along sessions +should be interspersed with frequent exercises

  • +
  • For pairwise or group work exercises, the instructor (or Zoom assistant) +should create breakout rooms with chosen number of participants in each

  • +
  • For single-person exercises, no breakout rooms are needed

  • +
  • Learners should be instructed to raise their hand when they need help. +This corresponds to putting up a red sticky note in in-person workshops.

  • +
  • TODO: what signal should be used for green sticky notes?

  • +
  • Polling can be used as formative assessment questions. The host creates +a poll based on a lesson template and requests learners to answer. +(TODO: polling seems not available in kth-se zoom subscription)

  • +
+
+
+

Breaks

+

Following an online event can be even more tiring than a physical event and +therefore also during online sessions we need to plan for breaks as we would +for an in-person event.

+
+ +
+
+
+
+

Lesson design

+

This is a checklist and hints when writing and designing a new lesson. +The master material is in Teaching Tech Together, primarily chapters 6 +and 12 for practicalities and 2 and 4 for big picture considerations. +But really, all the book. See the summary we +made or the actual +book. The article Ten quick tips for creating an +effective lesson is +also a good summary of the main points. +Finally, the Carpentries Curriculum Development Handbook gives practical information on how to design a new lesson and covers the entire lesson life-cycle with a good overview of the lesson release timeline.

+

This doesn’t replace your own knowledge in doing the actual teaching +part. Instead, the first half gives pointers on making sure your +audience can connect to the material, and the last half gives hints +to help you come up with good exercises and examples.

+
+

Backwards lesson design

+

Think test-driven development: decide what you want students to be able +to do, design exercises to measure it, then fill in the gaps with +teaching. You can see their +summary. The steps are:

+
    +
  1. Brainstorm what you want to cover.

  2. +
  3. Create or reuse learner personas - understand who you want to +teach. What do they care about? Perhaps as important is what they +don’t care about: make sure that you don’t go too in depth too +early and turn people off.

  4. +
  5. Create some summative assessments, that show what learners should +learn by the end. Try to connect these to the learner personas.

  6. +
  7. Create formative assessments (exercises) that let the learners +practice what you want them to learn. See below for hints on coming +up with good exercises. These should also connect to things the +learners will actually do, but can also be more of checkpoints.

  8. +
  9. Put exercises in a logical order, and fill in any gaps. Ideally +there should be 15-20 min of teaching between each exercise. Perhaps +most are short (a few longer examples as needed), to identify a +certain learning goal and misconception.

  10. +
  11. Write just enough material to get from one exercise to the other.

  12. +
+

The most important point here is to start from learner’s needs and how +they can feel connected, not from the tech details.

+

When advertising the course, connect it to your learner personas so +that you get the right audience and they know why they should come.

+
+
+

Emotional and intrinsic appeal, other basics

+

You can think of why people should feel emotionally connected to your +material - maybe it’s too much to expect people to get emotionally +invested, but if you try for that, you’ll end somewhere better.

+

Try to design around tasks and exercises which your audience will care +about. For example, don’t say “here are some shell commands”, but +“aren’t you tired of copying all of these files one by one… check +out the shell… once you know it, you will really feel at home. Here +are some typical things you might do.”. Intrinsic motivators include +sense of agency (being able to do things themselves), competence +(usefulness of what they are doing, feeling they know something), and +relatedness (doing things that others are doing).

+

A manual is reference, a tutorial builds a cognitive model. If you +can build the cognitive model and tell them the “why”, students may be +able to refer to the manuals themselves and become self-sufficient. +Thus, teaching should be more of a +tutorial, with good links to manuals (it can also explicitly teach +how to use the manuals).

+

Perhaps a related point is inclusiveness: make sure there’s not some +“in” crowd. Perhaps the best description I have seen: don’t assume +that some people are missing something, but that others have had the +fortune of learning it earlier. This may not matter in a purely +factual lesson design, but if you are trying to make things +intrinsically or emotionally appealing, it is essential.

+
+
+

Who is the audience?

+

Making the learner personas are essential to making a good lesson, +even if you think you know who you are teaching to. This is because +it grounds you into what your audience already knows (or doesn’t know) +and what they are interested in.

+

You also have different ways people can refer to the material:

+
    +
  • In a class, with an instructor guiding them

  • +
  • Reading along by themselves

  • +
  • In a class, being much more advanced than others, so that they skip +ahead and do advanced material themselves.

  • +
+
+
+

Planning

+
    +
  • Do some planning, and document it - the design process helps +others to teach and modify. At least put it in the README. (this +is the designer/maintainer’s guide)

    +
      +
    • Put the main points from the “backwards lesson design process” in +here, enough that it is easier for someone to improve your lesson +than to redo it.

    • +
    +
  • +
  • Make learner personas: what is your target audience?

  • +
  • Decide learning objectives based on the personas: high-level end +goals. What students get out, not what they do.

  • +
  • Also make a guide for teaching (instructor’s guide), “if you +want to present this, do this”.

    +
      +
    • How much preparation is needed? Is it enough to know the topic +and have read the material?

    • +
    • Things to prepare before the presentation. Does anything need to +be set up?

    • +
    • Practical notes on presenting.

    • +
    • Are there solutions to exercises somewhere? Are they needed?

    • +
    • Include some pre-assessment questions which can be asked at the +beginning.

    • +
    • Perhaps you should do this at the end, but at least starting the +instructor’s guide at the beginning will frame your writing.

    • +
    +
  • +
+
+
+

Writing

+

There is not much here yet, mostly just follow the “backwards lesson design” +above. The hardest part is coming up with good exercises, so our +practical advice is to mix and match from the two taxonomies at the +bottom and the exercise types. Try to think of diverse types of +exercises.

+

Exercise design is the time it is most useful to be with others to do +brainstorming, so we highly recommend discussing with others at this +point. Because exercises are used to set the overall outline of the +lesson, this also gives people a say in the overall outline - in a +very concrete way.

+
    +
  • Make sure you include the emotional starting point at the beginning - why +should you care and why is this cool?

  • +
  • This should also be at the start and end of each section: not just what +or how, but why?

  • +
  • Part of this is also having a student’s guide, so that +people independently studying can know how to follow the material.

  • +
  • It’s OK to have more material than can be presented or than people +should know, but label things well, including labeling the difficulty.

    +
      +
    • In the beginning, what sections are expected to be taught in +short/long versions? What’s advanced/optional?

    • +
    • Label advanced and optional sections as such. Perhaps also really +basic sections that can be skipped for that reason.

    • +
    +
  • +
+

Plan for mixed abilities. It’s OK to have optional (basic) and +advanced sections, as long as they are clearly labeled. Mainly, don’t +have people think that you are uncoordinated because you are skipping +advanced sections.

+

Once you are done, update maintainer’s and instructor’s guides.

+
+
+

Introduction (and conclusion)

+

The introduction is the first thing people hear, and needs special +thought. Don’t start with a cold open, just going straight to the +topic (“what” or “how”). Instead, have some careful motivation +(“why”). It could be especially good to talk about what is wrong with +the current state of affairs (give a good, simple example) and why it +should be improved. Then start talking about what the improvements +are.

+

Ideally, the introduction should serve as an self-contained abstract +of your material. If you need to teach your lesson in only 10% of the +time you have, can you use just the introduction to do it?

+

Conclusion should remind people about why this is cool and discuss +what comes next.

+
+
+

Thinking of exercises

+

Not every exercise has to be an amazing hand-on example. It’s mixing +with smaller, more conceptual things to reduce the cognitive load and +be able to have more frequent exercises.

+

One of your other primary goals should be to make your exercises +relevant. Abstract will lead to disconnection. Connect the exercises +to the real world. Also, can you tell a complete story with +exercises? (Remember, in backwards lesson design, the exercises +form the story of the lesson.)

+

Remember that not every exercise has to be long. Try to have +frequent short exercises to get immediate feedback, with some long +ones.

+

Good exercises are the most important factor in a good lesson. Even +if you are preparing the rest of the lesson mostly alone, consider a +good long brainstorming session to go from “list of topics to cover” +to “sequence of exercises”.

+

When you are stuck thinking “how can I make an exercise that covers +X”, think of the lists below inspiration. Not every exercise has to be an +sophisticated hands-on thing, so don’t be afraid to use different +types:

+

Basic types:

+
    +
  • Multiple choice (easy to get feedback via a classroom tool - try to +design each wrong answer so that it identifies a specific +misconception).

  • +
  • Code yourself (traditional programming)

  • +
  • Code yourself + multiple choice to see what the answer is (allows +you to get feedback)

  • +
  • Inverted coding (given code, have to debug)

  • +
  • Parsons problems (working solution but lines in random order, +learner must only put in proper order)

  • +
  • Fill in the blank

  • +
+

More advanced:

+
    +
  • Tracing execution

  • +
  • Tracing values through code flow (e.g. what is the sequence of +values that x takes on?)

  • +
  • Reverse execution (find input that gives an output)

  • +
  • Minimal fix (given broken code, make it work)

  • +
  • Theme and variations (working code, adapt to other type of +situation/problem)

  • +
  • Refactoring

  • +
+

More conceptual:

+
    +
  • Draw a diagram

  • +
  • Label diagram

  • +
  • Matching problem: two sets of Q/A, match them.

  • +
+

Thinking through the learning taxonomies also helps to come up with +diverse types of exercises:

+
    +
  • Bloom’s taxonomy: hierarchical skill levels (can you help students +to “grow a level”?):

    +
      +
    • Remembering

    • +
    • Understanding

    • +
    • Applying

    • +
    • Analyzing

    • +
    • Evaluating

    • +
    • Creating

    • +
    +
  • +
  • Fink’s taxonomy: complementary types instead of hierarchical:

    +
      +
    • Foundational knowledge

    • +
    • Applications

    • +
    • Integration

    • +
    • Human dimension

    • +
    • Caring

    • +
    • Learning how to learn

    • +
    +
  • +
+
+
+
+

Lesson review

+

This presents a checklist for reviewing lessons that already exist. +You should also read lesson-design.md as well - +this is roughly a checklist to the things there.

+

Remember to keep the story of the lesson in mind. Many people are +focusing on the small matters (during every change), but only +occasionally do people look at the big pictures. That’s why a proper +review starts with looking at the big picture, instead of adjusting +small things and possibly derailing the story.

+

This is roughly sorted from highest priority for short review to +lowest priority for big refactorings.

+
+

Issues

+
    +
  • Look through the issue tracker to see what is relevant, remember and +follow up when going through the sections below.

  • +
+
+
+

Lesson guides

+

Instructor’s guide:

+
    +
  • What sections should be taught for what audiences?

  • +
  • Common pitfalls when teaching

  • +
  • Any required setup in advance?

    +
      +
    • Any special config files that need to be cleared on instructor’s +computer when teaching?

    • +
    +
  • +
+

Maintainer’s guide:

+
    +
  • Learning objectives (necessary to know its place)

  • +
  • Learner personas (necessary to know its place)

  • +
  • After you’re done analyzing, is there anything in the maintainer’s +guide you need to update? (The maintainer’s guide is probably in +most cases the same as the instructor’s guide)

    +
      +
    • Design philosophy, how to modify while preserving the overall +character.

    • +
    +
  • +
+

Student reference guide:

+
    +
  • Anything to fix or already?

  • +
  • Keep this in mind when you get to episode details.

  • +
+
+
+

Lesson overview

+
    +
  • Is the introduction intrinsically motivating enough? Does it +promote an emotional connection to existing problems?

  • +
  • Student’s guide and framing: will a student know when this is +relevant to them and how it will benefit them?

    +
      +
    • Doesn’t need to include word-for-word learner personas, but should +convey this somehow.

    • +
    +
  • +
  • Are the difficulty and prerequisites stated?

  • +
+
+
+

Episode overview

+
    +
  • Read the intro and conclusion to every section/episode.

    +
      +
    • Do they make sense when you read them in order, without reading +the text in between?

    • +
    • Do they motivate each section well enough (not just explain what, +but why it’s cool?)

    • +
    +
  • +
  • Do they have learning objectives at top and food for thought at the +bottom?

  • +
  • Are optional or advanced episodes marked as such?

  • +
  • Does the episode (or lesson overall) say what is next, to keep +people interested in growth?

  • +
+
+
+

Episode details

+
    +
  • Read through each exercise (with no other text in between). Does it +make a logical progression?

  • +
  • Exercises labeled with difficulty, optional, etc.

  • +
  • Optional advanced exercises or material in places where advanced +users may get far ahead.

  • +
  • Each exercise is self-contained: a helper can read just the exercise +area and get an idea of what is supposed to happen and why.

  • +
  • Update the student’s reference guide as you are going through the +details.

  • +
  • Remove duplicate or unnecessary information when possible. Things +are always added, rarely removed. Shorter is usually better. If +something shouldn’t be removed, perhaps mark it as advanced or +optional.

  • +
+
+
+

Major Refactorings

+

Always start with the big picture: does it make sense? When +refactoring, always start off with backwards lesson design again (see +lesson-design.md) and fully go through that.

+

After the above, do the details. Remember the guides still.

+

Before you start major refactoring and rewriting, think if it makes +sense. Have you figured out why it’s the way it is based on the +instructor’s guide? If you do a big refactoring, make sure you update +the maintainer’s guide!

+

Before you embark on a big refactoring step, please pitch your idea +in a GitHub issue and collect feedback from others. Maybe even hold a +brainstorming session.

+
+
+
+
+
+

Writing technical docs

+

This is a guideline for non-teaching technical documentation, for +example HPC infra usage. Since many of us overlap with HPC or other +support roles and our CodeRefinery mindset partially overlaps, we have +some brief guidelines here.

+

There is far too much professional information for us to reproduce +here, but hopefully this is useful quick reference for a typical +person to get started. Check the links at the bottom for more.

+
+

What kind of doc?

+
    +
  • Tutorial - emphasis on concepts and mental model, after reading +you can do limited things.

  • +
  • Reference - more likely to read if you know the concepts and +want to know more advanced stuff.

  • +
  • Example - example of one specific thing. Good for copying and +pasting if you know enough to understand it.

  • +
+

“A good tutorial is different from a good reference. Very few things +are good at both at the same time.” - (I don’t remember who, seen in +Teaching Tech Together). Thus, both tutorials and reference are +useful. Sometimes, we need a tutorial for our stuff and can point to +outside material as a reference. People also really want examples +they can copy - is your infra similar enough that outside examples can +be copied?

+
+ +
+

Style suggestions

+

(not standards, since of course people do what they want anyway. Not +all things apply in all cases)

+
    +
  • Bold for definitions or the first time a concept is introduced. +Basically, a time where someone is likely to scan up the document to +remember what a certain concept is, such as “what’s a git stash?”

  • +
  • Italics for local emphasis.

  • +
  • Never feel bad to use simpler text, in the best case someone can +now understand, in the worst case there’s less mental effort.

  • +
  • Use an active/imperative voice (Y does X, do X to get Y), not +passive (X can be done by Y). Try to use present tense.

  • +
  • Make the docs skimmable - by looking at headings and first words in +each section, can you figure out what you need to focus on?

  • +
  • Use gender neutral text, of course.

  • +
+
+
+

Style guide

+

(Is it worth making a minimal academic HPC/tech doc style guide? The +benefit would be that we can share stuff better. There’s no need to +emulate or reproduce actual professional ones, since we probably +aren’t that formal.)

+
+
+

Other ideas

+

Consider documentation-driven development. Write basic docs, review, +then implement it.

+
+
+

See also

+

Of course, there is far more professional information than you can +find above.

+
    +
  • The Write the Docs guide +seems useful - especially about organizational aspects.

    + +
  • +
  • lesson-design.md might be useful to understand. +The “backwards lesson design process” is especially important to +think about: while you don’t have exercises, you do have goals to +accomplish you can design to.

  • +
  • Code Refinery lesson on Sphinx and Markdown

  • +
+
+
+
+

Meeting checklist

+

This checklist was made because we had a major issue with not +announcing good events to our community because we weren’t sure what +to do, thus a community doesn’t form. These steps should be taken to +announce any event unless there is a specific reason not to (for +example, a workshop is well underway and organizers known). You don’t +have to follow what you see here, but the point is to make +announcements as boring as possible, so that it gets done quickly and +well-enough.

+
+

As soon as meeting topic/time is decided

+
    +
  • Decide central HackMD/join link. (Join link can be decide later by +putting it in the hackmd).

  • +
  • Create a calendar event for yourself, and send it to related +people. You should be ready to forward this to people who request. +It’s OK if the event only includes HackMD link (+ join link, if +known).

  • +
  • [Mailing list: not yet present, we are relying on the other options +here.]

  • +
  • Make a post in #announce. Don’t be shy, just do it. +<time:TAB will produce a time picker that adjusts for +everyone’s timezones.

    +
    At <time:...>, there will be a [meeting on topic].  Topics will
    +include [a few highlights to let people know who should attend].
    +
    +HackMD (including connection details): <link>
    +More info: #[stream-name]
    +
    +If you want a calendar invite, send [me] a private message (or
    +react with :email: quickly if I know your email already).
    +
    +
    +
  • +
  • Make a Twitter post for most meetings, if you want a broader +community to attend.

    +
      +
    • You can do this yourself via the “tweet-together” Github Action:

      + +
    • +
    • You can do it from the web interface, find the “Create new tweet” +button from the readme.

    • +
    • Edit the file path. It pre-fills YYYY/MM outside of the text +box, but you can backspace and change that to current year/month.

    • +
    • Suggested template:

      +
      [title] will be held at [time CEST]. [optional: why should
      +someone attend?  Attend if...]
      +
      +More info via our chat https://coderefinery.github.io/manuals
      +[tags]
      +
      +
      +
    • +
    • Suggested tags

      +
        +
      • CodeRefinery: #coderefinery

      • +
      • Nordic-RSE: #RSEng

      • +
      • Research software hour: #RSEng

      • +
      +
    • +
    • Ideally, someone else should merge quickly after checking facts +Don’t wait for “permission” or something like that which may never +come, we agree that more tweeting is a good thing.

    • +
    +
  • +
+
+
+

Days before the meeting

+
    +
  • Send reminders to the #announcements streams. You can find the old +topic and reply to it, quoting the whole text.

  • +
+
+
+

Archive meeting agenda

+
    +
  • Archive the agenda, if needed.

  • +
+
+
+
+

Workshop preparation meeting

+

Each workshop should have a preparation call among instructors, +experts, hosts, etc. This is separate from the helper training call.

+
+

Topics of workshop instructor meeting

+
    +
  • Introduction round

  • +
  • Go over Instructor introduction and other pages in this section

    +
      +
    • New staff: go over in more details.

    • +
    +
  • +
  • The role of expert helpers.

  • +
  • Everyone: discuss the roles in the workshop

  • +
  • For each lesson, a meeting between a former instructor and the +current one (even if current one is experienced teaching it).

    +
      +
    • Set up any possible co-teaching arrangements.

    • +
    +
  • +
  • Discuss hand-over times each day

  • +
  • Breaks should be descussed among instructors for each day, but +default is 10 minutes between xx:50 and xx:10 each hour.

  • +
  • Practice instructor tech setup (screenshare, etc): can also be done +in the one-on-one meeting.

  • +
  • Joining CodeRefinery: what comes next?

  • +
+
+
+

Don’t forget

+
    +
  • Update Zoom client (later than mid-October 2020) for breakout room +features. Zoom alone isn’t enough.

  • +
+
+
+

Common CodeRefinery conventions to remember

+
    +
  • Breaks are not negotiable, minimum 10 minutes

  • +
  • Sessions can’t be extended indefinitely, it’s OK to run out of time +and skip things (in fact, we expect this: all lessons have op. All +lessons have optional episodes. Not finishing is normal, in fact.

    +
      +
    • Emphasize to learners that we can’t cover everything and don’t +expect to.

    • +
    +
  • +
  • During workshop, we communicate via:

    +
      +
    • HackMD

    • +
    • Zulipchat

    • +
    • Zoom chat is minor and most people don’t need to watch.

    • +
    +
  • +
+
+
+
+

Summary of Teaching Tech Together

+

Teaching Tech Together is a book +compiled by Greg Wilson which is about the pedagogy and practical +hints of teaching technology in informal environments. It is a very +good resource, and the main point is that research does back up +teaching, it’s not all intuition. Many citations are included.

+

This page contains a summary of the most important points. The point +is that one can quickly refer to this before writing a new lesson or +teaching a course. The article Ten quick tips for creating an +effective lesson is +also a good summary of the main lesson design points of this book.

+

Useful appendices:

+ +
+

Ch1: Introduction

+
    +
  • Novice = no good mental model of what they are learning, “not even +wrong”

  • +
  • A manual is not equal to a tutorial - a tutorial needs to build a +mental model from scratch.

  • +
  • Formative assessment = determine what the misconceptions are.

  • +
+
+
+

Ch2: Building mental models

+
    +
  • “Expert blind spot” = experts have more links, so don’t see what +links are missing.

  • +
  • Concept maps as a metaphor for connections

  • +
  • 7+/-2 concepts can fit in short term memory at once

  • +
  • Get feedback from others, then give feedback to others, then +self-feedback (last one is “deliberate practice”)

  • +
+
+
+

Ch3: Expertise and memory

+
    +
  • Cognitive load: too much is bad and makes learning slow

  • +
  • Faded example: blank out certain things in an example which are +added as an exercise/example (what you want to progressively +teach). Seeing examples is good, debugging as an example.

  • +
  • “I want to do something, not learn how to do everything”

  • +
  • Parsons problems - give working code but in random order, +students must put it into the right order.

  • +
  • Minimal manual: one page micromanuals on specific tasks. Helps +training but loses content.

  • +
  • The last exercise of this chapter has some good hints for making +useful graphics.

  • +
+
+
+

Ch4: Cognitive load

+
    +
  • Cognitive load is divided into intrinsic load (background required +learn), germane load (mental effort to link new to old), and +extraneous load (everything else that distracts from learning). +(this is “cognitive load theory”)

  • +
  • A paper claimed that self-guided learning is less effective, because +people are overloaded: you have to both learn new facts and learn +how to use them at the same time.

  • +
  • Strategies: use exercises well that minimize tho load. a) parsons +problems, b) labeled subgoals, c) split attention (separate +channels, but complimentary rather than redundant), d) minimal +manuals

  • +
+
+
+

Ch5: Individual learning

+

(chapter about how people can help themselves)

+
    +
  • Six strategies: a) spaced practice, b) retrieval practice, c) +interleaving (abcbac better than aabbcc), d) elaboration (explain to +self), e) concrete examples, f) dual coding (e.g. words and +pictures, or different forms of same material).

  • +
  • Manage time well

  • +
  • Peer assessment

  • +
+
+
+

Ch6: A lesson design process

+
    +
  • Backwards lesson design, similar to test-driven development: 1) +brainstorm ideas for what to cover, 2) create learner personas to +figure out who you want to teach, 3) create formative assessments to +give learners a chance to exercise what they are trying to learn +(3-4 per hour), 4) put formative exercises in order, 5) write the +teaching material around this.

  • +
  • Learner persons, to guide your design process: a) general +background, b) what they already know, c) what they think they +want to know, d) how course will help, e) special needs.

  • +
  • Learning objectives: write objectives and think of what depth of +understanding you are getting too. Consider Bloom’s taxonomy: a) +remember, b) understand, c) apply, d) analyze, e) evaluate, f) +create.

  • +
  • Fink’s taxonomy (unlike Bloom’s, complimentary not hierarchical): a) +foundational knowledge, b) application, c) integration, d) human +dimension, e) caring, f) learning how to learn.

  • +
  • Maintainability: is it easier to update than replace? a) You have to +document the lesson design process, b) technical collaboration, c) +are people willing to collaborate? Or do teachers resample rather +than update?

  • +
+
+
+

Ch7: Actionable approximations of the truth

+

(chapter about learning programming specifically… title comes from +not necessarily having clear research that says what you should do, +but you have to do something anyway)

+
    +
  • Experts know what and how, novices lack both but most teachers +focus on what only.

  • +
  • Think about teaching debugging and using it as examples - the how.

  • +
  • If you are teaching programming specifically, just read the +chapter.

  • +
+
+
+

Ch8: Teaching as performance art

+
    +
  • Get feedback on your teaching. People aren’t born teachers, and +feedback isn’t in the western teaching culture enough.

  • +
  • Use live coding. It’s much more effective, especially because it’s +two way and you can demonstrate making mistakes. a) embrace your +mistakes, b) ask for predictions, c) take it slow, d) be seen and +heard (stand + microphone), e) mirror your learner’s environment, f) +use the screen wisely (make it big enough), g) double devices (one +to present, one for notes), h) use diagrams, i) avoid distractions, +j) improvise after you know the material, k) face the screen only +occasionally

  • +
  • Drawbacks of live coding, which you can minimize over time: a) going +too slow, b) exercises can be too deep and have too much cognitive +load (give skeleton code).

  • +
+
+
+

Ch9: In the classroom

+
    +
  • Code of conduct: teaching isn’t for those that are already “in”, +it’s for those that aren’t. If you don’t notice problems and +enforce it transparently, it means nothing though.

  • +
  • Peer instruction. Discuss in groups. e.g. multiple choice +question, if there is a wide variety of wrong answers, have them +discuss in groups.

  • +
  • Teach teaching: different strategies, consider what you want to do: +a) teach teaching (taking turns) b) teach and assist (going around +helping) c) alternative teaching (group with more specialized +instruction), d) teacher and observer, e) parallel teaching (two +groups, same material), f) station teaching (rotate through +stations).

  • +
  • If co-teaching, plan ahead: a) confirm roles at start, b) work out +some hand signals for common conditions, c) each person should talk +at least 10-15 min at a time, d) person who isn’t teaching shouldn’t +distract, though leading questions OK, e) check what your partner +will teach after you are done, f) inactive teacher stays engaged, +not doing own stuff.

  • +
  • Plan for mixed abilities, especially false beginners who have +studied the material before.

  • +
  • Can you make a collaborative not online document?

  • +
  • Sticky notes

  • +
  • Don’t start from blank pages, give some starting point. +Many other good points in the chapter +itself.

  • +
+
+
+

Ch10: Motivation and demotivation

+
    +
  • Extrinsic vs intrinsic motivation. Extrinsic: have to do it for job +or something. Intrinsic: do it for self, you want to encourage +intrinsic motivation. Drivers of intrinsic motivation: a) +competence, b) autonomy, c) relatedness (connection to others).

  • +
  • Consider usefulness and time to master. Focus on useful and fast. +Useful = authentic tasks, things people will actually use.

  • +
  • Avoid demotivation: for adults, a) unpredictability, b) +indifference, c) unfairness. Specific examples: a) contemptuous +attitude, b) saying existing skills are worthless, c) complex or +detailed technical discussion, d) pretending you know more than +they do, e) the word “just” as in, it’s “just easy”, f) software +installation problems, g) giving impossible challenges to fail at to +try to learn something, if not understanding.

  • +
  • Consider accessibility and inclusivity - consider things are harder +for others, try to understand diversity of backgrounds.

  • +
+
+
+

Ch11: Teaching online

+
    +
  • Disadvantage of MOOCs: can’t clear up individual misconceptions

  • +
  • The chapter has various good ideas, including how to make sure +everyone is heard (certain group doesn’t dominate online +discussions), short cycles and short exercises, require some small +group work, use videos to engage rather than instruct (people can +read faster), identify and clear up misconceptions early.

  • +
  • Flipped classroom: watch lectures on own time, do exercises and +discuss in class time.

  • +
+
+
+

Ch12: Exercise types

+
    +
  • Multiple choice, code yourself, code+multiple choice, inverted +coding (given code, test and debug), fill in the blanks, Parsons +problems (given questions but in wrong order).

  • +
  • Tracing execution, tracing values, reverse execution (find input for +output), minimal fix, theme and variations, refactoring exercise. +Pen and paper exercises.

  • +
  • Diagrams and connection: draw diagram, label diagram, matching +problems.

  • +
  • Autograding is hard, in particular most automatic grading tools +don’t provide useful feedback messages. Also, automatic grading can +only test low-level skills, not higher abstractions like code +review.

  • +
+
+
+

Ch13: Building community

+

(Chapter about forming a community of teachers and learners working +together)

+
+
+

Ch14: Marketing

+
    +
  • Think about what you are offering to who. Who are the target +audiences and why should they be care and become invested?

  • +
+
+
+

Ch15: Partnerships

+
    +
  • Main two points are work within schools or outside of schools. If +inside, part of academic programs? Academic programs and especially +teachers change very slowly.

  • +
+
+
+

Ch16: Why I teach

+

(A note from the author)

+
+
+
+
+
+

CodeRefinery Zulipchat

+

The CodeRefinery zulipchat is +where our primary discussion, planning, and action takes place. Many +things are announced only via zulipchat. This is a public chat and +everybody is welcome to join, no invitation needed, and we explicitly +invite anyone to give ideas in any thread.

+

The chat is a joint community of CodeRefinery (teaching), NordicHPC +(infrastructure), and Nordic-RSE (usage and software), which are other +Nordic projects about scientific computing which share some of the +same people. Together, we have a network of all aspects of modern +scientific computing.

+

Unlike Slack, zulipchat is very heavily threaded, and it is easy to +follow along without being active all the time. Respond within the +topic (=thread) that is relevant, or make a new thread. Sometimes you +can find old threads to revive. Don’t worry, everything is flexible +and you’ll quickly learn by watching (and don’t worry about going +wrong).

+
+

Streams

+

Once you join the chat, you will be subscribed to some default +streams (a stream is basically a channel). The first thing you +should do is join some more streams, depending on your interest. Join +more streams by clicking gear icon by the steams list on the left side +on that chat, then selecting what you are interested in.

+

Gear icon to join a stream

+

If you mute a stream, you can see the contents if you click on it, +but you won’t get notifications. If you mute a topic, it will be +hidden from view but you can later unmute it in your personal +settings. Under stream settings, you can request email notifications +for all messages in a certain stream (possibly useful for the announce +streams).

+

CodeRefinery streams:

+
    +
  • #general: Any topic and random chat (including for the other +projects below)

  • +
  • #coderefinery: About the project itself. CodeRefinery members +should be in this channel.

  • +
  • #carpentries: About Carpentries or CodeRefinery as a Carpentries +lesson program.

  • +
  • #lessons: CodeRefinery lesson discussion, one for each lesson we +maintain.

  • +
  • #workshops: Organizing workshops and other events. One topic +for each event.

  • +
+
    +
  • One stream for coordinating each major workshop that requires a lot +of chat, for example #tools-workshop (the standard workshop), +python-for-scicomp, kickstart-aalto, etc.

  • +
+
    +
  • #workshop-chat: High-volume staff chat during workshops. You +typically join during a workshop, and leave when done to avoid the +flood.

  • +
  • #help: Ask questions and get advice from others. Tell +interesting things you learned via “TIL”s

  • +
  • #new members: Feel free to introduce yourself here

  • +
  • #announce:

  • +
  • #infrastructure: CodeRefinery +gitlab talk.

  • +
+

Nordic research software engineer community:

+ +

Nordic HPC:

+
    +
  • #NordicHPC: NordicHPC. +Discussion about computing infrastructure (not just HPC)

  • +
+

Misc streams in our sphere of influence:

+ +

You can make topical private streams for groups that significantly +overlap with our community. Currently, Zulip admins can’t add +themselves or others to private streams.

+
+
+

Clients

+

Zulipchat can be used in a web browser, there’s a desktop app, mobile +apps, and even a terminal client installable using pip.

+
+
+

Reacting and voting

+

We want everyone to take part in chat and express their thoughts, but +of course people don’t want to give pointless agreeing replies (but +you can always welcome to do that, too). So, we encourage everyone to +use reactions in cases they want to express agreement/disagreement but +not so much they want to send a message. Common reactions you might +see are 👍, 👎 (thumbs up/down, agree with general sentiment), 🐙 +(:octopus:, awesome/amazing/ace), and well, plenty more that are +obvious.

+

We also use reactions to express some idea of a more concrete +vote, to empower people to take an action (otherwise, it is +difficult to get a decision on anything). This is not formal or +necessarily binding (so it’s not really a vote), but a useful +intermediate system for a young project. If you see a message +proposing something and you want to say, in no uncertain terms, “I +think you should do that” or not, let us know by the following:

+
    +
  • ↔️ (+0, :left_right:: I see this and am neutral.

  • +
  • 🔼, 🔽 (+1, -1, :upvote:, :downvote:) or similar: I +agree/disagree with this.

  • +
  • ⏬, ⏫ (+2, -2, :double_up:, :double_down:): I agree/disagree +with this and am willing to work on making it happen/finding an +alternative.

  • +
+

If you want to do something, ask for opinions, and a reasonable time +later it seems the sentiment is positive, consider yourself empowered +to do it. If you are voting, feel free to be creative with emojis or +numbers, but realize that other reactions may not be so explicit. Note +that if you are negative, you should explain why or alternatives, +otherwise your opinion may not be weighted so much. The person doing +the thing decides what to do (and this is open source: we find a way +for everyone to do what they need to do).

+

Do you think you aren’t important enough to vote? That’s wrong, +because we are usually interested in the thoughts of outsiders. We +can see who voted and use that to weight our decision if needed.

+
+
+

Privacy

+

All activity (except private steams) should be considered public, and +the data controller is zulipchat.com. Zulip admins can’t add +themselves or others to private streams, but still: there is no +contract guaranteeing confidentiality.

+
+
+
+

Contributing to CodeRefinery

+

CodeRefinery is an open-source project. All our work is open, and we +accept any type of contributions: there is a lot more than instructing +to run a successful workshop. Also, CodeRefinery is really more of a +group of like-minded people than one particular plan, so you are +welcome to join just to hang out and share ideas.

+

If you aren’t sure you are ready for more, you can always lurk in the chat +(passively watch our community) and become more active when you feel +the time is right.

+

These manuals (and in general, other guides we have) describe the +past, not (only) the future. They are made so that new people can +know what we typically have done, so they can work on the future (even +if it’s different).

+

A good way to get started is to take the lead of some workshop (doing +it like it was before), then do it again with your own improvements.

+
+

How to take part

+
    +
  • Join the CodeRefinery chat, give comments or submit +emoji reactions to show how you feel about things. Many things are +announced only through the chat.

  • +
  • Come to our +meetings- the +monthly community calls are for a broad audience, but anyone is +welcome come to the weekly meetings.

  • +
  • Attend a CodeRefinery workshop - they teach the very tools we use to +collaborate!

  • +
+
+
+

Action: Join our “community teaching training”

+

CodeRefinery isn’t just about doing teaching ourselves, but improving +your teaching. Whether you focus on teaching, or it’s a side-activity +to your other tasks, the CodeRefinery (online) teaching can help you +avoid re-inventing good practices and prepare you for teaching +together.

+

Read more: Community +teaching training

+
+
+

Action: Advertise and/or help out in our online courses

+

CodeRefinery runs many open, online courses, which anyone can attend. +Some of them can be attended by anyone via livestream, even without +registering (yes, this really works - we get high ratings for this). +You could simply advertise our courses, or go even further and run +local breakout rooms.

+

Take it a step further and help out with the course, whether it’s as +an instructor, helper, or some other role. Of course, anyone is +welcome to help, even without advertising the courses!

+

Read more: Local breakout rooms and Roles overview.

+
+
+

Action: Teach openly and allow others to join

+

Go to the next level and adopt CodeRefinery strategies for your own +courses, so that others can join at little cost to yourself. By +opening, you start to find more lesson developers and instructors, so +that your courses can reach the next level of quality and impact. +Soon, you will wonder why you ever bothered teaching alone.

+

Read more: Open your courses to others

+
+
+

Other types of contributions

+

As an open project, there are any number of ways you can contribute:

+
    +
  • Take on any of the roles in a workshop - with +co-teaching, it is surprisingly easy to go straight to instructor, +but there are also many other roles.

  • +
  • Help with lesson maintenance (read and make suggestions) or become a +maintainer of a lesson. Watch GitHub repositories to get notified +of issues and pull requests, and help review. Anyone can watch any +repository, and comments from outsiders do help us review things faster.

  • +
+
+
+
+

Local breakout rooms

+

Some CodeRefinery courses are designed to be large scale, with +distributed registration. In short, this means there is a livestream +that anyone in the world can watch. Since we can’t handle a +registration and personal support for everyone in the world, you can +open registration to attend the course.

+
+

Principles

+
    +
  • We have a livestream, open to everyone in the world. The +CodeRefinery MOOC strategy strategy allows us to reach a huge audience +in a decentralized manner.

    +
      +
    • If courses don’t have a livestream, we can still reach many people +because of HackMD and teams. From the list below, steps 2b and 2c +work with this option.

    • +
    +
    +_images/mooc-diagram.png +

    Decentralized teaching allows us to reach many more people than +we could otherwise.

    +
    +
  • +
  • Most attendees can ask from help through HackMD +(Collaborative document mechanics and controls), which works very well

  • +
  • There are periodic exercise sessions, where learners and teams can +work together.

  • +
+
+
+

Step 1: Local breakout room

+
    +
  • Create your own breakout room - whether online or a physical space. +That means for example ask some friends to join you to watch the stream +and collaborate with the exercises.

  • +
  • Our exercise sessions are very clearly announced and communicated. +During these times, the livestream goes silent, and you can work +within your breakout rooms. The end of the exercise sessions and +breaks are clearly communicated as well - we support your breakout +room scheduling as much as possible.

  • +
  • Attendees can ask general questions via HackMD

  • +
  • You can continue your local support even after the course.

  • +
  • You may want to run local “installation help” sessions.

  • +
+
+
+

Step 2: Registration

+
    +
  • If you have a broad audience, you may want to make your own +registration form, completely separated from ours. That may help +with reservations and catering if any.

  • +
  • Please have everyone to register in our form anyway +to help us in reporting our impact.

  • +
  • You may (but don’t have to) create teams, where you have one +team leader for 5-6 learners. The team leader guides the +team and supports collaboration and community - and lets us scale +much better than we could otherwise. Teams also support retention +after the course, especially if they knew each other before +registering. (See Team leaders / Helpers / Exercise leaders)

  • +
  • We would like to know statistics from how many people attended from +your location for our impact reports. (still, the top priority is +reaching as many people as possible, we’ll adjust reporting to what works)

  • +
+
+
+

Step 2b: Joint registration

+
    +
  • You can direct people to our registration form as a matter of +simplicity, but we add an option for your institution.

  • +
  • Learners join our Zoom session, and we create a breakout room for +your institution and direct all learners there.

  • +
  • Since you provide help to your own learners, we can more easily +scale than we could otherwise.

  • +
+
+
+

Step 2c: Joint registration, you provide team leaders for your teams

+
    +
  • A lot like “joint registration”, but for workshops where we +centrally organize teams.

  • +
  • You locally recruit team leaders for your +own learners. This saves us the effort of recruiting exercise +leaders and allows us to scale more.

  • +
+
+
+

Summary

+

As you can see, there are many models, from distributed and simple to +centralized. It’s best to talk in chat and see what will work best +for each workshop, but we are generally biased towards more +decentralized approaches for large courses.

+
+
+
+

Open your courses to others

+

CodeRefinery strategies allow you to reach a larger audience without +much extra work from you. Once you open to other attendees, you also +naturally get co-instructors who want to help improve your material. +This allows you to reach the next level of quality and impact, even +for your own local audience.

+
+

Principles

+
    +
  • Thanks to the CodeRefinery MOOC strategy, +you can easily reach more people than you could otherwise.

  • +
  • It may seem hard, but there are many small steps to take and you can +gradually scale up.

  • +
+
+
+

How-to

+
    +
  • Learn by example: attend our courses, advertise our courses, and +volunteer, too.

  • +
  • Read all of the manuals here - we try to document everything we +can, but they are always going to be a work in progress.

  • +
  • Attend our community teaching +training to +network with others and learn from the experts.

  • +
+
+
+
+

About CodeRefinery

+
+

History

+

CodeRefinery began as a Nordic e-Infrastructure Collaboration (NeIC) +based off of some previous workshops at the KTH, Stockholm. The first +round of funding was from 2016 - 2018, and a second round is going from +2018-2021. Thus, so far, it has always had some paid staff (each up +to 0.5 full-time equivalent of their primary jobs). Most of these +staff are from some sort of computing center.

+

Over time, it has evolved into a more open project direction.

+
+
+

Governance

+

There is a steering group within NeIC which governs the CodeRefinery +project. However, strictly speaking that mainly covers activities done +via NeIC funding. The materials and open-source project is open to all.

+

There are currently no formal decision making processes. Typically, +decisions related to some repository go through the process of…

+
    +
  • Submit an issue or pull request

  • +
  • Discuss in the issue and/or

  • +
  • Discuss in a CodeRefinery team meeting

  • +
  • If there is rough consensus, then commit it.

  • +
+

In general, most decisions (of the open project) result in some sort +of commit in git. If the reaction is positive in a CodeRefinery +meeting, then it’s accepted. (Most day-to-day things aren’t discussed +in the meetings, only major things affecting the whole project.) +In general, if you are open and discuss, then do what will improve the +project for you.

+
+
+

Communication methods

+

This is an exhaustive list of our communication methods

+
    +
  • CodeRefinery zulipchat

  • +
  • CodeRefinery team meetings (announced in zulipchat)

  • +
  • Team email list (in practice, only used for calendar invites)

  • +
  • Github repositories issues and pull requests

  • +
+
+

Chat

+

Zulipchat is our primary means of communication. Subscribe to +at least the #coderefinery, #lessons, and #workshops, #general, #announce, and +#help channels to fully integrate to the CodeRefinery side of things.

+
+
+

Team meetings

+

These tend to happen every ~2 weeks. Mainly, we discuss NeIC project, +workshop organization matters, and how to organize ourselves. Most +work on actual lessons happens in Github issues.

+

You can find upcoming meetings by TODO.

+
+
+

Github

+

We are focused around the material we make, and for that, most +discussion happens in Github issues. For more abstract discussion on +lessons, there is a topic in the #lessons chat corresponding to each +lesson.

+
+
+
+

Decisions

+

There is no formal process of decisions. It should be brought up in +chat, then brought up in a meeting. In the meeting, be very clear +about what you need a decision or advice on.

+
+
+

Core team

+

There is currently no formal “core team” - only those who are most +active. If you hang around, contribute a lot, you will end up being +seen as “core”.

+
+
+

Joining

+

There is currently no formal joining process. Take part, and +contribute as you would like.

+

The usual way of joining would be to decide how CodeRefinery has to +adapt to serve your needs, and start proposing ways to do that. +Reading existing pull requests and giving a comment of “approve” is a +great way to get noticed.

+
+
+
+

CodeRefinery governance

+
+

CodeRefinery Community

+

Right now, the CodeRefinery community is small, so we do not want to +make things very formal. However, we expect things to formalize in +proportion to its need.

+

In short:

+
    +
  • Team meetings are approximately once a week. Rough consensus is +used to make decisions. Read more: +https://coderefinery.org/organization/meetings/

  • +
  • Important decisions should also be announced and discussed via chat +in advance, and ideally at several meetings.

  • +
  • Because this is a small project, the deciding factor is “what does +someone want to do?”. Meetings provide a way to empower people to +take action which may otherwise be hard to find in asynchronous +chat, despite the voting.

  • +
  • The monthly “Community calls” allow us to get a perspective of a +broader audience and bring in new members.

  • +
  • This document will be updated (by pull request+discussion) as we +improve our governance in the future.

  • +
+

In the future:

+
    +
  • An advisory role could to taken on by some sort of community council +or board made up of partner representatives and community +representatives.

  • +
+
+
+

NeIC project

+

The Nordic e-Infrastructure collaboration funds a +part of CodeRefinery, and with that comes a certain standard of +governance and reporting +(see also the collaboration agreement). +However, we consider this to be in parallel +to the community project (with the community project being more +important).

+

There is a lot of overlap between the NeIC-sponsored staff and the +community, but the community will increase in proportion over time.

+
+
+
+

Outreach plan

+

This is a prototype the CodeRefinery outreach and marketing plan.

+

Since most of us are not very good at marketing, this is actually a +summary of the book The new rules of marketing and PR : how to use +content marketing, podcasting, social media, AI, live video, and +newsjacking to reach buyers directly (David Meerman Scott, 8th ed.) +with descriptions of how it can apply to CodeRefinery. The book is +available at my university’s O’Reilly Online Learning platform through +our library for free. If you like what you read here, consider +checking it out - the book was a very good inspiration for someone +that needs to outreach better, but is not at all that kind of person +and needs some inspiration for how to even think about it.

+

Perhaps this summary is useful to others outside of CodeRefinery as +well.

+

Currently, this page is one person’s description and their own +interpretation9 as it applies to CodeRefinery. Over time, it should +be adapted to represent a broader view, this paragraph updated, +possibly the current content archived, and the new plan made into a +new page.

+
+

Introduction

+

Many people need marketing and outreach: CodeRefinery isn’t trying to +sell things, but we are trying to encourage people to make a choice to +gain skills. It’s free, but it does have a cost: time. We think that +it does save more time in the long run, but then again, how many +businesses sell things that will save money in the long run?

+

We need to encourage people to make a specific choice, and we need to +tell them why we think that is the best choice for them.

+
+
+

1 The Old Rules of Marketing and PR Are Ineffective in an Online World

+

“Interruption advertising” doesn’t work (anymore?). Few people want +to have their life interrupted with a TV commercial, banner ad, or +email from university administrators telling them to make some +choice. People think of different things now.

+

For CodeRefinery, you could argue that flyers, emails from university +staff, etc. are all some form of interruption advertising.

+

There’s all kind of anecdotes about how advertisement, mentions in the +press, and so on aren’t useful, but we wouldn’t do those anyway. +Although, we do want press, that’s not the main way we get people to +take our courses. (maybe it helps our funding, though)

+
+
+

2 The New Rules of Marketing and PR

+

People do, however, take recommendations from people they know. Social +media lets people communicate. The match is clear. By making good +use of social media, we can reach people directly.

+

(this chapter starts off with an example of social media inspiring the +author to visit Saariselkä in Finnish Lapland, which was interesting +to see.)

+
+
+

3 Reaching Your Buyers Directly

+

Social media lets people reach buyers directly. This is obvious.

+

But, how to use social media. You don’t want to go doing interruption +advertising, trying to use it to directly sell your stuff. Instead, +produce good, free content which people will want to consume. Most of +your activity should be about this, which gets people interested, and +makes them want more. Then, when they want to go deeper or are ready +to make a purchase, they come to you.

+

CodeRefinery does nothing but make free content, so how does this +apply to us? Well, we have to think more. Our main content costs a +lot of time, so we need to think of content that is shorter and easier +to consume. For example:

+
    +
  • Short videos or pictures explaining things.

  • +
  • Short blog posts about tips or tricks, which have a clear, catchy, +immediately useful title.

  • +
  • Tweeting links to specific pages we have just made, which are +especially useful standalone.

  • +
  • Short “git hacks” or clever things, which people like and share, and +makes them want to attend a workshop.

  • +
  • “Research software minute” videos?

  • +
+

You have to think of buyer personas - backwards design all of your +material. Don’t make anything unless you know who it is for, and then +make sure it is suitable for that person. Know their goal, how they +speak, and where they are (what content do they consume?).

+

CodeRefinery buyer personas could include:

+
    +
  • Learners

  • +
  • team leaders

  • +
  • Group leaders or university staff who can recommend their audience +to attend a workshop

  • +
  • Prospective instructors and helpers

  • +
  • Funders and high-level leadership

  • +
+
+
+

4 Social Media and Your Targeted Audience

+

Descriptions of what social media is. A somewhat useful metaphor is +that the web is like a city. Social media are things like bars or +cafes. You don’t go there and start asking people to do something or +offering free samples and expect people to like it. You network, +talk, maybe tell some interesting stories. Maybe someone figures out +who you are and would want to know more about what you do.

+
+
+

5 The Content‐Rich Website

+

Websites matter - people will go there and check it out. Blogs are +good, they last longer than any single social media operator and +provide long-term web traffic. Websites (and everything) need +specific skills and a manager. The website needs a personality and +voice.

+

CodeRefinery should make sure that there is are clear target pages or +sections for each of our target personas below. We should make sure +we don’t use jargon that we would use, or have the website organized +by our own operations as opposed to learner personas. We should also +make sure the website is accessible and mobile-friendly.

+
+
+

6 Marketing and PR in Real Time

+

Following social media in real time can let you know what people +think. This can be an even better feedback method than surveys, etc. +By responding in real time (this can take effort), you can have +conversations there (in the open) which is also very good for +outreach.

+

CodeRefinery could consider monitoring more of social media. TODO: +how to do this?

+
+
+

7 Artificial Intelligence and Machine Learning for Marketing and PR

+

We know about AI and so on. We also know it’s not magic. There were +discussions about using AI to generate some content, such as tweets +from web pages.

+

I didn’t see much useful for CodeRefinery here, however some ideas +(run our webpages through a text summarizer to get the most important +sentences to help us make tweets) might be useful.

+
+
+

8 You Are What You Publish: Building Your Marketing and PR Plan

+

This is the chapter that puts everything above together, before it +goes off into details of the implementation next.

+
    +
  1. Understand what we want. Until a goal is clear, it is hard to +justify the effort (and also, I guess ask for others help do +it). (CR: we could say “better science” but it can also mean things +like “attend workshops” or “ensure funding for the project”)

    +
      +
    • More registrations?

    • +
    • More followers?

    • +
    • More views of videos?

    • +
    • More funding?

    • +
    • More team leaders?

    • +
    +
  2. +
  3. List the buyer personas relevant to us. (See chapter 3 for the list)

  4. +
  5. Create a persona around each of these buyers. (CR: see chapter 3 +above for the details).

    +
      +
    • What are their goals?

    • +
    • What do we want them to do?

    • +
    • What content do they consume?

    • +
    • How do they make their buying choices? (CR: how do you decide how +to spend your time?)

    • +
    • How do they speak, talk, and read?

    • +
    • Subscribe to and follow the media they follow.

    • +
    +
  6. +
  7. Develop (free) content that interests each of these buyers.

  8. +
  9. Develop a measuring plan. Think about how we can measure success, +both in immediate engagement and making the decision we want (what +we actually want).

  10. +
+
+
+

9 Growing Your Business: How Marketing and PR Drive Sales

+

Salespeople don’t mediate between buyers and companies anymore. +Instead, people can find so much information themselves, and make +purchases self-service. Websites and other material have to be target +to buyers (= potential learners) who are deciding if they want to +purchase (= attend a course). Websites and material should have a +personality (= our website shouldn’t be written as boring as a +scientific paper). It’s OK to do fun things. Social aspects to the +site is good - e.g. comments section, social media share buttons.

+
    +
  1. Begin with informational content (not necessarily about you).

  2. +
  3. Nudge towards what you want (= attend a course, etc.)

  4. +
  5. Make it easy to close the deal. (CR: clear “notify me” mailing list +link on every relevant page. Maybe even make sure we have +continually open registration for the next workshop - each workshop +is ready for registration when the previous one ends. When we have +multiple types of workshops, includeable html snippets that has links +to register for every upcoming workshop?)

  6. +
+

Don’t underestimate the value of figurehead leaders (~=CEOs) being +social - don’t just delegate it to separate marketers.

+

Is the analogy of salespeople even relevant for CodeRefinery? +Probably not, but maybe we could say that official requirement, +recommended courses, university staff aren’t so important. People +will check our websites and other material to see if they want to +attend.

+

Every website, lesson, and so on has to have very clear information +targeted to a possible reader right at the beginning, so that a +potential learner might see “is this git lesson right for me?” and +they will find “yes”.

+

Our website should be current.

+
+
+

10 Strategies for Creating Awesome Content

+

This section has different strategies and types of content. Types of +content include: blogs, audio, video, photos, infographics, charts, +email newsletters, presentations, long-form written content, research +reports, virtual events, e-books, white papers, apps.

+

Think about how you make the content: don’t just write about +yourself. Consider the problems your buyers face and make content +that solves those problems. Write for your personas. Advertise what +you do. Think what could possibly go viral. Don’t forget that it +should be accessible.

+

CodeRefinery: in addition to the above, we should take part in other +events, for example show up at Open Science days and give +presentations, various awareness weeks (in person or online?), +conference hashtags, etc.

+
+
+

11 How to Write for Your Buyers

+

Write like your buyers talk (we’ve said this before), and don’t use +pointless jargon or meaningless words to make you sound smarter. +Humor is OK. Think like a journalist (especially for some content +types).

+
+
+

12 Social Networking as Marketing

+

Facebook pages, Facebook groups. Linkedin profiles, companies, etc. +There are many more, but think about what is right for you, don’t do +something just because it is there. Consider your personal brand - +make sure your profile information says something. There is a +recommendation 85% sharing and engaging, 10% original content, 5% +promoting yourself. Social media is like exercise: you need to make +it part of your routine, or you will stop doing it. It can easily +take an hour per day.

+

For CodeRefinery, we know we should be more active on Twitter, which +seems like the most suitable network for us. Are there any types of +badges we can use for professional social networks? Can we declare +hashtags and publish them on our website permanently, so we don’t have +to decide them for every workshop?

+

Most people in CodeRefinery seem to be hesitant to use social network +sites heavily, for good reason. We should really encourage and +support those who do want to use them to do so on our behalf, as much +as possible.

+
+
+

13 Blogging to Reach Your Buyers

+

Blogs are very important - and unlike social networks, they stay under +your control long-term, and drive search traffic straight to you. +Consider who you want to reach - potential learners? existing +learners? other thought leaders? Blog about things that they are +interested in and you are passionate about.

+

Don’t forget to monitor other blogs from people who do similar things, +to keep up to date with what is going on. Comment on other blogs and +link back to you. Invite other bloggers to visit you and blog about +their experiences - this is good for both of you.

+

CodeRefinery probably knows that it should blog more. Some ideas +about what to blog about are in previous sections. We should make it +easier to share posts, and would we even want to try for a commenting +feature (might be too much, though…).

+
+
+

14 An Image Is Worth a Thousand Words

+
+
+

15 Video and Your Buyers

+
+
+

16 Audio Content via Podcasting and Social Audio

+
+
+

17 How to Use News Releases to Reach Buyers Directly

+
+
+

18 Your Newsroom: A Front Door for Much More Than the Media

+
+
+

19 The New Rules for Reaching the Media

+
+
+

20 Newsjacking Your Way into the Media

+

(I haven’t fully read this chapter yet)

+

The idea here is that when something interesting to your audience and +relevant to you comes up in the news, react to it / contribute +something to it, perhaps preferably in a way that can be re-shared. +Or in a way that other journalists. Be careful, don’t do this +dis-respectfully or spammily.

+

In CodeRefinery, different things in the science news could be +relevant to react to.

+
+
+

21 Search Engine Marketing

+
+
+

22 Make It Happen

+
+
+
+

Download this guide as single-page HTML, +pdf, or +epub.

+

All material within this repository is licensed CC-BY.

+
+ + +
+
+
+ +
+ +
+

© Copyright 2018-2023, The CodeRefinery team.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/_builds/singlehtml/objects.inv b/_builds/singlehtml/objects.inv new file mode 100644 index 00000000..0fbbe5ec Binary files /dev/null and b/_builds/singlehtml/objects.inv differ diff --git a/_images/breakout--exercises.png b/_images/breakout--exercises.png new file mode 100644 index 00000000..0c9171bf Binary files /dev/null and b/_images/breakout--exercises.png differ diff --git a/_images/chat--join-stream.png b/_images/chat--join-stream.png new file mode 100644 index 00000000..ae277c6b Binary files /dev/null and b/_images/chat--join-stream.png differ diff --git a/_images/chat.jpg b/_images/chat.jpg new file mode 100644 index 00000000..7caf1aaf Binary files /dev/null and b/_images/chat.jpg differ diff --git a/_images/clock.jpg b/_images/clock.jpg new file mode 100644 index 00000000..8013fe84 Binary files /dev/null and b/_images/clock.jpg differ diff --git a/_images/exercise_options.png b/_images/exercise_options.png new file mode 100644 index 00000000..e756d9e8 Binary files /dev/null and b/_images/exercise_options.png differ diff --git a/_images/green.jpg b/_images/green.jpg new file mode 100644 index 00000000..bee26a0b Binary files /dev/null and b/_images/green.jpg differ diff --git a/_images/hackmd--archivelink.png b/_images/hackmd--archivelink.png new file mode 100644 index 00000000..70e76639 Binary files /dev/null and b/_images/hackmd--archivelink.png differ diff --git a/_images/hackmd--controls.png b/_images/hackmd--controls.png new file mode 100644 index 00000000..46a74c75 Binary files /dev/null and b/_images/hackmd--controls.png differ diff --git a/_images/hackmd--during-break-and-poll.png b/_images/hackmd--during-break-and-poll.png new file mode 100644 index 00000000..266016ea Binary files /dev/null and b/_images/hackmd--during-break-and-poll.png differ diff --git a/_images/hackmd--full-demo.png b/_images/hackmd--full-demo.png new file mode 100644 index 00000000..0988b6f2 Binary files /dev/null and b/_images/hackmd--full-demo.png differ diff --git a/_images/hackmd--questions.png b/_images/hackmd--questions.png new file mode 100644 index 00000000..a4b88456 Binary files /dev/null and b/_images/hackmd--questions.png differ diff --git a/_images/hackmd--questions2.png b/_images/hackmd--questions2.png new file mode 100644 index 00000000..a6091991 Binary files /dev/null and b/_images/hackmd--questions2.png differ diff --git a/_images/hand.jpg b/_images/hand.jpg new file mode 100644 index 00000000..242c2f6f Binary files /dev/null and b/_images/hand.jpg differ diff --git a/_images/instructor-tech-online/IMG_20211021_140148_DRO.jpg b/_images/instructor-tech-online/IMG_20211021_140148_DRO.jpg new file mode 100755 index 00000000..b7d37818 Binary files /dev/null and b/_images/instructor-tech-online/IMG_20211021_140148_DRO.jpg differ diff --git a/_images/instructor-tech-online/IMG_20211025_121909_DRO-labeled.jpg b/_images/instructor-tech-online/IMG_20211025_121909_DRO-labeled.jpg new file mode 100644 index 00000000..ced49795 Binary files /dev/null and b/_images/instructor-tech-online/IMG_20211025_121909_DRO-labeled.jpg differ diff --git a/_images/instructor-tech-online/IMG_20211025_121909_DRO.jpg b/_images/instructor-tech-online/IMG_20211025_121909_DRO.jpg new file mode 100755 index 00000000..3b0b7300 Binary files /dev/null and b/_images/instructor-tech-online/IMG_20211025_121909_DRO.jpg differ diff --git a/_images/instructor-tech-online/instructor.png b/_images/instructor-tech-online/instructor.png new file mode 100644 index 00000000..718f2a89 Binary files /dev/null and b/_images/instructor-tech-online/instructor.png differ diff --git a/_images/instructor-tech-online/learner-largescreen.png b/_images/instructor-tech-online/learner-largescreen.png new file mode 100644 index 00000000..3b6d2cdd Binary files /dev/null and b/_images/instructor-tech-online/learner-largescreen.png differ diff --git a/_images/instructor-tech-online/learner-normal.png b/_images/instructor-tech-online/learner-normal.png new file mode 100644 index 00000000..590135e5 Binary files /dev/null and b/_images/instructor-tech-online/learner-normal.png differ diff --git a/_images/instructor-tech-online/learner-small.png b/_images/instructor-tech-online/learner-small.png new file mode 100644 index 00000000..5d5f4216 Binary files /dev/null and b/_images/instructor-tech-online/learner-small.png differ diff --git a/_images/instructor-tech-online/screenshare-fullhd.png b/_images/instructor-tech-online/screenshare-fullhd.png new file mode 100644 index 00000000..eda9d42d Binary files /dev/null and b/_images/instructor-tech-online/screenshare-fullhd.png differ diff --git a/_images/instructor-tech-online/screenshare-jupyter.png b/_images/instructor-tech-online/screenshare-jupyter.png new file mode 100644 index 00000000..1e7bb5cf Binary files /dev/null and b/_images/instructor-tech-online/screenshare-jupyter.png differ diff --git a/_images/instructor-tech-online/screenshare-rsh.png b/_images/instructor-tech-online/screenshare-rsh.png new file mode 100644 index 00000000..1bbb1ccc Binary files /dev/null and b/_images/instructor-tech-online/screenshare-rsh.png differ diff --git a/_images/instructor-tech-online/screenshare-vertical.png b/_images/instructor-tech-online/screenshare-vertical.png new file mode 100644 index 00000000..28e18b06 Binary files /dev/null and b/_images/instructor-tech-online/screenshare-vertical.png differ diff --git a/_images/instructor-tech-online/zoom-portion-of-screen.png b/_images/instructor-tech-online/zoom-portion-of-screen.png new file mode 100644 index 00000000..79d88e7e Binary files /dev/null and b/_images/instructor-tech-online/zoom-portion-of-screen.png differ diff --git a/_images/instructor.png b/_images/instructor.png new file mode 100644 index 00000000..718f2a89 Binary files /dev/null and b/_images/instructor.png differ diff --git a/_images/layout--instructor-complex.png b/_images/layout--instructor-complex.png new file mode 100644 index 00000000..ea436204 Binary files /dev/null and b/_images/layout--instructor-complex.png differ diff --git a/_images/layout--learner-hackmd-discussion.png b/_images/layout--learner-hackmd-discussion.png new file mode 100644 index 00000000..e53dadf0 Binary files /dev/null and b/_images/layout--learner-hackmd-discussion.png differ diff --git a/_images/layout--learner-hackmd.png b/_images/layout--learner-hackmd.png new file mode 100644 index 00000000..bc8f152b Binary files /dev/null and b/_images/layout--learner-hackmd.png differ diff --git a/_images/layout--learner-livestream-sidebyside-onebrowser-x320p.png b/_images/layout--learner-livestream-sidebyside-onebrowser-x320p.png new file mode 100644 index 00000000..f736c889 Binary files /dev/null and b/_images/layout--learner-livestream-sidebyside-onebrowser-x320p.png differ diff --git a/_images/layout--learner-livestream-sidebyside-onebrowser.png b/_images/layout--learner-livestream-sidebyside-onebrowser.png new file mode 100644 index 00000000..1681abbf Binary files /dev/null and b/_images/layout--learner-livestream-sidebyside-onebrowser.png differ diff --git a/_images/layout--learner-livestream-sidebyside-separatehackmd.png b/_images/layout--learner-livestream-sidebyside-separatehackmd.png new file mode 100644 index 00000000..c5aa000c Binary files /dev/null and b/_images/layout--learner-livestream-sidebyside-separatehackmd.png differ diff --git a/_images/layout--learner-sidebyside.png b/_images/layout--learner-sidebyside.png new file mode 100644 index 00000000..b02f503b Binary files /dev/null and b/_images/layout--learner-sidebyside.png differ diff --git a/_images/layout--learner-top.png b/_images/layout--learner-top.png new file mode 100644 index 00000000..cdf3c70b Binary files /dev/null and b/_images/layout--learner-top.png differ diff --git a/_images/layout--learner-top.xcf b/_images/layout--learner-top.xcf new file mode 100644 index 00000000..3dc9131c Binary files /dev/null and b/_images/layout--learner-top.xcf differ diff --git a/_images/layout--learner-with-hackmd.png b/_images/layout--learner-with-hackmd.png new file mode 100644 index 00000000..d4ff6394 Binary files /dev/null and b/_images/layout--learner-with-hackmd.png differ diff --git a/_images/layout--learner-workspace.png b/_images/layout--learner-workspace.png new file mode 100644 index 00000000..ce9c7582 Binary files /dev/null and b/_images/layout--learner-workspace.png differ diff --git a/_images/layout--paneldiscussion.png b/_images/layout--paneldiscussion.png new file mode 100644 index 00000000..99a2b015 Binary files /dev/null and b/_images/layout--paneldiscussion.png differ diff --git a/_images/learner-largescreen.png b/_images/learner-largescreen.png new file mode 100644 index 00000000..3b6d2cdd Binary files /dev/null and b/_images/learner-largescreen.png differ diff --git a/_images/learner-normal.png b/_images/learner-normal.png new file mode 100644 index 00000000..590135e5 Binary files /dev/null and b/_images/learner-normal.png differ diff --git a/_images/learner-small.png b/_images/learner-small.png new file mode 100644 index 00000000..5d5f4216 Binary files /dev/null and b/_images/learner-small.png differ diff --git a/_images/mooc-diagram.png b/_images/mooc-diagram.png new file mode 100644 index 00000000..2b0a98ba Binary files /dev/null and b/_images/mooc-diagram.png differ diff --git a/_images/myteam-helper.jpg b/_images/myteam-helper.jpg new file mode 100644 index 00000000..abedd200 Binary files /dev/null and b/_images/myteam-helper.jpg differ diff --git a/_images/myteam.jpg b/_images/myteam.jpg new file mode 100644 index 00000000..8b0508f4 Binary files /dev/null and b/_images/myteam.jpg differ diff --git a/_images/obs--controls.png b/_images/obs--controls.png new file mode 100644 index 00000000..8e5b9668 Binary files /dev/null and b/_images/obs--controls.png differ diff --git a/_images/obs--desk-combined.jpg b/_images/obs--desk-combined.jpg new file mode 100644 index 00000000..31973c07 Binary files /dev/null and b/_images/obs--desk-combined.jpg differ diff --git a/_images/obs--vertical-slide-presentation.png b/_images/obs--vertical-slide-presentation.png new file mode 100644 index 00000000..bbccde2c Binary files /dev/null and b/_images/obs--vertical-slide-presentation.png differ diff --git a/_images/participants.jpg b/_images/participants.jpg new file mode 100644 index 00000000..dcbd1bdb Binary files /dev/null and b/_images/participants.jpg differ diff --git a/_images/problem-breakout.jpg b/_images/problem-breakout.jpg new file mode 100644 index 00000000..8b2afe38 Binary files /dev/null and b/_images/problem-breakout.jpg differ diff --git a/_images/problem.jpg b/_images/problem.jpg new file mode 100644 index 00000000..6603cd6f Binary files /dev/null and b/_images/problem.jpg differ diff --git a/_images/rename1.jpg b/_images/rename1.jpg new file mode 100644 index 00000000..d08bf90f Binary files /dev/null and b/_images/rename1.jpg differ diff --git a/_images/rename2.jpg b/_images/rename2.jpg new file mode 100644 index 00000000..eacec5bf Binary files /dev/null and b/_images/rename2.jpg differ diff --git a/_images/s10-kickstart-prompt-log.png b/_images/s10-kickstart-prompt-log.png new file mode 100644 index 00000000..415799fb Binary files /dev/null and b/_images/s10-kickstart-prompt-log.png differ diff --git a/_images/s5-shell-intro-dark.png b/_images/s5-shell-intro-dark.png new file mode 100644 index 00000000..a1aef3c5 Binary files /dev/null and b/_images/s5-shell-intro-dark.png differ diff --git a/_images/s8-modular-code-development.png b/_images/s8-modular-code-development.png new file mode 100644 index 00000000..5f4361cd Binary files /dev/null and b/_images/s8-modular-code-development.png differ diff --git a/_images/s9-git-intro.png b/_images/s9-git-intro.png new file mode 100644 index 00000000..2fc1fa67 Binary files /dev/null and b/_images/s9-git-intro.png differ diff --git a/_images/screenshare-fullhd.png b/_images/screenshare-fullhd.png new file mode 100644 index 00000000..eda9d42d Binary files /dev/null and b/_images/screenshare-fullhd.png differ diff --git a/_images/screenshare-jupyter.png b/_images/screenshare-jupyter.png new file mode 100644 index 00000000..1e7bb5cf Binary files /dev/null and b/_images/screenshare-jupyter.png differ diff --git a/_images/screenshare-rsh.png b/_images/screenshare-rsh.png new file mode 100644 index 00000000..1bbb1ccc Binary files /dev/null and b/_images/screenshare-rsh.png differ diff --git a/_images/screenshare-vertical.png b/_images/screenshare-vertical.png new file mode 100644 index 00000000..28e18b06 Binary files /dev/null and b/_images/screenshare-vertical.png differ diff --git a/_images/screenshare/s10-kickstart-prompt-log.png b/_images/screenshare/s10-kickstart-prompt-log.png new file mode 100644 index 00000000..415799fb Binary files /dev/null and b/_images/screenshare/s10-kickstart-prompt-log.png differ diff --git a/_images/screenshare/s5-shell-intro-dark.png b/_images/screenshare/s5-shell-intro-dark.png new file mode 100644 index 00000000..a1aef3c5 Binary files /dev/null and b/_images/screenshare/s5-shell-intro-dark.png differ diff --git a/_images/screenshare/s6-array-demo.png b/_images/screenshare/s6-array-demo.png new file mode 100644 index 00000000..422c0c7f Binary files /dev/null and b/_images/screenshare/s6-array-demo.png differ diff --git a/_images/screenshare/s7-array-jobs.png b/_images/screenshare/s7-array-jobs.png new file mode 100644 index 00000000..17a95e4c Binary files /dev/null and b/_images/screenshare/s7-array-jobs.png differ diff --git a/_images/screenshare/s8-modular-code-development.png b/_images/screenshare/s8-modular-code-development.png new file mode 100644 index 00000000..5f4361cd Binary files /dev/null and b/_images/screenshare/s8-modular-code-development.png differ diff --git a/_images/screenshare/s9-git-intro.png b/_images/screenshare/s9-git-intro.png new file mode 100644 index 00000000..2fc1fa67 Binary files /dev/null and b/_images/screenshare/s9-git-intro.png differ diff --git a/_images/screenshare/shell-crash-course.png b/_images/screenshare/shell-crash-course.png new file mode 100644 index 00000000..a4c686aa Binary files /dev/null and b/_images/screenshare/shell-crash-course.png differ diff --git a/_images/teach-teaching--screenshot.png b/_images/teach-teaching--screenshot.png new file mode 100644 index 00000000..75cdb8d0 Binary files /dev/null and b/_images/teach-teaching--screenshot.png differ diff --git a/_images/team_status.png b/_images/team_status.png new file mode 100644 index 00000000..c1862868 Binary files /dev/null and b/_images/team_status.png differ diff --git a/_images/unmute.jpg b/_images/unmute.jpg new file mode 100644 index 00000000..436c48ae Binary files /dev/null and b/_images/unmute.jpg differ diff --git a/_images/zoom--breakout-join.png b/_images/zoom--breakout-join.png new file mode 100644 index 00000000..e2bce956 Binary files /dev/null and b/_images/zoom--breakout-join.png differ diff --git a/_images/zoom--breakout-room-button.png b/_images/zoom--breakout-room-button.png new file mode 100644 index 00000000..6c153185 Binary files /dev/null and b/_images/zoom--breakout-room-button.png differ diff --git a/_images/zoom--choose-room-inside-room.png b/_images/zoom--choose-room-inside-room.png new file mode 100644 index 00000000..ef32e058 Binary files /dev/null and b/_images/zoom--choose-room-inside-room.png differ diff --git a/_images/zoom--learner-names.png b/_images/zoom--learner-names.png new file mode 100644 index 00000000..39356971 Binary files /dev/null and b/_images/zoom--learner-names.png differ diff --git a/_images/zoom--leave-breakout-room.png b/_images/zoom--leave-breakout-room.png new file mode 100644 index 00000000..75e041af Binary files /dev/null and b/_images/zoom--leave-breakout-room.png differ diff --git a/_images/zoom--leave.png b/_images/zoom--leave.png new file mode 100644 index 00000000..432c4800 Binary files /dev/null and b/_images/zoom--leave.png differ diff --git a/_images/zoom--participants.png b/_images/zoom--participants.png new file mode 100644 index 00000000..580ba9ca Binary files /dev/null and b/_images/zoom--participants.png differ diff --git a/_images/zoom--reactions.png b/_images/zoom--reactions.png new file mode 100644 index 00000000..88ec071a Binary files /dev/null and b/_images/zoom--reactions.png differ diff --git a/_images/zoom--rename.png b/_images/zoom--rename.png new file mode 100644 index 00000000..c4042e23 Binary files /dev/null and b/_images/zoom--rename.png differ diff --git a/_images/zoom--settings-monitors-fullscreen.png b/_images/zoom--settings-monitors-fullscreen.png new file mode 100644 index 00000000..127689fe Binary files /dev/null and b/_images/zoom--settings-monitors-fullscreen.png differ diff --git a/_sources/LICENSE.md.txt b/_sources/LICENSE.md.txt new file mode 100644 index 00000000..60a0ee45 --- /dev/null +++ b/_sources/LICENSE.md.txt @@ -0,0 +1,400 @@ +--- +orphan: true +--- + +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. + diff --git a/_sources/broadcaster.rst.txt b/_sources/broadcaster.rst.txt new file mode 100644 index 00000000..5ece10c8 --- /dev/null +++ b/_sources/broadcaster.rst.txt @@ -0,0 +1,284 @@ +Broadcaster +=========== + +This page explains the setup and how-to guide for the OBS broadcaster. +This person manages the technical setup of :doc:`OBS ` and thus +the streaming. This person often is, but does not have to be, the OBS +director [todo: link] who switches the scenes and manages the +broadcast after it has started. + + + +Role of the broadcaster +----------------------- + +As the broadcaster, you manage the OBS application that captures Zoom +and sends it to the world. This is different from: + +* The **Director** manages the scenes and the overall flow of the + workshop (switches scenes, cues instructors when to start talking, + shares HackMD during the breaks). This person is often the + broadcaster, but for clarity we use more precise terms. + +* The **Host** is the interface between the instructors and the + audience: e.g. announcing instructors, keeping to the schedule, + etc.). They are very often the same as the Director. + +* The **Instructors** connect to Zoom and teach. If there is no + designated director, at least one instructor needs to know a bit + about that. + +The broadcaster has a lot of preparation work to do the first time +they get set up (future courses aren't so bad). They should expect +some panicked fixing of stuff right before each course starts. During +the courses themselves, the broadcaster is mainly sitting back making +sure nothing breaks. + + + +Initial setup +------------- + +Prerequisites: + +* A somewhat powerful computer dedicated for broadcasting (not used + for teaching as an instructor, the broadcaster *can* use an + instructor computer, but that is much more complicated). +* Stable internet connection (speed is not too important these days). + + * 20/5 download/upload Mbps is probably plenty good. 100/10 Mbps is + far more than is needed. + + * Wired connections, rather than wireless, are better (WiFi, + non-cellular uplink). However, you probably know your overall + stability the best: you want a continuous, smooth connection + without much `jitter + `__. + However, OBS settings can be tuned to have a larger buffer to + handle this. + + +Software installation: + +* `Install OBS `__ (Linux, Mac, Windows - + this is a mass market product so there is good support) +* Install `obs-websocket + `__. This is also + fairly widespread, but slightly less so than OBS. +* Zoom (but you likely already have that) + +Zoom setup: + +* Install Zoom. There's not much you need to do differently. + +* Some Zoom settings: + + * General → Use dual monitors → yes. Despite the name, this gives + Zoom two *windows*: one for the gallery view, one for the + screenshare (or active speaker if there is no screenshare). + + * General → Enter full screen automatically when starting or joining + a meeting → false + + * Screen Share → Enter full screen when a participant shares screen + → false (important) + + * Screen Share → Scale to fit shared content to Zoom window → true. + +OBS setup: + +* Clone the `obs-scenes repository + `__. This contains some + pre-made scenes which will set your OBS up for teaching nicely. + +* Import the TeachingStreaming profile + (Profile → Import → ``obs-scenes/profiles/Teaching_Streaming``). This contains things + like audio and encoder settings + + * TODO: this may need adjustment for your particular situation. At + least things like file paths will need to be adjusted. Look at + the obs-scenes readme for more information. + + * Most importantly, this sets it to 840 horizontal × 1080 vertical + (portrait mode). + +* Import the Teaching_Streaming_ZoomCapture scene collection (Scene + Collection → Import → + ``obs-scenes/scenes/Teaching_Streaming_ZoomCapture``). + +* You now need to configure some window captures, for example, you + need to tell OBS which window has the gallery of all instructors in + it. From the "Scenes" + + * Scene ``_GalleryCapture[hidden]`` → source ``ZoomMeeting-Gallery`` + right click → Properties → Window → select the Zoom gallery view + (for me it is titled "Zoom meeting"). TODO: adjust the size of + this window until it fits the pre-made scene [it looks nice and + large] + + * Scene ``_Screenshare-Zoom-Capture[hidden]`` → source + ``Zoom-SecondWindow`` right click → Properties → Window → select + the Zoom screenshare/active speaker window (for me it is titled + only "Zoom"). Adjust the size of this window until it nicely + fills the preview pane (the ideal size is 840×1080). + + * (optional) Scene ``_Hackmd-Capture[hidden]``: similar, select the + shared HackMD + + * (optional) Scene ``_Broadcaster-Screen[hidden]``: configure your + local desktop capture. + +* Configure the audio + + * Settings → Audio → Desktop Audio → "Default" (or if you want, + select an explicit device). This is what will capture Zoom by + monitoring your speakers/headphones. + + Note: prevent audio feedback! Be careful if you set this to + speakers, and you have a separate computer which you use for + teaching with a microphone that would hear those speakers: you + would get feedback. + + * Settings → Audio → Mic/Aux Audio → "Default" (or whatever device + you want). This would capture that computer's local microphone, + if you use it. (More likely, you would join the meeting as an + instructor, and thus use a separate computer to speak to people) + + * From the main OBS scene, rename the audio devices: + + * Bottom panel → Audio mixer → one of the devices → gear icon → + Rename → + + * Desktop capture to "Instructors" + * Mic to "BroadcasterMic" + +* Configure obs-websocket (set the listening socket + authentication). + + * Tools → Websocket server settings → {Enable websockets + server=true, Server port=(something), Enable authentication=true, + Password=something}. Share your IP address, server port, and + password with your other instructors. + +* Allow outside connections. On of these two: + + * Use `ngrok `__ to forward the connection + (including SSL). Read more from the obs-websocket documentation: + https://github.com/obsproject/obs-websocket/blob/4.x-current/SSL-TUNNELLING.md + . Note that the free plan limits to 4 simultaneous connections + and the connection information will change every time you restart, + which is not great. + + * Configure your router/firewall to allow incoming connections to you + IP address, on the port configured above. (it is this external IP + address that you need to share with other instructors. + +* Verify the obs-tablet-remote connection (see TODO director-setup). + + + +Before each day +--------------- + +* Set Twitch stream data: stream title, stream description, channel + about page. + +* Configure and check streams + +* Test everything + +* Basic information private message:: + + * zoom info: + * zoom link: + * attendee hackmd: + * notes hackmd: + * live preview: + * control panel: http://rkd.zgib.net/obs-tablet-remote/#!auto&host=HOST&port=PORT&password=PASSWORD&config=https://raw.githubusercontent.com/coderefinery/obs-config/master/obs-tablet-remote-config.json + + +Before each broadcast +--------------------- + +* Ensure anything from the above is done (obs-tablet-remote + connection, scene layout, etc). + +* Ensure Zoom scenes are correctly captured, flip through them to + verify. + +* Wait for first instructors to join. + +* Zoom: Disable sound on participants joining + +* In zoom, right click on a participant without video and "Hide + non-video participants". You may need three participants in order + to do this: if you have fewer, join through a browser or something. + +* Make other instructors co-hosts in the Zoom so that they can share + screen without the other person stopping. + +* Start recording / start streaming ~20-30 minutes in advance, with + audio muted and on the title card scene. Start recording at the + same time as streaming so you don't forget it! + +* Hand it off to the director (possible yourself) to flip the audio + and scene once icebreakers start. + + + +During the broadcast +-------------------- + +* You can not share screen with Zoom (it messes up the windows: + screenshare becomes gallery, the old gallery window disappears). + + * Instead, there is a separate OBS scene for local screenshare. + + * **But we recommend using a separate computer for broadcasting and + instructing**, to avoid this problem. + +* For the most part, the director does the scene switching (and you + might be the director) + +* You don't need to always be in front of the broadcasting computer, + but be available in case there are emergencies. + + + +Common problems +--------------- + +* **Internet connection goes down** + +* **OBS crashes** While this happens somewhat often during testing, + during live productions, when the settings are not being changed, it + has never been observed. Set all settings in advance, and maybe + quit and restart right before starting the broadcast. + +* **Audio is capturing the wrong inputs, or audio quality is bad** + + So once when broadcasting, the audio quality was horrible. It + turned out that the sound system got confused and the desktop audio + capture (zoom capture) was actually capturing the microphone. This + was *not* reflected in the OBS settings. + + To solve this, go to the OBS settings (you can adjust most, but not + all, settings while a stream/recording is ongoing). Flip the audio + devices to "disabled", then back to what it should be (possibly you + need to save in between?). + + It's possible there are other times you need to adjust the audio. + +* **I have HackMD open in view mode (to share) and HackMD open in edit + mode (to edit), but OBS keeps switching to share the editable + one**. OBS seems to go by window title. Try this: Use a different + browser, or run one of them in private mode (so that the title is + different). + + + +See also +-------- + +- There is plenty about OBS and streaming online, since it is a big + business now. You can find answers to most questions once you know + the basic theory. diff --git a/_sources/chat.md.txt b/_sources/chat.md.txt new file mode 100644 index 00000000..fa126bc7 --- /dev/null +++ b/_sources/chat.md.txt @@ -0,0 +1,145 @@ +(chat)= +# CodeRefinery Zulipchat + +The [CodeRefinery zulipchat](https://coderefinery.zulipchat.com) is +where our primary discussion, planning, and action takes place. Many +things are announced only via zulipchat. This is a public chat and +everybody is welcome to join, no invitation needed, and we explicitly +invite anyone to give ideas in any thread. + +The chat is a joint community of CodeRefinery (teaching), NordicHPC +(infrastructure), and Nordic-RSE (usage and software), which are other +Nordic projects about scientific computing which share some of the +same people. Together, we have a network of all aspects of modern +scientific computing. + +Unlike Slack, zulipchat is very heavily threaded, and it is easy to +follow along without being active all the time. Respond within the +topic (=thread) that is relevant, or make a new thread. Sometimes you +can find old threads to revive. Don't worry, everything is flexible +and you'll quickly learn by watching (and don't worry about going +wrong). + + +## Streams + +Once you join the chat, you will be subscribed to some default +streams (a stream is basically a channel). **The first thing you +should do is join some more streams, depending on your interest. Join +more streams by clicking gear icon by the steams list on the left side +on that chat, then selecting what you are interested in.** + +![Gear icon to join a stream](img/chat--join-stream.png) + +If you **mute a stream**, you can see the contents if you click on it, +but you won't get notifications. If you **mute a topic**, it will be +hidden from view but you can later unmute it in your personal +settings. Under stream settings, you can request email notifications +for all messages in a certain stream (possibly useful for the announce +streams). + +CodeRefinery streams: +* **#general**: Any topic and random chat (including for the other + projects below) +* **#coderefinery**: About the project itself. CodeRefinery members + should be in this channel. +* **#carpentries**: About Carpentries or CodeRefinery as a Carpentries + lesson program. +* **#lessons**: CodeRefinery lesson discussion, one for each lesson we + maintain. +* **#workshops**: Organizing workshops and other events. One topic + for each event. +- One stream for coordinating each major workshop that requires a lot + of chat, for example **#tools-workshop** (the standard workshop), + **python-for-scicomp**, **kickstart-aalto**, etc. +* **#workshop-chat**: High-volume staff chat during workshops. You + typically join during a workshop, and leave when done to avoid the + flood. +* **#help**: Ask questions and get advice from others. Tell + interesting things you learned via "TIL"s +* **#new members**: Feel free to introduce yourself here +* **#announce**: +* **#infrastructure**: [CodeRefinery + gitlab](https://coderefinery.org/repository/) talk. + + +Nordic research software engineer community: +* **#nordic-rse**: Discussion about + [Nordic-RSE](https://nordic-rse.org) + +Nordic HPC: +* **#NordicHPC**: [NordicHPC](https://nordichpc.github.io). + Discussion about computing infrastructure (not just HPC) + +Misc streams in our sphere of influence: +* **#RSHour**: [Research Software + Hour](https://researchsoftwarehour.github.io) planning +* **#finland**: Finland stuff, we won't complain about others. +* **#Aalto**: Aalto University community, you can reach [Aalto + Scientific Computing](https://scicomp.aalto.fi) staff there. +* **#hands-on-scicomp**: Discussions about the [Hands-on scientific + computing course](https://handsonscicomp.readthedocs.io). +* **#RSHour**: the [Research Software + Hour](https://researchsoftwarehour.github.io) web show. + +You can make topical private streams for groups that significantly +overlap with our community. Currently, Zulip admins can't add +themselves or others to private streams. + + +## Clients + +Zulipchat can be used in a web browser, there's a desktop app, mobile +apps, and even a terminal client installable using ``pip``. + + + +(voting)= + +## Reacting and voting + +We want everyone to take part in chat and express their thoughts, but +of course people don't want to give pointless agreeing replies (but +you can always welcome to do that, too). So, we encourage everyone to +use reactions in cases they want to express agreement/disagreement but +not so much they want to send a message. Common reactions you might +see are 👍, 👎 (thumbs up/down, agree with general sentiment), 🐙 +(`:octopus:`, awesome/amazing/ace), and well, plenty more that are +obvious. + +We also use reactions to express some idea of a more concrete +**vote**, to empower people to take an action (otherwise, it is +difficult to get a decision on anything). This is not formal or +necessarily binding (so it's not really a vote), but a useful +intermediate system for a young project. If you see a message +proposing something and you want to say, in no uncertain terms, "I +think you should do that" or not, let us know by the following: + +* ↔️ (+0, `:left_right:`: I see this and am neutral. +* 🔼, 🔽 (+1, -1, `:upvote:`, `:downvote:`) or similar: I + agree/disagree with this. +* ⏬, ⏫ (+2, -2, `:double_up:`, `:double_down:`): I agree/disagree + with this and am willing to work on making it happen/finding an + alternative. + +If you want to do something, ask for opinions, and a reasonable time +later it seems the sentiment is positive, consider yourself empowered +to do it. If you are voting, feel free to be creative with emojis or +numbers, but realize that other reactions may not be so explicit. Note +that if you are negative, you should explain why or alternatives, +otherwise your opinion may not be weighted so much. The person doing +the thing decides what to do (and this is open source: we find a way +for everyone to do what they need to do). + +Do you think you aren't important enough to vote? That's wrong, +because we are usually interested in the thoughts of outsiders. We +can see who voted and use that to weight our decision if needed. + + + +## Privacy + +All activity (except private steams) should be considered public, and +the data controller is zulipchat.com. Zulip admins can't add +themselves or others to private streams, but still: there is no +contract guaranteeing confidentiality. diff --git a/_sources/co-instructors.md.txt b/_sources/co-instructors.md.txt new file mode 100644 index 00000000..64c439ef --- /dev/null +++ b/_sources/co-instructors.md.txt @@ -0,0 +1,96 @@ +# Co-instructors + +Since we focus on {doc}`team-teaching`, almost everyone is a +co-instructor. But this page is focused on *onboarding new +co-instructors in their first lessons*, so focuses on explaining the +most common starting point. + + + +## Why co-teaching? + +```{figure} img/teach-teaching--screenshot.png +--- +align: right +figwidth: 50% +--- + +Demo of team teaching. Two people are speaking, in this case one +is typing and giving the small point of view, and one is explaining +the big point of view. +``` + +The dream of interactive teaching is hard to achieve: most audiences +are very quiet and even if someone does speak up, it is a small +fraction of the audience. We have found a better way: Build the +interaction straight in to the course by co-teaching. Instead of +trying to have a conversation with students, we have a conversation +among co-instructors. + +Co-teaching provides other benefits, such as easier preparation and +easier presentation. + + + +## How co-teaching works: guide and demo-giver + +Main article: {doc}`team-teaching`. + +We have developed several ways of team teaching, but for starters we +suggest the "guide and demo-giver" approach. The **guide** manages +the overall flow through the lesson. The **demo-giver** does the +typing during the demonstrations. So, for example: + +- The guide introduces a type-along session and walks through the + steps while... +- ... the demo-giver does the typing in the screenshare +- The guide and demo-giver ask each other about what is happening. + +During other times, the demo-giver and guide ask each other questions +when the other is talking. + + + +## Preparing for your first time + +```{figure} img/screenshare/s10-kickstart-prompt-log.png +--- +align: right +figwidth: 50% +--- + +An example of a beautiful screenshare. Note the portrait orientation +(you have half the screen free for notes and HackMD, learners have +half the screen free to do their own work). The terminal is +dark-on-light, a minimal prompt, no other fancy shell distractions, +there is a shell history visible, and slightly distinct colors between +the web browser and the terminal. +``` + +- There is some generic technical setup for your own computer - make a + clean environment that matches learners, make a good prompt, and so + on. See {doc}`instructor-tech-setup` and + {doc}`instructor-tech-online`. +- Watch the [Demo of CodeRefinery livestream teaching + ](https://www.youtube.com/watch?v=WjmttAniZX8) (read the + description for an explanation). +- Talk and plan with your co-instructors: decide which model of + co-teaching you will give. +- Plan the material, try to go through all of the exercises and + type-along. +- Do a run-through of the lesson, practicing what each person says. + This can be relatively quick (remember, most of the time in an + actual lesson is learners doing exercises alone). + + - Also check the technical setup - make sure that it looks good on + screen. + + + +## Top issues new co-instructors face + +See the instructor-intro for now. + +## See also + +* {doc}`instructor-intro`. diff --git a/_sources/coderefinery-mooc.rst.txt b/_sources/coderefinery-mooc.rst.txt new file mode 100644 index 00000000..bdd940e2 --- /dev/null +++ b/_sources/coderefinery-mooc.rst.txt @@ -0,0 +1,248 @@ +CodeRefinery MOOC strategy +========================== + +This page documents the CodeRefinery MOOC (massive open online course) strategy. It is not a real +MOOC (it's not massive enough yet), but it does reach out from one to +many, and can scale to basically all the world. + +.. admonition:: Video: The future of teaching + + "The future of teaching", + https://www.youtube.com/watch?v=S9Jor12Cxdc (45:31) is a talk + describing many aspects of this strategy in a concise form. + + +Technical setup summary +----------------------- + +We have a public broadcast, with goes out via a livestream. +Disconnected from this, people are watching the broadcast in a +*separate* Zoom meeting and doing exercises/breakouts there. Or, +people can watch via the livestream alone. Or there can be different +meetings. Or people could watch recorded videos later. + +The mental model here is "Watching TV together". We collectively watch +a show together. There are periodic intermissions where each watching +community discusses among themselves and works on the exercises. +Everyone feels they are a part of something big and that keeps people interested. + +We have clear communication channels from learner→instructor +(HackMD), helpers→instructors (chat), instructors→learners +(livestream). Of course instructors can directly communicate with the audience +during their breaks. + +The **Director** controls the stream and is responsible for keeping +things running smoothly. + + +Summary diagram +--------------- + +.. figure:: coderefinery-mooc/mooc-diagram.png + + The general presence and information flow within the MOOC strategy. + + +Instructors +----------- + +There is an **instructor Zoom meeting**. This is broadcasted via +Twitch, using :doc:`OBS ` (there is usually a separate director +or production manager for this, instructors don't need to worry +themselves with this). + +Compared to the classic style, advantages include: + +* You are freed from student management, others help manage the + audience and convey these important parts to you. +* Audio/video is muted during breaks, there is more opportunity to + discuss and plan what comes next with the instructors. + +Disadvantages: + +* You lose the direct access to all students (but how often would + someone speak up anyway?). + + +Instructors should keep in mind (many of these are not special to the +MOOC format, but are even more important): + + +* At all times you will have a director to help keep you on track: + just teach and watch chat (and HackMD when you have time, but others + do this and let you know). +* You will have a private Zoom meeting with only instructors (and any + other key helpers who want to be there). +* Share a vertical screen (840 × 1080 is our standard and your + maximum). This allows students + to keep half of their screen open for their own work. +* HackMD is the main way of receiving questions from students (just + like in our current courses). The HackMD helper can be in the + main stream to immediately ask questions from the audience, or your + co-instructors could do this. Really, perhaps both. +* During breaks and pauses, the livestream will be muted, so that + instructors (and helpers there) can talk without the audience + hearing. This greatly increases professionalism and makes it easier + to coordinate. +* There is the standard text chat (Zulip) to use to communicate with + other helpers. +* Of course, you can go join the student room during breaks, other + sessions, and so on. + +* Zoom polls won't work, since the instructors and audience aren't in + the same Zoom meeting. This is one reason we already use HackMD for + polls (though there are other options, such as presemo.aalto.fi, + which could work in even larger courses). + +* You will have more than just the registered students in another room + as an audience. Your audience includes students in the breakout + room meeting, livestream watchers, people in their own meetings with + a private team we don't know about, people broadcasting it to + physical rooms, people watching recordings later, and who knows who + else. + + * Try to speak with awareness of this diverse audience. You don't + need to change much, but go slowly and give plenty of time, and + you can say things like "If you are registered, ... . If you are + on your own, ... ." + + * Repeat back questions before answering them, so that people across + channels can follow. This is a usually good idea anyway, and also + it is natural when questions are coming through chat or notes. + + * Speak in terms of breaks and exercises sessions. + + * Speak in terms of relative times, since people will be in different + timezones. For example, say "We resume at + 50 minutes past the hour" and write "xx:50". + + * Realize there are different learning styles. Some people will + attempt all exercises. Some will passive watch and want demos. + +* We propose this general model for each lecture-exercise cycle: + + * Give the lecture part + * Introduce the exercises + * Short break (~5 minutes). People attempting exercises themselves + go into their other meetings and work on it. The learners + attempting it themselves will mute the stream. + * On-stream, do the exercise as a type-along or demo. This is useful + for some audience, and also is very useful in recordings. + * At the designated time, the learners come back to the livestream. + Depending on what you want, you could use the outcome of the demo + to discuss what we learned, do a whole new demo (perhaps faster + this time), or you go on. + +* You should also make it clear to the audience (mainly + helpers/team leaders) what the expectation for each exercise + session is. This should be written in the HackMD! + +* It is OK to decide you can't make things perfect for every audience. + The rest will understand this if you make this explicit. + + + +Director +-------- + +You job is to be aware of everything going on, and when there is a +question like "Do we need more time?" or "what should we do now?", you +can answer it. You can give people the pushes when they get slightly +off track (though others should always be willing to speak up when +this is needed, too). You maintain this awareness by watching as many +of the communication channels as you can. + +Hint: find your computer's detailed audio controls, so that you can +adjust volumes of multiple sources independently. This helps you be +in multiple meetings at once. (This may be useful for others that +want to attend multiple meetings.) + + + +Expert helpers and other staff +------------------------------ + +As a helper, your job stays pretty much the same. There is more +emphasis on making sure that all questions and comments are in the +HackMD. + +Some helpers can join the instructor meeting and directly relay +questions and thoughts, and in general provide the "voice of the +audience". This is a logical role for the HackMD helper. + + + +Audience and team leaders +----------------------------- + +The learners and team leaders focus on watching the material and +asking questions in HackMD, much as in a regular course. + +In the main meeting with breakouts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Here, there is a meeting (e.g. Zoom) which has a lot of learners in +it. There are two options for lectures: + +* Meeting host shares the livestream (video + audio) +* Participants individually open the livestream and watch, and go back + to the meeting when it is time to do exercises. + +All audience members ask questions and discuss in HackMD (just like in +regular workshops). The meeting chat is mainly used for +practicalities, and is not designed to be monitored by the audience. + +The most significant risk here is that learners have to mute the +livestream (or turn it off) during the exercise sessions if there are +demos going on while they are doing exercises. This means we may have +trouble getting their attention. + +Via livestream +~~~~~~~~~~~~~~ + +Here, each audience member watches Twitch independently. During the +exercise sessions, they can work alone, watch the demos, or work with +their own self-organized teams. + +Live +~~~~ + +The stream is broadcast in the physical classroom or meeting room +where a class or team is located. + +Recording +~~~~~~~~~ + +You can watch the recording, refer to the lesson page, and refer to +the archived HackMD notes afterwards. + + + +Open issues +----------- + +* It can require some cognitive effort to understand and keep track of + all of these different channels. But when we did it in + January/February, learners picked up quickly and there were few + complaints in the end. + +* HackMD spam: Lately, we have had one HackMD for all students + (registered or watching via the stream). There has yet to be any + spam or trolling problems, but it will happen if we get big enough. + We need a transition plan to private HackMD if needed. (Proposal: + have a backup HackMD. If spam starts, we email the new one and go + from there. + +* Chat/Q&A scaling: Will HackMD actually scale enough for us? What + alternatives do we have? + + + +See also +-------- + +* :doc:`how-to-attend-stream` +* :doc:`livestream-teaching` +* Livestream teaching demo video: + https://www.youtube.com/watch?v=WjmttAniZX8 (carefully read the + video description to understand what is going on) diff --git a/_sources/contributing.md.txt b/_sources/contributing.md.txt new file mode 100644 index 00000000..2d5a8621 --- /dev/null +++ b/_sources/contributing.md.txt @@ -0,0 +1,91 @@ +(volunteering)= + +# Contributing to CodeRefinery + +CodeRefinery is an open-source project. All our work is open, and we +accept any type of contributions: there is a lot more than instructing +to run a successful workshop. Also, CodeRefinery is really more of a +group of like-minded people than one particular plan, so you are +welcome to join just to hang out and share ideas. + +If you aren't sure you are ready for more, you can always {ref}`lurk +in the chat ` +(passively watch our community) and become more active when you feel +the time is right. + +These manuals (and in general, other guides we have) describe the +past, not (only) the future. They are made so that new people can +know what we typically have done, so they can work on the future (even +if it's different). + +A good way to get started is to take the lead of some workshop (doing +it like it was before), then do it again with your own improvements. + + + +## How to take part + +- Join the {ref}`CodeRefinery chat `, give comments or submit + emoji reactions to show how you feel about things. Many things are + announced only through the chat. +- Come to our + [meetings](https://coderefinery.org/organization/meetings/)- the + monthly community calls are for a broad audience, but anyone is + welcome come to the weekly meetings. +- Attend a CodeRefinery workshop - they teach the very tools we use to + collaborate! + + + +## Action: Join our "community teaching training" + +CodeRefinery isn't just about doing teaching ourselves, but improving +your teaching. Whether you focus on teaching, or it's a side-activity +to your other tasks, the CodeRefinery (online) teaching can help you +avoid re-inventing good practices and prepare you for teaching +together. + +Read more: [Community +teaching training](https://coderefinery.github.io/community-teaching/) + + + +## Action: Advertise and/or help out in our online courses + +CodeRefinery runs many open, online courses, which anyone can attend. +Some of them can be attended by anyone via livestream, even without +registering (yes, this really works - we get high ratings for this). +You could simply advertise our courses, or go even further and run +local breakout rooms. + +Take it a step further and help out with the course, whether it's as +an instructor, helper, or some other role. Of course, anyone is +welcome to help, even without advertising the courses! + +Read more: {doc}`local-breakout-rooms` and {doc}`roles-overview`. + + + +## Action: Teach openly and allow others to join + +Go to the next level and adopt CodeRefinery strategies for your own +courses, so that others can join at little cost to yourself. By +opening, you start to find more lesson developers and instructors, so +that your courses can reach the next level of quality and impact. +Soon, you will wonder why you ever bothered teaching alone. + +Read more: {doc}`open-your-courses` + + + +## Other types of contributions + +As an open project, there are any number of ways you can contribute: + +- Take on any of the {doc}`roles ` in a workshop - with + co-teaching, it is surprisingly easy to go straight to instructor, + but there are also many other roles. +- Help with lesson maintenance (read and make suggestions) or become a + maintainer of a lesson. Watch GitHub repositories to get notified + of issues and pull requests, and help review. Anyone can watch any + repository, and comments from outsiders do help us review things faster. diff --git a/_sources/director.md.txt b/_sources/director.md.txt new file mode 100644 index 00000000..936ab001 --- /dev/null +++ b/_sources/director.md.txt @@ -0,0 +1,109 @@ +# Director + +The director manages the flow of the course, and in particular the +flow when things do *not* go according to plan. During livestream +courses, the director also manages the stream scene/audio selection. + + +* Gives introductions and wrap-ups (to the days, sessions, and + instructors), or at least ensures they happen. +* Ensures good flow of the course overall + * Is aware enough of the schedule so that they can decisively adjust + it when needed. + * Keeps time, ensures breaks + * Actively discusses with the instructors about these practical + arrangements (e.g. negotiating best break times) +* (livestreaming) Flips the livestream scenes when necessary, cues + instructors. + + + +## Managing the schedule + +The director manages the overall flow: making sure the instructors are +ready, icebreakers happen, transitions are smooth, people are +introduced, breaks happen, HackMD is shared at the appropriate times, +and so on. + +During large courses, there are many different instructors and certain +exercises/lessons may randomly take longer (no matter how much +preparation there is). The audience expects this, and in practice +decisively accepting and adjusting the schedule (or deciding not to) +makes things smooth. + +The Director is usually the instructor coordinator, so knows the +schedule well. The instructor should be empowered to decide (after +checking chat, HackMD, and other instructors) what to do, and can +directly announce the new schedule. This takes confidence, but don't +worry: you have plenty of people to consult with, ask advice from +those around and then make your choice. + +You should also make sure that HackMD is updated with breaks, +exercises, and so on. You will probably be the one sharing HackMD +during the breaks. + + + +## Switching scenes and audio + +During a livestream course, various video inputs are mixed +(screenshare, instructor gallery, title card, HackMD) and +broadcasted. This gives one extra level of management that is needed: +yes, it is more overhead, but the advantages are that the instructors +can mute the livestream and have a private discussion. This is great +for breaks and exercise times, and really helps with the flow a lot. + +So, for example: +- Start the course on the "title card" +- Switch to gallery view for introduction +- Switch to screenshare (and adjust PiP size) during teaching +- Share HackMD during the break and then make PiP size zero +- Repeat for next courses. + +The available controls include: + +- Audio: the audio capture can be turned on and off: + - "Instructors": the capture of the Zoom + - "Mic": this is the *local microphone* of the capture computer and + should not normally be adjusted. + +- Scene selection: there is a button to select among these scenes + - "Title card": graphics used before learners arrive + - "Gallery": instructors + - "Screenshare": capture of the Zoom screenshare + - "Hackmd": just what it says + +```{sidebar} PiP example + +![](img/teach-teaching--screenshot.png) +In the upper left of the screen you see the instructor PiP +overlaid on the HackMD screenshare. +``` + +- Picture in Picture display: adjust size and layout of this + + - The **size** can be adjusted to fit the screen + - To turn it **off**, make the size zero + - The cropping can be adjusted based on the number of people in + the Zoom display. + + +## OBS remote control via obs-tablet-remote + +The broadcaster will provide you with a URL to go to the remote +control. TODO: picture + +This is an example (note: it won't work, because you don't have OBS running): + +- coderefinery.github.io/obs-tablet-remote/#!auto&host=HOST&port=4444&password=PASSWORD&config=https://raw.githubusercontent.com/coderefinery/obs-config/master/obs-tablet-remote-config.json + + +Go to this URL. It will prompt you for a password (or the broadcaster +might add the password to the URL already). The OBS remote control +will open with a pre-arranged configuration for your course, with +buttons corresponding to the controls you see above. + + + +## See also +(none yet) diff --git a/_sources/exercise-coordinator.md.txt b/_sources/exercise-coordinator.md.txt new file mode 100644 index 00000000..a0b7f763 --- /dev/null +++ b/_sources/exercise-coordinator.md.txt @@ -0,0 +1,8 @@ +# Exercise coordinator + +Also called team leader coordinator. + +The exercise coordinator makes sure that the hands-on idea of the workshop is preserved. They remind the instructors to check and report their exercises before the workshop. They are also the contact person for the team leaders and organize the team leader onboarding before the workshop. + +If wished, they can also host the exercise Zoom room and support the registration coordinator with building the teams for the breakout rooms in Zoom. + diff --git a/_sources/expert-helpers.md.txt b/_sources/expert-helpers.md.txt new file mode 100644 index 00000000..5dc6e303 --- /dev/null +++ b/_sources/expert-helpers.md.txt @@ -0,0 +1,93 @@ +# Expert helpers + +We mainly have expert helpers for large workshops. + +* As an expert helper, your main job is to move between different + groups and make sure that groups are doing well. + +* You might be summoned to a group whose helper needs extra help, or + take the place of a helper if a group doesn't have one. + * Watch HackMD/Zulip for this, though requests might come in from + other channels, too. + +* No one is expected to know everything, but an expert helper should be + able to find a person who can answer, or confident enough to say + they should move on. + +* Make sure you have a new (newer than 15 october 2020) Zoom client, + so that you can join arbitrary breakout rooms. + * If you don't, then you have to ask to be put into some room, and + then you can swap to any other room. + +* Report an overview of the pulse of the breakout rooms in zulipchat + (or hackmd). Is everyone behind? People finishing early? Big + differences between them? Questions which we should bring up in the + main room? + +* Monitor if any team leaders need extra help or training. Should we + improve our team leader training? + +## Tasks + +There's not much difference between a team leader and expert helper, but we +envision this role standing by and jumping into rooms when there's a +difficult problem. + +- Sometimes, you wait around for a problem that needs your attention. + But it's better to be proactive and go into the rooms yourself and + check them out. Talk to the organizers/instructors to see which you + should do. +- You aren't assigned to particular breakout room, but **you can + switch between them** (but it's not obvious how): + - To do this, you *do* get assigned into one room initially. Join + that room. *After* you are in the room, click on "Breakout + Rooms", and then `Join` to switch to a different room of your + choice. + - You also always have the option "Leave breakout room" (if in a + room) or "Join your assigned room" (if in main room and assigned + one). +- **Your role is to switch between breakout rooms and check up on them.** + - e.g. join room 1, take a look/ask how it is, then join room 2, + then 3, then back to 1, and repeat. + - Of course, stay in one longer, if it's needed. + - Make a note of any important questions to be asked in the main + room afterwards. +- Try to divide up the breakout rooms between the staff, and try to + join and catch up with the same rooms (this promotes familiarity). + - E.g. A rotates between rooms 1-3, B gets rooms 4-7, C gets rooms + 8-11. +- **Make sure to watch the HackMD for expert helper requests**, this could help + you decide which room to jump to next. Comment when you are heading + there. + +Concrete example for an expert helper's time: +* I join breakout room 5 randomly. I spend 15 seconds watching, then + ask if things are going OK. If everything is good, I move on within + a minute since I am not needed (if there is a good break, I'll ask + "everything OK? good, see you around."). If there are questions + that I can help with, I answer them. If they seem to be struggling, + then I will make a note in the HackMD and stay a while longer and + watch/help. + + +## Common issues and solutions + +- A room is very slow, the person sharing the screen is working quite + slowly. + - Kindly suggest that you or someone else take over and go through + it faster + - Yes, this is hard to say nicely +- No one wants to take initiative and screen share + - If you think everyone is confident enough, this can be OK + - But especially at the beginning of the workshops, you can share + your own screen and go along with people. + +- Someone is having trouble installing software + - "Perhaps we can take a look at this after the workshop? We try + to make sure everything is installed beforehand, but " + +Other reference: + +* {doc}`team-leaders`: important reference +* {doc}`hackmd-helper`: You may spend a lot of time watching hackmd. + diff --git a/_sources/governance.md.txt b/_sources/governance.md.txt new file mode 100644 index 00000000..b2e26ac9 --- /dev/null +++ b/_sources/governance.md.txt @@ -0,0 +1,44 @@ +# CodeRefinery governance + + +## CodeRefinery Community + +Right now, the CodeRefinery community is small, so we do not want to +make things very formal. However, we expect things to formalize in +proportion to its need. + +In short: + +- Team meetings are approximately once a week. Rough consensus is + used to make decisions. Read more: + https://coderefinery.org/organization/meetings/ +- Important decisions should also be announced and discussed via chat + in advance, and ideally at several meetings. +- Because this is a small project, the deciding factor is "what does + someone want to do?". Meetings provide a way to empower people to + take action which may otherwise be hard to find in asynchronous + chat, despite the {ref}`voting `. +- The monthly "Community calls" allow us to get a perspective of a + broader audience and bring in new members. +- This document will be updated (by pull request+discussion) as we + improve our governance in the future. + +In the future: + +- An advisory role could to taken on by some sort of community council + or board made up of partner representatives and community + representatives. + + +## NeIC project + +The [Nordic e-Infrastructure collaboration](https://neic.no) funds a +part of CodeRefinery, and with that comes a certain standard of +governance and reporting +(see also the [collaboration agreement](https://coderefinery.org/about/reports/phase-3-collaboration-agreement.pdf)). +However, we consider this to be in parallel +to the community project (with the community project being more +important). + +There is a lot of overlap between the NeIC-sponsored staff and the +community, but the community will increase in proportion over time. diff --git a/_sources/hackmd-helper.md.txt b/_sources/hackmd-helper.md.txt new file mode 100644 index 00000000..a265c3b7 --- /dev/null +++ b/_sources/hackmd-helper.md.txt @@ -0,0 +1,177 @@ +# HackMD manager + +We have one person who is a "HackMD helper". This isn't the only +person that should edit and answer, but one person shouldn't have too +much else on their mind so can focus on it. They also make sure that +HackMD is updated with exercise, break, and other meta-information to +keep people on track. + +Below, (*) = important. + +## Before the workshop + +* Create a new hackmd for the workshop +* make sure that **editing is enabled for anyone without login** +* Add workshop information, links to the workshop page and material +and an example question and answer to the top of the hackmd (see below) + +## Most things to edit (everyone) + +Make it easy to post after the course and consistent to follow: + +* Tag all names with `[name=XXX]` (so they can be removed later), + remove other personal data or make it obvious. +* Add in information on exercises (new section for them, link, end + time, what to accomplish) +* Make a logical section structure (`#` for title, `##` for sections, + `###` for episodes, etc. - or what makes sense) + + + +## General HackMD practices + +```{figure} img/hackmd--full-demo.png +:align: right + +A live demo of HackMD during a Q&A time. The two instructors are +discussing some of the import answers. Multiple learners have asked +questions, multiple answers, and some remaining to be answered +``` + + + +Keep it formatted well: + +- (*) Tag names you see with `[name=XXX]` so that we can remove it + later. +- Heading level `#` is only the page title +- Add a new `##` heading when a new *lesson* or similar thing is + started (introduction, icebreaker, break between lessons, etc) +- Add a new `###` heading when a new *episode*, *exercise*, *break* + (within exercise session) +- Ensure people are asking questions at the bottom, direct them there + if they aren't. +- (*) Ensure each question is a bullet point. Each answer or follow-up + should be a bullet point below. + - Should you use more deeply nested bullet points, or have only one + level below the initial question? It depends on the context, but + if a conversation goes on too long, try not to let it go too + deep. + + +Update with meta-talk, so that learners can follow along easily: + +- Add Icebreaker and introductory material of the day. Try to talk to + people as they joined to get them to open HackMD and answer. +- Anything important for following along should not be only said via + voice. It needs to be in the HackMD, too. +- New lessons or episodes, with links to them. +- For exercises, link to exercise and add the duration, end time, + goals. If these are unclear, bring it up to the instructor by voice. +- Add a status display about breaks. + + +Screenshare it when necessary: + +- During breaks and other times, share the HackMD (including the + notification about break, and when it ends). +- It is nice if the arrangement allows some of the latest questions to + be seen, so people are reminded to ask there. +- Someone else may do this, but should make sure it happens. + +Answer questions + +- If there is an question that should be answered by the instructor by + voice, bring it up (by voice) to the instructor immediately. +- During breakout sessions, watch for HackMD notifications about + breakout rooms that need help + and direct someone to that room. +- How soon do you answer questions? Two points of view: + - Answer questions right away: can be really intense to follow. + - Wait some so that we don't overload learners: reduces the info + flow. But then do people need to check back more often. + - You need to find your own balance. Maybe a quick answer right + away, and more detailed later. Or delay answers during the most + important parts of the lecture. +- Avoid wall-of-text answers. If reading an answer takes too long, it + puts the person (and other people who even try to read it) behind + even more by taking up valuable mental energy. If an answer needs a + wall of text, consider these alternatives: + - Progressive bullet points getting more detailed (first ones + useful alone for basic cases) + - Don't be worried to say "don't worry about this now, let's talk + later." + - Figure out the root problem instead of answering every possible + interpretation + - Declare it advanced and that you will come back later. + +Ensure it can be posted quickly: + +- HackMD gets posted to the workshop webpage. For this, it needs some + minimal amount of formatting (it doesn't need to be perfect, just + not horrible). +- All names and private information needs to be stripped. This is why + you should rigorously tag all names with `[name=XXX]` so they can be + removed (see above). + - Learner names can be completely removed. CR staff names can be + `[name=CR]` or something similar. + - There may be other private URLs at the top or bottom. + +- If possible, send the PR adding the HackMD to the workshop webpage + (though others can do this, too). + + + +## HackMD format example + +``` +# Workshop, day 1 + + +## Lesson name +https://coderefinery.github.io/lesson/ + +### Episode name +https://coderefinery.github.io/01-episode/ + +- This is a question + - Anwser + - More detailed answer +- question + - answer + +### Exercises: +https://link-to-exercise/.../.../#section +20 minutes, until xx:45 +Try to accomplish all of points 1-3. Parts 4-5 are optional. + +Breakout room status: +- room 2, need help with Linux permissions +- room 5, done + +### Break +:::danger +We are on a 10 minute break until xx:10 +::: + + +## Lesson 2 +https://coderefinery.github.io/lesson-2/ + +``` + +## Posting HackMD to website + +HackMD should be posted sooner rather than later, and hopefully the +steps above will make it easy to do so quickly. You could wait a few +hours, to allow any remaining questions to be asked an answered. + +- Download as markdown +- Remove any private links at the top +- Adjust headings so that they are reasonable +- Look for private info and remove it + - Search document for `[name=???]` (change to `[name=staff]` or + `[name=learner]`) + - Any names not tagged with `[name=]` + - usernames in URLs + - private links diff --git a/_sources/hackmd-mechanics.md.txt b/_sources/hackmd-mechanics.md.txt new file mode 100644 index 00000000..2d132863 --- /dev/null +++ b/_sources/hackmd-mechanics.md.txt @@ -0,0 +1,83 @@ +(how-to-hackmd)= +# Collaborative document mechanics and controls + +[Hackmd](https://hackmd.io) or [HedgeDoc](https://hedgedoc.org/) are real-time text editor online. We use it to: +* As a threaded chat, to **answer questions and provide other information** without + interrupting the main flow of the room. +* provide everyone with a **more equal opportunity to ask questions**. +* **create notes** which will be archived, for your later reference. + +You do not need to login/create an account to be able to edit the document. + +## Basic controls + +```{figure} img/hackmd--controls.png + +This may look slightly different on mobile devices and small windows. +``` + +- At the top (left or right), you can switch between **view**, + **edit**, and **split view and edit** modes. + +- You write in [markdown](https://commonmark.org/help/) here. Don't + worry about the syntax, just see what others do and try to be like + that! Someone will come and fix any problems there may be. + +- Please go back to view mode if you think you won't edit for a + while - it will still live update. + + +## Asking questions + +**Always ask questions and add new sections at the very bottom**. +You can also answer and comment on older questions, too. + +```{figure} img/hackmd--questions2.png + +Questions and answers in bullet points +``` + +Since we plan to publish the questions and answers later as part +of the workshop page, we recommend to not use any names. You can indicate +your own name to make it easier to discuss more during the workshop but +then always use this form: `[name=Myname]`. This makes it easier for +us to automatically remove all names before publishing the notes. + +Other hints: + +- Use `+1` to agree with a statement or question (we are more likely + to comment on it). + +- Please leave some blank lines at the bottom + +- NOTE: Please don't "select all", it highlights for everyone and adds a + risk of losing data (there are periodic backups, but not instant). + +- It can be quite demanding to follow the collaborative document closely. Keep an eye + on it, but consider how distracted you may get from the course. For + things beyond the scope of the course, we may come back and answer + later. + + +## Don't get overwhelmed + +There can be a flood of information on the collaborative document. Scan for what is +important, then if you would like come back later. But it is +important to keep checking it. + + +## Privacy + +- Assume the collaborative document is **public and published: you never + need to put your name there**. + +- The collaborative document will be **published on the website afterwards**. We will + remove all non-instructors names, but it's easier if you don't add + it there in the first place. + +- Please keep the link private during the workshop, since since + security is "editable by those who have the link". + +- You can use `[name=YOURNAME]`, to name yourself. We *will* remove + all names (but not the comments) before archiving the notes (use + this format to make it easy for us). diff --git a/_sources/host.md.txt b/_sources/host.md.txt new file mode 100644 index 00000000..c4d1a622 --- /dev/null +++ b/_sources/host.md.txt @@ -0,0 +1,66 @@ +# Host + +WARNING: page out of date, this is also split to the director. + +- Make all of other staff and expert helpers co-hosts. +- Take attendance in spreadsheet, if we do that. + - TODO: provide sample spreadsheet + - It might be easiest to take attendance all at once, in the middle + of the session, after everyone has been assigned to breakout + rooms. + + + +## Breakout rooms + +- Rename people to include breakout room number (other co-hosts should + help and hopefully do most of this work too), though. (this is a + continuous process as people drop out and rejoin) +- Assign people to breakout rooms (this is a continuous process) +- Merge breakout rooms as necessary, to try to keep them balanced well +- Constantly watch for new people joining, rename them, and assign + them to breakout rooms. + - Note, you might have merged the room they were originally in, so + they might end up in an empty room! +- Plan for the future: how many helpers might be missing, which rooms + need to be merged. Can you keep the merging somewhat consistent + over time? + + + +## Recording + +Recording workshops provides a way for learners to get an instant +review of what was covered, increasing learning. We don't currently +intend for workshop recordings to be useful to new people learning +later, but they could be. + +- Record the workshop or give permission for others to record. + - If you are recording, you can't leave and go to other rooms. + - Perhaps a separate computer could record? +- spotlight speaker +- dual monitor mode? +- ensure that screen is always being shared? +- stay in speaker view (not gallery view) +- start and stop recording +- rename recording immediately `dayN-lessonname-zoom.mp4` and upload + to google drive. + + + +## Streaming + +All of the steps needed to record mean that you can stream, too. In +fact, you could look at streaming as a side-effect of recording (or a +way to record). + +- spotlight speaker +- start streaming +- dual monitor mode? +- ensure that screen is always being shared? +- stay in speaker view (not gallery view) +- have stream feed open. If you see it change to gallery view, fix it + immediately. +- stop streaming +- download recording from twitch, rename to + `dayN-lessonname-twitch.mp4` and upload to google drive. diff --git a/_sources/how-to-attend-inperson.md.txt b/_sources/how-to-attend-inperson.md.txt new file mode 100644 index 00000000..f57979f0 --- /dev/null +++ b/_sources/how-to-attend-inperson.md.txt @@ -0,0 +1,89 @@ +(attend-inperson)= +# Attending an in-person workshop + +We are glad you would like to attend an in-person workshop. This page +will help you mentally and physically prepare. + +Our workshops are interactive and hands-on, and you will get the most +out of them if you can take part in all exercises, unlike a normal +academic lecture where you mainly listen. Thus, please read this and +come prepared! + + + +## General prerequisites, software installation, etc. + +Check your workshop page for the general setup specific to that +workshop. + +- Often, there is something to install. We usually ask you to install + things so that your computer is set up to do work later. +- There may be some basic skills, such as the command line shell, to + review in advance. + + +If all else fails, join the workshop well in advance and ask +for help then. Usually, there will be enough time to get ready for +the day. + + + +## Take the workshop seriously + +It's easy to think "it's just a class, it's easy to passively watch". +However, for an interactive workshop you do need to take part to get +the most of out it, and our workshops are targeted to that. If you +read this page and the workshop prerequisites, you should be OK. + + + +## Social + +Attend with someone! Register together and try to sit near them. +This will create a network of learning and practice that will last +much longer. + +If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills. + + + +## Computer and equipment + +Bring your laptop and charger, of course. If you use external mice, +etc, it would be good to bring them too. You'll be on your device a +lot. + +Usually, you'll need to look at both the lesson webpage and the window +where you are doing the exercises at the same time. Consider how you +can arrange windows to do this best. + + + +## Time management + +Try your very best to attend the whole workshops; at least don't miss +the early sessions. Later sessions depend on earlier ones, and it's +easy to get behind. Tell others this is important so that you can +free your schedule. + +Arrive 10 minutes early to get ready. + + + + + +## Final notes + +Arrive 10 minutes in advance to get set-up. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start. + +There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions. + +Sign up on the [notify me +list](https://coderefinery.org/workshops/upcoming/#notify-me) to hear +about what comes next. diff --git a/_sources/how-to-attend-online.md.txt b/_sources/how-to-attend-online.md.txt new file mode 100644 index 00000000..f17471f6 --- /dev/null +++ b/_sources/how-to-attend-online.md.txt @@ -0,0 +1,127 @@ +(attend-online)= +# Attending a Zoom workshop + +We are glad you would like to attend an online workshop. This page +will help you mentally and physically prepare. + +Our workshops are interactive and hands-on, and you will get the most +out of them if you can take part in all exercises, unlike a normal +academic lecture where you mainly listen. Thus, please read this and +come prepared! + + + +## General prerequisites, software installation, etc. + +Check your workshop page for the general setup specific to that +workshop. + +- Often, there is something to install. We usually ask you to install + things so that your computer is set up to do work later. +- There may be some basic skills, such as the command line shell, to + review in advance. + +**Do the installation and configuration in advance, and double check +it.** In real workshops, problems here slow us down a lot, and if +you don't prepare, you will immediately fall behind. If there is a +pre-workshop session for installation, go there if needed. + +If all else fails, join the workshop well in advance and ask +for help then. Usually, there will be enough time to get ready for +the day. + + + +## Take the workshop seriously + +It's easy to think "it's just online, it's easy to passively watch". +However, for an interactive workshop you do need to take part to get +the most of out it, and our workshops are targeted to that. If you +read this page and the workshop prerequisites, you should be OK. + +*Don't do multiple meetings*, *reserve the entire timeslots on your +calendar*, *attend every session*, *do the preparation*. + + + +## Social + +Attend with someone! Register together and try to be in their same +group. You could even reserve a room and work together. This will +create a network of learning and practice that will last much longer. + +If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills. + + + +## Workspace + +Get a good, quiet workspace. Make sure it is comfortable enough to +stay at for a while. + +An extra monitor is useful but not required, since there is a lot of +stuff to follow: the stream itself, the lesson webpage, and the window +where you are doing the assignment. You could also use a second +device to watch the stream (but if you do, see the +[Zoom](zoom-mechanics.md) page for info about screen sharing). + +You'll be expected to talk at some times and take part, not simply be +quiet and listen all the time. Try to be in a place where you can +speak without disturbing others. By the same token, you'll be +listening for a long time, and your ears may get tired of headphones. +If you have good enough external speakers, be somewhere that you can +use them (perhaps only sometimes - when it doesn't interfere with your +microphone.) + +If you work in a large office, consider attending from home or in a +meeting room so that you can speak and listen more freely. If you +need and extra monitor or more comfortable seating space and don't +have that at home, consider working at your office. Yes, these are +conflicting ideas, you need to find what works best for you. + + + +## Time management + +Despite what most people think, attending things online can be harder +than in-person. + +Don't schedule overlapping meetings, reserve the entire timeslots, +minimze distractions. It's easy to think you can do multiple things +at once when doing it online, but really it's a trap. + +Join the workshop 10 minutes early to get ready. + +There will be breaks, but even long ones go by very fast, and this +gives you limited time to make coffee, eat, etc. We try to limit +ourselves to half-days because of this, but consider preparing food, +coffee, etc. in advance. + +Make sure you take the breaks, walk around some, etc. + + + +## Live streaming + +If the workshop is also streamed, see +{doc}`Live streaming ` for how to attend that +way. + + + + +## Final notes + +Join the stream 10 minutes in advance. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start. + +There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions. + +Sign up on the [notify me +list](https://coderefinery.org/workshops/upcoming/#notify-me) to hear +about what comes next. diff --git a/_sources/how-to-attend-stream.md.txt b/_sources/how-to-attend-stream.md.txt new file mode 100644 index 00000000..df9de4eb --- /dev/null +++ b/_sources/how-to-attend-stream.md.txt @@ -0,0 +1,202 @@ +(attend-stream)= +# Attending an livestream workshop + +We are glad you would like to attend an livestream workshop. This page +will help you prepare and get the most out of the workshop and take +advantage of the diverse ways to attend. + +Even though it's a one-to-many livestream, the course is still +interactive. In fact, it's more interactive, since everyone can Q&A +at the same time via {doc}`HackMD `. Since we can +record without privacy risk, you are better able to catch up and +review. Read on to learn more. + +- You might register to Zoom breakout rooms, which *are* interactive. +- {doc}`HackMD ` allows you to ask questions anonymously - + even better than a normal workshop! Once we have a few tens of people in + any workshop, people don't ask voice questions anyway. +- In some workshops, you can register for breakout rooms to get + interactive assistance during the exercise/breakout sessions. + + + +## How it works + +- You open the livestream in a web browser. This is the "TV", it is + always on (but sometimes silent). +- If you are part of an exercise/breakout group, be with them. The + stream will tell you when the exercise/collaboration times are, and + you go to there. + - If you are attending Zoom exercise session, open this at the + beginning. Leave it minimized when it's not active. + - If you are with an in-person group, be together. When the stream + is quiet, you can interact freely. + +- The livestream is a portrait screenshare, so that it will only take + up half of your screen (and the other half is for you to work). (If + you are in a physical meeting room with a projector or second + monitor, it can be half the livestream and half the HackMD - this + will make sense when you see it). + + +```{figure} img/layout--learner-livestream-sidebyside-onebrowser.png + +Screen layout with livestream on one side and workshop on the other. +``` + + +## General prerequisites, software installation, etc. + +Check your workshop page for the general setup specific to that +workshop. + +- Often, there is something to install on your own computer. (We + usually ask you to set up your own computer, so you can continue + working independently later.) +- There may be some basic skills, such as the command line shell, to + review in advance. + +**Do the installation and configuration in advance, and double check +it.** Our instructions are standard enough that someone local should +be able to help you, if some central install help isn't provided. The +livestream can't wait for individual people (but a local group can +provide live support). + + + +## Take the workshop seriously + +It's easy to think "it's just online, it's easy to passively watch". +And that is OK! We'd rather have someone watch in case it might be +useful, than exclude people who don't have time. Our material is +available for later. In this case, please don't register for our +Zoom/in-person sessions, since that can take a spot from others. + +However, we design the workshops to be interactive, and there is a lot +of time scheduled for hands-on work and Q&A. Reading this page and +preparing will help you to make the most of it: *don't do multiple +meetings*, *reserve the entire timeslots on your calendar*, *attend +every session*, *do the preparation*. + + + + +## Social + +Attend with someone! Register together and try to be in their same +group. You could even reserve a room and work together. This will +create a network of learning and practice that will last much longer. + +If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills. + + + +## Workspace + +Get a good, quiet workspace. Make sure it is comfortable enough to +stay at for a while. + +An extra monitor is useful but not required, since there is a lot of +stuff to follow: the stream itself, the lesson webpage, and the window +where you are doing the assignment. You could also use a second +device to watch the stream. However, we do design things to fit on +one computer. + +If you have registered to attend breakout rooms, you'll be expected +to talk at some times and take part, not simply be +quiet and listen all the time. Try to be in a place where you can +speak without disturbing others. By the same token, you'll be +listening for a long time, and your ears may get tired of headphones. +If you have good enough external speakers, be somewhere that you can +use them (perhaps only sometimes - when it doesn't interfere with your +microphone.) + +If you work in a large office, consider attending from home or in a +meeting room so that you can speak and listen more freely. If you +need and extra monitor or more comfortable seating space and don't +have that at home, consider working at your office. Yes, these are +conflicting ideas, you need to find what works best for you. + + + +## Time management + +Paying attention to something requires time, whether it is online or +in-person. + +Don't schedule overlapping meetings, reserve the entire timeslots, +minimize distractions. It's easy to think you can do multiple things +at once when doing it online, but really it's a trap. + +Plan to join the stream 10 minutes early to get ready - we start with +icebreakers and discussion then. + +There will be breaks, but even long ones go by very fast, and this +gives you limited time to make coffee, eat, etc. We try to limit +ourselves to half-days because of this, but consider preparing food, +coffee, etc. in advance. + +Make sure you take the breaks, walk around some, etc. + + + +## Accessibility + +We believe that livestream workshops offer a wide variety of tools +which are useful to allow everyone to succeed. Consider how you want +to attend to make it the best for you: + +* Our material is provided in writing (lesson websites), by voice, and + by demo. You don't have to strictly follow along at the speed we + teach. +* We record videos and post the notes so you can review at your own + pace later on. Videos don't include audience voice or video, so you + don't have to be afraid to interact. +* HackMD allows anyone to ask questions anonymously and + asynchronously, without interrupting others. On the other hand, + there are a *lot* of questions, so don't watch too closely if it is + distracting. We continue answering questions for a little bit after + each day ends, so you can ask even if you can't write the question + on time. +* Lesson websites/HackMD use standard web technologies, so that + browser accessibility plugins can be used (for example making the + font more accessible, check browser extensions). +* Twitch can be live-captioned using the Google Chrome browser. Our + videos on YouTube provide automatic captions immediately, since + videos are released immediately they don't come too late for you. + Other standard browser extensions can also provide other video + accessibility services without asking us. +* You can follow along without providing any personal data + (registration, Twitch works with cookies blocked) - though + registration helps our reporting. + + + +## Communication + +Most communication goes through [HackMD](hackmd-mechanics). Make sure +that you open it and try it out during the icebreakers - it will +become obvious then. There will be an absolute flood of information +there, so watch strategically and don't let yourself get overloaded. + +HackMD is much better than chat, since you can ask *anonymously*, you +can ask *at the same time as others*, and *multiple people can +answer*, and *we fix it up and publish it at the end*. + + + +## Final notes + +Join the stream 10 minutes in advance. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start. + +There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions. + +Sign up on the [notify me +list](https://coderefinery.org/workshops/upcoming/#notify-me) to hear +about what comes next. diff --git a/_sources/icebreakers.md.txt b/_sources/icebreakers.md.txt new file mode 100644 index 00000000..7b3916f5 --- /dev/null +++ b/_sources/icebreakers.md.txt @@ -0,0 +1,143 @@ +# Icebreakers + +This is a list of possible icebreaker questions. + +You should make it very clear that *everyone* should answer the +question, and thus it should be very broad. The point is to make sure +they know how to use the tools. Make sure that the question feels +inclusive - not just that people can answer, but that it doesn't make +people feel they are far behind others. + +If you ask people to add there name as part of an introduction, the +document becomes personal data and must be controlled more, and sets +you on a path to extensive editing before it can be released. Think +before you do this - maybe you just ask for information about +backgrounds without names. + + +## Other references + +* + + +## Relevant to workshop + +An icebreaker isn't supposed to be relevant to the workshop, but it +could be useful some days or as a second question. + +- What from this workshop are you going to use in the near future? +- What was the most confusing thing from yesterday? +- Have you already used what you have learned in the course during + your work? If so, what? +- What is the most useful thing you know, that you wish someone had + just told you about computing when you first started it? + +### Adapted from [pre-workshop survey](https://github.com/coderefinery/pre-workshop-survey/blob/main/questions/questions.md) + +- What is the operating system that you will use during the course (on your laptop)? + - macOS + - Linux + - Windows + - Other + +- Have you used version control? If yes, which? + - I don't know what it is + - I haven't used version control but I know what it is + - I have used version control, but I don't know which system + - Git + - Mercurial + - Subversion + - CVS + - Perforce + - Bazaar + - Other + +- Which programming languages are you using or will you use in your projects? + - Matlab + - R + - Python + - Perl + - C + - C++ + - Fortran 77 + - Fortran 90+ + - Julia + - Haskell + - Go + - Rust + - Other + +- Are you using automated testing platforms (e.g. Travis CI, Jenkins or GitLab CI) in your programming project(s)? + - No and I don't know what it is + - No but I know what it is + - Yes + +- Are you employing code review in your programming project(s)? + - No and I don't know what it is + - No but I know what it is + - Yes + +- Are you using the Jupyter Notebooks in your programming project(s)? + - No and I don't know what it is + - No but I know what it is + - Yes + +- Are you using a web-based repository for your code(s)? Which ones? + - I'm not using a web-based repository + - GitHub + - GitLab + - Bitbucket + - Redmine + - source.coderefinery.org + - Other + +- How would you describe your programming experience? + - I have no programming experience + - Basic understanding and experience, I have looked through code and made minor adjustments + - I have written my own simple programs + - I have written many small codes and/or contributed to large complex software + - I am an expert + +- How comfortable are you with the Unix/Linux command line working in a terminal window? + - I know what most of the following commands do: cd, ls, cat, mv, rm, chmod, man, mkdir, cp, ssh + - I do not know what most of these commands do + +- Please mark the sessions that you are most interested in. + - Introduction to version control + - Documentation + - Jupyter notebooks + - Collaborative distributed version control + - Managing complexity and modular code development + - Automated testing + - Git branch design + - Software licensing + - Reproducible research + + +## General questions + +- What’s a good icebreaker question? +- How is the weather where you live? +- How are you doing? +- Are you happy to continue this workshop for another week? +- Is that an Iphone? +- If you could have anything what you want for dinner today, what would it be? +- What cool thing/tool have you discovered/learned the past days? + (independently of this course) +- Is this course part of your work? Or do you spend free time on it? +- Do you like olives? +- Are you annoyed at the size of anaconda? +- What’s your favourite pizza? +- Do pineapples :pineaplle: belong on pizza? +- What did you have for breakfast? +- Do you like Python? +- Where’s your favorite place to nap? +- Do you use git or identify as one? +- When and how did you learn to program? + + + +## Credits + +Most of these questions came from a "What is an icebreaker" question +in the first Mega-CodeRefinery workshop. diff --git a/_sources/index.md.txt b/_sources/index.md.txt new file mode 100644 index 00000000..97e42923 --- /dev/null +++ b/_sources/index.md.txt @@ -0,0 +1,89 @@ +# CodeRefinery operation manuals + +This site contains various manuals about CodeRefinery workshops and +teaching/lesson development in general. + +These pages document past history, but they don't dictate future. +They are a starting point: feel free to be adventurous. + +(toc-learners)= + +```{toctree} +:caption: Learners +:maxdepth: 1 + +how-to-attend-stream.md +how-to-attend-online.md +how-to-attend-inperson.md +Zoom mechanics and signals +Hackmd mechanics +``` + +```{toctree} +:caption: Workshop playbook +:maxdepth: 1 + +roles-overview +team-leaders +instructors +co-instructors +hackmd-helper +expert-helpers +host +registration-coordinator +exercise-coordinator +workshop-marketing +director +broadcaster +video-editor +workshop-organizers +workshop-playbook +``` + +```{toctree} +:caption: Online teaching +:maxdepth: 1 +online +coderefinery-mooc +obs +online-training +``` + +```{toctree} +:caption: Lesson design +:maxdepth: 1 + +Lesson design tutorial and reference +Lesson review checklist +``` + +```{toctree} +:caption: Misc +:maxdepth: 1 + +Writing technical docs +meeting-checklist +workshop-prep-call +Summary of the book "Teaching Teach Together" + +``` + +```{toctree} +:caption: About CodeRefinery +:maxdepth: 1 + +Chat +Contributing +local-breakout-rooms +open-your-courses +The project +governance +outreach +Logo and artwork +``` + +Download this guide as [single-page HTML](https://coderefinery.github.io/manuals/_builds/singlehtml/), +[pdf](https://coderefinery.github.io/manuals/_builds/CodeRefineryManuals.pdf), or +[epub](https://coderefinery.github.io/manuals/_builds/CodeRefineryManuals.epub). + +All material within this repository is licensed [CC-BY](LICENSE.md). diff --git a/_sources/indico/hints.md.txt b/_sources/indico/hints.md.txt new file mode 100644 index 00000000..f78f0210 --- /dev/null +++ b/_sources/indico/hints.md.txt @@ -0,0 +1,21 @@ +# Indico hints + +## Emailing people + +* Go to registration list +* Filter people based on who you need +* Select all (this selects only the visible people; you can confirm + this by looking at the names in the email box, though you can't see + them all our count them) +* Actions → Email +* Compose your email (warning: it is easy to lose everything, there is + no saving) +* Preview email to make sure it works +* **Ensure that it is sent from support@coderefinery.org** + * If you want a real test, you could register and send the first + draft to yourself (make sure you copy the full text first, + otherwise you lose the placeholders) +* **Copy full text before you send the email**, otherwise you lose the + form fields. +* Click send +* Don't worry diff --git a/_sources/indico/in-person.md.txt b/_sources/indico/in-person.md.txt new file mode 100644 index 00000000..7dec7761 --- /dev/null +++ b/_sources/indico/in-person.md.txt @@ -0,0 +1,9 @@ +# Indico in-person workshop workflow + + +## Flow + +* People register +* Confirm the people you want to accept. + +TODO: Is there anything else to note? diff --git a/_sources/indico/index.md.txt b/_sources/indico/index.md.txt new file mode 100644 index 00000000..6ceeb87e --- /dev/null +++ b/_sources/indico/index.md.txt @@ -0,0 +1,14 @@ +# Indico registration system + +This describes the Indico registration system as used by +CodeRefinery. Indico is a open-source registration system suitable for large +scientific meetings. NeIC runs one at https://indico.neic.no which we +routinely use. + +```{toctree} + +setup +in-person +online +hints +``` diff --git a/_sources/indico/online.md.txt b/_sources/indico/online.md.txt new file mode 100644 index 00000000..bbebfde1 --- /dev/null +++ b/_sources/indico/online.md.txt @@ -0,0 +1,53 @@ +# Indico online workshop workflow + +This describes the workflow in Indico online workshops + +## Basic types + +Registration types = {Learner, team leader, Livestream only} + +## Flow + +* People may register in any of the types. +* When people get accepted to `Type={Learner,team leader}`, they are + confirmed using the Indico moderation "approve registrations" + feature. (These people then become `State=Completed`) +* After soft deadline, accept the number of learners you think you can + handle (see above). + * Non-accepted people are moved to `Type=Livestream` but this is + mainly to help them, people can still register. +* A new field "I confirm I can attend via Zoom" is made visible. + Everyone in `State=Completed` is expected to log in and click this + box. + * Other non-accepted people +* Those who do not make `Confirm=Yes` are moved to `Type=Livestream`. + * Note: any saving of the form, even by staff, will set + `Confirm=No`. So `Confirm=No` does *not* mean that they declined, + it could also be staff who saved the form. +* If there are remaining free spots, they are given to those who are + `Type=Livestream Confirm=Yes`. +* Everyone else is set to `Type=Livestream` +* The event registration form is edited, so that the number of + `Type=Learner` spots is set to the actual number registered. Then, + no one else can register as a learner. + * This could be done a bit earlier in the process, but it prevents + even organizers from moving people between categories. Thus, it's + slightly more convenient to leave it free than have to adjust the + registration form every time you need to switch someone to learner + (for example, registering on a team) + +## Email filters + +During registration + +* People who want to in Zoom, `State!=Withdrawn Type={Learner,Exercise + Leader}` + +After confirmation + +* People in Zoom, `State!=Withdrawn Type={Learner,team leader}` +* PEople in livestream, `State!=Withdrawn Type=Livestream` + + + + diff --git a/_sources/indico/setup.md.txt b/_sources/indico/setup.md.txt new file mode 100644 index 00000000..1d87dccd --- /dev/null +++ b/_sources/indico/setup.md.txt @@ -0,0 +1,100 @@ +# Indico event setup + +We use the NeIC Indico service, , so you need to create +an account at . + +Radovan is manager of the CodeRefinery category in +indico.neic.no and will need to grant you permissions to create event pages. + +To create a new workshop page, it is easiest to clone a previous event. This +copies the registration form and metadata, but not the pre-workshop survey +which needs to be manually imported as a json file. + + +## Step-by-step instructions: + +### Copy basics from latest event + +- Visit , and click CodeRefinery which takes you to . +- Click the latest workshop event. You might need to show "events in the future" to see the latest event. +- Go to admin mode (click the pen symbol on top toolbar, "Switch to the management area of this event"). +- Click the "Clone" button, and select "Clone Once". Click "Next" button. +- For "What should be cloned", select + "Registration forms" (do not clone "ACLs and protection settings"). + Uncheck "Refresh user information". Click "Next". +- Confirm category "CodeRefinery", and click "Next". +- Select the start date and time of the workshop, click "Clone". +- You are now on the cloned event page (confirm that the event number changed), and you should start updating the information. + +### Update copied event information + +- Adjust permissions so that only the workshop organizer(s)/coordinator(s) has/have access to the forms and data. + In order to have better control over who has access we do not copy "ACLs and protection settings" from older events. +- Update the Title, Description, Date, Time, Room, Venue and Address fields by clicking the pen symbols on the right. +- Click "Protection" and remove administrators who were copied from past event but should not have access to this event. +- Click "Registration" from the left-hand menu, and confirm that there is one or two registration forms, probably with a wrong title. +- Click the "Manage" button on the "List of registration forms", + - Click "Edit" on the "General settings" + - Update the registration form name and both the fields "Contact info" and "List of recipients" with your own email address to get notifications on new registrations. + - **Waiting list:** + - *Indico doesn't have an actual waiting list functionality. To implement a waiting list, we use moderated registrations and confirm all registrations up to max capacity (eg. 40). Registrations after that up to maximum number of participants (eg. 60) are left unconfirmed and an email is sent manually from Indico to the registrant that they are on the waiting list. Now we have a waiting list of size 60 - 40 = 20.* + - Activate "Moderated" which will require each registration to be approved. + - Set maximum number of participants (after which registration is closed), this should be *room capacity* + *waiting list size*. Click "Save". + - Then go back to "Manage" and verify and configure the "Registration Form": + read all fields and check that nothing outdated has been cloned to this + event. Adapt the dates. + +#### More information about the registration process + +- The Description field in the general settings should contain additional information about the registration process: + ``` + Welcome to the registration page for the Online CodeRefinery workshop March 22-24 and 29-31! + + To complete your registration, you need to: + + 1) Enter your registration details by clicking the "Register now" button below. + 2) Fill in the pre-workshop survey by clicking the "Fill out the survey" button below. + + Confirmation email + After filling out the registration form you will receive an automatic + confirmation email, but please note that all registrations go to a waiting + list first. Please contact to support@coderefinery.org if you don't receive + this confirmation email within a couple of days after signing-up.  + + Questions? + If you have any questions about your registration status, please write to support@coderefinery.org. + + Looking forward to seeing you at the workshop! + ``` + +### Import survey + +- Now click "Surveys" from the left hand menu. You will now import the standard pre-workshop survey from a json file. +- Go to and clone the repository. +- Go back to the Indico Surveys page, and click "Create survey" +- Name the survey "Pre-workshop survey", enable the option "Anonymous submissions" and disable "Only logged-in users". Click "Save". +- Back on the "Surveys" page, click "Manage" on the newly created "Pre-workshop-survey" survey. +- It will say "Survey not ready". Click "Prepare questionnaire". +- Click the "Import" button, click "Choose from your computer", and find the file exported-survey.json" from the pre-workshop-survey repository you cloned. Click "Save". +- Go back to the survey page (click "Surveys" on the left), and click "Manage". Click the "Open now" button to let the survey go live. + + +### Open registration + +- Go to the Registration page from the left-hand menu, and click "Manage". +- It will say "Registrations are not open yet". Click "Start now" for both regular and staff registration forms to open for registrations. +- Click the blue "Switch to display view" on the top left. +- Confirm that both the "Surveys" and "Registration" links can be seen. +- Click both links to do a test registration +- Once you manage to test-register, update the workshop webpage, and announce via Twitter. + + +### Exporting registrations + +- Go to the Registration page from the left-hand menu, and click "Registrations" which + takes you to the list of registrations.. +- Click the check-box on the menu just above the list of registrations and select "All". +- Click on "Export" from the top menu, select "CSV" and choose a download directory. +- You can use the [read_csv.py](https://github.com/coderefinery/manuals/blob/master/scripts/read_csv.py) to parse the CSV file and print + selected fields, e.g. email addresses to be used in sending out information to + participants. diff --git a/_sources/instructor-intro.md.txt b/_sources/instructor-intro.md.txt new file mode 100644 index 00000000..2caa09ce --- /dev/null +++ b/_sources/instructor-intro.md.txt @@ -0,0 +1,189 @@ +# Instructor introduction + +This page gives general instructor and expert helper introduction +material. These people are responsible for more than one breakout +room, and have to have an overview of more of the course. In short, +if you want to take the next step in CodeRefinery, this is the place +to start. + +```{seealso} + +{doc}`co-instructors` for an intro for starting co-instructors. +``` + +## How do you get started? + +That's what this page is about (well, and the [instructor +training](https://coderefinery.github.io/instructor-training/)). We +believe that you best learn by working with others in practice, and +provide plenty of opportunities to do that. + + +## Starting materials + +Reading here: the other pages in the section, see sidebar. +* {doc}`team-teaching` +* {doc}`presenting` +* {doc}`instructor-tech-setup` +* {doc}`instructor-tech-online` + +Also read the team leader information +* {doc}`team-leaders` - general on motivation and how to prepare for + breakout rooms + +Reading elsewhere: +* [CodeRefinery instructor + training](https://coderefinery.github.io/instructor-training/) +* [Carpentries instructor training](https://carpentries.github.io/instructor-training/) + + + +## As an instructor + +Most of our workshops are very collaborative arrangements: you are +rarely alone. This is one way of looking at it: + +* Look at and revise the workshops before they teach, making small, + incremental improvements. But, you don't have to (and in some + sense, it's good if they stabilize some more). + +* Especially go over the examples when preparing. + +* Have a chat with someone else (probably another instructor or + expert helper) before teaching. We encourage this for + everyone, even experienced instructors, to better transfer knowledge + among each other and stay up to date with the latest developments. + +* Teach independently or co-teach. Ideally, co-teach the first + time(s). Really, we'd like to get to the point where we *always* + co-teach. Co-teaching doesn't mean different people take different + lessons, but two people teach all parts of the same lesson by + turning it into a discussion between the two instructors. TODO: + produce information on this. + +### in the main session + +As an instructor, when preparing your lesson you first need to decide how to balance between the +main room and breakout sessions. + +- **Clearly say when a learner watches, when they type along, when they should + work on something independently as an exercise.** +- CodeRefinery is traditionally a hands-on workshop, so breakout-room sessions should be a large part of the workshop. +- We usually keep the main room mostly for general discussions. Small exercises or polls can also be done in the main room, for all hands-on exercises we divide the learners into breakout-rooms each with one team leader. +- To give you an idea about how the work in the breakout rooms is going, monitor the hackmd closely and if time allows try to visit a few breakout rooms to see how it is going and if needed adjust the timing. + + +### Preparing for the breakouts (in the main room) + +**As an instructor, you need to clearly define what the tasks of each +breakout session is (even if it is just "explore and discuss").** +Online courses need more **"meta talk"** about how you expect things +to go, since it's not as easy to read the room or fill in expectations +later (distractions, hard to communicate to breakout rooms after +opened). + +- Clearly say what the tasks of the breakout session will be. +- Put that task and a link to the part of the lesson in the hackmd. +- Clearly say how long each breakout session will be (make sure it's + long enough and adjust during the exercise session if needed) +- Clearly say if things in the future will depend on this exercise (is + someone completely lost if they don't make it to the end. Halfway?) +- Try to make breakout sessions longer: + - imagine a 5 minute overhead for each session, getting people + there, deciding who does what, acquainted with what they need to + do, and debugging problems. + - 10 minutes is quite short, 20 minutes is best. + - **Can you say less and let people discover it for themselves?** + +As a team leader, if anything is unclear to you, it is very unclear to +others. Comment/Ask in the HackMD or speak up and ask! + +## Top issues new instructors face + +```{figure} img/screenshare/s10-kickstart-prompt-log.png +:align: right +:width: 50% + +An example of a beautiful screenshare. Note the portrait orientation +(you have half the screen free for notes and HackMD, learners have +half the screen free to do their own work). The terminal is +dark-on-light, a minimal prompt, no other fancy shell distractions, +there is a shell history visible, and slightly distinct colors between +the web browser and the terminal. +``` + +- Breaks are not negotiable, minimum 10 minutes. + +- Breakout sessions too short. Make them as long as possible, don't + expect to come back for new intro, then go back. + +- People will accomplish less than you expect. Expect learners to be 5 + times slower than you, at best! + +- All the other tools and stuff will go wrong. Try to not bring in a + dependency when you don't need it. + +- Trying to accomplish too much: it's OK to cut out and adapt to the + audience. Have a reserve session at the end you prepare, but are + ready to skip. + +- Not clearly separating (in the learner's mind, by meta-talk), the + differences between *demo*, *type-along*, and + *exercise*/*exercise-prep*. + - Demo and type-along are hard to do at the same time: they are very + different types of focus + - Type-along and exercise of the same thing are not good to combine, + leads to duplication + +- Explaining how, but not why. + +- Running out of time to making your environment match the + learner's. + +- Running out of time to set up good screen sharing practices + (terminal history, portion of screen, remote history) in advance. + +- Assuming learners remember what they have already learned, or know + the prerequisites. Or have stuff installed and configured. + +- Not managing expectations: learners think that you will accomplish + everything, and feel sad when you don't. Instead, say explicitly + what everyone should follow along, what you might want to watch, + what is only a demo. + +- Following the lesson as written at all costs. + +For {doc}`livestream courses `: + +- Worrying too much (forgetting that there is a co-teacher and break + time where you can discuss and plan your next step). + +- Speaking like learners should be able to speak up with voice, + instead of "answer in HackMD or discuss within your groups." + +- Forgetting to save time for Q&A: there is *more* Q&A because of + HackMD. You might take a few minutes to screenshare HackMD and + after each exercise session, after each break, after each episode, + and at the end of each day. + +- "Stop screenshare" instead of letting the other person start and + take it from you. Or, the broadcaster switching the scene. Never + do "stop screenshare". + +- Forgetting to screenshare the HackMD during Q&A time (this is the + most important way learners know it is active, and thus feel a + connection to the course). + +- Forgetting there are multiple ways to attend: not everyone is in a + breakout room, not everyone has helpers nearby. Instead, use + phrasing such as "for those of you in breakout rooms, go there now. + Everyone, remember to ask any questions in the HackMD, even if you + are alone." + +- Planning to do a demo during team breakout sessions (teams will + still hear your voice, if they mute the stream it's hard to bring + them back). + +- Sharing a fullscreen, not the 840x1080 portrait layout. + +- Showing non-creative-commons material on the stream. diff --git a/_sources/instructor-stream.md.txt b/_sources/instructor-stream.md.txt new file mode 100644 index 00000000..77e5e67c --- /dev/null +++ b/_sources/instructor-stream.md.txt @@ -0,0 +1,64 @@ +# Being an instructor in livestreamed CodeRefinery workshop + +## Basic setup + +In a livestreamed CodeRefinery workshop, we have two types of learners: Active learners attending in Zoom and passive learners watching the stream. +Learners from both groups will watch the stream from their own browser and have the possibility to interact with the instructors and ask questions via HackMD +(a collaborative note taking tool: {doc}`hackmd-mechanics`). +Active, registered learners will additionally get interactive help in Zoom breakoutrooms during exercise sessions. +Learners on stream can either form private groups or do the exercises on their own. +Following our team teaching strategy, your are never alone as an instructor. While you are teaching, you can fully focus on the task at hand, your co-instructor will watch the chat and HackMD and relay all important information to you. + +## I am teaching in a workshop, what do I need to know/do? + +* Attend the instructor onboarding session ({doc}`instructor-intro`) +* Make sure you have your tech setup for the course: {doc}`instructor-tech-online` +* Consider joining the learners Zoom to help in breakoutrooms and answer questions in HackMD +* When your teaching time approaches, join the instructors Zoom. + * Stay muted and turn your video off until it is your turn to teach + * Setup your windows that you want to share during teaching + * When it is your turn to (co-)teach, + * All co-instructors, turn on your video + * Unmute yourself only when talking + * Share only the important portion of your screen in vertical mode + * If you need a reaction from learners, use HackMD + * Co-Instructor watches HackMD and relays important information/questions + * Exercises: clearly state which exercises should be done and at what time the teaching continues +* After your lesson, consider joining learners Zoom +* If you can, join after-course-day-hangout with other instructors +* Give feedback on your teaching experience with CodeRefinery + +We have also collected a lot of material around teaching which you are free to read: +* {doc}`coderefinery-mooc` +* {doc}`presenting` +* {doc}`teaching-tech-together` +* {doc}`online` + + +## Why team teaching? + +-> see also {doc}`team-teaching` + +* makes lesson more lively +* less chance of forgetting something essential +* one of the instructors can watch for good questions in HackMD and ask/answer them on stream +* less stressful for the individual +* easier to include new instructors +* easier debugging, finding typos etc on stream +* you are not alone + +## Why livestream? + +A livestream workshop allows us to reach an unlimited number of people, at the cost of not being as interactive as in classroom/zoom room. +However, we have had great experiences with the following strategy: + +* HackMD as collaborative note-taking tool allows learners to ask questions anonymously and everyone can answer these questions asynchronously. +* Learners can register to join Zoom breakout rooms, which are interactive and team leaders can help with any questions during exercise sessions and breaks. +* Learners can also form private breakout rooms or meet in person and watch the stream and do exercises together. + +While the full livestream setup is a bit complicated, you as an instructor do not have to worry about anything but your teaching. +We have setup the whole system in a way that only active instructors are shown in stream, which makes video postproduction faster. +What makes our setup different from your 'usual zoom class' is that our instructors Zoom room that you are in while instructing is completely separate from the learners, while providing interaction possibility via HackMD. + + + diff --git a/_sources/instructor-tech-online.md.txt b/_sources/instructor-tech-online.md.txt new file mode 100644 index 00000000..7271fa3e --- /dev/null +++ b/_sources/instructor-tech-online.md.txt @@ -0,0 +1,174 @@ +# Instructor technical setup, online + +```{seealso} +This is online-specific instructor tech setup. For general, see +{doc}`instructor-tech-setup` which also applies here. +``` + +The information in this is currently specific to Zoom teaching and +livestream teaching. + +```{admonition} Final checklist + +See the list in {doc}`instructor-tech-setup`, which includes points for +online. +``` + +## Audio + +Audio quality, and balance between instructors, is *absolutely +critical* to good online work, especially teaching. Consider the +following: + +* Can you adjust your microphone volume from very low to + higher-than-needed? Make sure your dynamic range is larger than + "barely working", so that you have some room to adjust for later. +* Do you have a high-quality headset? A headset with microphone is + the most reliable, but if you can get a desktop setup working + well, that can be good too. Always have a high-quality headset for + backup anyway. +* If you have a bluetooth headset, consider: + + * Bluetooth headsets have significant latency compared to wired or + purpose-built wireless protocols like gaming headsets have. + * The microphone might not have enough bandwidth (if it's part of + the same headset). + * Bluetooth 5 is much better in both latency and quality. + * Consider investing (or getting your work to invest in) some + high-quality headset or desktop audio gear. + +* "Ducking" is when the first words are silenced/quieted by noise + cancellation, until it detects speaking. To avoid this, don't use + "high" noise cancellation (as low as possible is better). If you + need high cancellation because of background noise, switch to your + headset. + + + +## Screen sharing + +You have to assume the smallest screen from learners and plan for +that. You should share a **portrait** screen: either a portion of +your screen, or one window in portrait mode. See the examples below. + +- Learners have a small screen, and need room for their own terminals + and web browser open, too. A big screen or multiple monitors is + the special case. +- Sharing a 1920x1080 screen is not a good idea: you need to make all + the text size large so that learners can scale it down to have room + to do their work. Pixels are wasted. **Instead, force yourself to + save space by using a normal font size but sharing less of your + screen.** +- Zoom now has a "share portion of screen" (Screen sharing → Advanced + → Share a portion of the screen). +- For livestreaming, our aspect ration is 840×1080 (**portrait**). + This is a bit less than half your screen. This is 43% of the width + of your screen and the full height, for a standard FullHD screen. + +When streaming/recording: **Never stop sharing a screen, ask someone +else to take it over**. +There is a chance that the view goes to "gallery view" in the +recording or stream, which makes video editing harder or disrupts +learner privacy. + + + +### Screen share examples + +These are layouts of the actual screen or portion of screen being +shared: + +```{figure} img/instructor-tech-online/screenshare-fullhd.png +:width: 75% + +**S1**: A FullHD 1920x1080 screen shared. +``` + +```{figure} img/instructor-tech-online/screenshare-vertical.png +:width: 50% + +**S2**: A vertical screen layout shared. Note the extra shell history at the +top. The web browser is at the bottom, because the Zoom toolbar can +cover the bottom bit. +``` + +```{figure} img/instructor-tech-online/screenshare-jupyter.png +:width: 50% + +**S3**: A sort-of GUI (Jupyter) shared vertically. +``` + +```{figure} img/instructor-tech-online/screenshare-rsh.png +:width: 75% + +**S4**: This isn't a screenshare from CodeRefinery, but may be instructive. +Note the horizontal layout and shell history at the bottom right. +``` + +```{figure} img/screenshare/s5-shell-intro-dark.png +:width: 75% + +**S5**: Similar to above, but dark. Includes contents on the right. +``` + +```{figure} img/screenshare/s8-modular-code-development.png +:width: 50% + +**S8**: Jupyter + terminal, including the ``fish`` shell and the +terminal history. +``` + +```{figure} img/screenshare/s9-git-intro.png +:width: 50% + +**S9**: Similar to S8. Lesson + terminal, ``tmux`` plus terminal history +and dark background. +``` + +```{figure} img/screenshare/s10-kickstart-prompt-log.png +:width: 50% + +**S10**: HPC Kickstart course. Note the colors contrast of the +windows and colors of the prompt and text. The history is smaller and +doesn't take up primary working space. The working directory is +in the window titlebar. +``` + + +### Screen layout: learners + +This is how learners can arrange their screen: + +```{figure} img/instructor-tech-online/learner-largescreen.png +:width: 75% + +**L1**: Learner with a large screen, Zoom in dual-monitor mode so that the +instructur pictures are not shown. Screenshare is on the left side, +HackMD at bottom left, terminal and web browser on the right. +``` + +```{figure} img/instructor-tech-online/learner-normal.png +:width: 75% + +**L2**: A learner with a single large screen (Zoom in "single monitor mode"). +Instructor screen share at right, learner stuff at left. +``` + +```{figure} img/instructor-tech-online/learner-small.png +:width: 75% + +**L3**: A learner with a particularly small screen. Instructur screenshare at +left, your windows at right. +``` + +## Screen layout: instructors + +This is what the instructor sees on their screen: + +```{figure} img/instructor-tech-online/instructor.png +:width: 75% + +**I1**: Vertical instructor setup. Zoom is sharing a portion of the left +side, the right side is free for following HackMD, chat, etc (but +don't overload yourself). +``` diff --git a/_sources/instructor-tech-setup.md.txt b/_sources/instructor-tech-setup.md.txt new file mode 100644 index 00000000..feae0a8e --- /dev/null +++ b/_sources/instructor-tech-setup.md.txt @@ -0,0 +1,315 @@ +# Instructor technical setup + +```{seealso} +* {doc}`instructor-tech-online` for screen sharing layouts. +``` + +```{admonition} Final checklist +- Have you moved your configurations away and done the course setup + instead (or left it unconfigured)?: `.bashrc` (or equivalent), + `.gitconfig`, `.ssh`, `.conda`, etc. +- Are you using a software environment as described in the workshop + instructions (conda, virtualenv, etc). Is it clean and without + extra stuff installed? +- Is your setup as boring-looking as possible, if you are teaching at + the beginning of the workshop? The first sessions aren't the time + for distractions. +- Is your terminal + - Dark text on light background? + - Do you know key-bindings to change the font size quickly? +- Do you have command history set up? If in doubt, use + [prompt-log](https://github.com/rkdarst/prompt-log/) and `tail` the + output in a separate smaller window. +- Do you have a clean web browser session (different profile for + demos)? +- If you use an advanced shell, do you have a simpler shell (bash) set + up for the demos? +- (if online) have you practiced Zoom screensharing "Share a portion + of the screen" in portrait-mode? See + {doc}`instructor-tech-online`. +- (if online) have you checked your audio settings? Join a test + meeting with someone and understand your microphone sound + adjustments. Can you control it for the full range from very quiet + to very loud, so that you can make whatever adjustments needed? Is + your best microphone/headset ready? *Audio quality and balance is + critical.* +- Have you shown your setup to someone else for feedback? +``` + +Appearance matters. When you look at other professionally made videos +online, they look good. As a presenter, you also need to work to make +your screen look pleasing to the eye. It also has to be similar to a +learner's screen, so that they are not distracted with your different +configuration or appearance. + + + +## Simple or fancy screen? + +As a teacher of tech, you also +*need to make sure that your screen supports the learning process*: +you have conflicting goals of: + +* Making your screen look simple, to not distract from what you are + trying to teach, and +* Showing more advanced setups, so that others can learn and improve. + +In general, try to use a simpler arrangement at the beginning of +workshops. You, or other teachers, can begin showing more advanced +screen layouts once learners are able to see what is important and +what is extra. + + + +## Check with someone before you start teaching + +**Most importantly, get your setup done well in advance and show your +co-teachers for feedback. Feedback and time to improve is very +important to make things beautiful.** + + + +## Clean your environment + +Do you have fancy ``.bashrc``, ``.gitconfig``, etc files? Move them +away so that you are as plain and normal as possible - beyond +appearances, you don't want to use any shortcuts that every learner +won't have access to (telling learners to add some configuration won't +work - some will miss it and be lost, or worse their system may have a +weird behavior in the future). + +Relevant files that are sometimes a problem: + +* ``.bashrc`` +* ``.gitconfig`` +* ``.ssh/config``, ``.ssh/authorized_keys`` +* ``.conda/*`` +* Any config for any program you will be demonstrating + + + +## Arrange your windows well + +This is mostly the topic of {doc}`instructor-tech-online` (our +recommendations for in-person window arrangements aren't so +up-to-date, but the same principles apply but you have a widescreen +view). + +- For online teaching, you will want to screenshare a portion of your + screen: half the screen in "portrait mode" so that the other half is + available. See {doc}`instructor-tech-online`. + + + +## Desktop environment + +- Is your overall desktop environment "normal"-looking? +- Do your window title bars take up lots of space? Is it possible to + reduce their size for the teaching - you want as much space for + large fonts as possible. + - Since you will only be sharing a portion of the screen, or have a + lower-resolution projector, these title bars take up more space + relative to the content. +- Same for desktop menu bars, etc. +- Do you need to go into light-mode theme? Dark text on light + background is much better than dark mode, so it is strongly + recommended to do this. +- Can you easily resize your windows for adjusting during teaching? + + + +## Web browser + +- Are you doing a lot in a web browser? Consider making a separate + profile that is just for demos. +- Install whatever basic safety extensions / ad blockers are most + relevant, but keep it simple otherwise. +- Can you turn off unneeded menu- and toolbars? +- Does your web browser have a way to reduce its menu bars and other + decoration size? + - Firefox-based browsers: go to `about:config` and set + `layout.css.devPixelsPerPx` to a value slightly smaller than one, + like `0.75`. Be careful you don't set it too small or large since + it might be hard to recover! When you set it to something smaller + than 1, all window decorations become smaller, and you compensate + by zooming in on the website more (you can set the default zoom to + be greater than 100% to compensate). Overall, you get more + information and less distraction. + + + +## Terminal + +### Terminal color schemes + +- Dark text on light background, *not* dark theme. Research and our + experience says that dark-text-on-light is better in some cases and + similar in others. +- Make a dedicated "demos" profile in your terminal emulator, if + relevant. Or use a different terminal emulator just for demos. +- You might want to make the background light grey, to avoid + over-saturating people's eyes and provide some contrast to the pure + white web browser. (this was an accessibility recommendation when + looking for ideal color schemes) +- Do you have any yellows or reds in your prompt or program outputs? + Adjust colors if possible. +- Eliminate menu bars and any other decoration that uses valuable + screen space. + +### Clearing the terminal + +- Don't clear terminal often (or ever - un-learn CTRL-L if possible). + Learner's can follow as fast as you! More people will wonder what + just got lost than are helped by seeing a blank screen. Push + ``ENTER`` a few times instead to add some white space. + + +### Terminal size + +- Font should be large (a separate history terminal can have a smaller + font). +- Be prepared to resize the terminal and font as needed. Know and use + keyboard shortcuts for changing the font size when you need to show + more columns (it's also OK if the terminal is wider than your screen + if most of the right side is not that important to see). You can + have a larger font normally, and make it smaller and the terminal + wider when you have long lines that learners need to see. + + +### Prompt + +Your prompt should be minimal: few distractions, and not take up many +columns of text. + +Learners have to read your prompt quickly, understand what you +entered, copy it, all the while not being distracted by everything +else or your screen. Day 1 git-intro is not the time to have your +fancy git-bash prompt, instead show them how to use git to get that +information. Set an easily-viewable prompt. + +- `prompt-log` (see the next section on command line history) does + this for you. +- The minimum to do is is `export PS1='\$ '`. +- Blank line between entries: `export PS1='\n\$ '`. +- Have a space after the `$` or `%` or whatever prompt character you + use. +- Strongly consider the bash shell. This is what most new people will + use, and bash will be less confusing to them. (Later in workshops, + using other shells and being more adventurous is OK - learners will + know what is essential to the terminal and what is extra for your + environment). + + +### Command line history + +You need to find a way to show the recent commands you have entered, +outside of your main window, so that learners can see the recent +commands. + +Consider prompt-log by rkdarst +(). It adds a interesting idea +that *the command you enter is also in color* and also provides +terminal history *before the command returns* (see below). + +Arrange two terminals, so that there is the main work window and the +history window with a font smaller size - the history can be off to +the side. + +See the following screenshot for an ideal arrangement: + +```{figure} img/screenshare/s10-kickstart-prompt-log.png +:width: 50% + +**S10**: HPC Kickstart course. Note the colors contrast of the +windows and colors of the prompt and text. The history is smaller and +doesn't take up primary working space. The working directory is +in the window titlebar. +``` + + + +``````{admonition} Other command line history tools +--- +class: dropdown +--- + +We used to recommend these, and some are still recommended. But, the +long text is a distraction by now, so it is hidden by default. + +Also check the [shell exporter by +sabryr](https://github.com/Sabryr/Teaching-aids), which copies recent +history to a remote server. + +**Simple**: The simple way is `PROMPT_COMMAND="history -a"` and then +`tail -f -n0 ~/.bash_history`, but this doesn't capture ssh, +subshells, and only shows the command after it is completed. + +**Better yet still simple**: Many Software Carpentry instructors use +[this script](https://github.com/rgaiacs/swc-shell-split-window), +which sets the prompt, splits the terminal window using tmux and displays command history +in the upper panel. Requirement: [tmux](https://github.com/tmux/tmux/wiki) + +**Better (bash)**: This prints the output before the command is run, +instead of after. Tail with `tail -f ~/demos.out`. + +``` +BASH_LOG=~/demos.out +bash_log_commands () { + # https://superuser.com/questions/175799 + [ -n "$COMP_LINE" ] && return # do nothing if completing + [[ "$PROMPT_COMMAND" =~ "$BASH_COMMAND" ]] && return # don't cause a preexec for $PROMPT_COMMAND + local this_command=`HISTTIMEFORMAT= history 1 | sed -e "s/^[ ]*[0-9]*[ ]*//"`; + echo "$this_command" >> "$BASH_LOG" +} +trap 'bash_log_commands' DEBUG +``` + +**Better (zsh)**: This works like above, with zsh. Tail with `tail -f +~/demos.out`. + +``` +preexec() { echo $1 >> ~/demos.out } +``` + +**Better (fish)**: This works like above, but for fish. Tail with +`tail -f ~/demos.out`. + +``` +function cmd_log --on-event fish_preexec ; echo "$argv" >> ~/demos.out ; end +``` + +**Better (tmuxp)**: This will save some typing. [TmuxP](https://tmuxp.git-pull.com/) is a Python program (`pip install tmuxp`) that gives you programmable `tmux` sessions. One configuration that works (in this case for `fish` shell): + +```yaml +session_name: demo +windows: + - window_name: demo + layout: main-horizontal + options: + main-pane-height: 7 + panes: + - shell_command: + - touch /tmp/demo.history + - tail -f /tmp/demo.history + - shell_command: + - function cmd_log --on-event fish_preexec ; echo "$argv" >> /tmp/demo.history ; end +``` + +**Windows PowerShell**: In [Windows Terminal](https://docs.microsoft.com/en-us/windows/terminal/), +a split can be made by pressing `CTRL+SHIFT+=`. Then, in one of the splits, the following +PowerShell command will start tracking the shell history: +``` +Get-Content (Get-PSReadlineOption).HistorySavePath -Wait +``` +Unfortunately, this only shows commands after they have been executed. + + +``` +# used for the fish shell (note: untested) +tail -f -n 0 ~/fish_history | sed -u -e s'/- cmd:/ \>/' + +# used for zsh shell (put this into a script file) +clear >$(tty) +tail -n 0 -f ~/.zsh_history | awk -F\; 'NF!=1{printf("\n%s",$NF)}NF==1{printf("n %s ",$1)}' +``` +`````` diff --git a/_sources/instructors.md.txt b/_sources/instructors.md.txt new file mode 100644 index 00000000..54becbf6 --- /dev/null +++ b/_sources/instructors.md.txt @@ -0,0 +1,61 @@ +# Instructors + +Instructors are the ones who "lecture" in the workshops - but of +course there are many other roles which are helping with the teaching, +most notably team leaders and other helpers. + +This page links guides on various aspects of being an instructor. + +Join the `#workshops` stream in the [coderefinery Zulip chat](https://coderefinery.zulipchat.com) and see what workshops are planned. +Below a few things that might be of interest if you want to teach with us: + +```{toctree} +:maxdepth: 1 + +instructor-intro +instructor-stream +livestream-teaching +team-teaching +Lesson presentation hints/checklist +instructor-tech-setup +instructor-tech-online +``` + +## Responsibilities of an instructor + +- Review, triage, and work on lesson issues +- Define exercises +- Communicate exercise list to Exercise coordinator +- Set up and test a quality screen share +- Coordinate with co-instructor +- Communicate software requirements to Instructor coordinator +- Communicate timing adjustments to Instructor coordinator +- After planning/editing the lesson: Do a dry run (prefereably with someone "new" to the topic) + + +## From team leader/helper to more + +Here is one possible pathway from learner to (whatever else). This is +an *idea* for a pathway but by no means a requirement - you can join +at whatever step you like, and steps don't have to happen in order. +Maybe you are interested in some or the other. There are also roles +completely outside of this pathway. + +* After being a learner, you come back as an team leader/helper. +* When you have a solid understanding of all materials, you may join + as an expert helper. +* You begin co-teaching episodes with someone else + * We find that co-teaching is a good way to start. In this, there + are two people, one person assumes the big-picture discussion, and + the other the typing and explaining what they are doing. By + making the lesson a discussion instead of a lecture, it's more + dynamic. +* Eventually, you get confident enough to teach yourself (though + really we should always be co-teaching...) +* Somewhere in there (before or after instructor, depending on your + interests), you may want to try to be a HackMD helper or Zoom host. + These are more about coordinating all the other people involved in + the workshop. + +Let's emphasize again: this is one pathway, but you should do what you +want. diff --git a/_sources/lesson-design.md.txt b/_sources/lesson-design.md.txt new file mode 100644 index 00000000..c772528f --- /dev/null +++ b/_sources/lesson-design.md.txt @@ -0,0 +1,245 @@ +# Lesson design + +This is a checklist and hints when writing and designing a new lesson. +The master material is in Teaching Tech Together, primarily chapters 6 +and 12 for practicalities and 2 and 4 for big picture considerations. +But really, all the book. See [the summary we +made](teaching-tech-together.md) or [the actual +book](http://teachtogether.tech/). The article [Ten quick tips for creating an +effective lesson](https://doi.org/10.1371/journal.pcbi.1006915) is +also a good summary of the main points. +Finally, the [Carpentries Curriculum Development Handbook](https://cdh.carpentries.org/) gives practical information on how to design a new lesson and covers the entire lesson life-cycle with a good overview of the lesson release timeline. + +This doesn't replace your own knowledge in doing the actual teaching +part. Instead, the first half gives pointers on making sure your +audience can connect to the material, and the last half gives hints +to help you come up with good exercises and examples. + + +## Backwards lesson design + +Think test-driven development: decide what you want students to be able +to do, design exercises to measure it, then fill in the gaps with +teaching. You can see [their +summary](http://teachtogether.tech/en/template/). The steps are: + +1. Brainstorm what you want to cover. +2. Create or reuse learner personas - understand who you want to + teach. What do they care about? Perhaps as important is what they + don't care about: make sure that you don't go too in depth too + early and turn people off. +3. Create some summative assessments, that show what learners should + learn by the end. Try to connect these to the learner personas. +4. Create formative assessments (exercises) that let the learners + practice what you want them to learn. See below for hints on coming + up with good exercises. These should also connect to things the + learners will actually do, but can also be more of checkpoints. +5. Put exercises in a logical order, and fill in any gaps. Ideally + there should be 15-20 min of teaching between each exercise. Perhaps + most are short (a few longer examples as needed), to identify a + certain learning goal and misconception. +6. Write just enough material to get from one exercise to the other. + +The most important point here is to start from learner's needs and how +they can feel connected, not from the tech details. + +When advertising the course, connect it to your learner personas so +that you get the right audience and they know why they should come. + + +## Emotional and intrinsic appeal, other basics + +You can think of why people should feel emotionally connected to your +material - maybe it's too much to expect people to get emotionally +invested, but if you try for that, you'll end somewhere better. + +Try to design around tasks and exercises which your audience will care +about. For example, don't say "here are some shell commands", but +"aren't you tired of copying all of these files one by one... check +out the shell... once you know it, you will really feel at home. Here +are some typical things you might do.". Intrinsic motivators include +**sense of agency** (being able to do things themselves), **competence** +(usefulness of what they are doing, feeling they know something), and +**relatedness** (doing things that others are doing). + +A manual is reference, a tutorial builds a cognitive model. If you +can build the cognitive model and tell them the "why", students may be +able to refer to the manuals themselves and become self-sufficient. +Thus, teaching should be more of a +tutorial, with good links to manuals (it can also explicitly teach +how to use the manuals). + +Perhaps a related point is inclusiveness: make sure there's not some +"in" crowd. Perhaps the best description I have seen: don't assume +that some people are missing something, but that others have had the +fortune of learning it earlier. This may not matter in a purely +factual lesson design, but if you are trying to make things +intrinsically or emotionally appealing, it is essential. + + +## Who is the audience? + +Making the **learner personas** are essential to making a good lesson, +even if you think you know who you are teaching to. This is because +it grounds you into what your audience already knows (or doesn't know) +and what they are interested in. + +You also have different ways people can refer to the material: +- In a class, with an instructor guiding them +- Reading along by themselves +- In a class, being much more advanced than others, so that they skip + ahead and do advanced material themselves. + + +## Planning + +- Do some planning, and *document it* - the design process helps + others to teach and modify. At least put it in the README. (this + is the **designer/maintainer's guide**) + - Put the main points from the "backwards lesson design process" in + here, enough that it is easier for someone to improve your lesson + than to redo it. +- Make learner personas: what is your target audience? +- Decide learning objectives based on the personas: high-level end + goals. What students get out, not what they do. +- Also make a *guide* for teaching (**instructor's guide**), "if you + want to present this, do this". + - How much preparation is needed? Is it enough to know the topic + and have read the material? + - Things to prepare before the presentation. Does anything need to + be set up? + - Practical notes on presenting. + - Are there solutions to exercises somewhere? Are they needed? + - Include some pre-assessment questions which can be asked at the + beginning. + - Perhaps you should do this at the end, but at least starting the + instructor's guide at the beginning will frame your writing. + + +## Writing + +There is not much here yet, mostly just follow the "backwards lesson design" +above. The hardest part is coming up with good exercises, so our +practical advice is to mix and match from the two taxonomies at the +bottom and the exercise types. Try to think of diverse types of +exercises. + +Exercise design is the time it is most useful to be with others to do +brainstorming, so we highly recommend discussing with others at this +point. Because exercises are used to set the overall outline of the +lesson, this also gives people a say in the overall outline - in a +very concrete way. + +- Make sure you include the emotional starting point at the beginning - why + should you care and why is this cool? +- This should also be at the start and end of each section: not just what + or how, but why? +- Part of this is also having a **student's guide**, so that + people independently studying can know how to follow the material. +- It's OK to have more material than can be presented or than people + should know, but *label things well*, including *labeling the difficulty*. + - In the beginning, what sections are expected to be taught in + short/long versions? What's advanced/optional? + - Label advanced and optional sections as such. Perhaps also really + basic sections that can be skipped for that reason. + +Plan for mixed abilities. It's OK to have optional (basic) and +advanced sections, as long as they are clearly labeled. Mainly, don't +have people think that you are uncoordinated because you are skipping +advanced sections. + +Once you are done, update maintainer's and instructor's guides. + + +## Introduction (and conclusion) + +The introduction is the first thing people hear, and needs special +thought. Don't start with a cold open, just going straight to the +topic ("what" or "how"). Instead, have some careful motivation +("why"). It could be especially good to talk about what is wrong with +the current state of affairs (give a good, simple example) and why it +should be improved. Then start talking about what the improvements +are. + +Ideally, the introduction should serve as an self-contained abstract +of your material. If you need to teach your lesson in only 10% of the +time you have, can you use just the introduction to do it? + +Conclusion should remind people about why this is cool and discuss +what comes next. + + +## Thinking of exercises + +Not every exercise has to be an amazing hand-on example. It's mixing +with smaller, more conceptual things to reduce the cognitive load and +be able to have more frequent exercises. + +One of your other primary goals should be to make your exercises +*relevant*. Abstract will lead to disconnection. Connect the exercises +to the real world. Also, can you tell a complete story with +exercises? (Remember, in backwards lesson design, the exercises +form the story of the lesson.) + +Remember that not every exercise has to be long. Try to have +frequent short exercises to get immediate feedback, with some long +ones. + +Good exercises are the most important factor in a good lesson. Even +if you are preparing the rest of the lesson mostly alone, consider a +good long brainstorming session to go from "list of topics to cover" +to "sequence of exercises". + +When you are stuck thinking "how can I make an exercise that covers +X", think of the lists below inspiration. Not every exercise has to be an +sophisticated hands-on thing, so don't be afraid to use different +types: + +Basic types: +- Multiple choice (easy to get feedback via a classroom tool - try to + design each wrong answer so that it identifies a specific + misconception). +- Code yourself (traditional programming) +- Code yourself + multiple choice to see what the answer is (allows + you to get feedback) +- Inverted coding (given code, have to debug) +- Parsons problems (working solution but lines in random order, + learner must only put in proper order) +- Fill in the blank + +More advanced: +- Tracing execution +- Tracing values through code flow (e.g. what is the sequence of + values that `x` takes on?) +- Reverse execution (find input that gives an output) +- Minimal fix (given broken code, make it work) +- Theme and variations (working code, adapt to other type of + situation/problem) +- Refactoring + +More conceptual: +- Draw a diagram +- Label diagram +- Matching problem: two sets of Q/A, match them. + + +Thinking through the learning taxonomies also helps to come up with +diverse types of exercises: + +- Bloom's taxonomy: hierarchical skill levels (can you help students + to "grow a level"?): + - Remembering + - Understanding + - Applying + - Analyzing + - Evaluating + - Creating +- Fink's taxonomy: complementary types instead of hierarchical: + - Foundational knowledge + - Applications + - Integration + - Human dimension + - Caring + - Learning how to learn + + diff --git a/_sources/lesson-review.md.txt b/_sources/lesson-review.md.txt new file mode 100644 index 00000000..b94dd56c --- /dev/null +++ b/_sources/lesson-review.md.txt @@ -0,0 +1,106 @@ +# Lesson review + +This presents a checklist for reviewing lessons that already exist. +You should also read [lesson-design.md](lesson-design.md) as well - +this is roughly a checklist to the things there. + +Remember to keep the *story* of the lesson in mind. Many people are +focusing on the small matters (during every change), but only +occasionally do people look at the big pictures. That's why a proper +review starts with looking at the big picture, instead of adjusting +small things and possibly derailing the story. + +This is roughly sorted from highest priority for short review to +lowest priority for big refactorings. + + +## Issues + +- Look through the issue tracker to see what is relevant, remember and + follow up when going through the sections below. + + +## Lesson guides + +Instructor's guide: + +- What sections should be taught for what audiences? +- Common pitfalls when teaching +- Any required setup in advance? + - Any special config files that need to be cleared on instructor's + computer when teaching? + +Maintainer's guide: + +- Learning objectives (necessary to know its place) +- Learner personas (necessary to know its place) +- After you're done analyzing, is there anything in the maintainer's + guide you need to update? (The maintainer's guide is probably in + most cases the same as the instructor's guide) + - Design philosophy, how to modify while preserving the overall + character. + +Student reference guide: + +- Anything to fix or already? +- Keep this in mind when you get to episode details. + + +## Lesson overview + +- Is the introduction intrinsically motivating enough? Does it + promote an emotional connection to existing problems? +- Student's guide and framing: will a student know when this is + relevant to them and how it will benefit them? + - Doesn't need to include word-for-word learner personas, but should + convey this somehow. +- Are the difficulty and prerequisites stated? + + +## Episode overview + +- Read the intro and conclusion to every section/episode. + - Do they make sense when you read them in order, without reading + the text in between? + - Do they motivate each section well enough (not just explain what, + but why it's cool?) +- Do they have learning objectives at top and food for thought at the + bottom? +- Are optional or advanced episodes marked as such? +- Does the episode (or lesson overall) say what is next, to keep + people interested in growth? + + +## Episode details + +- Read through each exercise (with no other text in between). Does it + make a logical progression? +- Exercises labeled with difficulty, optional, etc. +- Optional advanced exercises or material in places where advanced + users may get far ahead. +- Each exercise is self-contained: a helper can read just the exercise + area and get an idea of what is supposed to happen and why. +- Update the student's reference guide as you are going through the + details. +- Remove duplicate or unnecessary information when possible. Things + are always added, rarely removed. Shorter is usually better. If + something shouldn't be removed, perhaps mark it as advanced or + optional. + + +## Major Refactorings + +Always start with the big picture: does it make sense? When +refactoring, always start off with backwards lesson design again (see +lesson-design.md) and fully go through that. + +After the above, do the details. Remember the guides still. + +Before you start major refactoring and rewriting, think if it makes +sense. Have you figured out why it's the way it is based on the +instructor's guide? If you do a big refactoring, make sure you update +the maintainer's guide! + +Before you embark on a big refactoring step, please pitch your idea +in a GitHub issue and collect feedback from others. Maybe even hold a +brainstorming session. diff --git a/_sources/livestream-teaching.md.txt b/_sources/livestream-teaching.md.txt new file mode 100644 index 00000000..1f50113a --- /dev/null +++ b/_sources/livestream-teaching.md.txt @@ -0,0 +1,120 @@ +# Teaching via livestreaming + +We've all done a lot of teaching via Zoom, but the CodeRefinery +livestream is a new concept. This introduces teachers/helpers to the +idea (and for a detailed reference, see {doc}`coderefinery-mooc`). + +```{admonition} Video + +Watch a demo on YouTube: . +(When watching, also carefully read the video description/chapter +titles, which provide more the explanation of what is going on). +``` + + +Compared to Zoom teaching: + +- You are in a Zoom meeting with only instructors/staff +- Someone (not you) captures this meeting and broadcasts it via + livestream to all the audience. +- The audience can't directly talk with you (but when there is a large + audience, who does anyway?). Instead, always say things like "What + do you think? Write in the HackMD. [proceed to screenshare it and + discuss answers]" +- You don't need to worry much about managing the audience. Others do + this and relay information as you need. You should pay more + attention to HackMD. + + + +## Basic meeting setup + +There is an "instructor Zoom meeting". There are no students here, +and everything can and will be captured, recorded, published, and +livestreamed. + +* In the call are instructors, the Zoom host, and possibly some other + helpers who might occasionally comment. +* The cameras of instructors are captured via Zoom gallery view. + This is show as both a "teacher view" as well as "overlay on + screenshare". +* If you have your camera off, you will *not* appear in the stream. + So turn your camera off when you are in the instructor meeting but + not presenting. Ask others, but in principle it is fine to join, + stay hidden, and interact when relevant. +* During the breaks/exercise times, the livestream itself (via OBS) + gets *muted* and *switched to another scene*. So, you are free to + unmute, talk, and chat with other instructors. This is a great way + to relax and prepare for the next segments! This actually lowers + the pressure to pre-plan every part in advance. +* By the same token, you can join the meeting during the previous + break to get all set up. +* Zulipchat serves as the overall connection between the different + parts of the course and instructor backchannel. This is the least + important place for the current active instructor to watch (but + might be useful for a co-instructor or expert helper to occasionally + check). + + + +## Screensharing + +You can share your screen normally via Zoom. The livestream is fixed +to an aspect ratio of 840 pixels wide × 1080 pixels high (this is so +that the learner has half of their screen available). **You can not +do a full landscape live-coding follow-along screenshare (nor is this +good practice in other workshops).** + +* In **Zoom**, you can either share one window or Advanced → Share a + portion of the screen → move the overlay to a portrait view. Don't + worry about making it exactly 840×1080, OBS automatically fits it + and we can adjust it during the setup time. + +* If you have a landscape presentation (as opposed to live coding), + just share your whole screen, and the OBS operator will scale things + properly if it doesn't automatically work. Note that the 4:3 aspect + ratio is better than 16:9, but that usually has black bars on the + side. This can be removed via OBS. + +* Don't stop screenshare unexpectedly - wait for the broadcaster to + switch to gallery view. **If you stop screenshare unexpectedly, the + stream reverts to someone picture full-screen.** Because of Zoom + "dual-monitor mode", sharing screen does not prevent the gallery + from showing. + + + +## HackMD and audience feedback + +HackMD (or similar document-based things) is our preferred +communication system. The biggest problem is that it is *too* useful, +and too many people ask questions, which will easily overload you. To +solve this, we have co-teachers (non-typer can watch HackMD), HackMD +helpers (watch and answer basic questions). + +There are several general strategies: +* Occasionally screenshare the HackMD. This emphasizes to the + audience that questions there *do* get noticed. +* Rely on other helpers to answer most questions. +* During Q&A time, go to the HackMD and comment on the most important + questions. +* Call on co-teachers, "do we have any good questions from HackMD?" +* Co-teachers should be more than willing to interrupt with relevant + questions right away. + +You can't use Zoom polls and so on. Instead, use HackMD cleverly. +For example, below you see a poll (people add `o` to make a bar +graph), and a free response: + +``` +Have you used HackMD before? +yes: oooooooo +no: oooo + +What do you like about it? +- answer +- answer +- . +- . +- . +``` diff --git a/_sources/local-breakout-rooms.md.txt b/_sources/local-breakout-rooms.md.txt new file mode 100644 index 00000000..a75668b5 --- /dev/null +++ b/_sources/local-breakout-rooms.md.txt @@ -0,0 +1,91 @@ +# Local breakout rooms + +Some CodeRefinery courses are designed to be large scale, with +distributed registration. In short, this means there is a livestream +that anyone in the world can watch. Since we can't handle a +registration and personal support for everyone in the world, *you* can +open registration to attend the course. + + + +## Principles + +- We have a livestream, open to everyone in the world. The + {doc}`coderefinery-mooc` strategy allows us to reach a huge audience + in a decentralized manner. + + - If courses don't have a livestream, we can still reach many people + because of HackMD and teams. From the list below, steps 2b and 2c + work with this option. + + ```{figure} coderefinery-mooc/mooc-diagram.png + + Decentralized teaching allows us to reach many more people than + we could otherwise. + ``` + +- Most attendees can ask from help through HackMD + ({doc}`hackmd-mechanics`), which works very well +- There are periodic exercise sessions, where learners and teams can + work together. + + +## Step 1: Local breakout room + +- Create your own breakout room - whether online or a physical space. + That means for example ask some friends to join you to watch the stream + and collaborate with the exercises. +- Our exercise sessions are very clearly announced and communicated. + During these times, the livestream goes silent, and you can work + within your breakout rooms. The end of the exercise sessions and + breaks are clearly communicated as well - we support your breakout + room scheduling as much as possible. +- Attendees can ask general questions via {doc}`HackMD + ` +- You can continue your local support even after the course. +- You may want to run local "installation help" sessions. + + +## Step 2: Registration + +- If you have a broad audience, you may want to make your own + registration form, completely separated from ours. That may help + with reservations and catering if any. +- Please have everyone to register in our form anyway + to help us in reporting our impact. +- You may (but don't have to) create **teams**, where you have one + team leader for 5-6 learners. The team leader guides the + team and supports collaboration and community - and lets us scale + much better than we could otherwise. Teams also support retention + after the course, especially if they knew each other before + registering. (See {doc}`team-leaders`) +- We would like to know statistics from how many people attended from + your location for our impact reports. (still, the top priority is + reaching as many people as possible, we'll adjust reporting to what works) + + +## Step 2b: Joint registration + +- You can direct people to our registration form as a matter of + simplicity, but we add an option for your institution. +- Learners join our Zoom session, and we create a breakout room for + your institution and direct all learners there. +- Since you provide help to your own learners, we can more easily + scale than we could otherwise. + + +## Step 2c: Joint registration, you provide team leaders for your teams + +- A lot like "joint registration", but for workshops where we + centrally organize teams. +- You locally recruit {doc}`team leaders ` for your + own learners. This saves us the effort of recruiting exercise + leaders and allows us to scale more. + + +## Summary + +As you can see, there are many models, from distributed and simple to +centralized. It's best to talk in chat and see what will work best +for each workshop, but we are generally biased towards more +decentralized approaches for large courses. diff --git a/_sources/meeting-checklist.rst.txt b/_sources/meeting-checklist.rst.txt new file mode 100644 index 00000000..27822d2b --- /dev/null +++ b/_sources/meeting-checklist.rst.txt @@ -0,0 +1,89 @@ +Meeting checklist +================= + +This checklist was made because we had a major issue with *not +announcing good events* to our community because we weren't sure what +to do, thus a community doesn't form. These steps should be taken to +announce any event unless there is a specific reason not to (for +example, a workshop is well underway and organizers known). You don't +*have* to follow what you see here, but the point is to make +announcements as boring as possible, so that it gets done quickly and +well-enough. + + +As soon as meeting topic/time is decided +---------------------------------------- + +* Decide central HackMD/join link. (Join link can be decide later by + putting it in the hackmd). + +* Create a calendar event for yourself, and send it to related + people. You should be ready to forward this to people who request. + It's OK if the event only includes HackMD link (+ join link, if + known). + +* [Mailing list: not yet present, we are relying on the other options + here.] + +* Make a post in #announce. Don't be shy, just do it. + ``, there will be a [meeting on topic]. Topics will + include [a few highlights to let people know who should attend]. + + HackMD (including connection details): + More info: #[stream-name] + + If you want a calendar invite, send [me] a private message (or + react with :email: quickly if I know your email already). + +* Make a Twitter post for most meetings, if you want a broader + community to attend. + + * You can do this yourself via the "tweet-together" Github Action: + + * CodeRefinery: + https://github.com/coderefinery/coderefinery-twitter/ + * Nordic-RSE: + https://github.com/nordic-rse/ + * Research Software Hour: CR + AaltoSciComp + + * You can do it from the web interface, find the "Create new tweet" + button from the readme. + + * Edit the file path. It pre-fills ``YYYY/MM`` outside of the text + box, but you can backspace and change that to current year/month. + + * Suggested template:: + + [title] will be held at [time CEST]. [optional: why should + someone attend? Attend if...] + + More info via our chat https://coderefinery.github.io/manuals + [tags] + + * Suggested tags + + * CodeRefinery: ``#coderefinery`` + * Nordic-RSE: ``#RSEng`` + * Research software hour: ``#RSEng`` + + * Ideally, someone else should merge quickly after checking facts + Don't wait for "permission" or something like that which may never + come, we agree that more tweeting is a good thing. + + + +Days before the meeting +------------------------ +* Send reminders to the #announcements streams. You can find the old + topic and reply to it, quoting the whole text. + + + +Archive meeting agenda +---------------------- +* Archive the agenda, if needed. diff --git a/_sources/obs.rst.txt b/_sources/obs.rst.txt new file mode 100644 index 00000000..38cff5c4 --- /dev/null +++ b/_sources/obs.rst.txt @@ -0,0 +1,466 @@ +Open Broadcaster Software theory +================================ + +This page describes the theory around OBS. For practical steps to +run a course, see :doc:`broadcaster`. + +Open Broadcaster Software is an amazing open-source audio/video +production tool. It's probably not professional grade, but is used in +serious events and will make a non-professional feel professional. +The main point is that, instead of being limited to what your meeting +software can do, you can: + +- create more advanced mixes of screens/video/etc, without having to + do post-processing. +- do more with the (local recording, streaming) +- do this all better, for example, exclude the audience speaking from + the recording. + +It is a GUI application, so is not that hard to figure out, but there are a +lot of initial concepts. This page isn't a comprehensive tutorial, +but will introduce the basic concepts and what you can get out of it, +and you can either figure out the rest or read other tutorials. + + + +Vision +------ + +When teaching online, we are usually limited by our online meeting +software. This forces us to make certain trade-offs to fit the +limitations of the software, so that we can't reach our full +potential. By using more advanced technology, we can do more: have +interactive sessions while also recording and preserving privacy. For +more information, see the :doc:`online teaching guide `. + + +Basics +------ + +.. admonition:: Basic audio/video glossary + :class: dropdown + + Open Broadcasting Software (OBS) + OBS, whose current implementation is known OBS Studio. It is a + multi-platform audio/video mixer, recorder, and streamer. It + doesn't do any editing, but you can flexibly mix stuff when + producing for a one-shot product. + + streaming + Media which is delivered to the user continuously. The term + implies over the Internet. + + livestreaming + Streaming of source that is live, delivered in near real-time. + Lately, it is popularized by livestreaming games and other + activities, which provides us a lot of accessible tools to use. + + Livestreaming tools have opened a significant way for anyone to + be able to interact in real-time with a large audience online. + + recording + Saving the streaming data locally for later use. And other + stuff, you probably know this. + + Twitch + A popular livestreaming site. Popular with gamers, but has all + kinds of live-streaming events. + + codec + COding and DECoding. As a noun, the algorithm used to encode + and decode sound or video. There are many different codecs, + with different properties of + compression, CPU usage, etc. The codec is independent of the + program actually used to encode/decode, and also (somewhat, not + entirely) independent of the container format. + + container format + File format that contains the audio/video data. There are + different formats, and the container format is independent of + the codec of the material inside (but not all codecs work in all + containers). There are containers for both streaming and + recorded media. + + encoder + The program that compresses raw video to the codec for + distribution. Of course, there are also decoders. You need the + right decoder for each codec, but most things you would use + these days are widespread. + + bitrate + Amount of data of the media stream over time. Usually measured in + Megabits (not bytes, also note the actual unit is + Megabit/second). As an example, + Netflix on mainstream "high" quality is about 5 Mbit, and Twitch + recommends ~6 Mbit at most. Netflix on low quality is about .7 + Mbit, but of course all these are for movies, not relatively + static screenshares. + + The more movement in a scene, the more bitrate required to + encode that at a constant quality. + + constant bitrate (CBR) + Encoding method where the bitrate does not vary over time. + There is only a small encoding buffer to handle times with a + large amount of movement. + + Twitch and other live streaming sites recommend CBR because of + the way the Internet works. With a live stream, a constant + stream of data is needed. Internet congestion + control protocols can keep a constant stream going when the + stream is constant. If + there is a sudden increase in instantaneous bitrate (with VBR + and a section with lots of movement), congestion control + not be able to keep up and buffers empty, causing lag. + + Similar considerations apply to other playback modes, such as + embedded devices with limited CPU power, thus the idea of + encoding "targets" (profiles optimized for certain classes of + devices). Mainstream personal computers tend to have enough + power to decode anything, so this isn't a major consideration. + + variable bitrate (VBR) + Encoding method where instantaneous bitrate varies depending on + how much information is needed at each instantaneous point of + time, to encode the complexity of the current scene. In x264, + this is usually done as "CRF". + + latency + Time delay between two events. In a livestream, time delay + between the performer's actions and the audience seeing it. + This is caused by countless buffers: encoding buffer, network + buffers, network transmission time, decoding buffer, etc. Lower + latency increases performance demands on the hardware and + network, so you need to strike a balance. + + On Twitch, "low latency mode" gives you 10-15 seconds of latency. + + x264 + A common open-source encoder. Used as an internal encodign + backend for many different programs. + + x264 → crf + In x264, a variable bitrate encoding mode (constant rate + factor). Values are between 0 and 51, but reasonable values are + low 20s. For example, 23 is the default and looks good for all + practical purposes. + + Real-time messaging protocol (RTMP) + A common protocol for live + streaming. It is proprietary, but was later opened and is now + one of the main standards. + + HTTP Live Streaming (HLS) + The other common streaming protocol. + + + +User interface basics +~~~~~~~~~~~~~~~~~~~~~ + +OBS is a graphical program. Once you start it up, you see various +user interface features: + +.. figure:: img/obs--controls.png + + Basic OBS control layout + +Of primary note are the following concepts: + +Preview area + Shows what is currently being broadcasted or recorded, or will be + if you turn it on. There is also a separate "Studio mode" with a + preview area, and live area. The preview area is used to prepare + the stream, you can make it live when you want. + +Scenes + A certain layout that can be broadcasted. On the lower left is + your scene collection, and you can add, delete, reorder, and rename + scenes. By clicking on a scene, you switch to it and it begins + broadcasting/recording. + +Sources + An image source which can be composed together in a scene. Scenes + can be added, deleted, recorded. Via the preview area, sources can + be graphically moved around to your liking. There is a + comprehensive set of positional and image effect transforms you can + make. + + Sources can have **filters** applied to them, which do some sort of + video transformation (for example, background removal). There are + also **transformations**, which affect the position in the scene. + Put together, you can do almost anything you would like. + +Audio sources + You can take audio input from various sources: mainly, microphones + or as a monitor of a computer audio device (to, for example, play + sound). Audio sources are configured in settings, but can be + muted/have volume adjusted in the respective area of the screen. + + Audio sources also have **filters**. + +Control buttons + There are buttons to start/stop recording/streaming. The output + locations are configured in the settings. + + +Configuration +------------- + +Here, we will go over the main parts of configuration. We won't say +everything, since this is graphical program and you can mostly click +around and find your own customization you would like. + +Because of the popularity of streaming, it is easy to find more +tutorials and recommendations for anything here. Add "streaming" or +"OBS" to your search. + + + +Basic configuration +~~~~~~~~~~~~~~~~~~~ + +These options are found in the "Settings" dialog. These are just +generally suggested defaults and when you might want to tone them. + +File → Settings → Stream + Here, you would configure the streaming service, if any. + +File → Settings → Output + Here, you configure streaming/recording output parameters. + + If you use **Simple**, you pretty much can't go wrong. If you are + mainly screensharing and don't have much action video, you can + make the bitrate much lower, for example 2500 Kbps. The slower + "encoder preset" is, the more CPU power that will be spent to get + that quality, so the less space it will use. The better your CPU + is, the slower you can make it; "fast" to "slow" are reasonable. + + If you use **advanced** you have more options: + + Streaming: Rate control=CBR, 2500 Kbps, other options don't matter + so much, defaults should be fine. You can search for + recommendations online, but realize that most others stream + high-action games so their settings are much higher than you need. + + Recording: Recording format, mp4 (mkv would be better, but we need + to check that it can be uploaded to common sites). Encoder=x264, + Rate control=CRF, CRF=22, Keyframe interval=auto, CPU + preset=medium (or slower, for better CPUs) + (slower=use more CPU to do better + encoding, either higher quality or lower bitrate. Veryfast--Slow + is a good range), + Profile=main, Tune=None + +File → Settings → Video + Here, you set the base size of the picture you will be using. + You could do FullHD at 1920x1080, or HD at 1280x720. For vertical + recording, we recommend you do 840x1080. Use your chosen value + for both Base and Output resolutions. 30 FPS. + + When setting your video size, traditionally people tell you to be + as large as possible (to attract viewers). However, this guide is + focused on teaching + and learning, and for that a) we want our content to be as + accessible as possible. There is no need for as many pixels as + possible, as we often say "present from your smallest screen", and + you can do that by artificially restricting yourself. b) We have + found a vertical screen works well: a learner can have the + video/stream taking up half of their screen, and the other half + available for doing their own work. + + +Click around through the other menus in settings and see if there is +anything to configure to your own needs. + + +Scene configuration +~~~~~~~~~~~~~~~~~~~ + +After the above, you can set up scenes basically however you would +like. However, as a starting point I propose these scenes to get you +started (and I propose we standardize on these names, so that we +can make some uniform scripting tools): + +* **Title**, the logos and titles of the event. +* **Gallery**, a gallery of the people presenting (or the one). When + presenting from a Zoom meeting, this is a capture of the gallery + view in dual-monitor mode. +* **Local** is a local screenshare, that you get by capturing your own + screen. +* **Remote** is a screenshare by someone remote. If you are capturing + from a Zoom meeting, it is the capture of the second window of the + dual-monitor mode. +* **Notes** is some HackMD or other material you might want to show + during discussion periods or breaks. + + +Common types of sources (scene elements) include: + +* Static image (e.g. logo or background) +* Desktop capture, for your local desktop. You can crop it (in the + source config) to share only a portion of your desktop. +* Single-window capture. Note that this is smarter than Zoom, + since it can capture the full window even if is not on top. +* Text (which works, but is not very powerful) +* Solid colors +* Other scenes. You can make one scene, then insert it into other + scenes to avoid duplication of scene elements scene elements. + +The sources themselves can be moved around graphically, which is good for +setting things up. When there are more demanding needs, the source +transformation can be edited for more precise control (right click on +source in preview → edit transformation). There are +source *filters*, which can do video effects such as removing a color. +Some sources can be cropped in the source-specific config as well. + + + +Audio configuration +~~~~~~~~~~~~~~~~~~~ + +Audio configuration is simpler than video configuration, since there +are fewer different sources. On the other hand, it is harder to +see what is going on (no preview) so it is harder to adjust it +perfectly, and easier to cause problems like loops. + +The main concept is that your computer may have different input and +output sound devices ("cards"). For example, I can output sound from +some application on my monitor's speakers, while sound from other +applications on the headphones at the same time. Find your computer's +way to see and configure what is going on under the hood. + +There are two types of audio inputs: + +* **Microphones**, obviously recording from a microphone. +* **Monitors** (as in, monitor a sound card), recording what is + currently being played on another + sound card. This is what is used to capture audio from a remote + meeting, such as Zoom. + +You set the active audio input in the application settings. The +volumes of these can be independently adjusted - you want typical +volume to be in the yellow zone. Advice for various operating systems +include: + +* Linux using PulseAudio: ``pavucontrol`` +* Windows: ??? +* MacOS: ??? + +Under "advanced audio properties" (a menu item, also available from +the gear icon in the audio area) you have several more options. + +* You can add various filters, such as noise reduction. +* You can group audio sources into various **audio tracks**, and the + stream/recordings can use different tracks. For example, a person + may stream with music but leave that out of the recorded video. Or, + you might record a video with two different audio tracks, one just + the presenter and one with presenter + audience. +* You can monitor the audio, which plays what is being recorded back + over the headphones and speakers for you to check. Make sure you + don't make any loops! + +Audio configuration is a big deal. You can look at thees other +guides: + +* ??? + +High-quality audio is quite important. I've spent far too long +playing with it, and my conclusion is that I don't know enough to make +it better than what I have now. I could use a better microphone, but +then I had to add noise reduction and the quality ended up the same as +a "worse" headset microphone that was close to my mouth that seemed to +have automatic noise reduction. Your environment (noise, amount of +echo) matters just as much as your microphone. + +I propose a central recommendation: *talk about audio quality*. Start +meetings early and test it. Communicate about problems early, don't +ignore and think it's "good enough for now". + + + +Recording and streaming +~~~~~~~~~~~~~~~~~~~~~~~ + +Once you have done the above, you can record and stream by clicking +the buttons. + +One piece of advice: always keep the recording going, and then +stop/restart it when you need to cut. It's easier to delete the +unnecessary segments than realize you forgot to push "record". + + + +Projector and loopback output +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Beyond recording and streaming, there are several more ways to use the +output that can feed into other applications. + +With **projectors** you can display the scene locally on another +monitor or window. + +* The **fullscreen projector** displays the scene to a monitor. As + the name says, this could be used to send it to an external + projector or capture card via HDMI. Or even preview locally, or + screenshared in an online meeting. + +* The **windowed projector** does similar, but makes a new window that + can be moved and resized. This can be captured as a single-window + screenshare in an online meeting. + + +The **loopback output** creates a **virtual camera device**. This +appears to other applications as a camera, just like the camera that +captures your video. +Other applications can use this as the input just like another +webcam. So, you could make a fancy scene that is used instead of your +normal camera's picture. +Or, in Zoom you can share screen from "second camera" - +which would use this scene. (Note in Zoom it will interpret it as a +landscape picture, regardless of what aspect ration you actually use. +Thus, this isn't very suitable for vertical screen sharing.) + + + + +Example configurations +---------------------- + +Recording your own demo +~~~~~~~~~~~~~~~~~~~~~~~ + +Scenes: Title, Gallery, Local. Variable bitrate. + +Online teaching event +~~~~~~~~~~~~~~~~~~~~~ + +Scenes: + +* Title +* Gallery - contains galleryCapture +* Local - capture of your screen, when you need to teach. Has + galleryCapture in top-right corner +* Remote: capture of Zoom second window (which has been + adjusted to be same resolution as your base canvas size). Also has + galleryCapture in top-right corner. +* Notes: contains HackMD + galleryCapture +* galleryCapture - contains the Zoom gallery capture. This gets + inserted into the other scenes above. + +Audio: + +* Microphone capture +* Monitor of sound card which has the Zoom output + +Outputs: + +* Recorded locally. Start and restart recording after every + transition that you would want to publish separately. (Better to cut + more than less, to have logically organized shorter segments. Also, + always keep it recording, in case you forget to turn it back on!). + +* Stream to your preferred site. + +* Use windowed projector or Zoom capture to send the output directly + to a Zoom meeting. But, that requires careful audio routing. diff --git a/_sources/online-training.md.txt b/_sources/online-training.md.txt new file mode 100644 index 00000000..1e9d0d32 --- /dev/null +++ b/_sources/online-training.md.txt @@ -0,0 +1,153 @@ +# Online training manual OLD + +```{note} + +This hasn't been updated since we developed our {doc}`MOOC strategy `. +``` + +Also please read our [lessons learned](https://coderefinery.org/blog/2020/04/14/first-online-workshop/). + +This manual covers general guidelines for conducting online +training as well as specific tips on using [Zoom](https://zoom.us/). + + +## For the instructors + +If you have an old spare laptop, connect to the call as a second "you" and you can +watch and verify your screensharing and fontsize to avoid "Am I sharing the screen? +Hopefully you see what I see." + + +## How to avoid "Zoom bombing" + +- Either set a password or use waiting rooms +- Share connection details only with participants and helpers, not on the web +- Disable file transfer +- Disable "Allow removed participants to rejoin" + + +## Preparation + +- Schedule the meeting/webinar in the online Zoom system +- do not auto-mute participants' microphones, as this also happens when you enter breakout rooms. +- Decide roles: + - Decide the Zoom host and co-hosts + - Use panelists? (Zoom webinar feature) + - Decide instructor and backup-instructor in case of network issues + - Decide helpers. One helper should be responsible for monitoring + Zoom, i.e. the chat window, hand-raising and other feedback +- Co-hosts, breakout rooms and feedback controls need to be enabled (on + website) before the meeting starts. If options are reconfigured, the meeting + may need to be ended and restarted for them to take effect. +- Create enough breakout rooms at the beginning since this cannot be easily changed during the meeting. +- TODO: set up pre-lesson polling? (zoom feature) Maybe unnecessary in view of pre-workshop survey +- Instructors and helpers should use a reliable camera and microphone. + Computer microphone might not be enough since audio quality will depend on + instructor's head angle and proximity to screen. +- Workshop owner creates a HackMD which will be used for collaborative note taking. + + +## At the beginning of the session + +- Allow time at the beginning of the session to debug video/audio and to + arrange windows. This takes few minutes so better do not start with teaching + from minute 1. Plan for an early 5-minute break to debug this. +- We cannot assume that all Zoom participants have the same and up to date + client and some clients do not contain "sticky notes" feedback or a button to + raise hands so agree with participants on signals (e.g. typing `\hand` in the + chat window seems to be standard).- +- We demonstrate how HackMD works and use it in an ice-breaker (roll call or asking a questions). + + +## Recording of sessions + +If you plan on recording and publishing the session, prepare in advance so that +you don't have a difficult editing job later. +Make sure that you (or users) don't show any personal or confidential information. +Think about what happens if users speak: do you ask for permission to publish +in advance (maybe encouraging people not to), or edit it out later (taking +your time later). + +If you plan to record the session, make sure that everybody is aware that the +sessions is recorded, informed about how the recording will be used, and gives +consent to be recorded: + + +In Zoom it's important to start recording in the form you want the video to be +in (e.g. start recording when screen is shared so that it stays there): + + +Set screen background to black. We saw a glitch in Zoom which caused the +background image to flash above the screen, if it was pure black it would be +less distracting. + + +## Zoom-specific installations instructions sent out before workshop/lesson + +- Recommend to install Zoom app. Browser is possible but more limited +- Test-launch zoom and test microphone, speaker and camera (lower left corner buttons) +- Instruct participants to watch a zoom introduction (TODO: insert link), + and play around with zoom.us/test to get acquainted with interface. +- Optional: set up virtual background +- "During the workshop, you might be asked by a helper to share your screen. + Make sure to keep private information away from the screen you share." + + +### Contingency plans + +- Be prepared for intermittent network problems. +- There should be a backup instructor in case the main + instructors disconnects +- Learners might occasionally experience lag and temporary + network hickups. This makes it particularly important to + speak slowly and repeat important topics. + + +## Breakout rooms + +- Breakout rooms can be used both by helpers to assist individual + learners during an exercise, or for multiple learners working on + a group exercise. +- When creating groups, the host or co-hosts can choose automatic setup, + where only the number of groups is selected and the distribution into + groups is automatic, or manual setup where the host/co-hosts distribute + learners into groups. +- Host needs to move helpers, co-hosts cannot enter rooms on their own. +- Somebody asking for help gets assigned to a room together with a helper. +- TODO: is it possible to create breakout room for only some participants, + leaving other learners unaffected? This is crucial for helping participants + during exercises who have raised their hand. Need to test this +- Host and co-hosts can join any room and jump between rooms. This should be + used during collaborative exercises to see how the exercise is progressing + or participate in the group work. +- When a collaborative exercise is about to end, the host/co-hosts can + broadcast a message into all groups. +- When the host/co-hosts end a breakout room session, participants in groups + have 60 seconds to finish before the session terminates. + + +## Exercises + +- Just like in a regular workshop, demonstrations and type-along sessions + should be interspersed with frequent exercises +- For pairwise or group work exercises, the instructor (or Zoom assistant) + should create breakout rooms with chosen number of participants in each +- For single-person exercises, no breakout rooms are needed +- Learners should be instructed to raise their hand when they need help. + This corresponds to putting up a red sticky note in in-person workshops. +- TODO: what signal should be used for green sticky notes? +- Polling can be used as formative assessment questions. The host creates + a poll based on a lesson template and requests learners to answer. + (TODO: polling seems not available in kth-se zoom subscription) + + +## Breaks + +Following an online event can be even more tiring than a physical event and +therefore also during online sessions we need to plan for breaks as we would +for an in-person event. + + +## More resources + +- diff --git a/_sources/online.md.txt b/_sources/online.md.txt new file mode 100644 index 00000000..e556ca74 --- /dev/null +++ b/_sources/online.md.txt @@ -0,0 +1,126 @@ +# Online teaching + +In 2020, we were forced to start teaching online. Is this good or +bad? + +The promise of the Internet was that we could reach everyone in the +world. Instead, we immediately learned to hide or Zoom links from +anyone except the people who register in advance to hide from trolls. +We directly translate in-person to online, and wonder why we don't +have as much engagement. It doesn't have to be this way. +CodeRefinery has developed a vision of this teaching that can take the +best of both worlds. + +```{admonition} Video: The future of teaching + +"The future of teaching", + (45:31) is a talk +describing many aspects of this strategy in a concise form. +``` + + +## What is different about online? + +Online teaching requires a certain mindset. + +First off, it is *different*, and different is not better or worse. +You must rethink your existing assumptions and design for the current world. + +Some differences in mindset include: +* If the material is online, why pay attention *now*. Why not find + the same or similar material when you need it? If the course isn't + online, still you realize you can do a web search and find something + equivalent later. +* Why *dedicate* myself to this now? Why night attend a course + passively now, get the basics, and come back later when I need to + really understand something? +* How to best use the tools? I might have only one screen to take the + course (and no projector to watch), but the instructor material is + also closer. Why type things myself, if my normal work is copying + from StackOverflow anyway? +* Related to the above, you can't use attendance as a proxy for + engagement. You have to actually engage people, or accept that + passive attendees are OK. Do you measure the benefit of people + watching the course later? +* Everyone knows how to way of attending in-person courses. But there + are different ways to attend online courses, and you don't get as + much feedback from others. You need to be *explicit*. + +Once you learn to take advantage of online formats, you might never go +back! + +## Taxonomy of online teaching + +This isn't a strict division, but here is a rough vision of steps to +take, from simplest to more advanced. + +### (1) By yourself, in a meeting + +It's you and a group of students in a meeting (e.g. Zoom). This can +reach people, but it's easy to lose the attention of attendees. +Because you need to avoid trolls and protect privacy, you may have a +private registration and you may not publish recordings. This gives +limited usefulness in the future. + +Key aspects: +* Set up a good screen share ({doc}`instructor-tech-online`) +* Be explicit on how to attend. Plan for not only attention during + the course but something that has a lasting usefulness. +* Possibly use HackMD for discussions/questions + ({doc}`hackmd-mechanics`, {doc}`hackmd-helper`, need new info) + + +### (2a) Group teaching, in a meeting + +One of the advantages of online teaching is it doesn't require +full-time physical attendance, so you can more easily bring in a +diverse set of helpers, which greatly reduces your load. + +* Definitely use HackMD instead of chat ({doc}`hackmd-mechanics`) +* Separate roles more, so that the instructor only needs to focus on + teaching. Other helpers can come and go or attend part-time. + ({doc}`instructor-intro`, general info: {doc}`roles-overview`) + * Exercise/breakout room leaders + * Expert helpers, helping students + * Zoom host + * HackMD watcher + +At the same time, you can start grouping learners together into small +groups. This is the equivalent of different tables in a physical +workshop. +* Zoom breakout rooms can group people together +* You need to be explicit about how the groups work. Even in person, + many learners work independently even when forced into a group. +* Add "team leaders" (helpers, former students) to guide each + group. + +### (2b) Higher production values + +Now we reach the real promise of online teaching: by using streaming +platforms, you can reach everyone in the world. No registration is +needed and anyone can take part. The disadvantage is that you don't +have close interaction with the learners (by design: removing these +close interactions how you can accept everyone). + +This focuses on technical setup + +* OBS Studio for producing good recordings/stream ({doc}`obs`) +* HackMD for questions from the audience ({doc}`hackmd-mechanics`) + +### (2c) Multiple ways of attending + +One no longer has to limit yourself to interactive watching + +* Streaming +* Encourage in-person "watching parties" +* Make videos available ({doc}`video-editor`) +* Make videos available *immediately*, for catch-up purposes + + +### (3) High-accessibly zen-level courses + +Finally, we get to our final state: You can combine the contradictory +options: privacy for learners, but anyone can attend. Interactive +course, but people can refer to it later. + +This is more a mindset thing, and combines everything from above. diff --git a/_sources/open-your-courses.md.txt b/_sources/open-your-courses.md.txt new file mode 100644 index 00000000..44399830 --- /dev/null +++ b/_sources/open-your-courses.md.txt @@ -0,0 +1,28 @@ +# Open your courses to others + +CodeRefinery strategies allow you to reach a larger audience without +much extra work from you. Once you open to other attendees, you also +naturally get *co-instructors* who want to help improve your material. +This allows you to reach the next level of quality and impact, even +for your own local audience. + + + +## Principles + +- Thanks to the {doc}`CodeRefinery MOOC strategy `, + you can easily reach more people than you could otherwise. +- It may seem hard, but there are many small steps to take and you can + gradually scale up. + + + +## How-to + +- Learn by example: attend our courses, advertise our courses, and + {doc}`volunteer `, too. +- Read all of the manuals here - we try to document everything we + can, but they are always going to be a work in progress. +- Attend our [community teaching + training](https://coderefinery.github.io/community-teaching/) to + network with others and learn from the experts. diff --git a/_sources/outreach.rst.txt b/_sources/outreach.rst.txt new file mode 100644 index 00000000..0cd329da --- /dev/null +++ b/_sources/outreach.rst.txt @@ -0,0 +1,344 @@ +Outreach plan +============= + +This is a prototype the CodeRefinery outreach and marketing plan. + +Since most of us are not very good at marketing, this is actually a +summary of the book *The new rules of marketing and PR : how to use +content marketing, podcasting, social media, AI, live video, and +newsjacking to reach buyers directly* (David Meerman Scott, 8th ed.) +with descriptions of how it can apply to CodeRefinery. The book is +available at my university's O'Reilly Online Learning platform through +our library for free. If you like what you read here, consider +checking it out - the book was a very good inspiration for someone +that needs to outreach better, but is not at all that kind of person +and needs some inspiration for how to even think about it. + +Perhaps this summary is useful to others outside of CodeRefinery as +well. + +Currently, this page is one person's description and their own +interpretation9 as it applies to CodeRefinery. Over time, it should +be adapted to represent a broader view, this paragraph updated, +possibly the current content archived, and the new plan made into a +new page. + + +Introduction +------------ + +Many people need marketing and outreach: CodeRefinery isn't trying to +sell things, but we are trying to encourage people to make a choice to +gain skills. It's free, but it does have a cost: time. We think that +it does save more time in the long run, but then again, how many +businesses sell things that will save money in the long run? + +We need to encourage people to make a specific choice, and we need to +tell them why we think that is the best choice for them. + + +1 The Old Rules of Marketing and PR Are Ineffective in an Online World +---------------------------------------------------------------------- + +"Interruption advertising" doesn't work (anymore?). Few people want +to have their life interrupted with a TV commercial, banner ad, or +email from university administrators telling them to make some +choice. People think of different things now. + +For CodeRefinery, you could argue that flyers, emails from university +staff, etc. are all some form of interruption advertising. + +There's all kind of anecdotes about how advertisement, mentions in the +press, and so on aren't useful, but we wouldn't do those anyway. +Although, we do want press, that's not the main way we get people to +take our courses. (maybe it helps our funding, though) + + +2 The New Rules of Marketing and PR +----------------------------------- + +People do, however, take recommendations from people they know. Social +media lets people communicate. The match is clear. By making good +use of social media, we can reach people directly. + +(this chapter starts off with an example of social media inspiring the +author to visit Saariselkä in Finnish Lapland, which was interesting +to see.) + + +3 Reaching Your Buyers Directly +------------------------------- + +Social media lets people reach buyers directly. This is obvious. + +But, how to use social media. You don't want to go doing interruption +advertising, trying to use it to directly sell your stuff. Instead, +produce good, free content which people will want to consume. Most of +your activity should be about this, which gets people interested, and +makes them want more. Then, when they want to go deeper or are ready +to make a purchase, they come to you. + +CodeRefinery does nothing but make free content, so how does this +apply to us? Well, we have to think more. Our main content costs a +lot of time, so we need to think of content that is shorter and easier +to consume. For example: + +* Short videos or pictures explaining things. +* Short blog posts about tips or tricks, which have a clear, catchy, + immediately useful title. +* Tweeting links to specific pages we have just made, which are + especially useful standalone. +* Short "git hacks" or clever things, which people like and share, and + makes them want to attend a workshop. +* "Research software minute" videos? + +You have to think of buyer personas - backwards design all of your +material. Don't make anything unless you know who it is for, and then +make sure it is suitable for that person. Know their goal, how they +speak, and where they are (what content do they consume?). + +CodeRefinery buyer personas could include: + +* Learners +* team leaders +* Group leaders or university staff who can recommend their audience + to attend a workshop +* Prospective instructors and helpers +* Funders and high-level leadership + + +4 Social Media and Your Targeted Audience +----------------------------------------- + +Descriptions of what social media is. A somewhat useful metaphor is +that the web is like a city. Social media are things like bars or +cafes. You don't go there and start asking people to do something or +offering free samples and expect people to like it. You network, +talk, maybe tell some interesting stories. Maybe someone figures out +who you are and would want to know more about what you do. + + +5 The Content‐Rich Website +-------------------------- + +Websites matter - people will go there and check it out. Blogs are +good, they last longer than any single social media operator and +provide long-term web traffic. Websites (and everything) need +specific skills and a manager. The website needs a personality and +voice. + +CodeRefinery should make sure that there is are clear target pages or +sections for each of our target personas below. We should make sure +we don't use jargon that we would use, or have the website organized +by our own operations as opposed to learner personas. We should also +make sure the website is accessible and mobile-friendly. + + +6 Marketing and PR in Real Time +------------------------------- + +Following social media in real time can let you know what people +think. This can be an even better feedback method than surveys, etc. +By responding in real time (this can take effort), you can have +conversations there (in the open) which is also very good for +outreach. + +CodeRefinery could consider monitoring more of social media. TODO: +how to do this? + + +7 Artificial Intelligence and Machine Learning for Marketing and PR +------------------------------------------------------------------- + +We know about AI and so on. We also know it's not magic. There were +discussions about using AI to generate some content, such as tweets +from web pages. + +I didn't see much useful for CodeRefinery here, however some ideas +(run our webpages through a text summarizer to get the most important +sentences to help us make tweets) might be useful. + + +8 You Are What You Publish: Building Your Marketing and PR Plan +--------------------------------------------------------------- + +This is the chapter that puts everything above together, before it +goes off into details of the implementation next. + +1. Understand what we want. Until a goal is clear, it is hard to + justify the effort (and also, I guess ask for others help do + it). (CR: we could say "better science" but it can also mean things + like "attend workshops" or "ensure funding for the project") + + * More registrations? + * More followers? + * More views of videos? + * More funding? + * More team leaders? + +2. List the buyer personas relevant to us. (See chapter 3 for the list) +3. Create a persona around each of these buyers. (CR: see chapter 3 + above for the details). + + * What are their goals? + * What do we want them to do? + * What content do they consume? + * How do they make their buying choices? (CR: how do you decide how + to spend your time?) + * How do they speak, talk, and read? + * Subscribe to and follow the media they follow. + +4. Develop (free) content that interests each of these buyers. +5. Develop a measuring plan. Think about how we can measure success, + both in immediate engagement and making the decision we want (what + we actually want). + + +9 Growing Your Business: How Marketing and PR Drive Sales +--------------------------------------------------------- + +Salespeople don't mediate between buyers and companies anymore. +Instead, people can find so much information themselves, and make +purchases self-service. Websites and other material have to be target +to buyers (= potential learners) who are deciding if they want to +purchase (= attend a course). Websites and material should have a +personality (= our website shouldn't be written as boring as a +scientific paper). It's OK to do fun things. Social aspects to the +site is good - e.g. comments section, social media share buttons. + +1. Begin with informational content (not necessarily about you). +2. Nudge towards what you want (= attend a course, etc.) +3. Make it easy to close the deal. (CR: clear "notify me" mailing list + link on every relevant page. Maybe even make sure we have + continually open registration for the next workshop - each workshop + is ready for registration when the previous one ends. When we have + multiple types of workshops, includeable html snippets that has links + to register for every upcoming workshop?) + +Don't underestimate the value of figurehead leaders (~=CEOs) being +social - don't just delegate it to separate marketers. + +Is the analogy of salespeople even relevant for CodeRefinery? +Probably not, but maybe we could say that official requirement, +recommended courses, university staff aren't so important. People +will check our websites and other material to see if they want to +attend. + +Every website, lesson, and so on has to have very clear information +targeted to a possible reader right at the beginning, so that a +potential learner might see "is this git lesson right for me?" and +they will find "yes". + +Our website should be current. + + +10 Strategies for Creating Awesome Content +------------------------------------------ + +This section has different strategies and types of content. Types of +content include: blogs, audio, video, photos, infographics, charts, +email newsletters, presentations, long-form written content, research +reports, virtual events, e-books, white papers, apps. + +Think about how you make the content: don't just write about +yourself. Consider the problems your buyers face and make content +that solves those problems. Write for your personas. Advertise what +you do. Think what could possibly go viral. Don't forget that it +should be accessible. + +CodeRefinery: in addition to the above, we should take part in other +events, for example show up at Open Science days and give +presentations, various awareness weeks (in person or online?), +conference hashtags, etc. + + +11 How to Write for Your Buyers +------------------------------- + +Write like your buyers talk (we've said this before), and don't use +pointless jargon or meaningless words to make you sound smarter. +Humor is OK. Think like a journalist (especially for some content +types). + + +12 Social Networking as Marketing +--------------------------------- + +Facebook pages, Facebook groups. Linkedin profiles, companies, etc. +There are many more, but think about what is right for you, don't do +something just because it is there. Consider your personal brand - +make sure your profile information says something. There is a +recommendation 85% sharing and engaging, 10% original content, 5% +promoting yourself. Social media is like exercise: you need to make +it part of your routine, or you will stop doing it. It can easily +take an hour per day. + +For CodeRefinery, we know we should be more active on Twitter, which +seems like the most suitable network for us. Are there any types of +badges we can use for professional social networks? Can we declare +hashtags and publish them on our website permanently, so we don't have +to decide them for every workshop? + +Most people in CodeRefinery seem to be hesitant to use social network +sites heavily, for good reason. We should really encourage and +support those who do want to use them to do so on our behalf, as much +as possible. + + +13 Blogging to Reach Your Buyers +-------------------------------- + +Blogs are very important - and unlike social networks, they stay under +your control long-term, and drive search traffic straight to you. +Consider who you want to reach - potential learners? existing +learners? other thought leaders? Blog about things that they are +interested in and you are passionate about. + +Don't forget to monitor other blogs from people who do similar things, +to keep up to date with what is going on. Comment on other blogs and +link back to you. Invite other bloggers to visit you and blog about +their experiences - this is good for both of you. + +CodeRefinery probably knows that it should blog more. Some ideas +about what to blog about are in previous sections. We should make it +easier to share posts, and would we even want to try for a commenting +feature (might be too much, though...). + + +14 An Image Is Worth a Thousand Words +------------------------------------- + +15 Video and Your Buyers +------------------------ + +16 Audio Content via Podcasting and Social Audio +------------------------------------------------ + +17 How to Use News Releases to Reach Buyers Directly +---------------------------------------------------- + +18 Your Newsroom: A Front Door for Much More Than the Media +----------------------------------------------------------- + +19 The New Rules for Reaching the Media +--------------------------------------- + +20 Newsjacking Your Way into the Media +-------------------------------------- + +*(I haven't fully read this chapter yet)* + +The idea here is that when something interesting to your audience and +relevant to you comes up in the news, react to it / contribute +something to it, perhaps preferably in a way that can be re-shared. +Or in a way that other journalists. Be careful, don't do this +dis-respectfully or spammily. + +In CodeRefinery, different things in the science news could be +relevant to react to. + +21 Search Engine Marketing +-------------------------- + +22 Make It Happen +----------------- diff --git a/_sources/presenting.md.txt b/_sources/presenting.md.txt new file mode 100644 index 00000000..4fd70669 --- /dev/null +++ b/_sources/presenting.md.txt @@ -0,0 +1,113 @@ +# Lesson presentation hints + +This is a checklist/hints on what to do when standing up and giving a +presentation. Also see {doc}`instructor-tech-setup`. + + +## Before each lesson + +- Remember: sticky notes, water, extra whiteboard markers. + +- Make your text large enough to be seen in the back, then bigger. + Make your voice loud enough to be heard in the back, then louder. + +- As people are coming in, encourage them to sit next to someone with + a similar operating system - then, when helping each other, the + unimportant differences are minimized. + +- By the same token, don't allow people to sit alone: ask everyone to + set next to at least one other person. That way, people can help + each other. + +- Have a pen and paper next to you. When you notice problems in the + material, write it down right away during breaks in the type-along + parts. + +- Set up feedback system (chat, questions, etc) + + + + +## Starting off + +- Don't start off with tech details, say why this is important. Think + of what the emotional ("coolness") appeal is and start off with + that. +- Why will this be useful? + + +## Team teaching + +- Discuss with co-teachers and helpers about what each of you will do. + - Hand signals for common situations: too fast/slow in general, + louder, time for a break, "good enough, move on", "explain more + here". +- It can be hard for one person to manage everything. How can + multiple instructors take part? Probably the most common ones are: + - Teach teaching: alternating + - Commander and navigator: conceptually divide roles of big + picture teaching and doing the details. + - If "real" alternating, each section should be 10-15 min at + least, otherwise too much context switching is distracting. + - Teach and assist (master helper going around) + - Teach and observe. + - Asking directed questions to fill in gaps. +- Tell the students the way the teachers will work together, so that + it seems coordinated rather than someone is interrupting. + + +## During the lessons + +- Helpers can read [the team leader guide](team-leaders.md). + Encourage helpers to stand and be + constantly walking around, people rarely flag helpers from across + the room. +- Encourage the use of sticky notes (red=need help, green=I am done with the + solution). They can also be used for voting, e.g. red/green for two + answers of a multiple choice question. +- Don't touch the learner's keyboard! This is very hard to do, since + it's only natural to want to get things done quickly. The best idea + we have is to have a pen and sticky notes, when it's hard to spell + out a command to type, write it instead. +- If appropriate for your topic, create a cumulative + cheatsheet/diagram on the board as you are presenting. +- Take advantage of the mistakes/typos you make when teaching! + When you do a mistake and get an error message and realize what you did wrong, + explain what happened since this can offer valuable insights to learners. +- Ask "do you do X?" where X is what you are teaching. Instead, ask + "how do you do Y?". The first question implies something you are + doing wrong, the second is open-ended. + +## Exercise sessions + +- What to do during exercise sessions +- **never stop sharing screen**, ask someone else to share instead. +- Always go over the lesson with someone else the day before. + + +## Try to stick to the material + +- Don't try to show everything, show less, but show it clearly. +- Try not to completely deviate from the material. Ideally, rather influence the material before you teach. + Of course it is good to react to questions and to adapt the material to the audience, so sometimes an excursion can be very useful, + but make clear that you then deviate from the script + and be explicit about whether participants should follow what you do or only watch. +- If you want to show some extra steps in the terminal, show them perhaps at the end of an exercise block to not + "mess up" the exercise half-way and change it with respect to the material. +- It is good to mention an anecdote or two but be careful about mentioning too much new jargon which + only very few participants may relate to. + + +## Wrap up + +- Say what you taught and why. +- Say what comes next. Say where to get that. +- Update the instructor's guide and file issues for any problems you + noticed. +- Use the sticky notes to get good/bad feedback: have people write one + good and one to be improved thing, and leave the note on the door on + the way out. +- Get instant feedback from your co-teachers and helpers (students + too, if they offer any). + - Consider making notes on a 4-way diagram of + (content←→presentation) × (went well←→can be improved). diff --git a/_sources/registration-coordinator.md.txt b/_sources/registration-coordinator.md.txt new file mode 100644 index 00000000..dc1182d1 --- /dev/null +++ b/_sources/registration-coordinator.md.txt @@ -0,0 +1,10 @@ +# Registration coordinator + +The registration coordinator is responsible for the Indico registration page and the workshop homepage. +Usually the registration coordinator has the best position for sending emails. Drafting can be collaborated with outreach and marketing coordinator. +They keep and eye on the Helpdesk before, during and after every workshop and make sure everyone is registered and knows where to go. +After the workshop, they make sure the CodeRefinery webpage is up-to-date and all changes needed in the planning HackMD are ported to the template. +The registration coordinator also has the overview over statistics for reporting and adds those to the webpage after the workshop. + + + diff --git a/_sources/roles-overview.md.txt b/_sources/roles-overview.md.txt new file mode 100644 index 00000000..97d603bb --- /dev/null +++ b/_sources/roles-overview.md.txt @@ -0,0 +1,198 @@ +# Roles overview + +CodeRefinery has been able to scale online workshops while maintaining +an interactive feeling. This page describes the roles that we use in our workshops. + +Despite the many different roles documented here, **in practice many +of them are occupied by the same people**. +{ref}`Best-practices` below tells more about what tends to happen. +One of the advantages of our large workshops is that we have many more +staff on hand (often 10-15), thus allowing much more specialization +than small workshop can have (thus, the large number of roles below). +Many of our instructors give feedback such as "this is so much easier: +we only show up and teach!" + +A common pathway goes (Learner/team leader) → (Expert +helper/Instructor) → (More specialized roles). **Note that thanks to +our {doc}`team teaching or "co-teaching" `, it is really easy to join as +an instructor!** + +You can also find the common tasks in checklist-format under each roles section in the {doc}`Workshop playbook `. + +## Workshop roles + +### Learner + +Comes and learns. + +* Does necessary preparation and attends the workshop +* More info: {ref}`Learners section ` + +### Team leader + +Team leaders are only a small step above learners. They aren't +expected to know everything, but mainly keep their breakout rooms on +track - they could even be a slightly more confident learner. + +* Leads a breakout room + * keeps on track + * makes welcoming community + * answers some questions + * ask for more help when needed +* Attends a one-hour team leader preparation / onboarding session. +* More info: {doc}`team-leaders` + +### Instructor + +Obviously, instructors teach. Uniquely in our system, they have a lot +of support and generally can focus on the teaching part. + +* Prepares lesson and "just teaches" without worrying about other workshop matters +* {doc}`Team teaching `, you are not alone +* Attend instructor preparation calls +* Usually receives one-on-one mentoring in advance +* Other times during the workshop, usually serves as an expert helper +* More info: {doc}`instructors` + +### Expert helper + +Expert helpers are generalists who don't have other assigned roles. +Thanks to HackMD and breakout rooms, they have plenty to do. + +* All-around generalist who assists wherever is needed +* Answers questions in HackMD +* Supports team leaders in breakout rooms: rotates between + breakout rooms and checks how things are going +* Identifies important issues and raises them to the instructors, + "voice of the audience" +* More info: {doc}`expert-helpers` + +### Behind the scenes + +#### HackMD manager + +The HackMD manager closely watches HackMD to keep it organized and by +reading it in detail, can serve as the "voice of the audience" to the +instructors. + +* Ensures everything gets some answer quickly + * Even if it is "will be answered later" + * Can raise issues to instructors immediately if needed. + * In general serves as the instructors' "ear on the ground" +* Maintenance during the workshop + * Copies old information to archive HackMD if too much traffic + * Organizes sections and questions + * Notes break and exercise times +* Processes and archives HackMD after the course. +* More info: {doc}`hackmd-helper` + +#### Host + +The Host serves as the manager of learners during the course. + +* Learner Zoom meeting host (often). Often the registration + coordinator. +* Helps learners with organizational issues during the course + * Ensures that everyone is welcomed and knows what is going on + * Assign learners to breakout rooms + * Answers technical questions about the course itself +* Often the same person as the registration coordinator. +* More info: {doc}`host` + +#### Director + +The director manages the flow of the course: preparing and cueing +instructors, switching the livestream scenes, announcing schedule, +adjusting schedule as needed. + +* Instructor Zoom meeting host (often). Often the instructor + coordinator. +* Cues the sessions, makes sure they flow together well. +* Adjusts the flow when things do *not* go according to schedule. +* Has sufficient knowledge of the tech setup to do the scene + switching. +* More info: {doc}`director` + + +#### Broadcaster (livestream) + +The broadcaster is responsible for the livestreaming tech. + +* Only needed in livestream courses +* Installs and manages OBS control for livestreams + * Ideally is not teaching in the first session + * Is around in case of problems, otherwise the director does most of + the scene switching. +* Makes sure videos get processed and to Youtube in a timely manner, + or at least saves them where someone else can do it. +* More info: {doc}`broadcaster` + +#### Registration coordinator + +Oversees registration and generally everything on the participant side. + +* Communicate with participants +* Organize installation help session +* Contact person for learners +* Collect feedback +* Provide participation certificates +* More info: {doc}`registration-coordinator`) + +#### Instructor coordinator + +* Find instructors +* Coordinate the schedule and instructors for each event +* Organize {doc}`instructor onboarding ` +* Collect feedback +* More info : {doc}`instructors`. + +#### Outreach and marketing coordinator + +* Makes sure workshop gets advertised in different places +* You can find a list of commonly advertised places in the bottom of the {doc}`workshop-playbook`. + +### Team leader / Exercise coordinator + +* Communicate with all team leaders, contact person for them +* Makes sure all exercises are ready and commicated before and during the workshop +* Organize the {doc}`team leader onboarding session ` +* Usually attends as an expert helper to generally be available and + support all leaders. +* Collect feedback from team leaders +* More info: {doc}`exercise-coordinator` + +### Video editor + +* Watches videos and prepares for YouTube upload +* Uses + [ffmpeg-editlist](https://github.com/coderefinery/ffmpeg-editlist) + to process videos after the Broadcaster has made them available. +* Work should be done the day/evening of of the course + +(best-practices)= +## Best practices + +Roles that are often combined: + +* **Registration coordinator** and **Host** +* **Instructor coordinator** and **Director** +* **Expert helper** and anything +* **Instructor** and any other role (but not **Host**) + +Roles that should *not* be combined: + +* **Registration coordinator** and **Instructor coordinator** (these + two together tend to form the "core team") +* **Broadcaster**/**Director** and **Instructor** on the first sessions of each + day. +* **HackMD manager** and other roles (so *delegate* HackMD while you do + something else! this is OK.) +* **Host** and any active teaching (in big workshops at least - + learner management keeps you busy) + +Other notes: + +* **HackMD manager** can rotate between different people. +* **Expert helpers** can replace **team leaders** if they cannot join the + full workshop +* Coordinators delegate diff --git a/_sources/teaching-tech-together.md.txt b/_sources/teaching-tech-together.md.txt new file mode 100644 index 00000000..56620e44 --- /dev/null +++ b/_sources/teaching-tech-together.md.txt @@ -0,0 +1,210 @@ +(teaching-tech-together)= +# Summary of Teaching Tech Together + +[Teaching Tech Together](http://teachtogether.tech/) is a book +compiled by Greg Wilson which is about the pedagogy and practical +hints of teaching technology in informal environments. It is a very +good resource, and the main point is that research does back up +teaching, it's not all intuition. Many citations are included. + +This page contains a summary of the most important points. The point +is that one can quickly refer to this before writing a new lesson or +teaching a course. The article [Ten quick tips for creating an +effective lesson](https://doi.org/10.1371/journal.pcbi.1006915) is +also a good summary of the main lesson design points of this book. + +Useful appendices: +* [Backwards lesson design + template](http://teachtogether.tech/en/template/) +* [Checklist for events](http://teachtogether.tech/en/events/) + + +## Ch1: Introduction +* **Novice = no good mental model of what they are learning**, "not even + wrong" +* A manual is *not equal* to a tutorial - a tutorial needs to build a + mental model from scratch. +* Formative assessment = determine what the misconceptions are. + + +## Ch2: Building mental models +* "Expert blind spot" = experts have more links, so don't see what + links are missing. +* Concept maps as a metaphor for connections +* 7+/-2 concepts can fit in short term memory at once +* Get feedback from others, then give feedback to others, then + self-feedback (last one is "deliberate practice") + + +## Ch3: Expertise and memory +* Cognitive load: too much is bad and makes learning slow +* **Faded example**: blank out certain things in an example which are + added as an exercise/example (what you want to progressively + teach). Seeing examples is good, debugging as an example. +* "I want to do something, not learn how to do everything" +* **Parsons problems** - give working code but in random order, + students must put it into the right order. +* Minimal manual: one page micromanuals on specific tasks. Helps + training but loses content. +* The last exercise of this chapter has some good hints for making + useful graphics. + + +## Ch4: Cognitive load +* Cognitive load is divided into intrinsic load (background required + learn), germane load (mental effort to link new to old), and + extraneous load (everything else that distracts from learning). + (this is "cognitive load theory") +* A paper claimed that self-guided learning is less effective, because + people are overloaded: you have to both learn new facts and learn + how to use them at the same time. +* Strategies: use exercises well that minimize tho load. a) parsons + problems, b) labeled subgoals, c) split attention (separate + channels, but complimentary rather than redundant), d) minimal + manuals + +## Ch5: Individual learning +(chapter about how people can help themselves) +* Six strategies: a) spaced practice, b) retrieval practice, c) + interleaving (abcbac better than aabbcc), d) elaboration (explain to + self), e) concrete examples, f) dual coding (e.g. words and + pictures, or different forms of same material). +* Manage time well +* Peer assessment + +## Ch6: A lesson design process +* Backwards lesson design, similar to test-driven development: 1) + brainstorm ideas for what to cover, 2) create learner personas to + figure out who you want to teach, 3) create formative assessments to + give learners a chance to exercise what they are trying to learn + (3-4 per hour), 4) put formative exercises in order, 5) write the + teaching material around this. +* Learner persons, to guide your design process: a) general + background, b) what they already know, c) what they *think* they + want to know, d) how course will help, e) special needs. +* Learning objectives: write objectives and think of what depth of + understanding you are getting too. Consider Bloom's taxonomy: a) + remember, b) understand, c) apply, d) analyze, e) evaluate, f) + create. +* Fink's taxonomy (unlike Bloom's, complimentary not hierarchical): a) + foundational knowledge, b) application, c) integration, d) human + dimension, e) caring, f) learning how to learn. +* Maintainability: is it easier to update than replace? a) **You have to + document the lesson design process**, b) technical collaboration, c) + are people willing to collaborate? Or do teachers resample rather + than update? + +## Ch7: Actionable approximations of the truth +(chapter about learning programming specifically... title comes from +not necessarily having clear research that says what you *should* do, +but you have to do something anyway) +* Experts know *what* and *how*, novices lack both but most teachers + focus on *what* only. +* Think about teaching debugging and using it as examples - the *how*. +* If you are teaching programming specifically, just [read the + chapter](http://teachtogether.tech/en/pck/). + + +## Ch8: Teaching as performance art +* Get feedback on your teaching. People aren't born teachers, and + feedback isn't in the western teaching culture enough. +* Use live coding. It's much more effective, especially because it's + two way and *you can demonstrate making mistakes*. a) embrace your + mistakes, b) ask for predictions, c) take it slow, d) be seen and + heard (stand + microphone), e) mirror your learner's environment, f) + use the screen wisely (make it big enough), g) double devices (one + to present, one for notes), h) use diagrams, i) avoid distractions, + j) improvise after you know the material, k) face the screen only + occasionally +* Drawbacks of live coding, which you can minimize over time: a) going + too slow, b) exercises can be too deep and have too much cognitive + load (give skeleton code). + + +## Ch9: In the classroom +* Code of conduct: teaching isn't for those that are already "in", + it's for those that aren't. If you don't notice problems and + enforce it transparently, it means nothing though. +* Peer instruction. Discuss in groups. e.g. multiple choice + question, if there is a wide variety of wrong answers, have them + discuss in groups. +* Teach teaching: different strategies, consider what you want to do: + a) teach teaching (taking turns) b) teach and assist (going around + helping) c) alternative teaching (group with more specialized + instruction), d) teacher and observer, e) parallel teaching (two + groups, same material), f) station teaching (rotate through + stations). +* If co-teaching, plan ahead: a) confirm roles at start, b) work out + some hand signals for common conditions, c) each person should talk + at least 10-15 min at a time, d) person who isn't teaching shouldn't + distract, though leading questions OK, e) check what your partner + will teach after you are done, f) inactive teacher stays engaged, + not doing own stuff. +* Plan for mixed abilities, especially false beginners who have + studied the material before. +* Can you make a collaborative not online document? +* Sticky notes +* Don't start from blank pages, give some starting point. +Many other good points in [the chapter +itself](http://teachtogether.tech/en/classroom/). + + +## Ch10: Motivation and demotivation +* Extrinsic vs intrinsic motivation. Extrinsic: have to do it for job + or something. Intrinsic: do it for self, you want to encourage + intrinsic motivation. Drivers of intrinsic motivation: a) + competence, b) autonomy, c) relatedness (connection to others). +* Consider usefulness and time to master. Focus on useful and fast. + Useful = *authentic tasks*, things people will actually use. +* Avoid demotivation: for adults, a) unpredictability, b) + indifference, c) unfairness. Specific examples: a) contemptuous + attitude, b) saying existing skills are worthless, c) complex or + detailed technical discussion, d) pretending you know more than + they do, e) the word "just" as in, it's "just easy", f) software + installation problems, g) giving impossible challenges to fail at to + try to learn something, if not understanding. +* Consider accessibility and inclusivity - consider things are harder + for others, try to understand diversity of backgrounds. + +## Ch11: Teaching online +* Disadvantage of MOOCs: can't clear up individual misconceptions +* The chapter has various good ideas, including how to make sure + everyone is heard (certain group doesn't dominate online + discussions), short cycles and short exercises, require some small + group work, use videos to engage rather than instruct (people can + read faster), identify and clear up misconceptions early. +* Flipped classroom: watch lectures on own time, do exercises and + discuss in class time. + +## Ch12: Exercise types +* Multiple choice, code yourself, code+multiple choice, inverted + coding (given code, test and debug), fill in the blanks, Parsons + problems (given questions but in wrong order). +* Tracing execution, tracing values, reverse execution (find input for + output), minimal fix, theme and variations, refactoring exercise. + Pen and paper exercises. +* Diagrams and connection: draw diagram, label diagram, matching + problems. +* Autograding is hard, in particular most automatic grading tools + don't provide useful feedback messages. Also, automatic grading can + only test low-level skills, not higher abstractions like code + review. + +## Ch13: Building community +(Chapter about forming a community of teachers and learners working +together) + + +## Ch14: Marketing +* Think about what you are offering to who. Who are the target + audiences and why should they be care and become invested? + + +## Ch15: Partnerships +* Main two points are work within schools or outside of schools. If + inside, part of academic programs? Academic programs and especially + teachers change very slowly. + + +## Ch16: Why I teach +([A note from the author](http://teachtogether.tech/#s:finale)) diff --git a/_sources/team-leaders.md.txt b/_sources/team-leaders.md.txt new file mode 100644 index 00000000..f3b9302d --- /dev/null +++ b/_sources/team-leaders.md.txt @@ -0,0 +1,310 @@ +# Team leaders / Helpers / Exercise leaders + +We use this page during team leader onboarding. + +**Thanks for being a team leader :heart:**! +Without you, these large online workshops would not be possible. + +## TL;DR (Summary of this page) + +- Everyone watches the CodeRefinery stream ({ref}`how to attend via livestream `) +- Communication happens via collaborative document ({ref}`Collaborative document mechanics `) +- Exercises can be done individually, in a pre-formed or ad-hoc team online or in person +- Team leads are between the instructors and learners, please + - Keep track of things like learner progress, instructions and time and report them via collaborative document + - Be available for learners to ask their questions and lead discussions + - If idle, check the collaborative document for open questions and answer them + +If you want to contact us before the workshop you can send an email to our general email address or you can join the +{doc}`CodeRefinery chat ` (we recommend the `#workshops` stream, +and if you can't find it then `#general` is good). + +If you have fun being a team leader for the workshop, please visit our +{ref}`contributing page ` page, to find out about further +volunteering possibilities within CodeRefinery. + +## Code of Conduct + +We follow [a code of +conduct](https://coderefinery.org/about/code-of-conduct/) for all our +interactions before, during and after workshops, also for this session. + +We've designed the workshop so that it is very hard for one person to +ruin it for everyone. Within your team, you will need to take on the +role of ensuring a good environment. + +If you see anything that is not supporting an positive learning +environment, let us know! +* If it's a general issue that can be mentioned publicly, write it + immediately in the collaborative document. +* Send a message to if it is private and can + be handled asynchronously. + +## CodeRefinery project + +We teach all the essential tools which are usually skipped in +academic education so everyone can make full use of software, computing, and +data. We don't just give courses, but we are a training network that you can +join to share the effort and bring better courses to your community. + +## ..and you? + +Shortly introduce yourself in the collaborative document of the onboarding session: +* Who are you? +* What do you do? +* Where are you connecting from? + +## What is needed to be a team leader? + +Most importantly, *you do not have to know everything* (we don't, either), but you are expected to: + +- Have been to a CodeRefinery before and used git some since then, OR have some general experience with git (branching, + pull requests) and command line work, OR be able to generally follow + the path of the exercises that we have laid out. +- Be present in your teams physical/virtual room at least during exercise sessions of the workshop. +- Show a positive, motivating attitude to learners. +- Keep exercises going and let us know when there are difficult questions! + +> If you aren't sure if you can be a team leader: you probably can be one! + +## Who is joining this workshop? + +Be aware of the different + +* career stages (students, postdoc, researcher, professor, industry), +* backgrounds (computer scientist, IT, domain scientist, coding beginners,...), +* infrastructure (operating system, access restrictions, preferences on graphical vs command line interfaces, ...) and +* preferred programming languages (Python, R, Matlab, Julia, Fortran, ...) of your learners. + +There is also usually a great variety of pre- knowledge on the different topics of the workshop. + +Overview from the [pre-workshop survey]() + +## What will happen during workshop? + +The workshop schedule on the main workshop page contains +links to lesson material, including lists of exercises. + +The best analogy is **watching a popular sporting event on TV**. +There are periods of lots of activity, and clear periods of breaks where you +do your own thing. + +* **Everyone follows stream during lessons** - lessons, demos, exercise + intros, going over solutions, etc. +* **For questions and instructions we use a collaborative document** (more below). +* **Exercises during the lessons are done individually or in teams** and there is many + ways to do this: + * Watch and work alone + * Watch together and interact during exercises/breaks (in-person or + online) + * Reviewing/doing exercises later + + +```{figure} img/exercise_options.png +Overview of the different options of doing the exercises individually or in a team. +``` + +## Exercise sessions + +We try our best to be very explicit about what is going on. +Your first goal should be to make sure the learners are engaged and no one is left behind. + +The instructors should clearly tell which exercises and for how long (minimum 10-15 min); +if anything is unclear please ask via collaborative document, you are our safety net. + +**Make it easy for learners to ask for help**: +* Make sure your group knows your name and that you are their team lead. +* Always start by greeting people and ask how the lesson is going; report back if there is something instructors should be aware of. +* Encourage your team to also put answered questions in the collaborative document, someone else might be wondering the same thing. + +**Want extra help?** +* It is OK to not know something! +* Use the collaborative document if there is questions that you cannot answer. + Our instructors and expert helpers are watching it and try to answer every question. + +**Major problems?** +* Exercise time is limited, watch the time and keep things moving. +* If some debugging takes to long, it's reasonable to describe the problem in the + collaborative document. An expert helper may have seen the problem + before. +* If any one problem takes too long, it's OK to say "we don't have + time, let's come back" + + +```{figure} img/team_status.png +Example of collaborative document during an exercise session. a) clear description of +topics of the exercises. b) team status. c) as always, +questions at the bottom. +``` + +## What can I do to prepare for the workshop? + +As a team leader, we do not expect you to know all our [CodeRefinery training material](https://coderefinery.org/lessons/core/), but if you have time: + +- **Take a look at the exercises in advance** of each day (the exact + plan is on the workshop page. Lessons have an "exercise list" page that shows everything), check that you understand the general point of each of them. +- If you are interested, also read through the **instructor guides** for the lessons (there is a link at the top or sidebar of each lesson). +- Use github issues on the lesson github page to point out issues with exercises and the materials + +## Any questions? + +* Send us an email to +* If you want to, sign up for our [Zulip chat](https://coderefinery.zulipchat.com) to ask us anything, anytime. Use + `#tools-workshop` during the workshop itself (you need to join the stream, it is not default for new chat members). +* During the workshop, please use the collaborative document. + +## Path ahead + +Would you like to +* become an instructor? +* help organizing a workshop? +* contribute to lesson material? +* have any other ideas to contribute? +* community calls: see + +See our [website](https://coderefinery.org/get-involved/) and {ref}`volunteering`. +Best way to get started is to join the [Zulip chat](https://coderefinery.zulipchat.com). + +## Tips and Tricks + +This section provides some tips and tricks for being a team leader. Be aware that there are **different types of team leads (online/in-person/team of colleagues/team of strangers)** and these tipps may not apply to evryone. + +### How to create a positive learning environment? + +As a team leader, you have a crucial role during workshops: + +- You are between the learners and the organizers and instructors, please use the collaborative document to communicate. +- Encourage learners to learn from each other. +- Acknowledge that some of the material can be difficult and that people in your team will + learn more working together. +- Acknowledge when learners are confused and raise it to the instructors. + Understanding why learners are confused provides useful feedback for + instructors. You are our eyes and ears. +- As we said, you don't have to know everything, just like learners don't + necessarily know everything (we don't know everything, either). It's more + important to be responsive and work together. +- If you meet virtually: Turn on your camera, and encourage everyone else to do so as well. Have an introductory round in the first exercise session, to get to know your group. Whichever strategy you choose for your team, be present and encourage learners to ask questions. +- In an in-person workshop: Stand up and walk around, try to make rounds by everyone. If you are + convenient, students will ask. If you are sitting in the back, student's + won't. Students rarely try to get your attention from across the room if you + don't look ready. + +### Strategies for leading a team + +There are several strategies you can use to run your team, no matter if you meet in a physical or virtual room (Physical room would need a larger screen for every one to see though): + +Strategy 1: +- **Everyone does the exercises themselves until someone has a question** +- Encourage learners to ask multiple times; if necessary share your/learners screen and discuss. +- If everyone is active, this can be good, but there is a risk that the barrier for distrurbing the silence is too big. + +Strategy 2: +- **To start things off, team leader can share the screen.** +- Do not try to hide mistakes (they make good learning opportunities, "can you spot my mistake?") and discuss your solutions. +- It might be good to give learners some lead first, and use this only + if no one volunteers. + +Strategy 2: +- **Team leader asks someone to share the screen and go through the exercise.** +- You can encourage the others to guide the one who is sharing the + screen. Or let the person go on her/his own pace. + - If no one dares at first, you can also start sharing your screen and let the room tell you what to write. + - That way they see how it can go and the barrier shrinks. +- Try to alternate who is sharing the screen for each session. +- When someone has an issue, it is a good idea to switch screen share to them + and maybe even continue from there + +**You don't actually *have* to do the exercises**. You could apply +lesson material to your own team's work, review what was just said, +have a free-form discussion, etc. - if those are more valuable. You +can always come back to exercises later, or let learners do them as homework. + +### How to solve common problems in teams? + +- **One learner asks very many questions**, ends up monopolizing all of + the time. Other learners are left without help, and the whole group + may not get the exercises done + - Encourage them to ask in the collaborative document + - It can be very hard to say "no", but it's more important to have + balance than answer every question you are asked. If you need + to say no, you can try things such as "I'm sorry, but in order + to finish we need to go on now. We can keep working on it + later - would you like to watch?" +- There is some sort of problem that ends up taking a **lot of time** + - Work on it for a minute or two. + - Encourage to describe the problem in the collaborative document. Our expert helpers may be able to help. + Nothing wrong with this, because there is no deadline or time limit. +- No one asks any questions + - Make sure people know that you are there for them if they need help + - Some exercises are easier than others and people really may not need any help with some of them + - Remind that the recording can also be watched later, if people cannot keep up + - Use your time answering questions the collaborative document +### Please do not ... + +- Take over the learner's keyboard (neither physically nor remotely). It is rarely a good idea to type anything + for your learners and it can be demotivating for the learner because it + implies you don't think they can do it themselves or that you don't want to + wait for them. It also wastes a valuable opportunity for them to develop muscle + memory and other skills that are essential for independent work. Instead, try + to have a sticky note pad and pen / use the collaborative document and write the commands that they should type. +- Criticize certain programs, operating systems, or GUI applications, or + learners who use them. (Excel, Windows, etc.) +- Talk contemptuously or with scorn about any tool. Regardless of its + shortcomings, many of your learners may be using that tool. Convincing + someone to change their practices is much harder when they think you disdain + them. +- Dive into complex or detailed technical discussion with the one or two people + in the audience who have advanced knowledge and may not actually need to be + at the workshop. +- Pretend to know more than you do. People will actually trust you more if you + are frank about the limitations of your knowledge, and will be more likely to + ask questions and seek help. +- Use “just”, “easy”, or other demotivating words. These signal to the learner + that the instructor thinks their problem is trivial and by extension that + they therefore must be stupid for not being able to figure it out. +- Feign surprise at learners not knowing something. Saying things like “I can't + believe you don't know X” or “You've never heard of Y?” signals to the + learner that they do not have some required pre-knowledge of the material you + are teaching, that they don't belong at the workshop, and it may prevent them + from asking questions in the future. + + +## Background + +The following section provides some background on our workshop setup. +### Hierarchical workshops to scale + +Traditionally, a workshop has instructors and team leaders/helpers, but the +capacity is limited by instructors, so we are limited to ~30-40 people +at most. Then, we tried to scale to larger numbers: even up to and beyond 100 +people. For this, we have to rely on *team leaders* . A team leader does not have to be an expert in the +material, but should be able to keep things flowing. + +Team leaders are an essential part of the CodeRefinery workshop team and +allow CodeRefinery to scale to many more people than we could otherwise handle. +Team leaders will guide their team through the course, keep +time, and let us know when more help/time is needed during the exercise sessions. +Instructors and expert helpers are always available via the collaborative document. It is very +likely that you'll grow as a mentor and learn how to be a more efficient +teacher. + +### Teams + +A team could be for example a +group of colleagues/friends where one of the team members has a bit of knowledge +on the tools presented in the workhop. This person can act as team leader +for the workshop, but may still learn a thing or two themselves. In that way +you can work with people you know and the barrier for asking questions and +discuss together may be a bit lower than in a group of strangers. + +Sometimes we also allow learners to register as invidual learner with interest in being in a team. We then try to arrange those people in teams which stay together for all exercise sessions on all days and provide a zoom breakoutroom with a team/exercise leader. Since this is dependent on our team leader capacities, we cannot accept infinte amount of learners. +Being assigned a team as a learner allows people to form a bond and get the +rooms started sooner. We will try to keep you in the same team +room as long as we can, but we give no promises and will rearrange as +needed when people can't attend. + +## See also + +* Carpentries instructor training +* {ref}`Teaching Tech Together ` chapters 8, + 9, 10. diff --git a/_sources/team-teaching.rst.txt b/_sources/team-teaching.rst.txt new file mode 100644 index 00000000..057b8ee3 --- /dev/null +++ b/_sources/team-teaching.rst.txt @@ -0,0 +1,231 @@ +Team teaching +============= + +Listening to only one person talk can be boring. Listening to a discussion is +much less so. "Team teaching" can mean many things, but in this case we +are referring to **two instructors are both actively +involved in lecturing at the same time**, as some sort of conversation +between them. It is a form of co-teaching. + +When it works well, it makes a lecture much more dynamic and +engaging, and reduces the load for each person to plan everything +because you can rely on two minds to do it live. +The difficulty is that you need to coordinate and it is our nature to +keep talking while teaching, making a conversation difficult. + +.. seealso:: + + `Demo of CodeRefinery livestream teaching + `__. This shows a + demo of many parts of team teaching on a livestream - read the + video description for details. + + + +Basics +------ + +.. figure:: img/teach-teaching--screenshot.png + :align: right + :figwidth: 50% + + Demo of team teaching. Two people are speaking, in this case one + is typing and giving the small point of view, and one is explaining + the big point of view. + + +We can't claim to know the best way to do this yet, but we have seen ways +that work and don't work. + +The basic idea is that you want to keep a constant *conversation* +going. This can be a mutual discussion, one person explaining big +concepts and one the details, one person asking +questions and the other answering, or some other combination. *This +is different that two people teaching different sections.* + +There is less need for the instructors to prepare every single thing, +since you can rely +on the wisdom of the group to get you through areas you haven't +perfectly prepared. In fact, this is good, because then your learners will +see things go slightly wrong and your live debugging. +Still it can be useful to agree with your co-instructor on the choreography +of your session (more about this below). + +.. pull-quote:: + + One of the most important principles of ship handling is that there + be no ambiguity as to who is controlling the movements of the + ship. One person gives orders to the ship's engine, rudder, lines, + and ground tackle. This person is said to have the "conn." + + — James Alden Barber, 2005, "Introduction", The Naval + Shiphandler's Guide, p. 8. Mark B. Templeton, via `wikipedia `__ + +As the quote says, in any large enough operation, multiple people are +involved, but responsibilities should be clear. At least, the team +should know who is pushing things forward (even if, to make it seem +live, they still discuss among each other anyway). + +We propose two basic models, but of course there is a constant +continuum. +And in either model it can be good to switch roles every 20-30 minutes. + + + +Model 1: Guide and demo-giver +----------------------------- + +One person serves the role of **guide**, explaining the big picture +and possibly even the examples. The **demo-giver** shows the typing +and does the examples, and could take the role of a learner who is +asking about what is going on, the person who actually explains the +details, or an occasional commenter. Anyway, the guide is the one +navigating through the course and bringing up material in a logical +order for the audience and "has the conn". + +Hands-on demos and exercises work especially well like this. Here, +the guide would follow the outline and serve as the director (see +below). + +.. csv-table:: + :delim: | + :header-rows: 1 + + Guide | Demo-giver + Introduces most material | + Goes through theory | Asks questions that a learner may ask + Introduces type-along | + Explains steps of type-along | Types during type-along + Asks questions to Demo-giver during type-along | Explains details what they are typing and what happens + Looks at HackMD during type-along | Looks at HackMD during theory + Discusses during Q&A | Discusses during Q&A + + + +Model 2: Presenter and interviewer +----------------------------------- + +In this case, it is the **presenter** who is mostly explaining *and* +giving the demos, and generally trying to move the forward through the +material. The **interviewer** serves as a learner or spotter, fills +in gaps by asking relevant questions, and tries to comment to the +presenter when things are going off track. The interviewer "has the +conn". + +This is closer to normal teaching, so feels more natural to do. The +big disadvantage is that it's the tendency of the presenter to keep +talking, and the tendency of the interviewer to be nice and not +interrupt. This negates most of the benefit you would hope to have, +but is much better than solo teaching. + +Here, the presenter would follow the outline and serve as the +director (see below). + +.. csv-table:: + :delim: | + :header-rows: 1 + + Presenter | Interviewer + | Asks questions to presenter + Answers questions using their special knowledge | Follows up with learner questions + | Pushes forward though the material + | Asks questions that a learner may ask + | Introduces type-along + Explains type-along and material | Explains type-along and material + Looks at HackMD when possible | Looks at HackMD most of the time + Discusses during Q&A | Discusses during Q&A + + + +Hints +----- + +With more than one person, there is a risk of seeming uncoordinated +when the team doesn't know who is supposed to move the lesson forward. +It's not bad to have short discussions to decide what to do next, it +makes the show seem interactive. But if it happens too +much, it becomes noticeable. As quoted above, you could adopt a +principle which exists +in many domains: at any time, only one person is +in control. Implemented in team teaching, it becomes: *you explicitly +know who is in control* (the **director**). *The director is +responsible for understanding the current situation and checking with other +instructors, but in when you just need to something and no one has +strong opinions, you don't debate, the director decides.* The main +difference of Model 1 and Model 2 above is "is the director the one +mainly explaining new material, or the one asking questions". There +are also multiple layers of director: there may be the director for +the whole course, and the director/"conn" for the lesson. + +We can't tell you what works best for you. But the models above and +thinking about who the director is should let you have an efficient +discussion to decide your model. The need for a director is why we +don't recommend fully equal co-teachers. Instead, divide the course +into parts and use the two models for each part. + +- Of course, there are other roles in a workshop. + + - The **HackMD watcher** pays particular attention to the audience + questions. They might be a different person from the co-teachers + and they can interrupt anytime. + - The **Meeting host** manages the meeting itself. + - The Director could be completely separate from the people on + screen, and somehow sending signals to the teachers as needed. + But, unlike scripted media, the course reacts more to the audience + and it is better for the director to be in the lecture. + +- If you ever go off-plan, that's OK. You can discuss during the + lecture so the audience can know what you are doing and why. You + *want* to adjust to the audience more than you would in a solo + course. But at the same time, be wary of deviating too much from + the material that the watchers have, since it will be disorienting. + +- Two people works well. With three, it's hard to allow everyone to + speak equally and people tend to jump on top of each other in the + gaps - or no one talks, to give others a chance to say something. + You could have particular segments where different pairs of + people adopt the main roles, and others speak up if they want. Or, + at that point, make it a panel discussion format (multiple + presenters and one interviewer) + +- Of course, it helps to have a good plan of what you are going to + do. But if only one person knows that plan, this strategy can still + work, especially if that person is the presenter in model 2. + +- The less preparation you have, the more useful it is to strictly + define the roles of each person (to ensure someone is in charge of + moving it forward). + +Please send us more suggestions to add to this list. + + + +Preparation +----------- + +This is one proposed model for preparing for team teaching: + +- Talk with your co-teacher. These hints assume a two-person team. +- Decide what material will be covered, overall timing, strategy, etc. +- Divide up the material. In each section, decide the model to use + and roles. If in doubt, starting with the guide/demo-giver division + with the stronger instructor as guide works well. +- Decide who will be the director for each part. Perhaps a good idea + is to keep it consistent: the guide is always the director. +- At least one person prepares the outline (the order of topics to be + presented, key questions to ask, etc.) - usually the guide or + interviewer. The guide or interviewer + should be comfortable with it (and could even do it mostly alone), + everyone can give comments and make sure to read it at least once. +- Run as above. +- You don't need to plan every step in detail but it can be useful to prepare + the session together and step through the choreography (e.g. "now I will show + this and then give you the screen and then ask you to do this ... you will + lead this 20 minute block and then I will lead that 20 minute block and + please ask me questions while I present X"). + +Then, just go! Don't worry if it's not perfect, if either person +wonders what to do next, just pause some or ask the other. This +imperfection is what makes it more dynamic and exciting, and in almost +all cases the audience has been impressed with the co-teaching +strategy, even if it's not perfect. diff --git a/_sources/tech-docs.md.txt b/_sources/tech-docs.md.txt new file mode 100644 index 00000000..22841bc4 --- /dev/null +++ b/_sources/tech-docs.md.txt @@ -0,0 +1,118 @@ +# Writing technical docs + +This is a guideline for non-teaching technical documentation, for +example HPC infra usage. Since many of us overlap with HPC or other +support roles and our CodeRefinery mindset partially overlaps, we have +some brief guidelines here. + +There is far too much professional information for us to reproduce +here, but hopefully this is useful quick reference for a typical +person to get started. Check the links at the bottom for more. + + + +## What kind of doc? + +* **Tutorial** - emphasis on concepts and mental model, after reading + you can do limited things. + +* **Reference** - more likely to read if you know the concepts and + want to know more advanced stuff. + +* **Example** - example of one specific thing. Good for copying and + pasting if you know enough to understand it. + +"A good tutorial is different from a good reference. Very few things +are good at both at the same time." - (I don't remember who, seen in +Teaching Tech Together). Thus, both tutorials and reference are +useful. Sometimes, we need a tutorial for our stuff and can point to +outside material as a reference. People also really want examples +they can copy - is your infra similar enough that outside examples can +be copied? + + + +## Recommended sections/things to include + +(Of course, depending on what type of doc it is) + +* Introduction that says *when* this material is relevant and *why* + you might want to use it. (*who* it is written for, *when* it was + updated). Prerequisites. + +* If relevant, there is a *concepts* section at the beginning. + Perhaps define a few key terms. Possible prerequisites (required or + possibly useful). + +* Is the actual *content* good and understandable? Are any conceptual + or technical prerequisites mentioned in the introduction (or when + they are needed, if minor)? + +* *Examples* spread throughout. + +* A *conclusion* that wraps up and what happened, why, and what comes next. + +* "*See also*" section at the end if relevant. + +* If relevant, *exercises* at the end or spread throughout. Even if + this isn't the point, it makes people think and makes it minimally + useful for informal teaching. + + +## Style suggestions + +(not standards, since of course people do what they want anyway. Not +all things apply in all cases) + +* **Bold** for definitions or the first time a concept is introduced. + Basically, a time where someone is likely to scan up the document to + remember what a certain concept is, such as "what's a git stash?" + +* *Italics* for local emphasis. + +* Never feel bad to use simpler text, in the best case someone can + now understand, in the worst case there's less mental effort. + +* Use an active/imperative voice (Y does X, do X to get Y), not + passive (X can be done by Y). Try to use present tense. + +* Make the docs skimmable - by looking at headings and first words in + each section, can you figure out what you need to focus on? + +* Use gender neutral text, of course. + + +## Style guide + +(Is it worth making a minimal academic HPC/tech doc style guide? The +benefit would be that we can share stuff better. There's no need to +emulate or reproduce actual professional ones, since we probably +aren't that formal.) + + +## Other ideas + +Consider documentation-driven development. Write basic docs, review, +then implement it. + + +## See also + +Of course, there is far more professional information than you can +find above. + +* The [Write the Docs](https://www.writethedocs.org/guide/) guide + seems useful - especially about organizational aspects. + + * [Principles](https://www.writethedocs.org/guide/writing/docs-principles/) + + * [Styles and list of style + guides](https://www.writethedocs.org/guide/writing/style-guides/), + though most are probably too long for hobbyist reference. + +* [lesson-design.md](lesson-design.md) might be useful to understand. + The "backwards lesson design process" is especially important to + think about: while you don't have exercises, you do have goals to + accomplish you can design to. + +* Code Refinery lesson on [Sphinx and Markdown](https://coderefinery.github.io/documentation/sphinx/) diff --git a/_sources/templates/advertising-workshop.md.txt b/_sources/templates/advertising-workshop.md.txt new file mode 100644 index 00000000..fb5c5c00 --- /dev/null +++ b/_sources/templates/advertising-workshop.md.txt @@ -0,0 +1,14 @@ +# Advertising workshop + +Dear Professor X, + +My name is NAME and I work as a XXX in YYY. I'm contacting you now to spread the word about a workshop which I am co-organizing in LOCATION together with the CodeRefinery project (http://coderefinery.org/) organized under the NeIC organization. I found your contact information via ZZZ... + +CodeRefinery (http://coderefinery.org) aims to reach out to diverse academic communities which use and develop software in their research, and advocate more modern and efficient software development methods (such as collaborative distributed version control, automated testing, code documentation, managing code complexity, etc). CodeRefinery is not about efficient code, but rather efficient coding, and experience has shown that researchers have a lot to gain from our course material! + +A CodeRefinery workshop is planned for LOCATION in CITY on DATE, see the website here: URL + +The most natural audience for our workshops is PhD students and postdocs, but both more junior and senior people may find it valuable to attend. + +On behalf of the CodeRefinery team, +NAME diff --git a/_sources/templates/looking-for-helpers.md.txt b/_sources/templates/looking-for-helpers.md.txt new file mode 100644 index 00000000..ff08eee7 --- /dev/null +++ b/_sources/templates/looking-for-helpers.md.txt @@ -0,0 +1,33 @@ +# Looking for helpers + +This was part of a SNIC training newsletter. Saving it so that we can reuse +in future: + +``` +Engage as a tutor on the CodeRefinery online workshop, Nov 17-19 and 24-26, +9:00-12:00 + +Engage in the successful CodeRefinery workshop program, by becoming a tutor for +the exercise sessions and discussion groups. If you have been to a +CodeRefinery workshop, you will have experienced a very hands-on approach to +training with frequent exercise sessions and group discussions. In online +workshops these sessions take place in breakout rooms with 5-7 participants and +1-2 workshop tutors. Tutors answer questions from the learners, guide them +through the exercises and try to keep time. If needed, tutors can call on +experienced trainers in the background to help answer tricky questions. The +tutors are an important part of the CodeRefinery teaching concept and all the +workshops to scale to many more people than the instructors could otherwise +manage! + +If you have previously attended a CodeRefinery workshop, and/or use some of the +tools and methods covered in a workshop (Git, software testing, modern +documentation platforms etc.), then please consider joining a CodeRefinery +workshop as a tutor! Being a tutor is fun, it expands your network and develops +your teaching and mentoring skills. You always learn something new about a +subject by teaching it! + +If you would like to help on the upcoming workshop in November, please sign up +as a tutor on https://coderefinery.github.io/2020-11-17-online/. If you would +like to engage in later workshops, please register as a tutor on the notify-me +form (https://indico.neic.no/event/135/surveys/36). +``` diff --git a/_sources/templates/notify-me-announcement.md.txt b/_sources/templates/notify-me-announcement.md.txt new file mode 100644 index 00000000..70cecb9f --- /dev/null +++ b/_sources/templates/notify-me-announcement.md.txt @@ -0,0 +1,19 @@ +# Notify-me announcement + +Dear all, + +You are receiving this email because you have previously signed up for the "notify-me" list to get updates +on upcoming online or in-person CodeRefinery workshops. + +We now have the pleasure to announce that an [in-person/online] 3-day workshop will be held on LOCATION, on DATE. +Registration has just been opened, see the workshop webpage: +URL + +If you want to attend, don’t wait too long to register since the number of seats is limited. + +If you wish to unsubscribe from these announcements, please reply to this email. + +Hope to see you there! + +On behalf of the CodeRefinery team, +NAME diff --git a/_sources/templates/post-workshop-survey.md.txt b/_sources/templates/post-workshop-survey.md.txt new file mode 100644 index 00000000..4754ee7a --- /dev/null +++ b/_sources/templates/post-workshop-survey.md.txt @@ -0,0 +1,47 @@ +--- +orphan: true +--- + +# Post-workshop survey + +## First email + +``` +Subject: [CodeRefinery] 5-minute post-workshop survey + +Dear CodeRefinery alumnus, + +We hope that you enjoyed participating in a CodeRefinery workshop last semester and that it was +beneficial for your work and research! We don’t keep an attendance list, so apologies to those +of you who couldn't make it to the workshop... + +Please help us to improve our course material and teaching methods by answering our very brief questionnaire at +https://indico.neic.no/event/109/ +about whether and how the CodeRefinery workshop affected how you develop code. +All information you provide will be useful. Your participation is extremely valuable +and will help us to develop the project further. The average time to fill the form is around 5 minutes. + +Would you be interested in being a helper or instructor in future workshops? It's a great way to continue +developing your skills and expanding your network! We're always interested in recruiting new helpers +and instructors. If this sounds interesting to you, please get in touch by writing to +support@coderefinery.org or join our chat: https://coderefinery.zulipchat.com + +On behalf of the CodeRefinery team, +Thor +``` + +## Reminder 1 week after first email + +``` +Dear all, + +It's us, CodeRefinery, again. We just want to send this one reminder to kindly ask you to participate +in our 5-minute workshop-followup survey. To participate, please go to: +https://indico.neic.no/event/109/ + +Sorry for spamming (particularly to those of you who already participated), this is the last +you'll hear from us regarding the survey! + +Cheers, +Thor +``` diff --git a/_sources/templates/practical-info-to-online-participants.md.txt b/_sources/templates/practical-info-to-online-participants.md.txt new file mode 100644 index 00000000..507ec18e --- /dev/null +++ b/_sources/templates/practical-info-to-online-participants.md.txt @@ -0,0 +1,41 @@ +# Practical info (online) + +Dear all, + +The online CodeRefinery workshop TITLE is approaching! It will take place on DATE at START - END in Zoom room ZOOMID. +On the first day, we also have an optional session starting half an hour before START where you can connect, +test your video client and iron out any technical issues (we recommend attending this if you haven’t used Zoom before). + +If it turns out that you cannot attend, please let us know as soon as possible so that we can offer your seat to someone on the waiting list. + +We will be using a Zoom room with ID ZOOMID. We recommend that you install the Zoom client (https://zoom.us/download). +In order to join the room you will need the password ZOOMPASSWORD. +You will be encouraged (but not forced) to use a webcam during the workshop. +If you don't want the physical room you're in to be visible on the webcam, Zoom allows users to set up a virtual background: +https://support.zoom.us/hc/en-us/articles/210707503-Virtual-Background +You might also be asked to share your screen during group exercises or in interactions with a workshop helper. +Remember to keep private information away from the screen you share! + +You are expected to install some software on your computers before the workshop starts. +Please visit the workshop webpage WORKSHOPURL and go through each tool under "Software requirements", +and install whatever you're missing before the workshop starts. Note that you also need to create some accounts. +Note that each of these tools/accounts can easily be removed/deactivated after the workshop, if you so wish (see https://coderefinery.github.io/installation/accounts/). + +Don't hesitate to get in touch (support@coderefinery.org) if you run into any installation problems or have questions relating +to Zoom or other practical details. Note that we maintain a list of common installation issues that can occur at https://coderefinery.github.io/installation/troubleshooting/ + +If you haven't already filled the pre-workshop survey, please do that soon since it helps us with workshop preparation. +You can find it at: SURVEYURL. + +The workshop will be very focused on version control with Git. Some of you are already familiar with Git, but not all. +While we will be starting from the basics, we will be progressing quickly so it's useful if you spend a few minutes to read up on the basic idea of Git. +For this purpose, we have prepared this "refresher" material: https://coderefinery.github.io/git-refresher/ +Note that this material also contains important Git configuration steps which all of you should go through before the workshop starts, to save valuable time during the workshop. + +CodeRefinery strives to follow a Code of Conduct. Please have a look at +https://coderefinery.org/about/code-of-conduct/ so that we all are aware of how to treat each other respectfully. + +Don't hesitate to get in touch if you have any questions! + +Best, +MYNAME diff --git a/_sources/templates/practical-info-to-participants.md.txt b/_sources/templates/practical-info-to-participants.md.txt new file mode 100644 index 00000000..6f3243c9 --- /dev/null +++ b/_sources/templates/practical-info-to-participants.md.txt @@ -0,0 +1,43 @@ +# Practical info, in-person + +Dear all, + +The CodeRefinery CITY workshop on DATE is approaching! The location and schedule +is available on the workshop webpage: URL + +If it turns out that you cannot attend, please let us know as soon as possible +so that we can offer your seat to someone on the waiting list. + +You are expected to install some software on your laptops before the workshop +starts. Please visit the workshop webpage (URL) and go through each tool under +"Software requirements", and install whatever you're missing before the workshop +starts. Note that you also need a couple of accounts (GitHub and Read the Docs). +Note that each of these tools/accounts can easily be removed/deactivated after +the workshop, if you so wish (see https://coderefinery.github.io/installation/accounts/). + +Don't hesitate to get in touch (support@coderefinery.org) if you run into any +installation problems. We also maintain a list of common installation issues +that can occur at https://coderefinery.github.io/installation/troubleshooting/ + +If you haven't already filled the pre-workshop survey, please do that soon since +it helps us with workshop preparation. You can find it at: URL + +The workshop will have a strong focus on version control with Git. Some of you +are already somewhat familiar with Git, but not all. While we will be starting +from the basics, we will be progressing quickly so it's useful if you spend +10-20 minutes to read up on the basic idea of Git. For this purpose, we have +prepared this "refresher" material: +https://coderefinery.github.io/git-refresher/ + +Please have a look at this material before the workshop starts. Note that it +also contains important Git configuration steps which all of you should go +through before the workshop starts, to save valuable time during the workshop. + +CodeRefinery strives to follow a Code of Conduct. Please have a look at +https://coderefinery.org/about/code-of-conduct/ so that +we all are aware of how to treat each other respectfully. + +Don't hesitate to get in touch if you have any questions! + +Best, +Thor diff --git a/_sources/templates/waitin-list-notification.md.txt b/_sources/templates/waitin-list-notification.md.txt new file mode 100644 index 00000000..ac74604a --- /dev/null +++ b/_sources/templates/waitin-list-notification.md.txt @@ -0,0 +1,18 @@ +# Waiting list + +Dear NNN, + +thank you for request about the course: + +https://coderefinery.org/workshops/COURSE_HERE/ +The workshop is currently full but you are placed on the waiting list and I will inform you in case somebody else cancels and a seat frees up. + +In case this is too uncertain for you and you make other plans, please let me know. + +If you want to make sure to get a seat on the next workshop near you, please register on the "notify-me" list: https://coderefinery.org/workshops/upcoming/ + +We would love to give more courses and hope it works out for you. + + +Thank you in advance and best wishes, +CCCC diff --git a/_sources/the-project.md.txt b/_sources/the-project.md.txt new file mode 100644 index 00000000..22d41882 --- /dev/null +++ b/_sources/the-project.md.txt @@ -0,0 +1,87 @@ +# About CodeRefinery + +## History + +CodeRefinery began as a Nordic e-Infrastructure Collaboration (NeIC) +based off of some previous workshops at the KTH, Stockholm. The first +round of funding was from 2016 - 2018, and a second round is going from +2018-2021. Thus, so far, it has always had some paid staff (each up +to 0.5 full-time equivalent of their primary jobs). Most of these +staff are from some sort of computing center. + +Over time, it has evolved into a more open project direction. + + +## Governance + +There is a steering group within NeIC which governs the CodeRefinery +project. However, strictly speaking that mainly covers activities done +via NeIC funding. The materials and open-source project is open to all. + +There are currently no formal decision making processes. Typically, +decisions related to some repository go through the process of... + +* Submit an issue or pull request +* Discuss in the issue and/or +* Discuss in a CodeRefinery team meeting +* If there is rough consensus, then commit it. + +In general, most decisions (of the open project) result in some sort +of commit in git. If the reaction is positive in a CodeRefinery +meeting, then it's accepted. (Most day-to-day things aren't discussed +in the meetings, only major things affecting the whole project.) +In general, if you are open and discuss, then do what will improve the +project for you. + + +## Communication methods + +This is an exhaustive list of our communication methods + +- {doc}`CodeRefinery zulipchat ` +- CodeRefinery team meetings (announced in zulipchat) +- Team email list (in practice, only used for calendar invites) +- Github repositories issues and pull requests + +### Chat + +{doc}`Zulipchat ` is our primary means of communication. Subscribe to +at least the #coderefinery, #lessons, and #workshops, #general, #announce, and +#help channels to fully integrate to the CodeRefinery side of things. + +### Team meetings + +These tend to happen every ~2 weeks. Mainly, we discuss NeIC project, +workshop organization matters, and how to organize ourselves. Most +work on actual lessons happens in Github issues. + +You can find upcoming meetings by TODO. + +### Github + +We are focused around the material we make, and for that, most +discussion happens in Github issues. For more abstract discussion on +lessons, there is a topic in the #lessons chat corresponding to each +lesson. + +## Decisions + +There is no formal process of decisions. It should be brought up in +chat, then brought up in a meeting. In the meeting, be very clear +about what you need a decision or advice on. + +## Core team + +There is currently no formal "core team" - only those who are most +active. If you hang around, contribute a lot, you will end up being +seen as "core". + +## Joining + +There is currently no formal joining process. Take part, and +contribute as you would like. + +The usual way of joining would be to decide how CodeRefinery has to +adapt to serve your needs, and start proposing ways to do that. +Reading existing pull requests and giving a comment of "approve" is a +great way to get noticed. diff --git a/_sources/video-checking.rst.txt b/_sources/video-checking.rst.txt new file mode 100644 index 00000000..442f5add --- /dev/null +++ b/_sources/video-checking.rst.txt @@ -0,0 +1,105 @@ +Video checking OLD +================== + +.. note:: + + This is old information, these days we use `ffmpeg-editlist + `__ and ensure + that no learners are in the videos in the first place. + + +.. seealso:: + + :doc:`video-editing` tells how to edit yourself. This page + describes how to check a video for processing. + + +The purpose of this page is to give video processing volunteers a +starting point. CodeRefinery produces a lot of videos, and *learner +privacy is important*: we can't post videos until they are checked. +These videos are mainly useful to the learners of the very workshop, +so we need them quickly (and for every workshop). + +Overview +-------- + +* Ask for the directory of videos. It is on Google Drive or something + similar, but is not public. +* Look at the tracking issue. Find a unclaimed section of the course. +* Watch the video. + + * *Carefully* look for any appearances of learner video within the + video. + +* Copy the template below. +* Fill out the template. +* Paste the answers into an issue. + + + +Segment report +-------------- + +Template:: + + * [ ] Title: + * Filename: + * Start: + * End: + * Segments to cut: + * Audience visible: + Other notes for channel description: + +Example:: + + * Title: git-intro basics + * Filename: day1-obs + * Start: 25:13 + * End: 45:00 + * Segments to cut: 36:12 - 42:10 + * Audience visible: none + + Other notes for channel description: + + In this first episode, we go over the basics of using git for a single + local directory. + https://coderefinery.github.io/git-intro/02-basics/ + + +Why do we ask all this? It saves time for the person who has to +upload it to YouTube. + +* **Title**: what would it be called? You don't need to include the + workshop name, someone will add it. +* **Filename**: you don't need the full filename but indicate what + file you were searching (often we have a recording and backup + recording for each day) +* **Start**, **end**: start time of the segment + +* **Segments to cut**: Segments which should be cut out. Don't be + strict, it is better to get it out fast than cut out every 3-minute + break. But if there is a ~10 minute break or idle time, then we can + cut it. + +* **Audience visible**: Time periods where any audience (not including + staff). + +* **Other notes for channel description**: Describe the content of the + video, include any links. You can think what is useful for someone + to find this (but it doesn't have to be perfect). + + + +Other comments +-------------- + +* How small should segments be? First, it's better for videos to exist + than be perfect, so the 3-hour segment is better than nothing. Short + lessons (1.5 hour) are probably fine to be at once, and long ones (git + intro/collab) could possibly be each episode separately. Discuss with + others to see what you would like. + +* Ideally, there are two videos from each day: one recorded by Twitch + (raw dump of the stream), and one recorded by OBS/Zoom (local + recording). The OBS/Zoom recording is preferable. You can tell + them apart via the filenames. diff --git a/_sources/video-editing.rst.txt b/_sources/video-editing.rst.txt new file mode 100644 index 00000000..c9b69216 --- /dev/null +++ b/_sources/video-editing.rst.txt @@ -0,0 +1,208 @@ +Video editing OLD +================= + +.. note:: + + This is old information, these days we use `ffmpeg-editlist + `__ and ensure + that no learners are in the videos in the first place. + + +.. seealso:: + + :doc:`video-checking` for how to check a video and give an + edit-list to someone else to do the editing. + + +The purpose of this page is to give video processing volunteers a +starting point. (It also has some hints for workshop organizers). + +For some of our online lessons, we release videos on YouTube. This is +not necessarily for brand new people to watch and learn the material +(though they may), but especially for people who attended the workshop +to review what they saw. As such, it's more important to get them +published fast, than make them perfect. + + +What we want +------------ + +Our workshops consist of lectures, demo, and exercises in breakout +rooms. We record the main Zoom room, and also livestream the main +room via Twitch. We would like the video of the workshop to be +processed so that it can be released on YouTube. This should not be a +major production: it is more useful to those who want to review what +they saw in person, rather than a new person watching. + +We will provide the following: + +* Raw video files (probably two copies one recorded from Zoom and one + from Twitch - so there is a backup.) +* List of lessons (= final videos) and which raw files contain them + and when. +* List of instructors + +We want out: + +* One processed video file per lesson. +* With irrelevant breaks removed. +* Without any video from learners. We use Zoom so that learners + should not appear in the stream, but we can't be sure it works so + this needs to be checked. + +The rough process is: + +* Load up the right video files in the editor. +* Find the start of the lesson (hint: look for a change of + instructor - ask us if you need help!) and cut off the stuff before. +* Watch through the videos. Most of the lecture parts are fairly + standard and can be fast-forwarded through (it's rare for a + learner's picture to appear here). +* Cut out the idle time during breaks. +* In exercise sessions, learners go to breakout rooms, which are not + recorded. This part can be cut out, *but* sometimes the instructor + stays in the main room to do the exercises for the stream. + +* Don't be too precise. We aren't trying to make a masterpiece to end + all masterpieces, but a something for those who were at the workshop + to refer back to. So: + + * Imprecise start/stop/break times are fine + * Other random off-topic chat is fine + * Voices of learners is fine and expected + * **Video** of learners is **not ok** (really, this is the only + thing that needs care). + + + + +Before/during/immediately after the workshop +-------------------------------------------- + +- From day 1, advertise that "the workshop may be recorded and put on + YouTube. We will prevent any pictures and names from going there, + but your voice may be. Please don't include your name in hackmd + unless you accept it may be published. We support your right to be + anonymous in this workshop." + +- Same announcement at the start of the workshop. + +- Record in zoom. Note: when you start the recording, make sure that + someone is currently sharing the screen, *and* the screen is a good + size (e.g. normal Full HD, as opposed to some vertical shape). The + dimensions when the sharing first starts determines the dimensions + for the entire course. + +- Immediately after workshop, go to Twitch and download the raw + streamed version. You have to be logged in as the channel, then the + option is naturally provided to you. + +- Choose some standard, shared place and immediately upload videos + there. Recommended naming scheme:: + + day1-topic1-topic2-zoom.mp4 + day1-topic1-topic2-twitch.mp4 + + +Processing +---------- + +Processing principles: + +* **Remove any participant videos, if they accidentally make it into + the video file**. This is really the only serious rule in the + processing, if we didn't have to check this we could just upload the + raw ones and it would be good enough. +* Create one final video per lesson in the workshop +* Work incrementally, upload processed ones when you can, get quick + feedback. + +If it's not clear, the course organizers will provide a list of the +lessons (final outputs) and the respective inputs (which source files +go into it). + + +You can generally: + +* Use some video editor + + * iMovie on Mac + * OpenShot is a simple cross-platform editor (`tutorial + `__) + * (please give more ideas here) + +* (so far, this is not a general "how to edit video" guide... you will + need to find one for your editing program) + +* Create a new project for the output (e.g. the Jupyter lesson) + +* Import the raw video files which contain Jupyter (e.g. day 4). If + one lesson is split over multiple files, combine them. + +* Cut off the part before and after the lesson itself (saving + frequently). You'll have to figure out the start and end times, + this may be hard when there are several files. + +* Begin watching the lesson. Look for the following things: + + - Break time? Exercise session with irrelevant stuff in the video? + Cut the time out. + + - **Any non-instructors pictures in the stream?** Cut it out. + Sometimes you might need to blank the picture while + + - Don't be too perfectionist - the goal is to get something done, + not maek the perfect videos. + +* Export the videos with a high quality, e.g. ``jupyter.mp4``. It + will go to YouTube which will render lower resolutions, so you don't + need to worry about this so much. + +* Upload the videos to the ``processed`` subdirectory of the google + drive. Do this immediately, video by video. It's better to get + continuous feedback on this. You are done! + + +Publication +----------- + +We upload them to YouTube (not that we agree with all the ethics of +YouTube, but it seems like the least bad and most useful of the +options). + +* Preview the processed videos, do a quick check for any issues. + +* Upload to the channel. For one workshop, put all related videos + into a playlist. CC-BY license. + +* This is a prototype channel description you can copy:: + + git-intro 1/2, CodeRefinery 25.may-4.jun 2020 day 1 + + Day 1: git-intro: LINK-TO-LESSON + + Part of a series of video recordings of the CodeRefinery workshop, + 25.may-4.june. CodeRefinery teaches intermediate software + development skills to researchers in the Nordics. + + Workshop page: LINK-TO-WORKSHOP + Q&A for day 1: LINK-TO-HACKMD + + (table of contents below) + + +* Create a **table of contents** (can be done later, after uploading). + This divides the videos into chapters, with clickable links in the + description and labels in the video's time slider. In the bottom of + the description, put this text and it is automatically parsed:: + + 00:15 Introduction + 02:30 Motivation - https://coderefinery.github.io/git-intro/01-motivation/ + 17:17 Basics - https://coderefinery.github.io/git-intro/02-basics/ + 38:29 Staging - https://coderefinery.github.io/git-intro/04-staging-area/ + ... + + You may want to ask someone for help with this, since it can take + some time to go through the videos. + + Example with table of contents: https://youtu.be/r1tF2x5OLNA diff --git a/_sources/video-editor.rst.txt b/_sources/video-editor.rst.txt new file mode 100644 index 00000000..54af890a --- /dev/null +++ b/_sources/video-editor.rst.txt @@ -0,0 +1,52 @@ +Video editor +============ + +The video editor takes the raw recorded files from the broadcaster, +processes them, and uploads them to YouTube (or whatever). + + + +Overall priorities +------------------ + +1. No learner (or anyone not staff) video, audio, names, etc. are + present in the recordings. + +2. Good descriptions. + +3. Removing breaks and other dead time. + +4. Splitting videos into useful chunks (e.g. per-episode), perhaps + equal with the next one: + +5. Good Table of Contents information so learners can jump to the + right spots (this also helps with "good description".) + + +Modern: livestream method +------------------------- + +Modern livestream courses produce videos without any learners in +them. In this case, using +https://github.com/coderefinery/ffmpeg-editlist is sufficient. Look +at that repo for instructions. As an example, check out +https://github.com/AaltoSciComp/video-editlists-asc for some past +workshops. For example, ``kickstart-2022-winter.yaml`` is a +reasonable starting point to copy. + +It's our standard to have these videos on YouTube by the same evening +the course is held. It may be hard, but it's better to reduce the +quality to make it happen quickly than wait a while to get it perfect +(otherwise it might not happen at all). + + + +If the learner Zoom is recorded +------------------------------- + +If learners may be in the recordings, they need detailed checking +before they can be posted. See :doc:`video-checking` for the +preparation work and :doc:`video-editing` for the processing work. + +In practice, if things are recorded this way, they are almost never +released because it is too much work and it never gets done. diff --git a/_sources/workshop-administration.md.txt b/_sources/workshop-administration.md.txt new file mode 100644 index 00000000..3f03a5dc --- /dev/null +++ b/_sources/workshop-administration.md.txt @@ -0,0 +1,225 @@ + +# Organizing a CodeRefinery workshop + +Anyone can organize a CodeRefinery workshop and teach the CodeRefinery lessons which are +licensed under [CC-BY](https://creativecommons.org/licenses/by/4.0/). +However, making it a successful workshop requires careful planning and preparation. Here we will go +through practical aspects of organizing a workshop. + +## Email templates + +A collection of email templates: + +```{toctree} +:maxdepth: 1 +:glob: true + +templates/* +``` + +When adding new ones, add to an existing page (make a new section) +or. Try to avoid too much markdown formatting, so that a rendered +version can be copied to plain text email easily still. + +## Select a workshop coordinator + +One or two persons coordinate the workshop preparation and debrief. This does +not mean that they do all the work - they are encouraged to delegate tasks - +but they make sure that nothing gets forgotten. + + +## Other documents and references + +- Workshop organization overview: +- Instructions on how to set up a registration page in Indico (for NeIC affiliated staff): + {doc}`/indico/index` +- Email templates for workshop communication: + - [1-2 weeks before workshop starts](templates/practical-info-to-participants) + - [advertising workshop via private communication](templates/advertising-workshop) + - [looking for helpers](templates/looking-for-helpers) + +## Before the workshop + +### First steps + +- Recruit instructors - having at least 3 instructors is highly recommended. +- Find 1-2 workshop helpers [with an appropriate background](workshop-requirements-inperson.md). +- Reserve dates (coordinate this with the instructors) +- Reserve room +- Select a workshop coordinator +- Workshop coordinator creates a ticket with a checklist on and takes it (self-assigns) + +### Lecture room + +- Start looking for an appropriate lecture room early. +- See this [list of requirements](workshop-requirements-inperson.md) for + the lecture room. + +### Set up workshop page + +- Import the template at to your username + or the coderefinery organization, and name it like "2019-10-16-somecity". +- Update the required fields in `index.md` and push the commits. + The page should now be served at *username.github.io/2019-10-16-somecity/*. +- If the workshop will be customized to the needs of a particular audience, modify the schedule accordingly. +- If the workshop should be listed on : + - (Fork and) clone + - Under `coderefinery.org/_workshops/`, add a file named like `2019-10-16-somecity.md` which contains + the fields permalink, city and dates. For example: + ``` + --- + permalink: https://username.github.io/2019-10-16-city/ + city: Somecity + dates: October 16-18, 2019 + --- + ``` + - send a pull request with your new file. +- Create a registration form following {doc}`/indico/setup`. +- Open and test registration + +### Announcing the workshop + +- Twitter +- Email persons who registered to notify-me form +- Use local mailing lists and all channels possible + +For self-organized workshops: +- Write an email to support@coderefinery.org to get a pre-workshop survey link and registration form on + [https://indico.neic.no](https://indico.neic.no) + + +### Distribute the work + +- Make sure lessons are distributed + +### Preparing lessons + +- Go through the lesson material you will be teaching and think about how you + intend to teach it, and how much time you will be spending on each episode. +- Are there any unsolved issues that you can fix? +- Go through the instructor guides of the lessons you will be teaching. + - Review the intended learning outcomes, and try to keep these in mind while teaching. + - Try to memorize the typical pitfalls and common questions. +- Go through the [lesson presentation hints](https://github.com/coderefinery/manuals/blob/master/presenting.md). +- Go through the [helping and teaching guide](https://github.com/coderefinery/manuals/blob/master/helping-and-teaching.md), + and request all helpers to go through it too. + +### Prepare practicals + +- Order catering (coffee, tea, water, fruit, something sweet, etc.) +- Organize sticky notes +- Organize extension cables if needed +- Organize alternative wireless for those without Eduroam (if any) + +### Communication with participants + +- Send out practical information, including installation instructions, around 2 weeks ahead. + [Here is a template](templates/practical-info-to-participants). +- Emphasize that all software should be installed before the workshop starts, and point out + the [configuration problems and solutions](https://coderefinery.github.io/installation/troubleshooting/). +- Remind registered participants that they are either expected to show up or to cancel participation +- Also ask those without Eduroam to speak up. +- Maintain waiting list if needed +- Make sure we have enough pre-survey answers +- Close registration on the workshop page + +### 1-2 weeks before the workshop + +- Workshop coordinator organizes a call with all instructors and helpers to discuss the schedule to leave no doubts about timing. Also + discuss the survey results. +- Point helpers (and instructors) to the [tips for helpers](team-leaders.md). + +### Right before the workshop starts + +- Prepare a shared Google doc or with global write permissions, + consider creating a memorable short-link (e.g. bit.ly) + + +## Create exercise repositories + +- The collaborative Git lesson requires exercise repositories to + be set up. For this follow the instructor guide in the lesson material. + + +## Workshop preparation checklist + +- This checklist can be set up as an issue under + or on another + repository to keep track of the progress + ``` + - [ ] reserve dates + - [ ] decide workshop organizer + - [ ] (online) prepare Zoom link or (in-person) book lecture room + - [ ] announce (twitter, notify-me, mailing lists) + - [ ] team of instructors complete + - [ ] workshop website up + - [ ] lessons distributed + - [ ] prepare lessons + - [ ] create exercise repositories + - [ ] (in-person) prepare practicals (coffee/tea, sticky notes, extension cacles) + - [ ] (online) Zoom roles distributed + - [ ] registration open + - [ ] team of helpers complete + - [ ] registration closed + - [ ] enough pre-survey answers + - [ ] install instructions sent + - [ ] pre-workshop briefing held, helper training + - [ ] survey results shared with co-instructors/helpers + ``` + +## As participants arrive + +- Emphasize to participants that you need to sit with someone - don't work alone. +- Try to have participants sit next to someone with a similar operating + system if they have no preference, since they will face similar + problems. + + +## Introduction talk + +- See +- Have a 10 minute ice-breaker session where participants and instructors introduce themselves + and either describe their research in 2-3 sentences or what they hope to get out of the workshop. + + +## During workshop + +- While teaching, keep [these tips](https://github.com/coderefinery/manuals/blob/master/workshop-administration.md#during-workshop) in mind +- Don't start off with tech details, say why this is important. +- Try to [stick to the material](https://github.com/coderefinery/manuals/blob/master/presenting.md#try-to-stick-to-the-material), + although some excursions are useful. +- Keep up interactive feel by encouraging and asking questions +- Keep time +- For presentations which have shell commands, create a + cheatsheet/reference on the board in real time. +- Remind participants about sticky notes. +- Make sure we take regular breaks (at least a short break each hour) +- Give participants some time to also experiment (do not rush the classroom through exercises) +- Encourage optional feedback at the end of each day or end of each lesson + on sticky notes. Process the feedback immediately and adjust your teaching + (pace etc) accordingly +- Create GitHub issues for points which are confusing or problematic +- Take active part even in the lessons you're not teaching, e.g. by asking + questions and (politely) interject with clarifications when you think + something is confusing to the learners +- [Wrap up](https://github.com/coderefinery/manuals/blob/master/presenting.md#wrap-up), + say what you taught and why, and what comes next. + + +## At the end of workshop + +- Give credit to those who contributed and helped +- Use + + +## Post-workshop + +- Process and distribute feedback to co-instructors and others (e.g. type up in shared document) +- Debrief with instructors +- Process certificate requests + +## [Post-workshop survey](https://github.com/coderefinery/post-workshop-survey) + +To measure the long-term impact of CodeRefinery workshops it's useful to send out a +post-workshop survey. This survey can identify which topics taught in workshops are +particularly useful and which have less benefits for the participants. diff --git a/_sources/workshop-marketing.md.txt b/_sources/workshop-marketing.md.txt new file mode 100644 index 00000000..fb360b2d --- /dev/null +++ b/_sources/workshop-marketing.md.txt @@ -0,0 +1,15 @@ +# Workshop marketing + +The workshop marketing and outreach coordinator makes sure (by delegation) that the workshops are advertised in all known channels. +They also coordinate mass communications with all entities of the workshop. + +Some thoughts on target groups that should be tried to be reached: + +- Learners (many sub-categories with different time vs need trade-offs: students, junior researchers, senior researchers, lifelong learning) (join a workshop) +- team leaders (bring your friends, join to learn more and lead groups) +- Research leaders (people who can tell their students they need to attend CR) +- University staff (Computing, open sci, etc.) (people who can serve as local organizers and serve as local helpers) +- Potential instructors (teach, etc.) +- High-level management (provide us funding) + +You can find a list of commonly advertised places in the bottom of the {doc}`workshop-playbook`. \ No newline at end of file diff --git a/_sources/workshop-organizers.md.txt b/_sources/workshop-organizers.md.txt new file mode 100644 index 00000000..14e3ebb9 --- /dev/null +++ b/_sources/workshop-organizers.md.txt @@ -0,0 +1,16 @@ +# Workshop organizers + +Everyone can be part of the workshop organizing team. But we are mostly looking for help from the community for team leads, expert helpers and instructors. +If you want to help 'in the background', join the ´#workshops´ stream in the [coderefinery Zulip chat](https://coderefinery.zulipchat.com) and see what is planned. +There is a lot of roles to fill already before the actual workshop, as well as after: + +```{toctree} +:maxdepth: 1 + +Workshop basic requirements checklist (in person) +Workshop administration (reference) +indico/index +Icebreaker question ideas +video-checking +video-editing +``` diff --git a/_sources/workshop-playbook.md.txt b/_sources/workshop-playbook.md.txt new file mode 100644 index 00000000..3aa8812c --- /dev/null +++ b/_sources/workshop-playbook.md.txt @@ -0,0 +1,304 @@ +# Workshop checklist template + +This page is a checklist that we use when planning a CodeRefinery workshop +with 300 or more participants but may be useful in organizing other workshops as well. + +Let's keep this brief and copy-paste-able to HackMD/HedgeDoc for the actual planning. + +--- +# CodeRefinery workshop YYYY-MM-DD + +[toc] + +## Links + +``` +- [Workshop page]() +- This document: copy-paste link here from the Share-menu +- [Q&A document]() +- [Archive Q&A document]() +- [Twitch channel](https://www.twitch.tv/coderefinery/about) +- [Emails and communication]() +- [Zoom for onboarding and install help]() +``` + +:::danger +Add missing links! :arrow_up: +::: + + +## Workshop roles + +- Overview of the roles: https://coderefinery.github.io/manuals/roles-overview/ + +If you want to take part, add your name here, sign up in Indico and select "I +am interest in being a helper, co-instructor, or observer", and you will be +contacted. + + +### Instructors +([Description](https://coderefinery.github.io/manuals/instructors/)) + +Two names per lesson, first is primary + +- [ ] day 1 - git-intro: ???, ??? +- [ ] day 2 - git-intro: ???, ??? +- [ ] day 3 - git-collabiorative: ???, ??? +- [ ] day 4 - reproducible research: ???, ??? +- [ ] day 4 - social coding: ???, ??? +- [ ] day 5 - jupyter: ???, ??? +- [ ] day 5 - documentation: ???, ??? +- [ ] day 6 - testing: ???, ??? +- [ ] day 6 - modular code development: ???, ??? + + +### Expert helpers +([description](https://coderefinery.github.io/manuals/expert-helpers/)) + +If a central Zoom exercise room is provided: Help in our learner zoom, circle +around breakout rooms; there will probably be 2 or 3 rooms where we need to +provide the helper. Else: Help answering questions in Collaborative Q&A +document. + +- [ ] day 1 - git-intro: ???, ???, ... +- [ ] day 2 - git-intro: ???, ???, ... +- [ ] day 3 - git-collab: ???, ???, ... +- [ ] day 4 - reproducible research: ???, ???, ... +- [ ] day 4 - social coding: ???, ???, ... +- [ ] day 5 - jupyter: ???, ???, ... +- [ ] day 5 - documentation: ???, ???, ... +- [ ] day 6 - testing: ???, ???, ... +- [ ] day 6 - modular code development: ???, ???, ... + + +### Managing collaborative document +([description](https://coderefinery.github.io/manuals/hackmd-helper/#hackmd-manager)) + +Keep the document organized, check for unanswered questions, and archive notes each day. + +- [ ] preparation before workshop: +- [ ] day 1 - git-intro: ???, ???, ... +- [ ] day 2 - git-intro: ???, ???, ... +- [ ] day 3 - git-collab: ???, ???, ... +- [ ] day 4 - reproducible research: ???, ???, ... +- [ ] day 4 - social coding: ???, ???, ... +- [ ] day 5 - jupyter: ???, ???, ... +- [ ] day 5 - documentation: ???, ???, ... +- [ ] day 6 - testing: ???, ???, ... +- [ ] day 6 - modular code development: ???, ???, ... + + +## Workshop organization; roles "behind the scenes" + +Organiser roles and their responsibilities. This does not mean that a person will do +everything that is part of their responsibility, but they will make sure that +their responsibilities are followed-up and not forgotten. + + +### Event director +([description](https://coderefinery.github.io/manuals/director/)) + +- lead: +- backup: + +:::spoiler Checklist +- Before workshop + - [ ] Create planning document by copying this template + - [ ] Distribute roles using this document + - [ ] Ask collaborators/stakeholders to pick roles + - [ ] Add all sessions to [CodeRefinery calendar](https://github.com/coderefinery/calendar) separately + - [ ] Send calendar invite to all organizers, instructors, expert helpers, with all relevant links + - [ ] Decide if certificates will be possible and what is needed for getting a certificate/credits (ask from partner universities) + - [ ] Remind co-organizers to register + - [ ] Send summary email to all co-organizers will all important links in one place +- After the workshop: + - [ ] Summarize lessons learned and make it a blog post in [coderefinery.org repo](https://github.com/coderefinery/coderefinery.org) + - [ ] Coordinate post-workshop survey eg. in Indico + - [ ] Merge new edits from here (no names ofc) to the [Playbook](https://github.com/coderefinery/manuals/blob/master/workshop-playbook.md) + - [ ] Port changes from workshop page to [template page](https://github.com/coderefinery/template-workshop-webpage) + - [ ] On CR website move from ["upcoming"](https://github.com/coderefinery/coderefinery.org/blob/main/content/workshops/upcoming.md) to ["past"](https://github.com/coderefinery/coderefinery.org/blob/main/content/workshops/past.md) +::: + + +### Registration coordinator +([description](https://coderefinery.github.io/manuals/registration-coordinator)) + +- lead: +- backup: + +:::spoiler Checklist +- **ca. 2 months before = When workshop details are set:** + - [ ] Create [Indico registration page](https://indico.neic.no/category/5/) for the event + - [ ] Include event information + - [ ] Customise the registration form + - [ ] Customise the confirmation email (with outreach and marketing coordinator) + - [ ] Add Zoom link if any + - [ ] Point to workshop page + - [ ] Add collaborative document link if any + - [ ] Set up a workshop page from [template page](https://github.com/coderefinery/template-workshop-webpage) + - [ ] Add workshop to ["upcoming courses"](https://github.com/coderefinery/coderefinery.org/blob/main/content/workshops/upcoming.md) + - Remember to add all the emails to workshop page + - [ ] Open the registration +- **Every day:** + - Check [support email (Freshdesk)](https://coderefinery.zulipchat.com/#narrow/stream/215460-coderefinery/topic/freshdesk.20procedures) for requests/questions +- **Every week:** + - Check registrations for problems and read notes to organizers + - Identify if need to do something – basically, "playing" with the registration data to not forget anybody and not to forget follow-up + - Update [stats](https://github.com/coderefinery/workshop-stats) + - Update workshop-webpage if new local organisations +- **ca. 1 month before:** + - [ ] Reach out to participants ([examples from Mar 2023](https://github.com/coderefinery/2023-03-21-workshop/tree/main/content/communication)) + - [ ] [Team leaders](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/email-to-team-leads.md) + - [ ] [Those who indicated interest in co-organizing and co-teaching](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/email-to-co-org-helpers.md) + - [ ] [Communicate about self organising teams](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/exercise-teams-2023-03-09.md) +- **Two weeks before** + - [ ] [Send general information to all](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/practical-info-2023-03-09.md) + - Next steps, onboarding, installation + - Those who have a team, please organize your own zoom/video + - [ ] [Inform those who want in-person about known LOs](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/local-groups-2023-03-09.md) + - [ ] Try to match up learners and helpers who want to be part of a team +- **ca. 1 week before** + - [ ] Update Ondico auto-reply for last minute registrations + - [ ] Send [email with all links](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/links-2023-03-15.md) +- **1 day before!** + - [ ] Send a [reminder with links](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/links-2023-03-20.md) +- **During the workshop** + - [ ] Send [daily summaries](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/summary-day1.md) (with exercise coordinator) + - [Some of them have also preparation instructions!](https://github.com/coderefinery/2023-03-21-workshop/blob/main/content/communication/summary-day2%2Bprep-day3.md) +- **After the workshop:** + - [ ] Add viewing statistics to [CodeRefinery webpage](https://github.com/coderefinery/coderefinery.org/tree/main/content/about/statistics) + - [ ] Use [statistics repo](https://github.com/coderefinery/workshop-stats) (feel free to edit) + - [ ] Close registration +::: + + +#### Broadcaster +([description](https://coderefinery.github.io/manuals/broadcaster/)) + +- lead: +- backup: + +:::spoiler Checklist +- [ ] Prepare ice-breakers for each day +- [ ] Create instructor Zoom and communicate it (with exercise coordinator and outreach and marketing coordinator) +- [ ] Publish recordings (does not do all the work but coordinates it) + - [ ] Prepare for upload (use [ffmpeg-editlist](https://github.com/coderefinery/ffmpeg-editlist) and collaborate) + - [ ] Upload videos and communicate (with outreach and marketing coordinator) +::: + + +### Instructor coordinator +([description](https://coderefinery.github.io/manuals/instructors/)) + +- lead: +- backup: + +:::spoiler Checklist +- [ ] Confirm that each lesson and session has co-instructors +- [ ] Schedule calls with each instructor pair to distill most important questions and tasks to them + - [ ] Show where the detailed schedule is and recommend to move it to instructor guide + - [ ] Discuss that the detailed schedule can and should be improved + - [ ] Show where Q&A and feedback from past workshop can be found + - [ ] Discuss plans for exercises: try 3 exercises each half-day, each not shorter than 20 mins + - [ ] Ask them to check their lesson's exercise list + - [ ] Ask for any software requirements changes + - [ ] Inform about audience (at the time of writing half of registrants prefer to follow on their own) - adapt exercise expectations to audience + - [ ] Check/test for high-quality screen share + - [ ] Discuss how we can give learners get a good experience +- [ ] Test software install instructions +- [ ] List instructors on the website (with exercise coordinator) +- [ ] Organize team leader on-boarding sessions (with exercise coordinator) +- [ ] After the workshop copy detailed schedule to the individual lesson repos as issues +::: + + +### Exercise and team leader coordinator +([description](https://coderefinery.github.io/manuals/exercise-coordinator/)) + +- lead: +- backup: + +:::spoiler Checklist +- **Before the workshop** + - [ ] Make sure exercise list is communicated (with outreach and marketing coordinator) + - [ ] List all team leads (who consent to being listed) on the website (with instructor coordinator) + - [ ] List expert helpers on the website (with instructor coordinator) + - [ ] Organize staff & helpers on-boarding sessions (with instructor coordinator) + - [ ] Send team leader onboarding summary email + save it to the website (with outreach and marketing coordinator) +- **After the workshop** + - [ ] Organize a de-briefing call with team leads to learn about their experiences and suggestions + - [ ] Help other roles in putting everybody who contributed and consents on the [website as credit](https://github.com/coderefinery/coderefinery.org/blob/main/content/about/contributors.md) + - [ ] After the workshop remove the [exercise repositories](https://coderefinery.github.io/git-collaborative/guide/#preparing-exercises) + - [ ] Help event director with post-workshop survey +::: + + +### Outreach and marketing coordinator +([description](https://coderefinery.github.io/manuals/workshop-marketing/)) + +- lead: +- backup: + +:::spoiler Checklist +- [ ] Create/update [advertising texts](https://github.com/coderefinery/template-workshop-webpage/tree/main/content/communication) and relevant news on the workshop page +- [ ] Newsletter + - https://tinyletter.com/coderefinery/archive + - draft: https://hackmd.io/@coderefinery/CRnewsletter_1_2023 +- [ ] Advertising texts on the workshop page + - https://coderefinery.github.io/2023-03-21-workshop/communication/ + - https://github.com/coderefinery/2023-03-21-workshop/tree/main/content/communication +- [ ] CodeRefinery Twitter + - https://coderefinery.zulipchat.com/#narrow/stream/119815-general/topic/tweet-toot-suggestions +- [ ] CodeRefinery Mastodon + - https://coderefinery.zulipchat.com/#narrow/stream/119815-general/topic/tweet-toot-suggestions +- [ ] CodeRefinery LinkedIn + - https://www.linkedin.com/events/coderefineryworkshopmarch21-23a7031623728480272384/comments/ +- [ ] CHCAA LinkedIn (Aarhus University) +- [ ] Partner Twitter, retweet and own tweets + - [ ] Aalto Scientific Computing +- [ ] Partner newsletters + - [ ] Sigma2 + - [ ] SNIC/NAISS + - [ ] ENCCS + - [ ] CSC +- [ ] Partner websites training calendars + - [ ] CSC + - [ ] ENCCS + - [ ] UiB + - [ ] AU (Aarhus University) +- [ ] Partner and other email lists + - [ ] Aalto STEM students + - [ ] Aalto triton users + - [ ] Delta doctoral network + - [ ] UiB researcher + - [ ] UiB HPC + - [ ] NERSC Bergen + - [ ] Bjerknes Bergen + - [ ] University of Oslo computational biology + - [ ] University of Oslo Phd and Postdocs + - [ ] University of Oslo Dcince contact (?) + - [ ] Research institutes in all countries +- [ ] Partner posters + - [ ] Aalto (CS,U,NBE,PHYS,VAARE) +::: + + +### Certificate coordinator + + +- lead: +- backup: ASC team (the process can be run by anyone and we are now using a ticketing system to track requests) + +:::spoiler Checklist +- [ ] Make sure that instructions on certificates are disseminated multiple times + - [ ] Workshop page, emails + ``` + - Learner sends materials to scip _at_ aalto.fi. This opens a ticket in Aalto "esupport" system + - The person who generates the certificate verifies quickly that the tasks were completed. + - We then work with https://github.com/coderefinery/generate-certificates to generate PDF certificates + - Certificate is sent to the person and ticket is closed + - Aalto specific: + - The local version of that repository is at /scratch/rse/generate-certificates/. The commands were slightly modified so that the default working directory is not the home folder + - Aalto students can also obtain directly the 1 ECTS credit. See internal process at ASC pages. + ``` +::: diff --git a/_sources/workshop-prep-call.md.txt b/_sources/workshop-prep-call.md.txt new file mode 100644 index 00000000..980af7c2 --- /dev/null +++ b/_sources/workshop-prep-call.md.txt @@ -0,0 +1,46 @@ +# Workshop preparation meeting + +Each workshop should have a preparation call among instructors, +experts, hosts, etc. This is separate from the {doc}`helper training +call `. + + + +## Topics of workshop instructor meeting + +- Introduction round +- Go over {doc}`instructor-intro` and other pages in this section + - New staff: go over in more details. +- The role of {doc}`expert helpers `. +- Everyone: discuss the roles in the workshop +- For each lesson, a meeting between a former instructor and the + current one (even if current one is experienced teaching it). + - Set up any possible co-teaching arrangements. +- Discuss hand-over times each day +- Breaks should be descussed among instructors for each day, but + default is 10 minutes between xx:50 and xx:10 each hour. +- Practice instructor tech setup (screenshare, etc): can also be done + in the one-on-one meeting. +- Joining CodeRefinery: what comes next? + + + +## Don't forget + +- Update Zoom client (later than mid-October 2020) for breakout room + features. Zoom alone isn't enough. + + + +## Common CodeRefinery conventions to remember + +- Breaks are not negotiable, minimum 10 minutes +- Sessions can't be extended indefinitely, it's OK to run out of time + and skip things (in fact, we expect this: all lessons have op. All + lessons have optional episodes. Not finishing is normal, in fact. + - Emphasize to learners that we can't cover everything and don't + expect to. +- During workshop, we communicate via: + - HackMD + - Zulipchat + - Zoom chat is minor and most people don't need to watch. diff --git a/_sources/workshop-requirements-inperson.md.txt b/_sources/workshop-requirements-inperson.md.txt new file mode 100644 index 00000000..39d4c0c9 --- /dev/null +++ b/_sources/workshop-requirements-inperson.md.txt @@ -0,0 +1,62 @@ +# Workshop requirements - in person + +This checklist is for the pre-planning phase of in-person CodeRefinery +workshops: where you are deciding if you can host one and what room to +use. Let us know about the items on this list when you contact us. + +## Lecture room + +- The room needs to be sufficiently large (a typical workshop is attended by + around 20 learners and 4 instructors). +- There needs to be enough space for instructors to walk around and interact + with learners individually (a "flat" room is required). +- Learners should face the same direction, and learners should be able to sit + side-by-side for pairwise work. +- The room should preferably have windows, and be ventilated well enough so + that 20-30 people (and same amount of laptops) will not make it too warm. +- A coffee room (or similar) should be located nearby for the coffee breaks. +- Two overhead projectors are desirable, but if only one is available that will + work too. +- The projector screen needs to be large, and the resolution of the projector + needs to be good. +- Stable wireless connectivity for 20-30 people. +- Sufficiently many electricity outlets so that all participants can charge + their laptops. +- Standing board for instructor. + +## Helpers + +CodeRefinery workshops are hands-on and interactive, and a lot of time is +spent on exercises where participants learn by doing. Participants +explore themselves, and that means they need guides to help them if +they get stuck. + +We recommend that each site takes proactive steps to recruit at least +two helpers per workshop. We've noticed that helper diversity +promotes learning, so we recommend that organizers also make proactive +steps to have diverse helpers (male/female, international, etc.). +Local organizers should directly contact possible helpers and invite them. + +Good candidates are people who have any of: +- have attended a previous CodeRefinery workshop +- have a passion for teaching, scientific software development, open + source, open science, etc. +- are research software engineers or hold a similar technical research position +- have experience from teaching e.g. Software Carpentry workshops +- want to experience CodeRefinery but already have a good idea of most basics + + +## Other requirements + +When we organize a workshop or event at a new site, we may need help with some local arrangements, +including: + +- Booking a lecture room. +- Ordering coffee and refreshments. +- Advertise the workshop through local dissemination channels. + + +## After the workshop + +Would you like to [become a helper, instructor, or partner](https://coderefinery.org/get-involved/) +and make more workshops possible? diff --git a/_sources/zoom-mechanics-old.md.txt b/_sources/zoom-mechanics-old.md.txt new file mode 100644 index 00000000..4f11acac --- /dev/null +++ b/_sources/zoom-mechanics-old.md.txt @@ -0,0 +1,133 @@ +--- +orphan: true +--- + +# Zoom mechanics and controls + + +## How to mute and unmute + +In lower left corner of the client you can mute and unmute yourself: + +![unmute in lower left corner](img/unmute.jpg) + +In the *main room* during lectures, it is best to keep your microphone +muted in the main room unless you want to say something. It's OK to +unmute and speak up. + +If you are in a quiet place, it's best to stay unmuted in breakout +rooms and during active discussions. This will make discussion much +smoother - a quiet environment or headset microphone helps with the +flow a lot. + + +## Please use your real name (instead of a system default username) + +First, click on **"Participants"** (bottom, middle): + +![participants list button at bottom](img/participants.jpg) + +You can rename yourself by clicking the blue **"Rename"** next to your +name that appears when you hover over the button: + +![rename yourself button in participant list](img/rename1.jpg) + +A box to rename yourself appears: + +![rename yourself example](img/rename2.jpg) + + +## Indicate in your name if you are in a team and/or if you are a helper + +If you are part of a team, please indicate your team name or number +like `(myteam) Your Name`: + +![team name in your Zoom name](img/myteam.jpg) + +If you are a helper, please indicate like `(myteam, helper) Your Name` +also. The workshop might use the form `(myteam,H) Your Name` instead, +check what it requests: + +![team name+helper in zoom name](img/myteam-helper.jpg) + +This makes it easier for the workshop organizers to manage breakout rooms. + + +## Indicating your status + + +### How to signal if you are away from keyboard + +Please select the **"clock" symbol** if you are away or otherwise busy. +You can find this under the "more" icon in at the bottom of the +participants list: + +![Away from keyboard clock button](img/clock.jpg) + + +### How to signal when you completed a task successfully + +We will sometimes ask you to signal to us once you have successfully completed +an exercise or type-along step. You can do this using the **green "yes" +check symbol** under the participant list: + +![Green yes under participant list](img/green.jpg) + + +### How to ask a question + +If you want to ask a question please use the **"raise hand" symbol** +under participant list: + +![Raise hand under participant list](img/hand.jpg) + +If this symbol is not present in your Zoom client, you can type "\hand" in the +chat window: + +![chat button at bottom of screen](img/chat.jpg) + + +### How to signal a technical problem or that you got stuck + +If you hit a technical problem or got stuck somewhere in an exercise +or type-along, please let us know with the **red "no" circle symbol**: + +![No button on participant list](img/problem.jpg) + +We will then probably ask you to unmute and briefly describe the problem and then based +on the problem and timing we may assign you into a separate virtual room with a helper where +they can resolve the problem. + +Once we have assigned you a helper we will ask you and the helper to **"Join +Breakout Room"** (bottom right): + +![Join Breakout Room button at bottom of screen](img/problem-breakout.jpg) + + +### How to give feedback on the speed + +There are also signals for **go faster** and **go slower** and with +this you can indicate to +us whether we should adjust the speed. + + +## Other points + +### Zoom doesn't have to fullscreen when someone shares their screen. + +By default, when someone shares their screen, Zoom goes into +fullscreen mode. This can be inconvenient when you need to see +multiple windows at once. You can disable this with Settings → Screen +Share → "Enter full screen when participants share". + +### Dual monitor mode + +You can set the configuration option "dual monitor mode", which is +really more like "dual window mode": one window for screen sharing, +one for the people. It might be useful even with only one screen. + + +--- + +This is licensed under [CC-BY](https://github.com/coderefinery/manuals/blob/master/LICENSE) +and we encourage and appreciate reuse, modifications, and contributions. diff --git a/_sources/zoom-mechanics.md.txt b/_sources/zoom-mechanics.md.txt new file mode 100644 index 00000000..93279a86 --- /dev/null +++ b/_sources/zoom-mechanics.md.txt @@ -0,0 +1,98 @@ +(how-to-zoom)= +# Zoom mechanics and controls + +## Basics + +* Most Zoom controls are probably well known by now, but if not, view + [Zoom's basic + guide](https://support.zoom.us/hc/en-us/articles/200941109-Participant-controls-in-a-meeting) + +* **Mute** and **unmute** yourself from the buttons on bottom. +* You can **rename** yourself from the participants list (hover over + your name. +* We don't use Zoom chat for typical questions: use HackMD instead. + * Chat OK for administrative questions. +* When joining, please use the **name you used to register for the + course**. +* In **livestream workshops**, there is nothing in the main room: that + is broadcasted via livestream in a separate browser window, and you + switch as needed. + + + +## Audio/video on or off? + +* **Main room**: Stay muted, video off, unless you want to speak up. +* **Breakout rooms**: Try to leave on for most interactive + atmosphere. + + + +## Workshops with teams: your name should indicate your breakout room + +You will be told if this section is relevant to you. + +* Have your breakout room number in your name: + + * **(number) Your Name** + * **(number,H) The Name** for helpers + + ![Names with breakout room numbers](img/zoom--learner-names.png) + +* Rename yourself in a meeting by starting participants list: + + ![participants list button at bottom](img/zoom--participants.png) + + Rename is found if you hover your name and click "more" + + ![participants list button at bottom](img/zoom--rename.png) + + + +## Breakout rooms + +* Click the "breakout rooms" button at bottom and you can join a + room. + +* You can click "Join" to join your breakout room by yourself. + + * If you are joined via web, make sure your name is correct (see + above) and use Zoom chat to ask host to assign you to the room. + +* **Return to main room**: "Leave" button at bottom has an option for + "Return to main room". + + + +## Reactions + +We watch the participant list and can see these reactions (in the +application): + +![Zoom reactions via the bottom bar](img/zoom--reactions.png) + +* **Task completed**: Green check +* **Technical problem**: Red X +* **Need more time**: Slower "<<" +* You can signal **go faster** and **go slower** +* You can **Raise your hand** + + + +## Other settings + +![Other zoom settings](img/zoom--settings-monitors-fullscreen.png) + +* **Automatic fullscreen when screenshare starts** can be turned off +* **Dual monitor mode** makes separate windows for screenshare and participants + + + +## See also + +* The old version of this document is available at {doc}`zoom-mechanics-old`. + +--- + +This is licensed under [CC-BY](https://github.com/coderefinery/manuals/blob/master/LICENSE) +and we encourage and appreciate reuse, modifications, and contributions. diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 00000000..8549469d --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,134 @@ +/* + * _sphinx_javascript_frameworks_compat.js + * ~~~~~~~~~~ + * + * Compatability shim for jQuery and underscores.js. + * + * WILL BE REMOVED IN Sphinx 6.0 + * xref RemovedInSphinx60Warning + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 00000000..eeb0519a --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,899 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} +dl.field-list > dt:after { + content: ":"; +} + + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/coderefinery.ico b/_static/coderefinery.ico new file mode 100644 index 00000000..a2df0fb6 Binary files /dev/null and b/_static/coderefinery.ico differ diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 00000000..c718cee4 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 00000000..6cb60000 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 00000000..7059e231 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 00000000..f815f63f Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 00000000..f2c76e5b Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..e9f60ca9 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..855c845e --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..35acda2f Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..400014a4 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 00000000..4d13fc60 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 00000000..88ad05b9 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 00000000..c4e3d804 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 00000000..c6dff51f Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 00000000..bb195043 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 00000000..76114bc0 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 00000000..3404f37e Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 00000000..ae1307ff Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 00000000..3bf98433 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 00000000..19a446a0 --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 00000000..527b876c --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 00000000..c066c69a --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'dirhtml', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 00000000..a858a410 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery-3.6.0.js b/_static/jquery-3.6.0.js new file mode 100644 index 00000000..fc6c299b --- /dev/null +++ b/_static/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Broadcaster

+

This page explains the setup and how-to guide for the OBS broadcaster. +This person manages the technical setup of OBS and thus +the streaming. This person often is, but does not have to be, the OBS +director [todo: link] who switches the scenes and manages the +broadcast after it has started.

+
+

Role of the broadcaster

+

As the broadcaster, you manage the OBS application that captures Zoom +and sends it to the world. This is different from:

+
    +
  • The Director manages the scenes and the overall flow of the +workshop (switches scenes, cues instructors when to start talking, +shares HackMD during the breaks). This person is often the +broadcaster, but for clarity we use more precise terms.

  • +
  • The Host is the interface between the instructors and the +audience: e.g. announcing instructors, keeping to the schedule, +etc.). They are very often the same as the Director.

  • +
  • The Instructors connect to Zoom and teach. If there is no +designated director, at least one instructor needs to know a bit +about that.

  • +
+

The broadcaster has a lot of preparation work to do the first time +they get set up (future courses aren’t so bad). They should expect +some panicked fixing of stuff right before each course starts. During +the courses themselves, the broadcaster is mainly sitting back making +sure nothing breaks.

+
+
+

Initial setup

+

Prerequisites:

+
    +
  • A somewhat powerful computer dedicated for broadcasting (not used +for teaching as an instructor, the broadcaster can use an +instructor computer, but that is much more complicated).

  • +
  • Stable internet connection (speed is not too important these days).

    +
      +
    • 20/5 download/upload Mbps is probably plenty good. 100/10 Mbps is +far more than is needed.

    • +
    • Wired connections, rather than wireless, are better (WiFi, +non-cellular uplink). However, you probably know your overall +stability the best: you want a continuous, smooth connection +without much jitter. +However, OBS settings can be tuned to have a larger buffer to +handle this.

    • +
    +
  • +
+

Software installation:

+
    +
  • Install OBS (Linux, Mac, Windows - +this is a mass market product so there is good support)

  • +
  • Install obs-websocket. This is also +fairly widespread, but slightly less so than OBS.

  • +
  • Zoom (but you likely already have that)

  • +
+

Zoom setup:

+
    +
  • Install Zoom. There’s not much you need to do differently.

  • +
  • Some Zoom settings:

    +
      +
    • General → Use dual monitors → yes. Despite the name, this gives +Zoom two windows: one for the gallery view, one for the +screenshare (or active speaker if there is no screenshare).

    • +
    • General → Enter full screen automatically when starting or joining +a meeting → false

    • +
    • Screen Share → Enter full screen when a participant shares screen +→ false (important)

    • +
    • Screen Share → Scale to fit shared content to Zoom window → true.

    • +
    +
  • +
+

OBS setup:

+
    +
  • Clone the obs-scenes repository. This contains some +pre-made scenes which will set your OBS up for teaching nicely.

  • +
  • Import the TeachingStreaming profile +(Profile → Import → obs-scenes/profiles/Teaching_Streaming). This contains things +like audio and encoder settings

    +
      +
    • TODO: this may need adjustment for your particular situation. At +least things like file paths will need to be adjusted. Look at +the obs-scenes readme for more information.

    • +
    • Most importantly, this sets it to 840 horizontal × 1080 vertical +(portrait mode).

    • +
    +
  • +
  • Import the Teaching_Streaming_ZoomCapture scene collection (Scene +Collection → Import → +obs-scenes/scenes/Teaching_Streaming_ZoomCapture).

  • +
  • You now need to configure some window captures, for example, you +need to tell OBS which window has the gallery of all instructors in +it. From the “Scenes”

    +
      +
    • Scene _GalleryCapture[hidden] → source ZoomMeeting-Gallery +right click → Properties → Window → select the Zoom gallery view +(for me it is titled “Zoom meeting”). TODO: adjust the size of +this window until it fits the pre-made scene [it looks nice and +large]

    • +
    • Scene _Screenshare-Zoom-Capture[hidden] → source +Zoom-SecondWindow right click → Properties → Window → select +the Zoom screenshare/active speaker window (for me it is titled +only “Zoom”). Adjust the size of this window until it nicely +fills the preview pane (the ideal size is 840×1080).

    • +
    • (optional) Scene _Hackmd-Capture[hidden]: similar, select the +shared HackMD

    • +
    • (optional) Scene _Broadcaster-Screen[hidden]: configure your +local desktop capture.

    • +
    +
  • +
  • Configure the audio

    +
      +
    • Settings → Audio → Desktop Audio → “Default” (or if you want, +select an explicit device). This is what will capture Zoom by +monitoring your speakers/headphones.

      +

      Note: prevent audio feedback! Be careful if you set this to +speakers, and you have a separate computer which you use for +teaching with a microphone that would hear those speakers: you +would get feedback.

      +
    • +
    • Settings → Audio → Mic/Aux Audio → “Default” (or whatever device +you want). This would capture that computer’s local microphone, +if you use it. (More likely, you would join the meeting as an +instructor, and thus use a separate computer to speak to people)

    • +
    • From the main OBS scene, rename the audio devices:

      +
        +
      • Bottom panel → Audio mixer → one of the devices → gear icon → +Rename →

        +
          +
        • Desktop capture to “Instructors”

        • +
        • Mic to “BroadcasterMic”

        • +
        +
      • +
      +
    • +
    +
  • +
  • Configure obs-websocket (set the listening socket + authentication).

    +
      +
    • Tools → Websocket server settings → {Enable websockets +server=true, Server port=(something), Enable authentication=true, +Password=something}. Share your IP address, server port, and +password with your other instructors.

    • +
    +
  • +
  • Allow outside connections. On of these two:

    +
      +
    • Use ngrok to forward the connection +(including SSL). Read more from the obs-websocket documentation: +https://github.com/obsproject/obs-websocket/blob/4.x-current/SSL-TUNNELLING.md +. Note that the free plan limits to 4 simultaneous connections +and the connection information will change every time you restart, +which is not great.

    • +
    • Configure your router/firewall to allow incoming connections to you +IP address, on the port configured above. (it is this external IP +address that you need to share with other instructors.

    • +
    +
  • +
  • Verify the obs-tablet-remote connection (see TODO director-setup).

  • +
+
+
+

Before each day

+
    +
  • Set Twitch stream data: stream title, stream description, channel +about page.

  • +
  • Configure and check streams

  • +
  • Test everything

  • +
  • Basic information private message:

    +
    * zoom info:
    +* zoom link:
    +* attendee hackmd:
    +* notes hackmd:
    +* live preview:
    +* control panel: http://rkd.zgib.net/obs-tablet-remote/#!auto&host=HOST&port=PORT&password=PASSWORD&config=https://raw.githubusercontent.com/coderefinery/obs-config/master/obs-tablet-remote-config.json
    +
    +
    +
  • +
+
+
+

Before each broadcast

+
    +
  • Ensure anything from the above is done (obs-tablet-remote +connection, scene layout, etc).

  • +
  • Ensure Zoom scenes are correctly captured, flip through them to +verify.

  • +
  • Wait for first instructors to join.

  • +
  • Zoom: Disable sound on participants joining

  • +
  • In zoom, right click on a participant without video and “Hide +non-video participants”. You may need three participants in order +to do this: if you have fewer, join through a browser or something.

  • +
  • Make other instructors co-hosts in the Zoom so that they can share +screen without the other person stopping.

  • +
  • Start recording / start streaming ~20-30 minutes in advance, with +audio muted and on the title card scene. Start recording at the +same time as streaming so you don’t forget it!

  • +
  • Hand it off to the director (possible yourself) to flip the audio +and scene once icebreakers start.

  • +
+
+
+

During the broadcast

+
    +
  • You can not share screen with Zoom (it messes up the windows: +screenshare becomes gallery, the old gallery window disappears).

    +
      +
    • Instead, there is a separate OBS scene for local screenshare.

    • +
    • But we recommend using a separate computer for broadcasting and +instructing, to avoid this problem.

    • +
    +
  • +
  • For the most part, the director does the scene switching (and you +might be the director)

  • +
  • You don’t need to always be in front of the broadcasting computer, +but be available in case there are emergencies.

  • +
+
+
+

Common problems

+
    +
  • Internet connection goes down

  • +
  • OBS crashes While this happens somewhat often during testing, +during live productions, when the settings are not being changed, it +has never been observed. Set all settings in advance, and maybe +quit and restart right before starting the broadcast.

  • +
  • Audio is capturing the wrong inputs, or audio quality is bad

    +

    So once when broadcasting, the audio quality was horrible. It +turned out that the sound system got confused and the desktop audio +capture (zoom capture) was actually capturing the microphone. This +was not reflected in the OBS settings.

    +

    To solve this, go to the OBS settings (you can adjust most, but not +all, settings while a stream/recording is ongoing). Flip the audio +devices to “disabled”, then back to what it should be (possibly you +need to save in between?).

    +

    It’s possible there are other times you need to adjust the audio.

    +
  • +
  • I have HackMD open in view mode (to share) and HackMD open in edit +mode (to edit), but OBS keeps switching to share the editable +one. OBS seems to go by window title. Try this: Use a different +browser, or run one of them in private mode (so that the title is +different).

  • +
+
+
+

See also

+
    +
  • There is plenty about OBS and streaming online, since it is a big +business now. You can find answers to most questions once you know +the basic theory.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/chat/index.html b/chat/index.html new file mode 100644 index 00000000..85165142 --- /dev/null +++ b/chat/index.html @@ -0,0 +1,311 @@ + + + + + + CodeRefinery Zulipchat — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CodeRefinery Zulipchat

+

The CodeRefinery zulipchat is +where our primary discussion, planning, and action takes place. Many +things are announced only via zulipchat. This is a public chat and +everybody is welcome to join, no invitation needed, and we explicitly +invite anyone to give ideas in any thread.

+

The chat is a joint community of CodeRefinery (teaching), NordicHPC +(infrastructure), and Nordic-RSE (usage and software), which are other +Nordic projects about scientific computing which share some of the +same people. Together, we have a network of all aspects of modern +scientific computing.

+

Unlike Slack, zulipchat is very heavily threaded, and it is easy to +follow along without being active all the time. Respond within the +topic (=thread) that is relevant, or make a new thread. Sometimes you +can find old threads to revive. Don’t worry, everything is flexible +and you’ll quickly learn by watching (and don’t worry about going +wrong).

+
+

Streams

+

Once you join the chat, you will be subscribed to some default +streams (a stream is basically a channel). The first thing you +should do is join some more streams, depending on your interest. Join +more streams by clicking gear icon by the steams list on the left side +on that chat, then selecting what you are interested in.

+

Gear icon to join a stream

+

If you mute a stream, you can see the contents if you click on it, +but you won’t get notifications. If you mute a topic, it will be +hidden from view but you can later unmute it in your personal +settings. Under stream settings, you can request email notifications +for all messages in a certain stream (possibly useful for the announce +streams).

+

CodeRefinery streams:

+
    +
  • #general: Any topic and random chat (including for the other +projects below)

  • +
  • #coderefinery: About the project itself. CodeRefinery members +should be in this channel.

  • +
  • #carpentries: About Carpentries or CodeRefinery as a Carpentries +lesson program.

  • +
  • #lessons: CodeRefinery lesson discussion, one for each lesson we +maintain.

  • +
  • #workshops: Organizing workshops and other events. One topic +for each event.

  • +
+
    +
  • One stream for coordinating each major workshop that requires a lot +of chat, for example #tools-workshop (the standard workshop), +python-for-scicomp, kickstart-aalto, etc.

  • +
+
    +
  • #workshop-chat: High-volume staff chat during workshops. You +typically join during a workshop, and leave when done to avoid the +flood.

  • +
  • #help: Ask questions and get advice from others. Tell +interesting things you learned via “TIL”s

  • +
  • #new members: Feel free to introduce yourself here

  • +
  • #announce:

  • +
  • #infrastructure: CodeRefinery +gitlab talk.

  • +
+

Nordic research software engineer community:

+ +

Nordic HPC:

+
    +
  • #NordicHPC: NordicHPC. +Discussion about computing infrastructure (not just HPC)

  • +
+

Misc streams in our sphere of influence:

+ +

You can make topical private streams for groups that significantly +overlap with our community. Currently, Zulip admins can’t add +themselves or others to private streams.

+
+
+

Clients

+

Zulipchat can be used in a web browser, there’s a desktop app, mobile +apps, and even a terminal client installable using pip.

+
+
+

Reacting and voting

+

We want everyone to take part in chat and express their thoughts, but +of course people don’t want to give pointless agreeing replies (but +you can always welcome to do that, too). So, we encourage everyone to +use reactions in cases they want to express agreement/disagreement but +not so much they want to send a message. Common reactions you might +see are 👍, 👎 (thumbs up/down, agree with general sentiment), 🐙 +(:octopus:, awesome/amazing/ace), and well, plenty more that are +obvious.

+

We also use reactions to express some idea of a more concrete +vote, to empower people to take an action (otherwise, it is +difficult to get a decision on anything). This is not formal or +necessarily binding (so it’s not really a vote), but a useful +intermediate system for a young project. If you see a message +proposing something and you want to say, in no uncertain terms, “I +think you should do that” or not, let us know by the following:

+
    +
  • ↔️ (+0, :left_right:: I see this and am neutral.

  • +
  • 🔼, 🔽 (+1, -1, :upvote:, :downvote:) or similar: I +agree/disagree with this.

  • +
  • ⏬, ⏫ (+2, -2, :double_up:, :double_down:): I agree/disagree +with this and am willing to work on making it happen/finding an +alternative.

  • +
+

If you want to do something, ask for opinions, and a reasonable time +later it seems the sentiment is positive, consider yourself empowered +to do it. If you are voting, feel free to be creative with emojis or +numbers, but realize that other reactions may not be so explicit. Note +that if you are negative, you should explain why or alternatives, +otherwise your opinion may not be weighted so much. The person doing +the thing decides what to do (and this is open source: we find a way +for everyone to do what they need to do).

+

Do you think you aren’t important enough to vote? That’s wrong, +because we are usually interested in the thoughts of outsiders. We +can see who voted and use that to weight our decision if needed.

+
+
+

Privacy

+

All activity (except private steams) should be considered public, and +the data controller is zulipchat.com. Zulip admins can’t add +themselves or others to private streams, but still: there is no +contract guaranteeing confidentiality.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/co-instructors/index.html b/co-instructors/index.html new file mode 100644 index 00000000..7f44cea1 --- /dev/null +++ b/co-instructors/index.html @@ -0,0 +1,258 @@ + + + + + + Co-instructors — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Co-instructors

+

Since we focus on Team teaching, almost everyone is a +co-instructor. But this page is focused on onboarding new +co-instructors in their first lessons, so focuses on explaining the +most common starting point.

+
+

Why co-teaching?

+
+../_images/teach-teaching--screenshot.png +

Demo of team teaching. Two people are speaking, in this case one +is typing and giving the small point of view, and one is explaining +the big point of view.

+
+

The dream of interactive teaching is hard to achieve: most audiences +are very quiet and even if someone does speak up, it is a small +fraction of the audience. We have found a better way: Build the +interaction straight in to the course by co-teaching. Instead of +trying to have a conversation with students, we have a conversation +among co-instructors.

+

Co-teaching provides other benefits, such as easier preparation and +easier presentation.

+
+
+

How co-teaching works: guide and demo-giver

+

Main article: Team teaching.

+

We have developed several ways of team teaching, but for starters we +suggest the “guide and demo-giver” approach. The guide manages +the overall flow through the lesson. The demo-giver does the +typing during the demonstrations. So, for example:

+
    +
  • The guide introduces a type-along session and walks through the +steps while…

  • +
  • … the demo-giver does the typing in the screenshare

  • +
  • The guide and demo-giver ask each other about what is happening.

  • +
+

During other times, the demo-giver and guide ask each other questions +when the other is talking.

+
+
+

Preparing for your first time

+
+../_images/s10-kickstart-prompt-log.png +

An example of a beautiful screenshare. Note the portrait orientation +(you have half the screen free for notes and HackMD, learners have +half the screen free to do their own work). The terminal is +dark-on-light, a minimal prompt, no other fancy shell distractions, +there is a shell history visible, and slightly distinct colors between +the web browser and the terminal.

+
+
    +
  • There is some generic technical setup for your own computer - make a +clean environment that matches learners, make a good prompt, and so +on. See Instructor technical setup and +Instructor technical setup, online.

  • +
  • Watch the Demo of CodeRefinery livestream teaching + (read the +description for an explanation).

  • +
  • Talk and plan with your co-instructors: decide which model of +co-teaching you will give.

  • +
  • Plan the material, try to go through all of the exercises and +type-along.

  • +
  • Do a run-through of the lesson, practicing what each person says. +This can be relatively quick (remember, most of the time in an +actual lesson is learners doing exercises alone).

    +
      +
    • Also check the technical setup - make sure that it looks good on +screen.

    • +
    +
  • +
+
+
+

Top issues new co-instructors face

+

See the instructor-intro for now.

+
+
+

See also

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/coderefinery-mooc/index.html b/coderefinery-mooc/index.html new file mode 100644 index 00000000..baa4e04a --- /dev/null +++ b/coderefinery-mooc/index.html @@ -0,0 +1,397 @@ + + + + + + CodeRefinery MOOC strategy — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CodeRefinery MOOC strategy

+

This page documents the CodeRefinery MOOC (massive open online course) strategy. It is not a real +MOOC (it’s not massive enough yet), but it does reach out from one to +many, and can scale to basically all the world.

+
+

Video: The future of teaching

+

“The future of teaching”, +https://www.youtube.com/watch?v=S9Jor12Cxdc (45:31) is a talk +describing many aspects of this strategy in a concise form.

+
+
+

Technical setup summary

+

We have a public broadcast, with goes out via a livestream. +Disconnected from this, people are watching the broadcast in a +separate Zoom meeting and doing exercises/breakouts there. Or, +people can watch via the livestream alone. Or there can be different +meetings. Or people could watch recorded videos later.

+

The mental model here is “Watching TV together”. We collectively watch +a show together. There are periodic intermissions where each watching +community discusses among themselves and works on the exercises. +Everyone feels they are a part of something big and that keeps people interested.

+

We have clear communication channels from learner→instructor +(HackMD), helpers→instructors (chat), instructors→learners +(livestream). Of course instructors can directly communicate with the audience +during their breaks.

+

The Director controls the stream and is responsible for keeping +things running smoothly.

+
+
+

Summary diagram

+
+../_images/mooc-diagram.png +

The general presence and information flow within the MOOC strategy.

+
+
+
+

Instructors

+

There is an instructor Zoom meeting. This is broadcasted via +Twitch, using OBS (there is usually a separate director +or production manager for this, instructors don’t need to worry +themselves with this).

+

Compared to the classic style, advantages include:

+
    +
  • You are freed from student management, others help manage the +audience and convey these important parts to you.

  • +
  • Audio/video is muted during breaks, there is more opportunity to +discuss and plan what comes next with the instructors.

  • +
+

Disadvantages:

+
    +
  • You lose the direct access to all students (but how often would +someone speak up anyway?).

  • +
+

Instructors should keep in mind (many of these are not special to the +MOOC format, but are even more important):

+
    +
  • At all times you will have a director to help keep you on track: +just teach and watch chat (and HackMD when you have time, but others +do this and let you know).

  • +
  • You will have a private Zoom meeting with only instructors (and any +other key helpers who want to be there).

  • +
  • Share a vertical screen (840 × 1080 is our standard and your +maximum). This allows students +to keep half of their screen open for their own work.

  • +
  • HackMD is the main way of receiving questions from students (just +like in our current courses). The HackMD helper can be in the +main stream to immediately ask questions from the audience, or your +co-instructors could do this. Really, perhaps both.

  • +
  • During breaks and pauses, the livestream will be muted, so that +instructors (and helpers there) can talk without the audience +hearing. This greatly increases professionalism and makes it easier +to coordinate.

  • +
  • There is the standard text chat (Zulip) to use to communicate with +other helpers.

  • +
  • Of course, you can go join the student room during breaks, other +sessions, and so on.

  • +
  • Zoom polls won’t work, since the instructors and audience aren’t in +the same Zoom meeting. This is one reason we already use HackMD for +polls (though there are other options, such as presemo.aalto.fi, +which could work in even larger courses).

  • +
  • You will have more than just the registered students in another room +as an audience. Your audience includes students in the breakout +room meeting, livestream watchers, people in their own meetings with +a private team we don’t know about, people broadcasting it to +physical rooms, people watching recordings later, and who knows who +else.

    +
      +
    • Try to speak with awareness of this diverse audience. You don’t +need to change much, but go slowly and give plenty of time, and +you can say things like “If you are registered, … . If you are +on your own, … .”

    • +
    • Repeat back questions before answering them, so that people across +channels can follow. This is a usually good idea anyway, and also +it is natural when questions are coming through chat or notes.

    • +
    • Speak in terms of breaks and exercises sessions.

    • +
    • Speak in terms of relative times, since people will be in different +timezones. For example, say “We resume at +50 minutes past the hour” and write “xx:50”.

    • +
    • Realize there are different learning styles. Some people will +attempt all exercises. Some will passive watch and want demos.

    • +
    +
  • +
  • We propose this general model for each lecture-exercise cycle:

    +
      +
    • Give the lecture part

    • +
    • Introduce the exercises

    • +
    • Short break (~5 minutes). People attempting exercises themselves +go into their other meetings and work on it. The learners +attempting it themselves will mute the stream.

    • +
    • On-stream, do the exercise as a type-along or demo. This is useful +for some audience, and also is very useful in recordings.

    • +
    • At the designated time, the learners come back to the livestream. +Depending on what you want, you could use the outcome of the demo +to discuss what we learned, do a whole new demo (perhaps faster +this time), or you go on.

    • +
    +
  • +
  • You should also make it clear to the audience (mainly +helpers/team leaders) what the expectation for each exercise +session is. This should be written in the HackMD!

  • +
  • It is OK to decide you can’t make things perfect for every audience. +The rest will understand this if you make this explicit.

  • +
+
+
+

Director

+

You job is to be aware of everything going on, and when there is a +question like “Do we need more time?” or “what should we do now?”, you +can answer it. You can give people the pushes when they get slightly +off track (though others should always be willing to speak up when +this is needed, too). You maintain this awareness by watching as many +of the communication channels as you can.

+

Hint: find your computer’s detailed audio controls, so that you can +adjust volumes of multiple sources independently. This helps you be +in multiple meetings at once. (This may be useful for others that +want to attend multiple meetings.)

+
+
+

Expert helpers and other staff

+

As a helper, your job stays pretty much the same. There is more +emphasis on making sure that all questions and comments are in the +HackMD.

+

Some helpers can join the instructor meeting and directly relay +questions and thoughts, and in general provide the “voice of the +audience”. This is a logical role for the HackMD helper.

+
+
+

Audience and team leaders

+

The learners and team leaders focus on watching the material and +asking questions in HackMD, much as in a regular course.

+
+

In the main meeting with breakouts

+

Here, there is a meeting (e.g. Zoom) which has a lot of learners in +it. There are two options for lectures:

+
    +
  • Meeting host shares the livestream (video + audio)

  • +
  • Participants individually open the livestream and watch, and go back +to the meeting when it is time to do exercises.

  • +
+

All audience members ask questions and discuss in HackMD (just like in +regular workshops). The meeting chat is mainly used for +practicalities, and is not designed to be monitored by the audience.

+

The most significant risk here is that learners have to mute the +livestream (or turn it off) during the exercise sessions if there are +demos going on while they are doing exercises. This means we may have +trouble getting their attention.

+
+
+

Via livestream

+

Here, each audience member watches Twitch independently. During the +exercise sessions, they can work alone, watch the demos, or work with +their own self-organized teams.

+
+
+

Live

+

The stream is broadcast in the physical classroom or meeting room +where a class or team is located.

+
+
+

Recording

+

You can watch the recording, refer to the lesson page, and refer to +the archived HackMD notes afterwards.

+
+
+
+

Open issues

+
    +
  • It can require some cognitive effort to understand and keep track of +all of these different channels. But when we did it in +January/February, learners picked up quickly and there were few +complaints in the end.

  • +
  • HackMD spam: Lately, we have had one HackMD for all students +(registered or watching via the stream). There has yet to be any +spam or trolling problems, but it will happen if we get big enough. +We need a transition plan to private HackMD if needed. (Proposal: +have a backup HackMD. If spam starts, we email the new one and go +from there.

  • +
  • Chat/Q&A scaling: Will HackMD actually scale enough for us? What +alternatives do we have?

  • +
+
+
+

See also

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/contributing/index.html b/contributing/index.html new file mode 100644 index 00000000..27c1983b --- /dev/null +++ b/contributing/index.html @@ -0,0 +1,250 @@ + + + + + + Contributing to CodeRefinery — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Contributing to CodeRefinery

+

CodeRefinery is an open-source project. All our work is open, and we +accept any type of contributions: there is a lot more than instructing +to run a successful workshop. Also, CodeRefinery is really more of a +group of like-minded people than one particular plan, so you are +welcome to join just to hang out and share ideas.

+

If you aren’t sure you are ready for more, you can always lurk in the chat +(passively watch our community) and become more active when you feel +the time is right.

+

These manuals (and in general, other guides we have) describe the +past, not (only) the future. They are made so that new people can +know what we typically have done, so they can work on the future (even +if it’s different).

+

A good way to get started is to take the lead of some workshop (doing +it like it was before), then do it again with your own improvements.

+
+

How to take part

+
    +
  • Join the CodeRefinery chat, give comments or submit +emoji reactions to show how you feel about things. Many things are +announced only through the chat.

  • +
  • Come to our +meetings- the +monthly community calls are for a broad audience, but anyone is +welcome come to the weekly meetings.

  • +
  • Attend a CodeRefinery workshop - they teach the very tools we use to +collaborate!

  • +
+
+
+

Action: Join our “community teaching training”

+

CodeRefinery isn’t just about doing teaching ourselves, but improving +your teaching. Whether you focus on teaching, or it’s a side-activity +to your other tasks, the CodeRefinery (online) teaching can help you +avoid re-inventing good practices and prepare you for teaching +together.

+

Read more: Community +teaching training

+
+
+

Action: Advertise and/or help out in our online courses

+

CodeRefinery runs many open, online courses, which anyone can attend. +Some of them can be attended by anyone via livestream, even without +registering (yes, this really works - we get high ratings for this). +You could simply advertise our courses, or go even further and run +local breakout rooms.

+

Take it a step further and help out with the course, whether it’s as +an instructor, helper, or some other role. Of course, anyone is +welcome to help, even without advertising the courses!

+

Read more: Local breakout rooms and Roles overview.

+
+
+

Action: Teach openly and allow others to join

+

Go to the next level and adopt CodeRefinery strategies for your own +courses, so that others can join at little cost to yourself. By +opening, you start to find more lesson developers and instructors, so +that your courses can reach the next level of quality and impact. +Soon, you will wonder why you ever bothered teaching alone.

+

Read more: Open your courses to others

+
+
+

Other types of contributions

+

As an open project, there are any number of ways you can contribute:

+
    +
  • Take on any of the roles in a workshop - with +co-teaching, it is surprisingly easy to go straight to instructor, +but there are also many other roles.

  • +
  • Help with lesson maintenance (read and make suggestions) or become a +maintainer of a lesson. Watch GitHub repositories to get notified +of issues and pull requests, and help review. Anyone can watch any +repository, and comments from outsiders do help us review things faster.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/director/index.html b/director/index.html new file mode 100644 index 00000000..e421fa93 --- /dev/null +++ b/director/index.html @@ -0,0 +1,284 @@ + + + + + + Director — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Director

+

The director manages the flow of the course, and in particular the +flow when things do not go according to plan. During livestream +courses, the director also manages the stream scene/audio selection.

+
    +
  • Gives introductions and wrap-ups (to the days, sessions, and +instructors), or at least ensures they happen.

  • +
  • Ensures good flow of the course overall

    +
      +
    • Is aware enough of the schedule so that they can decisively adjust +it when needed.

    • +
    • Keeps time, ensures breaks

    • +
    • Actively discusses with the instructors about these practical +arrangements (e.g. negotiating best break times)

    • +
    +
  • +
  • (livestreaming) Flips the livestream scenes when necessary, cues +instructors.

  • +
+
+

Managing the schedule

+

The director manages the overall flow: making sure the instructors are +ready, icebreakers happen, transitions are smooth, people are +introduced, breaks happen, HackMD is shared at the appropriate times, +and so on.

+

During large courses, there are many different instructors and certain +exercises/lessons may randomly take longer (no matter how much +preparation there is). The audience expects this, and in practice +decisively accepting and adjusting the schedule (or deciding not to) +makes things smooth.

+

The Director is usually the instructor coordinator, so knows the +schedule well. The instructor should be empowered to decide (after +checking chat, HackMD, and other instructors) what to do, and can +directly announce the new schedule. This takes confidence, but don’t +worry: you have plenty of people to consult with, ask advice from +those around and then make your choice.

+

You should also make sure that HackMD is updated with breaks, +exercises, and so on. You will probably be the one sharing HackMD +during the breaks.

+
+
+

Switching scenes and audio

+

During a livestream course, various video inputs are mixed +(screenshare, instructor gallery, title card, HackMD) and +broadcasted. This gives one extra level of management that is needed: +yes, it is more overhead, but the advantages are that the instructors +can mute the livestream and have a private discussion. This is great +for breaks and exercise times, and really helps with the flow a lot.

+

So, for example:

+
    +
  • Start the course on the “title card”

  • +
  • Switch to gallery view for introduction

  • +
  • Switch to screenshare (and adjust PiP size) during teaching

  • +
  • Share HackMD during the break and then make PiP size zero

  • +
  • Repeat for next courses.

  • +
+

The available controls include:

+
    +
  • Audio: the audio capture can be turned on and off:

    +
      +
    • “Instructors”: the capture of the Zoom

    • +
    • “Mic”: this is the local microphone of the capture computer and +should not normally be adjusted.

    • +
    +
  • +
  • Scene selection: there is a button to select among these scenes

    +
      +
    • “Title card”: graphics used before learners arrive

    • +
    • “Gallery”: instructors

    • +
    • “Screenshare”: capture of the Zoom screenshare

    • +
    • “Hackmd”: just what it says

    • +
    +
  • +
+ +
    +
  • Picture in Picture display: adjust size and layout of this

    +
      +
    • The size can be adjusted to fit the screen

    • +
    • To turn it off, make the size zero

    • +
    • The cropping can be adjusted based on the number of people in +the Zoom display.

    • +
    +
  • +
+
+
+

OBS remote control via obs-tablet-remote

+

The broadcaster will provide you with a URL to go to the remote +control. TODO: picture

+

This is an example (note: it won’t work, because you don’t have OBS running):

+
    +
  • coderefinery.github.io/obs-tablet-remote/#!auto&host=HOST&port=4444&password=PASSWORD&config=https://raw.githubusercontent.com/coderefinery/obs-config/master/obs-tablet-remote-config.json

  • +
+

Go to this URL. It will prompt you for a password (or the broadcaster +might add the password to the URL already). The OBS remote control +will open with a pre-arranged configuration for your course, with +buttons corresponding to the controls you see above.

+
+
+

See also

+

(none yet)

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/exercise-coordinator/index.html b/exercise-coordinator/index.html new file mode 100644 index 00000000..e54cc62c --- /dev/null +++ b/exercise-coordinator/index.html @@ -0,0 +1,174 @@ + + + + + + Exercise coordinator — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Exercise coordinator

+

Also called team leader coordinator.

+

The exercise coordinator makes sure that the hands-on idea of the workshop is preserved. They remind the instructors to check and report their exercises before the workshop. They are also the contact person for the team leaders and organize the team leader onboarding before the workshop.

+

If wished, they can also host the exercise Zoom room and support the registration coordinator with building the teams for the breakout rooms in Zoom.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/expert-helpers/index.html b/expert-helpers/index.html new file mode 100644 index 00000000..d6b656d1 --- /dev/null +++ b/expert-helpers/index.html @@ -0,0 +1,287 @@ + + + + + + Expert helpers — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Expert helpers

+

We mainly have expert helpers for large workshops.

+
    +
  • As an expert helper, your main job is to move between different +groups and make sure that groups are doing well.

  • +
  • You might be summoned to a group whose helper needs extra help, or +take the place of a helper if a group doesn’t have one.

    +
      +
    • Watch HackMD/Zulip for this, though requests might come in from +other channels, too.

    • +
    +
  • +
  • No one is expected to know everything, but an expert helper should be +able to find a person who can answer, or confident enough to say +they should move on.

  • +
  • Make sure you have a new (newer than 15 october 2020) Zoom client, +so that you can join arbitrary breakout rooms.

    +
      +
    • If you don’t, then you have to ask to be put into some room, and +then you can swap to any other room.

    • +
    +
  • +
  • Report an overview of the pulse of the breakout rooms in zulipchat +(or hackmd). Is everyone behind? People finishing early? Big +differences between them? Questions which we should bring up in the +main room?

  • +
  • Monitor if any team leaders need extra help or training. Should we +improve our team leader training?

  • +
+
+

Tasks

+

There’s not much difference between a team leader and expert helper, but we +envision this role standing by and jumping into rooms when there’s a +difficult problem.

+
    +
  • Sometimes, you wait around for a problem that needs your attention. +But it’s better to be proactive and go into the rooms yourself and +check them out. Talk to the organizers/instructors to see which you +should do.

  • +
  • You aren’t assigned to particular breakout room, but you can +switch between them (but it’s not obvious how):

    +
      +
    • To do this, you do get assigned into one room initially. Join +that room. After you are in the room, click on “Breakout +Rooms”, and then Join to switch to a different room of your +choice.

    • +
    • You also always have the option “Leave breakout room” (if in a +room) or “Join your assigned room” (if in main room and assigned +one).

    • +
    +
  • +
  • Your role is to switch between breakout rooms and check up on them.

    +
      +
    • e.g. join room 1, take a look/ask how it is, then join room 2, +then 3, then back to 1, and repeat.

    • +
    • Of course, stay in one longer, if it’s needed.

    • +
    • Make a note of any important questions to be asked in the main +room afterwards.

    • +
    +
  • +
  • Try to divide up the breakout rooms between the staff, and try to +join and catch up with the same rooms (this promotes familiarity).

    +
      +
    • E.g. A rotates between rooms 1-3, B gets rooms 4-7, C gets rooms +8-11.

    • +
    +
  • +
  • Make sure to watch the HackMD for expert helper requests, this could help +you decide which room to jump to next. Comment when you are heading +there.

  • +
+

Concrete example for an expert helper’s time:

+
    +
  • I join breakout room 5 randomly. I spend 15 seconds watching, then +ask if things are going OK. If everything is good, I move on within +a minute since I am not needed (if there is a good break, I’ll ask +“everything OK? good, see you around.”). If there are questions +that I can help with, I answer them. If they seem to be struggling, +then I will make a note in the HackMD and stay a while longer and +watch/help.

  • +
+
+
+

Common issues and solutions

+
    +
  • A room is very slow, the person sharing the screen is working quite +slowly.

    +
      +
    • Kindly suggest that you or someone else take over and go through +it faster

    • +
    • Yes, this is hard to say nicely

    • +
    +
  • +
  • No one wants to take initiative and screen share

    +
      +
    • If you think everyone is confident enough, this can be OK

    • +
    • But especially at the beginning of the workshops, you can share +your own screen and go along with people.

    • +
    +
  • +
  • Someone is having trouble installing software

    +
      +
    • “Perhaps we can take a look at this after the workshop? We try +to make sure everything is installed beforehand, but “

    • +
    +
  • +
+

Other reference:

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/genindex/index.html b/genindex/index.html new file mode 100644 index 00000000..750a9555 --- /dev/null +++ b/genindex/index.html @@ -0,0 +1,169 @@ + + + + + + Index — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/governance/index.html b/governance/index.html new file mode 100644 index 00000000..dbbf9a2b --- /dev/null +++ b/governance/index.html @@ -0,0 +1,215 @@ + + + + + + CodeRefinery governance — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CodeRefinery governance

+
+

CodeRefinery Community

+

Right now, the CodeRefinery community is small, so we do not want to +make things very formal. However, we expect things to formalize in +proportion to its need.

+

In short:

+
    +
  • Team meetings are approximately once a week. Rough consensus is +used to make decisions. Read more: +https://coderefinery.org/organization/meetings/

  • +
  • Important decisions should also be announced and discussed via chat +in advance, and ideally at several meetings.

  • +
  • Because this is a small project, the deciding factor is “what does +someone want to do?”. Meetings provide a way to empower people to +take action which may otherwise be hard to find in asynchronous +chat, despite the voting.

  • +
  • The monthly “Community calls” allow us to get a perspective of a +broader audience and bring in new members.

  • +
  • This document will be updated (by pull request+discussion) as we +improve our governance in the future.

  • +
+

In the future:

+
    +
  • An advisory role could to taken on by some sort of community council +or board made up of partner representatives and community +representatives.

  • +
+
+
+

NeIC project

+

The Nordic e-Infrastructure collaboration funds a +part of CodeRefinery, and with that comes a certain standard of +governance and reporting +(see also the collaboration agreement). +However, we consider this to be in parallel +to the community project (with the community project being more +important).

+

There is a lot of overlap between the NeIC-sponsored staff and the +community, but the community will increase in proportion over time.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/hackmd-helper/index.html b/hackmd-helper/index.html new file mode 100644 index 00000000..4bc03799 --- /dev/null +++ b/hackmd-helper/index.html @@ -0,0 +1,361 @@ + + + + + + HackMD manager — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

HackMD manager

+

We have one person who is a “HackMD helper”. This isn’t the only +person that should edit and answer, but one person shouldn’t have too +much else on their mind so can focus on it. They also make sure that +HackMD is updated with exercise, break, and other meta-information to +keep people on track.

+

Below, (*) = important.

+
+

Before the workshop

+
    +
  • Create a new hackmd for the workshop

  • +
  • make sure that editing is enabled for anyone without login

  • +
  • Add workshop information, links to the workshop page and material +and an example question and answer to the top of the hackmd (see below)

  • +
+
+
+

Most things to edit (everyone)

+

Make it easy to post after the course and consistent to follow:

+
    +
  • Tag all names with [name=XXX] (so they can be removed later), +remove other personal data or make it obvious.

  • +
  • Add in information on exercises (new section for them, link, end +time, what to accomplish)

  • +
  • Make a logical section structure (# for title, ## for sections, +### for episodes, etc. - or what makes sense)

  • +
+
+
+

General HackMD practices

+
+../_images/hackmd--full-demo.png +

A live demo of HackMD during a Q&A time. The two instructors are +discussing some of the import answers. Multiple learners have asked +questions, multiple answers, and some remaining to be answered

+
+

Keep it formatted well:

+
    +
  • (*) Tag names you see with [name=XXX] so that we can remove it +later.

  • +
  • Heading level # is only the page title

  • +
  • Add a new ## heading when a new lesson or similar thing is +started (introduction, icebreaker, break between lessons, etc)

  • +
  • Add a new ### heading when a new episode, exercise, break +(within exercise session)

  • +
  • Ensure people are asking questions at the bottom, direct them there +if they aren’t.

  • +
  • (*) Ensure each question is a bullet point. Each answer or follow-up +should be a bullet point below.

    +
      +
    • Should you use more deeply nested bullet points, or have only one +level below the initial question? It depends on the context, but +if a conversation goes on too long, try not to let it go too +deep.

    • +
    +
  • +
+

Update with meta-talk, so that learners can follow along easily:

+
    +
  • Add Icebreaker and introductory material of the day. Try to talk to +people as they joined to get them to open HackMD and answer.

  • +
  • Anything important for following along should not be only said via +voice. It needs to be in the HackMD, too.

  • +
  • New lessons or episodes, with links to them.

  • +
  • For exercises, link to exercise and add the duration, end time, +goals. If these are unclear, bring it up to the instructor by voice.

  • +
  • Add a status display about breaks.

  • +
+

Screenshare it when necessary:

+
    +
  • During breaks and other times, share the HackMD (including the +notification about break, and when it ends).

  • +
  • It is nice if the arrangement allows some of the latest questions to +be seen, so people are reminded to ask there.

  • +
  • Someone else may do this, but should make sure it happens.

  • +
+

Answer questions

+
    +
  • If there is an question that should be answered by the instructor by +voice, bring it up (by voice) to the instructor immediately.

  • +
  • During breakout sessions, watch for HackMD notifications about +breakout rooms that need help +and direct someone to that room.

  • +
  • How soon do you answer questions? Two points of view:

    +
      +
    • Answer questions right away: can be really intense to follow.

    • +
    • Wait some so that we don’t overload learners: reduces the info +flow. But then do people need to check back more often.

    • +
    • You need to find your own balance. Maybe a quick answer right +away, and more detailed later. Or delay answers during the most +important parts of the lecture.

    • +
    +
  • +
  • Avoid wall-of-text answers. If reading an answer takes too long, it +puts the person (and other people who even try to read it) behind +even more by taking up valuable mental energy. If an answer needs a +wall of text, consider these alternatives:

    +
      +
    • Progressive bullet points getting more detailed (first ones +useful alone for basic cases)

    • +
    • Don’t be worried to say “don’t worry about this now, let’s talk +later.”

    • +
    • Figure out the root problem instead of answering every possible +interpretation

    • +
    • Declare it advanced and that you will come back later.

    • +
    +
  • +
+

Ensure it can be posted quickly:

+
    +
  • HackMD gets posted to the workshop webpage. For this, it needs some +minimal amount of formatting (it doesn’t need to be perfect, just +not horrible).

  • +
  • All names and private information needs to be stripped. This is why +you should rigorously tag all names with [name=XXX] so they can be +removed (see above).

    +
      +
    • Learner names can be completely removed. CR staff names can be +[name=CR] or something similar.

    • +
    • There may be other private URLs at the top or bottom.

    • +
    +
  • +
  • If possible, send the PR adding the HackMD to the workshop webpage +(though others can do this, too).

  • +
+
+
+

HackMD format example

+
# Workshop, day 1
+
+
+## Lesson name
+https://coderefinery.github.io/lesson/
+
+### Episode name
+https://coderefinery.github.io/01-episode/
+
+- This is a question
+  - Anwser
+  - More detailed answer
+- question
+  - answer
+
+### Exercises:
+https://link-to-exercise/.../.../#section
+20 minutes, until xx:45
+Try to accomplish all of points 1-3.  Parts 4-5 are optional.
+
+Breakout room status:
+- room 2, need help with Linux permissions
+- room 5, done
+
+### Break
+:::danger
+We are on a 10 minute break until xx:10
+:::
+
+
+## Lesson 2
+https://coderefinery.github.io/lesson-2/
+
+
+
+
+
+

Posting HackMD to website

+

HackMD should be posted sooner rather than later, and hopefully the +steps above will make it easy to do so quickly. You could wait a few +hours, to allow any remaining questions to be asked an answered.

+
    +
  • Download as markdown

  • +
  • Remove any private links at the top

  • +
  • Adjust headings so that they are reasonable

  • +
  • Look for private info and remove it

    +
      +
    • Search document for [name=???] (change to [name=staff] or +[name=learner])

    • +
    • Any names not tagged with [name=]

    • +
    • usernames in URLs

    • +
    • private links

    • +
    +
  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/hackmd-mechanics/index.html b/hackmd-mechanics/index.html new file mode 100644 index 00000000..4877ab2b --- /dev/null +++ b/hackmd-mechanics/index.html @@ -0,0 +1,248 @@ + + + + + + Collaborative document mechanics and controls — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Collaborative document mechanics and controls

+

Hackmd or HedgeDoc are real-time text editor online. We use it to:

+
    +
  • As a threaded chat, to answer questions and provide other information without +interrupting the main flow of the room.

  • +
  • provide everyone with a more equal opportunity to ask questions.

  • +
  • create notes which will be archived, for your later reference.

  • +
+

You do not need to login/create an account to be able to edit the document.

+
+

Basic controls

+
+../_images/hackmd--controls.png +

This may look slightly different on mobile devices and small windows.

+
+
    +
  • At the top (left or right), you can switch between view, +edit, and split view and edit modes.

  • +
  • You write in markdown here. Don’t +worry about the syntax, just see what others do and try to be like +that! Someone will come and fix any problems there may be.

  • +
  • Please go back to view mode if you think you won’t edit for a +while - it will still live update.

  • +
+
+
+

Asking questions

+

Always ask questions and add new sections at the very bottom. +You can also answer and comment on older questions, too.

+
+../_images/hackmd--questions2.png +

Questions and answers in bullet points

+
+

Since we plan to publish the questions and answers later as part +of the workshop page, we recommend to not use any names. You can indicate +your own name to make it easier to discuss more during the workshop but +then always use this form: [name=Myname]. This makes it easier for +us to automatically remove all names before publishing the notes.

+

Other hints:

+
    +
  • Use +1 to agree with a statement or question (we are more likely +to comment on it).

  • +
  • Please leave some blank lines at the bottom

  • +
  • NOTE: Please don’t “select all”, it highlights for everyone and adds a +risk of losing data (there are periodic backups, but not instant).

  • +
  • It can be quite demanding to follow the collaborative document closely. Keep an eye +on it, but consider how distracted you may get from the course. For +things beyond the scope of the course, we may come back and answer +later.

  • +
+
+
+

Don’t get overwhelmed

+

There can be a flood of information on the collaborative document. Scan for what is +important, then if you would like come back later. But it is +important to keep checking it.

+
+
+

Privacy

+
    +
  • Assume the collaborative document is public and published: you never +need to put your name there.

  • +
  • The collaborative document will be published on the website afterwards. We will +remove all non-instructors names, but it’s easier if you don’t add +it there in the first place.

  • +
  • Please keep the link private during the workshop, since since +security is “editable by those who have the link”.

  • +
  • You can use [name=YOURNAME], to name yourself. We will remove +all names (but not the comments) before archiving the notes (use +this format to make it easy for us).

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/host/index.html b/host/index.html new file mode 100644 index 00000000..20537bda --- /dev/null +++ b/host/index.html @@ -0,0 +1,248 @@ + + + + + + Host — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Host

+

WARNING: page out of date, this is also split to the director.

+
    +
  • Make all of other staff and expert helpers co-hosts.

  • +
  • Take attendance in spreadsheet, if we do that.

    +
      +
    • TODO: provide sample spreadsheet

    • +
    • It might be easiest to take attendance all at once, in the middle +of the session, after everyone has been assigned to breakout +rooms.

    • +
    +
  • +
+
+

Breakout rooms

+
    +
  • Rename people to include breakout room number (other co-hosts should +help and hopefully do most of this work too), though. (this is a +continuous process as people drop out and rejoin)

  • +
  • Assign people to breakout rooms (this is a continuous process)

  • +
  • Merge breakout rooms as necessary, to try to keep them balanced well

  • +
  • Constantly watch for new people joining, rename them, and assign +them to breakout rooms.

    +
      +
    • Note, you might have merged the room they were originally in, so +they might end up in an empty room!

    • +
    +
  • +
  • Plan for the future: how many helpers might be missing, which rooms +need to be merged. Can you keep the merging somewhat consistent +over time?

  • +
+
+
+

Recording

+

Recording workshops provides a way for learners to get an instant +review of what was covered, increasing learning. We don’t currently +intend for workshop recordings to be useful to new people learning +later, but they could be.

+
    +
  • Record the workshop or give permission for others to record.

    +
      +
    • If you are recording, you can’t leave and go to other rooms.

    • +
    • Perhaps a separate computer could record?

    • +
    +
  • +
  • spotlight speaker

  • +
  • dual monitor mode?

  • +
  • ensure that screen is always being shared?

  • +
  • stay in speaker view (not gallery view)

  • +
  • start and stop recording

  • +
  • rename recording immediately dayN-lessonname-zoom.mp4 and upload +to google drive.

  • +
+
+
+

Streaming

+

All of the steps needed to record mean that you can stream, too. In +fact, you could look at streaming as a side-effect of recording (or a +way to record).

+
    +
  • spotlight speaker

  • +
  • start streaming

  • +
  • dual monitor mode?

  • +
  • ensure that screen is always being shared?

  • +
  • stay in speaker view (not gallery view)

  • +
  • have stream feed open. If you see it change to gallery view, fix it +immediately.

  • +
  • stop streaming

  • +
  • download recording from twitch, rename to +dayN-lessonname-twitch.mp4 and upload to google drive.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-to-attend-inperson/index.html b/how-to-attend-inperson/index.html new file mode 100644 index 00000000..1d7e6d49 --- /dev/null +++ b/how-to-attend-inperson/index.html @@ -0,0 +1,244 @@ + + + + + + Attending an in-person workshop — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Attending an in-person workshop

+

We are glad you would like to attend an in-person workshop. This page +will help you mentally and physically prepare.

+

Our workshops are interactive and hands-on, and you will get the most +out of them if you can take part in all exercises, unlike a normal +academic lecture where you mainly listen. Thus, please read this and +come prepared!

+
+

General prerequisites, software installation, etc.

+

Check your workshop page for the general setup specific to that +workshop.

+
    +
  • Often, there is something to install. We usually ask you to install +things so that your computer is set up to do work later.

  • +
  • There may be some basic skills, such as the command line shell, to +review in advance.

  • +
+

If all else fails, join the workshop well in advance and ask +for help then. Usually, there will be enough time to get ready for +the day.

+
+
+

Take the workshop seriously

+

It’s easy to think “it’s just a class, it’s easy to passively watch”. +However, for an interactive workshop you do need to take part to get +the most of out it, and our workshops are targeted to that. If you +read this page and the workshop prerequisites, you should be OK.

+
+
+

Social

+

Attend with someone! Register together and try to sit near them. +This will create a network of learning and practice that will last +much longer.

+

If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills.

+
+
+

Computer and equipment

+

Bring your laptop and charger, of course. If you use external mice, +etc, it would be good to bring them too. You’ll be on your device a +lot.

+

Usually, you’ll need to look at both the lesson webpage and the window +where you are doing the exercises at the same time. Consider how you +can arrange windows to do this best.

+
+
+

Time management

+

Try your very best to attend the whole workshops; at least don’t miss +the early sessions. Later sessions depend on earlier ones, and it’s +easy to get behind. Tell others this is important so that you can +free your schedule.

+

Arrive 10 minutes early to get ready.

+
+
+

Final notes

+

Arrive 10 minutes in advance to get set-up. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start.

+

There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions.

+

Sign up on the notify me +list to hear +about what comes next.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-to-attend-online/index.html b/how-to-attend-online/index.html new file mode 100644 index 00000000..2bfff91f --- /dev/null +++ b/how-to-attend-online/index.html @@ -0,0 +1,276 @@ + + + + + + Attending a Zoom workshop — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Attending a Zoom workshop

+

We are glad you would like to attend an online workshop. This page +will help you mentally and physically prepare.

+

Our workshops are interactive and hands-on, and you will get the most +out of them if you can take part in all exercises, unlike a normal +academic lecture where you mainly listen. Thus, please read this and +come prepared!

+
+

General prerequisites, software installation, etc.

+

Check your workshop page for the general setup specific to that +workshop.

+
    +
  • Often, there is something to install. We usually ask you to install +things so that your computer is set up to do work later.

  • +
  • There may be some basic skills, such as the command line shell, to +review in advance.

  • +
+

Do the installation and configuration in advance, and double check +it. In real workshops, problems here slow us down a lot, and if +you don’t prepare, you will immediately fall behind. If there is a +pre-workshop session for installation, go there if needed.

+

If all else fails, join the workshop well in advance and ask +for help then. Usually, there will be enough time to get ready for +the day.

+
+
+

Take the workshop seriously

+

It’s easy to think “it’s just online, it’s easy to passively watch”. +However, for an interactive workshop you do need to take part to get +the most of out it, and our workshops are targeted to that. If you +read this page and the workshop prerequisites, you should be OK.

+

Don’t do multiple meetings, reserve the entire timeslots on your +calendar, attend every session, do the preparation.

+
+
+

Social

+

Attend with someone! Register together and try to be in their same +group. You could even reserve a room and work together. This will +create a network of learning and practice that will last much longer.

+

If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills.

+
+
+

Workspace

+

Get a good, quiet workspace. Make sure it is comfortable enough to +stay at for a while.

+

An extra monitor is useful but not required, since there is a lot of +stuff to follow: the stream itself, the lesson webpage, and the window +where you are doing the assignment. You could also use a second +device to watch the stream (but if you do, see the +Zoom page for info about screen sharing).

+

You’ll be expected to talk at some times and take part, not simply be +quiet and listen all the time. Try to be in a place where you can +speak without disturbing others. By the same token, you’ll be +listening for a long time, and your ears may get tired of headphones. +If you have good enough external speakers, be somewhere that you can +use them (perhaps only sometimes - when it doesn’t interfere with your +microphone.)

+

If you work in a large office, consider attending from home or in a +meeting room so that you can speak and listen more freely. If you +need and extra monitor or more comfortable seating space and don’t +have that at home, consider working at your office. Yes, these are +conflicting ideas, you need to find what works best for you.

+
+
+

Time management

+

Despite what most people think, attending things online can be harder +than in-person.

+

Don’t schedule overlapping meetings, reserve the entire timeslots, +minimze distractions. It’s easy to think you can do multiple things +at once when doing it online, but really it’s a trap.

+

Join the workshop 10 minutes early to get ready.

+

There will be breaks, but even long ones go by very fast, and this +gives you limited time to make coffee, eat, etc. We try to limit +ourselves to half-days because of this, but consider preparing food, +coffee, etc. in advance.

+

Make sure you take the breaks, walk around some, etc.

+
+
+

Live streaming

+

If the workshop is also streamed, see +Live streaming for how to attend that +way.

+
+
+

Final notes

+

Join the stream 10 minutes in advance. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start.

+

There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions.

+

Sign up on the notify me +list to hear +about what comes next.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/how-to-attend-stream/index.html b/how-to-attend-stream/index.html new file mode 100644 index 00000000..30c8e42c --- /dev/null +++ b/how-to-attend-stream/index.html @@ -0,0 +1,354 @@ + + + + + + Attending an livestream workshop — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Attending an livestream workshop

+

We are glad you would like to attend an livestream workshop. This page +will help you prepare and get the most out of the workshop and take +advantage of the diverse ways to attend.

+

Even though it’s a one-to-many livestream, the course is still +interactive. In fact, it’s more interactive, since everyone can Q&A +at the same time via HackMD. Since we can +record without privacy risk, you are better able to catch up and +review. Read on to learn more.

+
    +
  • You might register to Zoom breakout rooms, which are interactive.

  • +
  • HackMD allows you to ask questions anonymously - +even better than a normal workshop! Once we have a few tens of people in +any workshop, people don’t ask voice questions anyway.

  • +
  • In some workshops, you can register for breakout rooms to get +interactive assistance during the exercise/breakout sessions.

  • +
+
+

How it works

+
    +
  • You open the livestream in a web browser. This is the “TV”, it is +always on (but sometimes silent).

  • +
  • If you are part of an exercise/breakout group, be with them. The +stream will tell you when the exercise/collaboration times are, and +you go to there.

    +
      +
    • If you are attending Zoom exercise session, open this at the +beginning. Leave it minimized when it’s not active.

    • +
    • If you are with an in-person group, be together. When the stream +is quiet, you can interact freely.

    • +
    +
  • +
  • The livestream is a portrait screenshare, so that it will only take +up half of your screen (and the other half is for you to work). (If +you are in a physical meeting room with a projector or second +monitor, it can be half the livestream and half the HackMD - this +will make sense when you see it).

  • +
+
+../_images/layout--learner-livestream-sidebyside-onebrowser.png +

Screen layout with livestream on one side and workshop on the other.

+
+
+
+

General prerequisites, software installation, etc.

+

Check your workshop page for the general setup specific to that +workshop.

+
    +
  • Often, there is something to install on your own computer. (We +usually ask you to set up your own computer, so you can continue +working independently later.)

  • +
  • There may be some basic skills, such as the command line shell, to +review in advance.

  • +
+

Do the installation and configuration in advance, and double check +it. Our instructions are standard enough that someone local should +be able to help you, if some central install help isn’t provided. The +livestream can’t wait for individual people (but a local group can +provide live support).

+
+
+

Take the workshop seriously

+

It’s easy to think “it’s just online, it’s easy to passively watch”. +And that is OK! We’d rather have someone watch in case it might be +useful, than exclude people who don’t have time. Our material is +available for later. In this case, please don’t register for our +Zoom/in-person sessions, since that can take a spot from others.

+

However, we design the workshops to be interactive, and there is a lot +of time scheduled for hands-on work and Q&A. Reading this page and +preparing will help you to make the most of it: don’t do multiple +meetings, reserve the entire timeslots on your calendar, attend +every session, do the preparation.

+
+
+

Social

+

Attend with someone! Register together and try to be in their same +group. You could even reserve a room and work together. This will +create a network of learning and practice that will last much longer.

+

If you can attend a group, that is even better. You can bring your +own team leader to guide you (if the workshop works this way). Research +shows that groups that have multiple adopters have much more uptake of +new skills.

+
+
+

Workspace

+

Get a good, quiet workspace. Make sure it is comfortable enough to +stay at for a while.

+

An extra monitor is useful but not required, since there is a lot of +stuff to follow: the stream itself, the lesson webpage, and the window +where you are doing the assignment. You could also use a second +device to watch the stream. However, we do design things to fit on +one computer.

+

If you have registered to attend breakout rooms, you’ll be expected +to talk at some times and take part, not simply be +quiet and listen all the time. Try to be in a place where you can +speak without disturbing others. By the same token, you’ll be +listening for a long time, and your ears may get tired of headphones. +If you have good enough external speakers, be somewhere that you can +use them (perhaps only sometimes - when it doesn’t interfere with your +microphone.)

+

If you work in a large office, consider attending from home or in a +meeting room so that you can speak and listen more freely. If you +need and extra monitor or more comfortable seating space and don’t +have that at home, consider working at your office. Yes, these are +conflicting ideas, you need to find what works best for you.

+
+
+

Time management

+

Paying attention to something requires time, whether it is online or +in-person.

+

Don’t schedule overlapping meetings, reserve the entire timeslots, +minimize distractions. It’s easy to think you can do multiple things +at once when doing it online, but really it’s a trap.

+

Plan to join the stream 10 minutes early to get ready - we start with +icebreakers and discussion then.

+

There will be breaks, but even long ones go by very fast, and this +gives you limited time to make coffee, eat, etc. We try to limit +ourselves to half-days because of this, but consider preparing food, +coffee, etc. in advance.

+

Make sure you take the breaks, walk around some, etc.

+
+
+

Accessibility

+

We believe that livestream workshops offer a wide variety of tools +which are useful to allow everyone to succeed. Consider how you want +to attend to make it the best for you:

+
    +
  • Our material is provided in writing (lesson websites), by voice, and +by demo. You don’t have to strictly follow along at the speed we +teach.

  • +
  • We record videos and post the notes so you can review at your own +pace later on. Videos don’t include audience voice or video, so you +don’t have to be afraid to interact.

  • +
  • HackMD allows anyone to ask questions anonymously and +asynchronously, without interrupting others. On the other hand, +there are a lot of questions, so don’t watch too closely if it is +distracting. We continue answering questions for a little bit after +each day ends, so you can ask even if you can’t write the question +on time.

  • +
  • Lesson websites/HackMD use standard web technologies, so that +browser accessibility plugins can be used (for example making the +font more accessible, check browser extensions).

  • +
  • Twitch can be live-captioned using the Google Chrome browser. Our +videos on YouTube provide automatic captions immediately, since +videos are released immediately they don’t come too late for you. +Other standard browser extensions can also provide other video +accessibility services without asking us.

  • +
  • You can follow along without providing any personal data +(registration, Twitch works with cookies blocked) - though +registration helps our reporting.

  • +
+
+
+

Communication

+

Most communication goes through HackMD. Make sure +that you open it and try it out during the icebreakers - it will +become obvious then. There will be an absolute flood of information +there, so watch strategically and don’t let yourself get overloaded.

+

HackMD is much better than chat, since you can ask anonymously, you +can ask at the same time as others, and multiple people can +answer, and we fix it up and publish it at the end.

+
+
+

Final notes

+

Join the stream 10 minutes in advance. There is some advance +icebreakers and discussion you can take part in, and you get to breath +before we start.

+

There is usually discussion after the workshop. If you want, stick +around and give us immediate feedback and ask more questions.

+

Sign up on the notify me +list to hear +about what comes next.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/icebreakers/index.html b/icebreakers/index.html new file mode 100644 index 00000000..4e406592 --- /dev/null +++ b/icebreakers/index.html @@ -0,0 +1,351 @@ + + + + + + Icebreakers — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Icebreakers

+

This is a list of possible icebreaker questions.

+

You should make it very clear that everyone should answer the +question, and thus it should be very broad. The point is to make sure +they know how to use the tools. Make sure that the question feels +inclusive - not just that people can answer, but that it doesn’t make +people feel they are far behind others.

+

If you ask people to add there name as part of an introduction, the +document becomes personal data and must be controlled more, and sets +you on a path to extensive editing before it can be released. Think +before you do this - maybe you just ask for information about +backgrounds without names.

+ +
+

Relevant to workshop

+

An icebreaker isn’t supposed to be relevant to the workshop, but it +could be useful some days or as a second question.

+
    +
  • What from this workshop are you going to use in the near future?

  • +
  • What was the most confusing thing from yesterday?

  • +
  • Have you already used what you have learned in the course during +your work? If so, what?

  • +
  • What is the most useful thing you know, that you wish someone had +just told you about computing when you first started it?

  • +
+
+

Adapted from pre-workshop survey

+
    +
  • What is the operating system that you will use during the course (on your laptop)?

    +
      +
    • macOS

    • +
    • Linux

    • +
    • Windows

    • +
    • Other

    • +
    +
  • +
  • Have you used version control? If yes, which?

    +
      +
    • I don’t know what it is

    • +
    • I haven’t used version control but I know what it is

    • +
    • I have used version control, but I don’t know which system

    • +
    • Git

    • +
    • Mercurial

    • +
    • Subversion

    • +
    • CVS

    • +
    • Perforce

    • +
    • Bazaar

    • +
    • Other

    • +
    +
  • +
  • Which programming languages are you using or will you use in your projects?

    +
      +
    • Matlab

    • +
    • R

    • +
    • Python

    • +
    • Perl

    • +
    • C

    • +
    • C++

    • +
    • Fortran 77

    • +
    • Fortran 90+

    • +
    • Julia

    • +
    • Haskell

    • +
    • Go

    • +
    • Rust

    • +
    • Other

    • +
    +
  • +
  • Are you using automated testing platforms (e.g. Travis CI, Jenkins or GitLab CI) in your programming project(s)?

    +
      +
    • No and I don’t know what it is

    • +
    • No but I know what it is

    • +
    • Yes

    • +
    +
  • +
  • Are you employing code review in your programming project(s)?

    +
      +
    • No and I don’t know what it is

    • +
    • No but I know what it is

    • +
    • Yes

    • +
    +
  • +
  • Are you using the Jupyter Notebooks in your programming project(s)?

    +
      +
    • No and I don’t know what it is

    • +
    • No but I know what it is

    • +
    • Yes

    • +
    +
  • +
  • Are you using a web-based repository for your code(s)? Which ones?

    +
      +
    • I’m not using a web-based repository

    • +
    • GitHub

    • +
    • GitLab

    • +
    • Bitbucket

    • +
    • Redmine

    • +
    • source.coderefinery.org

    • +
    • Other

    • +
    +
  • +
  • How would you describe your programming experience?

    +
      +
    • I have no programming experience

    • +
    • Basic understanding and experience, I have looked through code and made minor adjustments

    • +
    • I have written my own simple programs

    • +
    • I have written many small codes and/or contributed to large complex software

    • +
    • I am an expert

    • +
    +
  • +
  • How comfortable are you with the Unix/Linux command line working in a terminal window?

    +
      +
    • I know what most of the following commands do: cd, ls, cat, mv, rm, chmod, man, mkdir, cp, ssh

    • +
    • I do not know what most of these commands do

    • +
    +
  • +
  • Please mark the sessions that you are most interested in.

    +
      +
    • Introduction to version control

    • +
    • Documentation

    • +
    • Jupyter notebooks

    • +
    • Collaborative distributed version control

    • +
    • Managing complexity and modular code development

    • +
    • Automated testing

    • +
    • Git branch design

    • +
    • Software licensing

    • +
    • Reproducible research

    • +
    +
  • +
+
+
+
+

General questions

+
    +
  • What’s a good icebreaker question?

  • +
  • How is the weather where you live?

  • +
  • How are you doing?

  • +
  • Are you happy to continue this workshop for another week?

  • +
  • Is that an Iphone?

  • +
  • If you could have anything what you want for dinner today, what would it be?

  • +
  • What cool thing/tool have you discovered/learned the past days? +(independently of this course)

  • +
  • Is this course part of your work? Or do you spend free time on it?

  • +
  • Do you like olives?

  • +
  • Are you annoyed at the size of anaconda?

  • +
  • What’s your favourite pizza?

  • +
  • Do pineapples :pineaplle: belong on pizza?

  • +
  • What did you have for breakfast?

  • +
  • Do you like Python?

  • +
  • Where’s your favorite place to nap?

  • +
  • Do you use git or identify as one?

  • +
  • When and how did you learn to program?

  • +
+
+
+

Credits

+

Most of these questions came from a “What is an icebreaker” question +in the first Mega-CodeRefinery workshop.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..bd0f5fb5 --- /dev/null +++ b/index.html @@ -0,0 +1,246 @@ + + + + + + CodeRefinery operation manuals — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CodeRefinery operation manuals

+

This site contains various manuals about CodeRefinery workshops and +teaching/lesson development in general.

+

These pages document past history, but they don’t dictate future. +They are a starting point: feel free to be adventurous.

+ + + + + + +

Download this guide as single-page HTML, +pdf, or +epub.

+

All material within this repository is licensed CC-BY.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/indico/hints/index.html b/indico/hints/index.html new file mode 100644 index 00000000..de7257a4 --- /dev/null +++ b/indico/hints/index.html @@ -0,0 +1,215 @@ + + + + + + Indico hints — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

Indico hints

+
+

Emailing people

+
    +
  • Go to registration list

  • +
  • Filter people based on who you need

  • +
  • Select all (this selects only the visible people; you can confirm +this by looking at the names in the email box, though you can’t see +them all our count them)

  • +
  • Actions → Email

  • +
  • Compose your email (warning: it is easy to lose everything, there is +no saving)

  • +
  • Preview email to make sure it works

  • +
  • Ensure that it is sent from support@coderefinery.org

    +
      +
    • If you want a real test, you could register and send the first +draft to yourself (make sure you copy the full text first, +otherwise you lose the placeholders)

    • +
    +
  • +
  • Copy full text before you send the email, otherwise you lose the +form fields.

  • +
  • Click send

  • +
  • Don’t worry

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/indico/in-person/index.html b/indico/in-person/index.html new file mode 100644 index 00000000..56f8d172 --- /dev/null +++ b/indico/in-person/index.html @@ -0,0 +1,198 @@ + + + + + + Indico in-person workshop workflow — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Indico in-person workshop workflow

+
+

Flow

+
    +
  • People register

  • +
  • Confirm the people you want to accept.

  • +
+

TODO: Is there anything else to note?

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/indico/index.html b/indico/index.html new file mode 100644 index 00000000..4014ba8f --- /dev/null +++ b/indico/index.html @@ -0,0 +1,222 @@ + + + + + + Indico registration system — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Indico registration system

+

This describes the Indico registration system as used by +CodeRefinery. Indico is a open-source registration system suitable for large +scientific meetings. NeIC runs one at https://indico.neic.no which we +routinely use.

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/indico/online/index.html b/indico/online/index.html new file mode 100644 index 00000000..2c4b51de --- /dev/null +++ b/indico/online/index.html @@ -0,0 +1,253 @@ + + + + + + Indico online workshop workflow — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Indico online workshop workflow

+

This describes the workflow in Indico online workshops

+
+

Basic types

+

Registration types = {Learner, team leader, Livestream only}

+
+
+

Flow

+
    +
  • People may register in any of the types.

  • +
  • When people get accepted to Type={Learner,team leader}, they are +confirmed using the Indico moderation “approve registrations” +feature. (These people then become State=Completed)

  • +
  • After soft deadline, accept the number of learners you think you can +handle (see above).

    +
      +
    • Non-accepted people are moved to Type=Livestream but this is +mainly to help them, people can still register.

    • +
    +
  • +
  • A new field “I confirm I can attend via Zoom” is made visible. +Everyone in State=Completed is expected to log in and click this +box.

    +
      +
    • Other non-accepted people

    • +
    +
  • +
  • Those who do not make Confirm=Yes are moved to Type=Livestream.

    +
      +
    • Note: any saving of the form, even by staff, will set +Confirm=No. So Confirm=No does not mean that they declined, +it could also be staff who saved the form.

    • +
    +
  • +
  • If there are remaining free spots, they are given to those who are +Type=Livestream Confirm=Yes.

  • +
  • Everyone else is set to Type=Livestream

  • +
  • The event registration form is edited, so that the number of +Type=Learner spots is set to the actual number registered. Then, +no one else can register as a learner.

    +
      +
    • This could be done a bit earlier in the process, but it prevents +even organizers from moving people between categories. Thus, it’s +slightly more convenient to leave it free than have to adjust the +registration form every time you need to switch someone to learner +(for example, registering on a team)

    • +
    +
  • +
+
+
+

Email filters

+

During registration

+
    +
  • People who want to in Zoom, State!=Withdrawn Type={Learner,Exercise Leader}

  • +
+

After confirmation

+
    +
  • People in Zoom, State!=Withdrawn Type={Learner,team leader}

  • +
  • PEople in livestream, State!=Withdrawn Type=Livestream

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/indico/setup/index.html b/indico/setup/index.html new file mode 100644 index 00000000..8bfd606a --- /dev/null +++ b/indico/setup/index.html @@ -0,0 +1,300 @@ + + + + + + Indico event setup — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Indico event setup

+

We use the NeIC Indico service, https://indico.neic.no/, so you need to create +an account at https://indico.neic.no/login/.

+

Radovan is manager of the CodeRefinery category in +indico.neic.no and will need to grant you permissions to create event pages.

+

To create a new workshop page, it is easiest to clone a previous event. This +copies the registration form and metadata, but not the pre-workshop survey +which needs to be manually imported as a json file.

+
+

Step-by-step instructions:

+
+

Copy basics from latest event

+
    +
  • Visit https://indico.neic.no/, and click CodeRefinery which takes you to https://indico.neic.no/category/5/.

  • +
  • Click the latest workshop event. You might need to show “events in the future” to see the latest event.

  • +
  • Go to admin mode (click the pen symbol on top toolbar, “Switch to the management area of this event”).

  • +
  • Click the “Clone” button, and select “Clone Once”. Click “Next” button.

  • +
  • For “What should be cloned”, select +“Registration forms” (do not clone “ACLs and protection settings”). +Uncheck “Refresh user information”. Click “Next”.

  • +
  • Confirm category “CodeRefinery”, and click “Next”.

  • +
  • Select the start date and time of the workshop, click “Clone”.

  • +
  • You are now on the cloned event page (confirm that the event number changed), and you should start updating the information.

  • +
+
+
+

Update copied event information

+
    +
  • Adjust permissions so that only the workshop organizer(s)/coordinator(s) has/have access to the forms and data. +In order to have better control over who has access we do not copy “ACLs and protection settings” from older events.

  • +
  • Update the Title, Description, Date, Time, Room, Venue and Address fields by clicking the pen symbols on the right.

  • +
  • Click “Protection” and remove administrators who were copied from past event but should not have access to this event.

  • +
  • Click “Registration” from the left-hand menu, and confirm that there is one or two registration forms, probably with a wrong title.

  • +
  • Click the “Manage” button on the “List of registration forms”,

    +
      +
    • Click “Edit” on the “General settings”

    • +
    • Update the registration form name and both the fields “Contact info” and “List of recipients” with your own email address to get notifications on new registrations.

    • +
    • Waiting list:

    • +
    • Indico doesn’t have an actual waiting list functionality. To implement a waiting list, we use moderated registrations and confirm all registrations up to max capacity (eg. 40). Registrations after that up to maximum number of participants (eg. 60) are left unconfirmed and an email is sent manually from Indico to the registrant that they are on the waiting list. Now we have a waiting list of size 60 - 40 = 20.

    • +
    • Activate “Moderated” which will require each registration to be approved.

    • +
    • Set maximum number of participants (after which registration is closed), this should be room capacity + waiting list size. Click “Save”.

    • +
    • Then go back to “Manage” and verify and configure the “Registration Form”: +read all fields and check that nothing outdated has been cloned to this +event. Adapt the dates.

    • +
    +
  • +
+
+

More information about the registration process

+
    +
  • The Description field in the general settings should contain additional information about the registration process:

    +
    Welcome to the registration page for the Online CodeRefinery workshop March 22-24 and 29-31!
    +
    +To complete your registration, you need to:
    +
    +1) Enter your registration details by clicking the "Register now" button below.
    +2) Fill in the pre-workshop survey by clicking the "Fill out the survey" button below.
    +
    +Confirmation email
    +After filling out the registration form you will receive an automatic
    +confirmation email, but please note that all registrations go to a waiting
    +list first. Please contact to support@coderefinery.org if you don't receive
    +this confirmation email within a couple of days after signing-up. 
    +
    +Questions?
    +If you have any questions about your registration status, please write to support@coderefinery.org.
    +
    +Looking forward to seeing you at the workshop!
    +
    +
    +
  • +
+
+
+
+

Import survey

+
    +
  • Now click “Surveys” from the left hand menu. You will now import the standard pre-workshop survey from a json file.

  • +
  • Go to https://github.com/coderefinery/pre-workshop-survey and clone the repository.

  • +
  • Go back to the Indico Surveys page, and click “Create survey”

  • +
  • Name the survey “Pre-workshop survey”, enable the option “Anonymous submissions” and disable “Only logged-in users”. Click “Save”.

  • +
  • Back on the “Surveys” page, click “Manage” on the newly created “Pre-workshop-survey” survey.

  • +
  • It will say “Survey not ready”. Click “Prepare questionnaire”.

  • +
  • Click the “Import” button, click “Choose from your computer”, and find the file exported-survey.json” from the pre-workshop-survey repository you cloned. Click “Save”.

  • +
  • Go back to the survey page (click “Surveys” on the left), and click “Manage”. Click the “Open now” button to let the survey go live.

  • +
+
+
+

Open registration

+
    +
  • Go to the Registration page from the left-hand menu, and click “Manage”.

  • +
  • It will say “Registrations are not open yet”. Click “Start now” for both regular and staff registration forms to open for registrations.

  • +
  • Click the blue “Switch to display view” on the top left.

  • +
  • Confirm that both the “Surveys” and “Registration” links can be seen.

  • +
  • Click both links to do a test registration

  • +
  • Once you manage to test-register, update the workshop webpage, and announce via Twitter.

  • +
+
+
+

Exporting registrations

+
    +
  • Go to the Registration page from the left-hand menu, and click “Registrations” which +takes you to the list of registrations..

  • +
  • Click the check-box on the menu just above the list of registrations and select “All”.

  • +
  • Click on “Export” from the top menu, select “CSV” and choose a download directory.

  • +
  • You can use the read_csv.py to parse the CSV file and print +selected fields, e.g. email addresses to be used in sending out information to +participants.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/instructor-intro/index.html b/instructor-intro/index.html new file mode 100644 index 00000000..26fd9a9c --- /dev/null +++ b/instructor-intro/index.html @@ -0,0 +1,364 @@ + + + + + + Instructor introduction — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructor introduction

+

This page gives general instructor and expert helper introduction +material. These people are responsible for more than one breakout +room, and have to have an overview of more of the course. In short, +if you want to take the next step in CodeRefinery, this is the place +to start.

+
+

See also

+

Co-instructors for an intro for starting co-instructors.

+
+
+

How do you get started?

+

That’s what this page is about (well, and the instructor +training). We +believe that you best learn by working with others in practice, and +provide plenty of opportunities to do that.

+
+
+

Starting materials

+

Reading here: the other pages in the section, see sidebar.

+ +

Also read the team leader information

+ +

Reading elsewhere:

+ +
+
+

As an instructor

+

Most of our workshops are very collaborative arrangements: you are +rarely alone. This is one way of looking at it:

+
    +
  • Look at and revise the workshops before they teach, making small, +incremental improvements. But, you don’t have to (and in some +sense, it’s good if they stabilize some more).

  • +
  • Especially go over the examples when preparing.

  • +
  • Have a chat with someone else (probably another instructor or +expert helper) before teaching. We encourage this for +everyone, even experienced instructors, to better transfer knowledge +among each other and stay up to date with the latest developments.

  • +
  • Teach independently or co-teach. Ideally, co-teach the first +time(s). Really, we’d like to get to the point where we always +co-teach. Co-teaching doesn’t mean different people take different +lessons, but two people teach all parts of the same lesson by +turning it into a discussion between the two instructors. TODO: +produce information on this.

  • +
+
+

in the main session

+

As an instructor, when preparing your lesson you first need to decide how to balance between the +main room and breakout sessions.

+
    +
  • Clearly say when a learner watches, when they type along, when they should +work on something independently as an exercise.

  • +
  • CodeRefinery is traditionally a hands-on workshop, so breakout-room sessions should be a large part of the workshop.

  • +
  • We usually keep the main room mostly for general discussions. Small exercises or polls can also be done in the main room, for all hands-on exercises we divide the learners into breakout-rooms each with one team leader.

  • +
  • To give you an idea about how the work in the breakout rooms is going, monitor the hackmd closely and if time allows try to visit a few breakout rooms to see how it is going and if needed adjust the timing.

  • +
+
+
+

Preparing for the breakouts (in the main room)

+

As an instructor, you need to clearly define what the tasks of each +breakout session is (even if it is just “explore and discuss”). +Online courses need more “meta talk” about how you expect things +to go, since it’s not as easy to read the room or fill in expectations +later (distractions, hard to communicate to breakout rooms after +opened).

+
    +
  • Clearly say what the tasks of the breakout session will be.

  • +
  • Put that task and a link to the part of the lesson in the hackmd.

  • +
  • Clearly say how long each breakout session will be (make sure it’s +long enough and adjust during the exercise session if needed)

  • +
  • Clearly say if things in the future will depend on this exercise (is +someone completely lost if they don’t make it to the end. Halfway?)

  • +
  • Try to make breakout sessions longer:

    +
      +
    • imagine a 5 minute overhead for each session, getting people +there, deciding who does what, acquainted with what they need to +do, and debugging problems.

    • +
    • 10 minutes is quite short, 20 minutes is best.

    • +
    • Can you say less and let people discover it for themselves?

    • +
    +
  • +
+

As a team leader, if anything is unclear to you, it is very unclear to +others. Comment/Ask in the HackMD or speak up and ask!

+
+
+
+

Top issues new instructors face

+
+../_images/s10-kickstart-prompt-log.png +

An example of a beautiful screenshare. Note the portrait orientation +(you have half the screen free for notes and HackMD, learners have +half the screen free to do their own work). The terminal is +dark-on-light, a minimal prompt, no other fancy shell distractions, +there is a shell history visible, and slightly distinct colors between +the web browser and the terminal.

+
+
    +
  • Breaks are not negotiable, minimum 10 minutes.

  • +
  • Breakout sessions too short. Make them as long as possible, don’t +expect to come back for new intro, then go back.

  • +
  • People will accomplish less than you expect. Expect learners to be 5 +times slower than you, at best!

  • +
  • All the other tools and stuff will go wrong. Try to not bring in a +dependency when you don’t need it.

  • +
  • Trying to accomplish too much: it’s OK to cut out and adapt to the +audience. Have a reserve session at the end you prepare, but are +ready to skip.

  • +
  • Not clearly separating (in the learner’s mind, by meta-talk), the +differences between demo, type-along, and +exercise/exercise-prep.

    +
      +
    • Demo and type-along are hard to do at the same time: they are very +different types of focus

    • +
    • Type-along and exercise of the same thing are not good to combine, +leads to duplication

    • +
    +
  • +
  • Explaining how, but not why.

  • +
  • Running out of time to making your environment match the +learner’s.

  • +
  • Running out of time to set up good screen sharing practices +(terminal history, portion of screen, remote history) in advance.

  • +
  • Assuming learners remember what they have already learned, or know +the prerequisites. Or have stuff installed and configured.

  • +
  • Not managing expectations: learners think that you will accomplish +everything, and feel sad when you don’t. Instead, say explicitly +what everyone should follow along, what you might want to watch, +what is only a demo.

  • +
  • Following the lesson as written at all costs.

  • +
+

For livestream courses:

+
    +
  • Worrying too much (forgetting that there is a co-teacher and break +time where you can discuss and plan your next step).

  • +
  • Speaking like learners should be able to speak up with voice, +instead of “answer in HackMD or discuss within your groups.”

  • +
  • Forgetting to save time for Q&A: there is more Q&A because of +HackMD. You might take a few minutes to screenshare HackMD and +after each exercise session, after each break, after each episode, +and at the end of each day.

  • +
  • “Stop screenshare” instead of letting the other person start and +take it from you. Or, the broadcaster switching the scene. Never +do “stop screenshare”.

  • +
  • Forgetting to screenshare the HackMD during Q&A time (this is the +most important way learners know it is active, and thus feel a +connection to the course).

  • +
  • Forgetting there are multiple ways to attend: not everyone is in a +breakout room, not everyone has helpers nearby. Instead, use +phrasing such as “for those of you in breakout rooms, go there now. +Everyone, remember to ask any questions in the HackMD, even if you +are alone.”

  • +
  • Planning to do a demo during team breakout sessions (teams will +still hear your voice, if they mute the stream it’s hard to bring +them back).

  • +
  • Sharing a fullscreen, not the 840x1080 portrait layout.

  • +
  • Showing non-creative-commons material on the stream.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/instructor-stream/index.html b/instructor-stream/index.html new file mode 100644 index 00000000..4e5c3e8e --- /dev/null +++ b/instructor-stream/index.html @@ -0,0 +1,258 @@ + + + + + + Being an instructor in livestreamed CodeRefinery workshop — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Being an instructor in livestreamed CodeRefinery workshop

+
+

Basic setup

+

In a livestreamed CodeRefinery workshop, we have two types of learners: Active learners attending in Zoom and passive learners watching the stream. +Learners from both groups will watch the stream from their own browser and have the possibility to interact with the instructors and ask questions via HackMD +(a collaborative note taking tool: Collaborative document mechanics and controls). +Active, registered learners will additionally get interactive help in Zoom breakoutrooms during exercise sessions. +Learners on stream can either form private groups or do the exercises on their own. +Following our team teaching strategy, your are never alone as an instructor. While you are teaching, you can fully focus on the task at hand, your co-instructor will watch the chat and HackMD and relay all important information to you.

+
+
+

I am teaching in a workshop, what do I need to know/do?

+
    +
  • Attend the instructor onboarding session (Instructor introduction)

  • +
  • Make sure you have your tech setup for the course: Instructor technical setup, online

  • +
  • Consider joining the learners Zoom to help in breakoutrooms and answer questions in HackMD

  • +
  • When your teaching time approaches, join the instructors Zoom.

    +
      +
    • Stay muted and turn your video off until it is your turn to teach

    • +
    • Setup your windows that you want to share during teaching

    • +
    • When it is your turn to (co-)teach,

      +
        +
      • All co-instructors, turn on your video

      • +
      • Unmute yourself only when talking

      • +
      • Share only the important portion of your screen in vertical mode

      • +
      • If you need a reaction from learners, use HackMD

      • +
      • Co-Instructor watches HackMD and relays important information/questions

      • +
      • Exercises: clearly state which exercises should be done and at what time the teaching continues

      • +
      +
    • +
    +
  • +
  • After your lesson, consider joining learners Zoom

  • +
  • If you can, join after-course-day-hangout with other instructors

  • +
  • Give feedback on your teaching experience with CodeRefinery

  • +
+

We have also collected a lot of material around teaching which you are free to read:

+ +
+
+

Why team teaching?

+

-> see also Team teaching

+
    +
  • makes lesson more lively

  • +
  • less chance of forgetting something essential

  • +
  • one of the instructors can watch for good questions in HackMD and ask/answer them on stream

  • +
  • less stressful for the individual

  • +
  • easier to include new instructors

  • +
  • easier debugging, finding typos etc on stream

  • +
  • you are not alone

  • +
+
+
+

Why livestream?

+

A livestream workshop allows us to reach an unlimited number of people, at the cost of not being as interactive as in classroom/zoom room. +However, we have had great experiences with the following strategy:

+
    +
  • HackMD as collaborative note-taking tool allows learners to ask questions anonymously and everyone can answer these questions asynchronously.

  • +
  • Learners can register to join Zoom breakout rooms, which are interactive and team leaders can help with any questions during exercise sessions and breaks.

  • +
  • Learners can also form private breakout rooms or meet in person and watch the stream and do exercises together.

  • +
+

While the full livestream setup is a bit complicated, you as an instructor do not have to worry about anything but your teaching. +We have setup the whole system in a way that only active instructors are shown in stream, which makes video postproduction faster. +What makes our setup different from your ‘usual zoom class’ is that our instructors Zoom room that you are in while instructing is completely separate from the learners, while providing interaction possibility via HackMD.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/instructor-tech-online/index.html b/instructor-tech-online/index.html new file mode 100644 index 00000000..e5517797 --- /dev/null +++ b/instructor-tech-online/index.html @@ -0,0 +1,336 @@ + + + + + + Instructor technical setup, online — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructor technical setup, online

+
+

See also

+

This is online-specific instructor tech setup. For general, see +Instructor technical setup which also applies here.

+
+

The information in this is currently specific to Zoom teaching and +livestream teaching.

+
+

Final checklist

+

See the list in Instructor technical setup, which includes points for +online.

+
+
+

Audio

+

Audio quality, and balance between instructors, is absolutely +critical to good online work, especially teaching. Consider the +following:

+
    +
  • Can you adjust your microphone volume from very low to +higher-than-needed? Make sure your dynamic range is larger than +“barely working”, so that you have some room to adjust for later.

  • +
  • Do you have a high-quality headset? A headset with microphone is +the most reliable, but if you can get a desktop setup working +well, that can be good too. Always have a high-quality headset for +backup anyway.

  • +
  • If you have a bluetooth headset, consider:

    +
      +
    • Bluetooth headsets have significant latency compared to wired or +purpose-built wireless protocols like gaming headsets have.

    • +
    • The microphone might not have enough bandwidth (if it’s part of +the same headset).

    • +
    • Bluetooth 5 is much better in both latency and quality.

    • +
    • Consider investing (or getting your work to invest in) some +high-quality headset or desktop audio gear.

    • +
    +
  • +
  • “Ducking” is when the first words are silenced/quieted by noise +cancellation, until it detects speaking. To avoid this, don’t use +“high” noise cancellation (as low as possible is better). If you +need high cancellation because of background noise, switch to your +headset.

  • +
+
+
+

Screen sharing

+

You have to assume the smallest screen from learners and plan for +that. You should share a portrait screen: either a portion of +your screen, or one window in portrait mode. See the examples below.

+
    +
  • Learners have a small screen, and need room for their own terminals +and web browser open, too. A big screen or multiple monitors is +the special case.

  • +
  • Sharing a 1920x1080 screen is not a good idea: you need to make all +the text size large so that learners can scale it down to have room +to do their work. Pixels are wasted. Instead, force yourself to +save space by using a normal font size but sharing less of your +screen.

  • +
  • Zoom now has a “share portion of screen” (Screen sharing → Advanced +→ Share a portion of the screen).

  • +
  • For livestreaming, our aspect ration is 840×1080 (portrait). +This is a bit less than half your screen. This is 43% of the width +of your screen and the full height, for a standard FullHD screen.

  • +
+

When streaming/recording: Never stop sharing a screen, ask someone +else to take it over. +There is a chance that the view goes to “gallery view” in the +recording or stream, which makes video editing harder or disrupts +learner privacy.

+
+

Screen share examples

+

These are layouts of the actual screen or portion of screen being +shared:

+
+../_images/screenshare-fullhd.png +

S1: A FullHD 1920x1080 screen shared.

+
+
+../_images/screenshare-vertical.png +

S2: A vertical screen layout shared. Note the extra shell history at the +top. The web browser is at the bottom, because the Zoom toolbar can +cover the bottom bit.

+
+
+../_images/screenshare-jupyter.png +

S3: A sort-of GUI (Jupyter) shared vertically.

+
+
+../_images/screenshare-rsh.png +

S4: This isn’t a screenshare from CodeRefinery, but may be instructive. +Note the horizontal layout and shell history at the bottom right.

+
+
+../_images/s5-shell-intro-dark.png +

S5: Similar to above, but dark. Includes contents on the right.

+
+
+../_images/s8-modular-code-development.png +

S8: Jupyter + terminal, including the fish shell and the +terminal history.

+
+
+../_images/s9-git-intro.png +

S9: Similar to S8. Lesson + terminal, tmux plus terminal history +and dark background.

+
+
+../_images/s10-kickstart-prompt-log.png +

S10: HPC Kickstart course. Note the colors contrast of the +windows and colors of the prompt and text. The history is smaller and +doesn’t take up primary working space. The working directory is +in the window titlebar.

+
+
+
+

Screen layout: learners

+

This is how learners can arrange their screen:

+
+../_images/learner-largescreen.png +

L1: Learner with a large screen, Zoom in dual-monitor mode so that the +instructur pictures are not shown. Screenshare is on the left side, +HackMD at bottom left, terminal and web browser on the right.

+
+
+../_images/learner-normal.png +

L2: A learner with a single large screen (Zoom in “single monitor mode”). +Instructor screen share at right, learner stuff at left.

+
+
+../_images/learner-small.png +

L3: A learner with a particularly small screen. Instructur screenshare at +left, your windows at right.

+
+
+
+
+

Screen layout: instructors

+

This is what the instructor sees on their screen:

+
+../_images/instructor.png +

I1: Vertical instructor setup. Zoom is sharing a portion of the left +side, the right side is free for following HackMD, chat, etc (but +don’t overload yourself).

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/instructor-tech-setup/index.html b/instructor-tech-setup/index.html new file mode 100644 index 00000000..4484d0c6 --- /dev/null +++ b/instructor-tech-setup/index.html @@ -0,0 +1,494 @@ + + + + + + Instructor technical setup — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructor technical setup

+
+

See also

+ +
+
+

Final checklist

+
    +
  • Have you moved your configurations away and done the course setup +instead (or left it unconfigured)?: .bashrc (or equivalent), +.gitconfig, .ssh, .conda, etc.

  • +
  • Are you using a software environment as described in the workshop +instructions (conda, virtualenv, etc). Is it clean and without +extra stuff installed?

  • +
  • Is your setup as boring-looking as possible, if you are teaching at +the beginning of the workshop? The first sessions aren’t the time +for distractions.

  • +
  • Is your terminal

    +
      +
    • Dark text on light background?

    • +
    • Do you know key-bindings to change the font size quickly?

    • +
    +
  • +
  • Do you have command history set up? If in doubt, use +prompt-log and tail the +output in a separate smaller window.

  • +
  • Do you have a clean web browser session (different profile for +demos)?

  • +
  • If you use an advanced shell, do you have a simpler shell (bash) set +up for the demos?

  • +
  • (if online) have you practiced Zoom screensharing “Share a portion +of the screen” in portrait-mode? See +Instructor technical setup, online.

  • +
  • (if online) have you checked your audio settings? Join a test +meeting with someone and understand your microphone sound +adjustments. Can you control it for the full range from very quiet +to very loud, so that you can make whatever adjustments needed? Is +your best microphone/headset ready? Audio quality and balance is +critical.

  • +
  • Have you shown your setup to someone else for feedback?

  • +
+
+

Appearance matters. When you look at other professionally made videos +online, they look good. As a presenter, you also need to work to make +your screen look pleasing to the eye. It also has to be similar to a +learner’s screen, so that they are not distracted with your different +configuration or appearance.

+
+

Simple or fancy screen?

+

As a teacher of tech, you also +need to make sure that your screen supports the learning process: +you have conflicting goals of:

+
    +
  • Making your screen look simple, to not distract from what you are +trying to teach, and

  • +
  • Showing more advanced setups, so that others can learn and improve.

  • +
+

In general, try to use a simpler arrangement at the beginning of +workshops. You, or other teachers, can begin showing more advanced +screen layouts once learners are able to see what is important and +what is extra.

+
+
+

Check with someone before you start teaching

+

Most importantly, get your setup done well in advance and show your +co-teachers for feedback. Feedback and time to improve is very +important to make things beautiful.

+
+
+

Clean your environment

+

Do you have fancy .bashrc, .gitconfig, etc files? Move them +away so that you are as plain and normal as possible - beyond +appearances, you don’t want to use any shortcuts that every learner +won’t have access to (telling learners to add some configuration won’t +work - some will miss it and be lost, or worse their system may have a +weird behavior in the future).

+

Relevant files that are sometimes a problem:

+
    +
  • .bashrc

  • +
  • .gitconfig

  • +
  • .ssh/config, .ssh/authorized_keys

  • +
  • .conda/*

  • +
  • Any config for any program you will be demonstrating

  • +
+
+
+

Arrange your windows well

+

This is mostly the topic of Instructor technical setup, online (our +recommendations for in-person window arrangements aren’t so +up-to-date, but the same principles apply but you have a widescreen +view).

+
    +
  • For online teaching, you will want to screenshare a portion of your +screen: half the screen in “portrait mode” so that the other half is +available. See Instructor technical setup, online.

  • +
+
+
+

Desktop environment

+
    +
  • Is your overall desktop environment “normal”-looking?

  • +
  • Do your window title bars take up lots of space? Is it possible to +reduce their size for the teaching - you want as much space for +large fonts as possible.

    +
      +
    • Since you will only be sharing a portion of the screen, or have a +lower-resolution projector, these title bars take up more space +relative to the content.

    • +
    +
  • +
  • Same for desktop menu bars, etc.

  • +
  • Do you need to go into light-mode theme? Dark text on light +background is much better than dark mode, so it is strongly +recommended to do this.

  • +
  • Can you easily resize your windows for adjusting during teaching?

  • +
+
+
+

Web browser

+
    +
  • Are you doing a lot in a web browser? Consider making a separate +profile that is just for demos.

  • +
  • Install whatever basic safety extensions / ad blockers are most +relevant, but keep it simple otherwise.

  • +
  • Can you turn off unneeded menu- and toolbars?

  • +
  • Does your web browser have a way to reduce its menu bars and other +decoration size?

    +
      +
    • Firefox-based browsers: go to about:config and set +layout.css.devPixelsPerPx to a value slightly smaller than one, +like 0.75. Be careful you don’t set it too small or large since +it might be hard to recover! When you set it to something smaller +than 1, all window decorations become smaller, and you compensate +by zooming in on the website more (you can set the default zoom to +be greater than 100% to compensate). Overall, you get more +information and less distraction.

    • +
    +
  • +
+
+
+

Terminal

+
+

Terminal color schemes

+
    +
  • Dark text on light background, not dark theme. Research and our +experience says that dark-text-on-light is better in some cases and +similar in others.

  • +
  • Make a dedicated “demos” profile in your terminal emulator, if +relevant. Or use a different terminal emulator just for demos.

  • +
  • You might want to make the background light grey, to avoid +over-saturating people’s eyes and provide some contrast to the pure +white web browser. (this was an accessibility recommendation when +looking for ideal color schemes)

  • +
  • Do you have any yellows or reds in your prompt or program outputs? +Adjust colors if possible.

  • +
  • Eliminate menu bars and any other decoration that uses valuable +screen space.

  • +
+
+
+

Clearing the terminal

+
    +
  • Don’t clear terminal often (or ever - un-learn CTRL-L if possible). +Learner’s can follow as fast as you! More people will wonder what +just got lost than are helped by seeing a blank screen. Push +ENTER a few times instead to add some white space.

  • +
+
+
+

Terminal size

+
    +
  • Font should be large (a separate history terminal can have a smaller +font).

  • +
  • Be prepared to resize the terminal and font as needed. Know and use +keyboard shortcuts for changing the font size when you need to show +more columns (it’s also OK if the terminal is wider than your screen +if most of the right side is not that important to see). You can +have a larger font normally, and make it smaller and the terminal +wider when you have long lines that learners need to see.

  • +
+
+
+

Prompt

+

Your prompt should be minimal: few distractions, and not take up many +columns of text.

+

Learners have to read your prompt quickly, understand what you +entered, copy it, all the while not being distracted by everything +else or your screen. Day 1 git-intro is not the time to have your +fancy git-bash prompt, instead show them how to use git to get that +information. Set an easily-viewable prompt.

+
    +
  • prompt-log (see the next section on command line history) does +this for you.

  • +
  • The minimum to do is is export PS1='\$ '.

  • +
  • Blank line between entries: export PS1='\n\$ '.

  • +
  • Have a space after the $ or % or whatever prompt character you +use.

  • +
  • Strongly consider the bash shell. This is what most new people will +use, and bash will be less confusing to them. (Later in workshops, +using other shells and being more adventurous is OK - learners will +know what is essential to the terminal and what is extra for your +environment).

  • +
+
+
+

Command line history

+

You need to find a way to show the recent commands you have entered, +outside of your main window, so that learners can see the recent +commands.

+

Consider prompt-log by rkdarst +(https://github.com/rkdarst/prompt-log/). It adds a interesting idea +that the command you enter is also in color and also provides +terminal history before the command returns (see below).

+

Arrange two terminals, so that there is the main work window and the +history window with a font smaller size - the history can be off to +the side.

+

See the following screenshot for an ideal arrangement:

+
+../_images/s10-kickstart-prompt-log.png +

S10: HPC Kickstart course. Note the colors contrast of the +windows and colors of the prompt and text. The history is smaller and +doesn’t take up primary working space. The working directory is +in the window titlebar.

+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/instructors/index.html b/instructors/index.html new file mode 100644 index 00000000..3c3f7e53 --- /dev/null +++ b/instructors/index.html @@ -0,0 +1,242 @@ + + + + + + Instructors — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Instructors

+

Instructors are the ones who “lecture” in the workshops - but of +course there are many other roles which are helping with the teaching, +most notably team leaders and other helpers.

+

This page links guides on various aspects of being an instructor.

+

Join the #workshops stream in the coderefinery Zulip chat and see what workshops are planned. +Below a few things that might be of interest if you want to teach with us:

+ +
+

Responsibilities of an instructor

+
    +
  • Review, triage, and work on lesson issues

  • +
  • Define exercises

  • +
  • Communicate exercise list to Exercise coordinator

  • +
  • Set up and test a quality screen share

  • +
  • Coordinate with co-instructor

  • +
  • Communicate software requirements to Instructor coordinator

  • +
  • Communicate timing adjustments to Instructor coordinator

  • +
  • After planning/editing the lesson: Do a dry run (prefereably with someone “new” to the topic)

  • +
+
+
+

From team leader/helper to more

+

Here is one possible pathway from learner to (whatever else). This is +an idea for a pathway but by no means a requirement - you can join +at whatever step you like, and steps don’t have to happen in order. +Maybe you are interested in some or the other. There are also roles +completely outside of this pathway.

+
    +
  • After being a learner, you come back as an team leader/helper.

  • +
  • When you have a solid understanding of all materials, you may join +as an expert helper.

  • +
  • You begin co-teaching episodes with someone else

    +
      +
    • We find that co-teaching is a good way to start. In this, there +are two people, one person assumes the big-picture discussion, and +the other the typing and explaining what they are doing. By +making the lesson a discussion instead of a lecture, it’s more +dynamic.

    • +
    +
  • +
  • Eventually, you get confident enough to teach yourself (though +really we should always be co-teaching…)

  • +
  • Somewhere in there (before or after instructor, depending on your +interests), you may want to try to be a HackMD helper or Zoom host. +These are more about coordinating all the other people involved in +the workshop.

  • +
+

Let’s emphasize again: this is one pathway, but you should do what you +want.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/lesson-design/index.html b/lesson-design/index.html new file mode 100644 index 00000000..2a46257e --- /dev/null +++ b/lesson-design/index.html @@ -0,0 +1,421 @@ + + + + + + Lesson design — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lesson design

+

This is a checklist and hints when writing and designing a new lesson. +The master material is in Teaching Tech Together, primarily chapters 6 +and 12 for practicalities and 2 and 4 for big picture considerations. +But really, all the book. See the summary we +made or the actual +book. The article Ten quick tips for creating an +effective lesson is +also a good summary of the main points. +Finally, the Carpentries Curriculum Development Handbook gives practical information on how to design a new lesson and covers the entire lesson life-cycle with a good overview of the lesson release timeline.

+

This doesn’t replace your own knowledge in doing the actual teaching +part. Instead, the first half gives pointers on making sure your +audience can connect to the material, and the last half gives hints +to help you come up with good exercises and examples.

+
+

Backwards lesson design

+

Think test-driven development: decide what you want students to be able +to do, design exercises to measure it, then fill in the gaps with +teaching. You can see their +summary. The steps are:

+
    +
  1. Brainstorm what you want to cover.

  2. +
  3. Create or reuse learner personas - understand who you want to +teach. What do they care about? Perhaps as important is what they +don’t care about: make sure that you don’t go too in depth too +early and turn people off.

  4. +
  5. Create some summative assessments, that show what learners should +learn by the end. Try to connect these to the learner personas.

  6. +
  7. Create formative assessments (exercises) that let the learners +practice what you want them to learn. See below for hints on coming +up with good exercises. These should also connect to things the +learners will actually do, but can also be more of checkpoints.

  8. +
  9. Put exercises in a logical order, and fill in any gaps. Ideally +there should be 15-20 min of teaching between each exercise. Perhaps +most are short (a few longer examples as needed), to identify a +certain learning goal and misconception.

  10. +
  11. Write just enough material to get from one exercise to the other.

  12. +
+

The most important point here is to start from learner’s needs and how +they can feel connected, not from the tech details.

+

When advertising the course, connect it to your learner personas so +that you get the right audience and they know why they should come.

+
+
+

Emotional and intrinsic appeal, other basics

+

You can think of why people should feel emotionally connected to your +material - maybe it’s too much to expect people to get emotionally +invested, but if you try for that, you’ll end somewhere better.

+

Try to design around tasks and exercises which your audience will care +about. For example, don’t say “here are some shell commands”, but +“aren’t you tired of copying all of these files one by one… check +out the shell… once you know it, you will really feel at home. Here +are some typical things you might do.”. Intrinsic motivators include +sense of agency (being able to do things themselves), competence +(usefulness of what they are doing, feeling they know something), and +relatedness (doing things that others are doing).

+

A manual is reference, a tutorial builds a cognitive model. If you +can build the cognitive model and tell them the “why”, students may be +able to refer to the manuals themselves and become self-sufficient. +Thus, teaching should be more of a +tutorial, with good links to manuals (it can also explicitly teach +how to use the manuals).

+

Perhaps a related point is inclusiveness: make sure there’s not some +“in” crowd. Perhaps the best description I have seen: don’t assume +that some people are missing something, but that others have had the +fortune of learning it earlier. This may not matter in a purely +factual lesson design, but if you are trying to make things +intrinsically or emotionally appealing, it is essential.

+
+
+

Who is the audience?

+

Making the learner personas are essential to making a good lesson, +even if you think you know who you are teaching to. This is because +it grounds you into what your audience already knows (or doesn’t know) +and what they are interested in.

+

You also have different ways people can refer to the material:

+
    +
  • In a class, with an instructor guiding them

  • +
  • Reading along by themselves

  • +
  • In a class, being much more advanced than others, so that they skip +ahead and do advanced material themselves.

  • +
+
+
+

Planning

+
    +
  • Do some planning, and document it - the design process helps +others to teach and modify. At least put it in the README. (this +is the designer/maintainer’s guide)

    +
      +
    • Put the main points from the “backwards lesson design process” in +here, enough that it is easier for someone to improve your lesson +than to redo it.

    • +
    +
  • +
  • Make learner personas: what is your target audience?

  • +
  • Decide learning objectives based on the personas: high-level end +goals. What students get out, not what they do.

  • +
  • Also make a guide for teaching (instructor’s guide), “if you +want to present this, do this”.

    +
      +
    • How much preparation is needed? Is it enough to know the topic +and have read the material?

    • +
    • Things to prepare before the presentation. Does anything need to +be set up?

    • +
    • Practical notes on presenting.

    • +
    • Are there solutions to exercises somewhere? Are they needed?

    • +
    • Include some pre-assessment questions which can be asked at the +beginning.

    • +
    • Perhaps you should do this at the end, but at least starting the +instructor’s guide at the beginning will frame your writing.

    • +
    +
  • +
+
+
+

Writing

+

There is not much here yet, mostly just follow the “backwards lesson design” +above. The hardest part is coming up with good exercises, so our +practical advice is to mix and match from the two taxonomies at the +bottom and the exercise types. Try to think of diverse types of +exercises.

+

Exercise design is the time it is most useful to be with others to do +brainstorming, so we highly recommend discussing with others at this +point. Because exercises are used to set the overall outline of the +lesson, this also gives people a say in the overall outline - in a +very concrete way.

+
    +
  • Make sure you include the emotional starting point at the beginning - why +should you care and why is this cool?

  • +
  • This should also be at the start and end of each section: not just what +or how, but why?

  • +
  • Part of this is also having a student’s guide, so that +people independently studying can know how to follow the material.

  • +
  • It’s OK to have more material than can be presented or than people +should know, but label things well, including labeling the difficulty.

    +
      +
    • In the beginning, what sections are expected to be taught in +short/long versions? What’s advanced/optional?

    • +
    • Label advanced and optional sections as such. Perhaps also really +basic sections that can be skipped for that reason.

    • +
    +
  • +
+

Plan for mixed abilities. It’s OK to have optional (basic) and +advanced sections, as long as they are clearly labeled. Mainly, don’t +have people think that you are uncoordinated because you are skipping +advanced sections.

+

Once you are done, update maintainer’s and instructor’s guides.

+
+
+

Introduction (and conclusion)

+

The introduction is the first thing people hear, and needs special +thought. Don’t start with a cold open, just going straight to the +topic (“what” or “how”). Instead, have some careful motivation +(“why”). It could be especially good to talk about what is wrong with +the current state of affairs (give a good, simple example) and why it +should be improved. Then start talking about what the improvements +are.

+

Ideally, the introduction should serve as an self-contained abstract +of your material. If you need to teach your lesson in only 10% of the +time you have, can you use just the introduction to do it?

+

Conclusion should remind people about why this is cool and discuss +what comes next.

+
+
+

Thinking of exercises

+

Not every exercise has to be an amazing hand-on example. It’s mixing +with smaller, more conceptual things to reduce the cognitive load and +be able to have more frequent exercises.

+

One of your other primary goals should be to make your exercises +relevant. Abstract will lead to disconnection. Connect the exercises +to the real world. Also, can you tell a complete story with +exercises? (Remember, in backwards lesson design, the exercises +form the story of the lesson.)

+

Remember that not every exercise has to be long. Try to have +frequent short exercises to get immediate feedback, with some long +ones.

+

Good exercises are the most important factor in a good lesson. Even +if you are preparing the rest of the lesson mostly alone, consider a +good long brainstorming session to go from “list of topics to cover” +to “sequence of exercises”.

+

When you are stuck thinking “how can I make an exercise that covers +X”, think of the lists below inspiration. Not every exercise has to be an +sophisticated hands-on thing, so don’t be afraid to use different +types:

+

Basic types:

+
    +
  • Multiple choice (easy to get feedback via a classroom tool - try to +design each wrong answer so that it identifies a specific +misconception).

  • +
  • Code yourself (traditional programming)

  • +
  • Code yourself + multiple choice to see what the answer is (allows +you to get feedback)

  • +
  • Inverted coding (given code, have to debug)

  • +
  • Parsons problems (working solution but lines in random order, +learner must only put in proper order)

  • +
  • Fill in the blank

  • +
+

More advanced:

+
    +
  • Tracing execution

  • +
  • Tracing values through code flow (e.g. what is the sequence of +values that x takes on?)

  • +
  • Reverse execution (find input that gives an output)

  • +
  • Minimal fix (given broken code, make it work)

  • +
  • Theme and variations (working code, adapt to other type of +situation/problem)

  • +
  • Refactoring

  • +
+

More conceptual:

+
    +
  • Draw a diagram

  • +
  • Label diagram

  • +
  • Matching problem: two sets of Q/A, match them.

  • +
+

Thinking through the learning taxonomies also helps to come up with +diverse types of exercises:

+
    +
  • Bloom’s taxonomy: hierarchical skill levels (can you help students +to “grow a level”?):

    +
      +
    • Remembering

    • +
    • Understanding

    • +
    • Applying

    • +
    • Analyzing

    • +
    • Evaluating

    • +
    • Creating

    • +
    +
  • +
  • Fink’s taxonomy: complementary types instead of hierarchical:

    +
      +
    • Foundational knowledge

    • +
    • Applications

    • +
    • Integration

    • +
    • Human dimension

    • +
    • Caring

    • +
    • Learning how to learn

    • +
    +
  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/lesson-review/index.html b/lesson-review/index.html new file mode 100644 index 00000000..52ea4d38 --- /dev/null +++ b/lesson-review/index.html @@ -0,0 +1,293 @@ + + + + + + Lesson review — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lesson review

+

This presents a checklist for reviewing lessons that already exist. +You should also read lesson-design.md as well - +this is roughly a checklist to the things there.

+

Remember to keep the story of the lesson in mind. Many people are +focusing on the small matters (during every change), but only +occasionally do people look at the big pictures. That’s why a proper +review starts with looking at the big picture, instead of adjusting +small things and possibly derailing the story.

+

This is roughly sorted from highest priority for short review to +lowest priority for big refactorings.

+
+

Issues

+
    +
  • Look through the issue tracker to see what is relevant, remember and +follow up when going through the sections below.

  • +
+
+
+

Lesson guides

+

Instructor’s guide:

+
    +
  • What sections should be taught for what audiences?

  • +
  • Common pitfalls when teaching

  • +
  • Any required setup in advance?

    +
      +
    • Any special config files that need to be cleared on instructor’s +computer when teaching?

    • +
    +
  • +
+

Maintainer’s guide:

+
    +
  • Learning objectives (necessary to know its place)

  • +
  • Learner personas (necessary to know its place)

  • +
  • After you’re done analyzing, is there anything in the maintainer’s +guide you need to update? (The maintainer’s guide is probably in +most cases the same as the instructor’s guide)

    +
      +
    • Design philosophy, how to modify while preserving the overall +character.

    • +
    +
  • +
+

Student reference guide:

+
    +
  • Anything to fix or already?

  • +
  • Keep this in mind when you get to episode details.

  • +
+
+
+

Lesson overview

+
    +
  • Is the introduction intrinsically motivating enough? Does it +promote an emotional connection to existing problems?

  • +
  • Student’s guide and framing: will a student know when this is +relevant to them and how it will benefit them?

    +
      +
    • Doesn’t need to include word-for-word learner personas, but should +convey this somehow.

    • +
    +
  • +
  • Are the difficulty and prerequisites stated?

  • +
+
+
+

Episode overview

+
    +
  • Read the intro and conclusion to every section/episode.

    +
      +
    • Do they make sense when you read them in order, without reading +the text in between?

    • +
    • Do they motivate each section well enough (not just explain what, +but why it’s cool?)

    • +
    +
  • +
  • Do they have learning objectives at top and food for thought at the +bottom?

  • +
  • Are optional or advanced episodes marked as such?

  • +
  • Does the episode (or lesson overall) say what is next, to keep +people interested in growth?

  • +
+
+
+

Episode details

+
    +
  • Read through each exercise (with no other text in between). Does it +make a logical progression?

  • +
  • Exercises labeled with difficulty, optional, etc.

  • +
  • Optional advanced exercises or material in places where advanced +users may get far ahead.

  • +
  • Each exercise is self-contained: a helper can read just the exercise +area and get an idea of what is supposed to happen and why.

  • +
  • Update the student’s reference guide as you are going through the +details.

  • +
  • Remove duplicate or unnecessary information when possible. Things +are always added, rarely removed. Shorter is usually better. If +something shouldn’t be removed, perhaps mark it as advanced or +optional.

  • +
+
+
+

Major Refactorings

+

Always start with the big picture: does it make sense? When +refactoring, always start off with backwards lesson design again (see +lesson-design.md) and fully go through that.

+

After the above, do the details. Remember the guides still.

+

Before you start major refactoring and rewriting, think if it makes +sense. Have you figured out why it’s the way it is based on the +instructor’s guide? If you do a big refactoring, make sure you update +the maintainer’s guide!

+

Before you embark on a big refactoring step, please pitch your idea +in a GitHub issue and collect feedback from others. Maybe even hold a +brainstorming session.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/livestream-teaching/index.html b/livestream-teaching/index.html new file mode 100644 index 00000000..fee46d19 --- /dev/null +++ b/livestream-teaching/index.html @@ -0,0 +1,297 @@ + + + + + + Teaching via livestreaming — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Teaching via livestreaming

+

We’ve all done a lot of teaching via Zoom, but the CodeRefinery +livestream is a new concept. This introduces teachers/helpers to the +idea (and for a detailed reference, see CodeRefinery MOOC strategy).

+
+

Video

+

Watch a demo on YouTube: https://www.youtube.com/watch?v=WjmttAniZX8. +(When watching, also carefully read the video description/chapter +titles, which provide more the explanation of what is going on).

+
+

Compared to Zoom teaching:

+
    +
  • You are in a Zoom meeting with only instructors/staff

  • +
  • Someone (not you) captures this meeting and broadcasts it via +livestream to all the audience.

  • +
  • The audience can’t directly talk with you (but when there is a large +audience, who does anyway?). Instead, always say things like “What +do you think? Write in the HackMD. [proceed to screenshare it and +discuss answers]”

  • +
  • You don’t need to worry much about managing the audience. Others do +this and relay information as you need. You should pay more +attention to HackMD.

  • +
+
+

Basic meeting setup

+

There is an “instructor Zoom meeting”. There are no students here, +and everything can and will be captured, recorded, published, and +livestreamed.

+
    +
  • In the call are instructors, the Zoom host, and possibly some other +helpers who might occasionally comment.

  • +
  • The cameras of instructors are captured via Zoom gallery view. +This is show as both a “teacher view” as well as “overlay on +screenshare”.

  • +
  • If you have your camera off, you will not appear in the stream. +So turn your camera off when you are in the instructor meeting but +not presenting. Ask others, but in principle it is fine to join, +stay hidden, and interact when relevant.

  • +
  • During the breaks/exercise times, the livestream itself (via OBS) +gets muted and switched to another scene. So, you are free to +unmute, talk, and chat with other instructors. This is a great way +to relax and prepare for the next segments! This actually lowers +the pressure to pre-plan every part in advance.

  • +
  • By the same token, you can join the meeting during the previous +break to get all set up.

  • +
  • Zulipchat serves as the overall connection between the different +parts of the course and instructor backchannel. This is the least +important place for the current active instructor to watch (but +might be useful for a co-instructor or expert helper to occasionally +check).

  • +
+
+
+

Screensharing

+

You can share your screen normally via Zoom. The livestream is fixed +to an aspect ratio of 840 pixels wide × 1080 pixels high (this is so +that the learner has half of their screen available). You can not +do a full landscape live-coding follow-along screenshare (nor is this +good practice in other workshops).

+
    +
  • In Zoom, you can either share one window or Advanced → Share a +portion of the screen → move the overlay to a portrait view. Don’t +worry about making it exactly 840×1080, OBS automatically fits it +and we can adjust it during the setup time.

  • +
  • If you have a landscape presentation (as opposed to live coding), +just share your whole screen, and the OBS operator will scale things +properly if it doesn’t automatically work. Note that the 4:3 aspect +ratio is better than 16:9, but that usually has black bars on the +side. This can be removed via OBS.

  • +
  • Don’t stop screenshare unexpectedly - wait for the broadcaster to +switch to gallery view. If you stop screenshare unexpectedly, the +stream reverts to someone picture full-screen. Because of Zoom +“dual-monitor mode”, sharing screen does not prevent the gallery +from showing.

  • +
+
+
+

HackMD and audience feedback

+

HackMD (or similar document-based things) is our preferred +communication system. The biggest problem is that it is too useful, +and too many people ask questions, which will easily overload you. To +solve this, we have co-teachers (non-typer can watch HackMD), HackMD +helpers (watch and answer basic questions).

+

There are several general strategies:

+
    +
  • Occasionally screenshare the HackMD. This emphasizes to the +audience that questions there do get noticed.

  • +
  • Rely on other helpers to answer most questions.

  • +
  • During Q&A time, go to the HackMD and comment on the most important +questions.

  • +
  • Call on co-teachers, “do we have any good questions from HackMD?”

  • +
  • Co-teachers should be more than willing to interrupt with relevant +questions right away.

  • +
+

You can’t use Zoom polls and so on. Instead, use HackMD cleverly. +For example, below you see a poll (people add o to make a bar +graph), and a free response:

+
Have you used HackMD before?
+yes: oooooooo
+no:  oooo
+
+What do you like about it?
+- answer
+- answer
+- .
+- .
+- .
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/local-breakout-rooms/index.html b/local-breakout-rooms/index.html new file mode 100644 index 00000000..947688d4 --- /dev/null +++ b/local-breakout-rooms/index.html @@ -0,0 +1,270 @@ + + + + + + Local breakout rooms — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Local breakout rooms

+

Some CodeRefinery courses are designed to be large scale, with +distributed registration. In short, this means there is a livestream +that anyone in the world can watch. Since we can’t handle a +registration and personal support for everyone in the world, you can +open registration to attend the course.

+
+

Principles

+
    +
  • We have a livestream, open to everyone in the world. The +CodeRefinery MOOC strategy strategy allows us to reach a huge audience +in a decentralized manner.

    +
      +
    • If courses don’t have a livestream, we can still reach many people +because of HackMD and teams. From the list below, steps 2b and 2c +work with this option.

    • +
    +
    +../_images/mooc-diagram.png +

    Decentralized teaching allows us to reach many more people than +we could otherwise.

    +
    +
  • +
  • Most attendees can ask from help through HackMD +(Collaborative document mechanics and controls), which works very well

  • +
  • There are periodic exercise sessions, where learners and teams can +work together.

  • +
+
+
+

Step 1: Local breakout room

+
    +
  • Create your own breakout room - whether online or a physical space. +That means for example ask some friends to join you to watch the stream +and collaborate with the exercises.

  • +
  • Our exercise sessions are very clearly announced and communicated. +During these times, the livestream goes silent, and you can work +within your breakout rooms. The end of the exercise sessions and +breaks are clearly communicated as well - we support your breakout +room scheduling as much as possible.

  • +
  • Attendees can ask general questions via HackMD

  • +
  • You can continue your local support even after the course.

  • +
  • You may want to run local “installation help” sessions.

  • +
+
+
+

Step 2: Registration

+
    +
  • If you have a broad audience, you may want to make your own +registration form, completely separated from ours. That may help +with reservations and catering if any.

  • +
  • Please have everyone to register in our form anyway +to help us in reporting our impact.

  • +
  • You may (but don’t have to) create teams, where you have one +team leader for 5-6 learners. The team leader guides the +team and supports collaboration and community - and lets us scale +much better than we could otherwise. Teams also support retention +after the course, especially if they knew each other before +registering. (See Team leaders / Helpers / Exercise leaders)

  • +
  • We would like to know statistics from how many people attended from +your location for our impact reports. (still, the top priority is +reaching as many people as possible, we’ll adjust reporting to what works)

  • +
+
+
+

Step 2b: Joint registration

+
    +
  • You can direct people to our registration form as a matter of +simplicity, but we add an option for your institution.

  • +
  • Learners join our Zoom session, and we create a breakout room for +your institution and direct all learners there.

  • +
  • Since you provide help to your own learners, we can more easily +scale than we could otherwise.

  • +
+
+
+

Step 2c: Joint registration, you provide team leaders for your teams

+
    +
  • A lot like “joint registration”, but for workshops where we +centrally organize teams.

  • +
  • You locally recruit team leaders for your +own learners. This saves us the effort of recruiting exercise +leaders and allows us to scale more.

  • +
+
+
+

Summary

+

As you can see, there are many models, from distributed and simple to +centralized. It’s best to talk in chat and see what will work best +for each workshop, but we are generally biased towards more +decentralized approaches for large courses.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/meeting-checklist/index.html b/meeting-checklist/index.html new file mode 100644 index 00000000..b83064a3 --- /dev/null +++ b/meeting-checklist/index.html @@ -0,0 +1,261 @@ + + + + + + Meeting checklist — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Meeting checklist

+

This checklist was made because we had a major issue with not +announcing good events to our community because we weren’t sure what +to do, thus a community doesn’t form. These steps should be taken to +announce any event unless there is a specific reason not to (for +example, a workshop is well underway and organizers known). You don’t +have to follow what you see here, but the point is to make +announcements as boring as possible, so that it gets done quickly and +well-enough.

+
+

As soon as meeting topic/time is decided

+
    +
  • Decide central HackMD/join link. (Join link can be decide later by +putting it in the hackmd).

  • +
  • Create a calendar event for yourself, and send it to related +people. You should be ready to forward this to people who request. +It’s OK if the event only includes HackMD link (+ join link, if +known).

  • +
  • [Mailing list: not yet present, we are relying on the other options +here.]

  • +
  • Make a post in #announce. Don’t be shy, just do it. +<time:TAB will produce a time picker that adjusts for +everyone’s timezones.

    +
    At <time:...>, there will be a [meeting on topic].  Topics will
    +include [a few highlights to let people know who should attend].
    +
    +HackMD (including connection details): <link>
    +More info: #[stream-name]
    +
    +If you want a calendar invite, send [me] a private message (or
    +react with :email: quickly if I know your email already).
    +
    +
    +
  • +
  • Make a Twitter post for most meetings, if you want a broader +community to attend.

    +
      +
    • You can do this yourself via the “tweet-together” Github Action:

      + +
    • +
    • You can do it from the web interface, find the “Create new tweet” +button from the readme.

    • +
    • Edit the file path. It pre-fills YYYY/MM outside of the text +box, but you can backspace and change that to current year/month.

    • +
    • Suggested template:

      +
      [title] will be held at [time CEST]. [optional: why should
      +someone attend?  Attend if...]
      +
      +More info via our chat https://coderefinery.github.io/manuals
      +[tags]
      +
      +
      +
    • +
    • Suggested tags

      +
        +
      • CodeRefinery: #coderefinery

      • +
      • Nordic-RSE: #RSEng

      • +
      • Research software hour: #RSEng

      • +
      +
    • +
    • Ideally, someone else should merge quickly after checking facts +Don’t wait for “permission” or something like that which may never +come, we agree that more tweeting is a good thing.

    • +
    +
  • +
+
+
+

Days before the meeting

+
    +
  • Send reminders to the #announcements streams. You can find the old +topic and reply to it, quoting the whole text.

  • +
+
+
+

Archive meeting agenda

+
    +
  • Archive the agenda, if needed.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 00000000..629c869d Binary files /dev/null and b/objects.inv differ diff --git a/obs/index.html b/obs/index.html new file mode 100644 index 00000000..af126d2c --- /dev/null +++ b/obs/index.html @@ -0,0 +1,582 @@ + + + + + + Open Broadcaster Software theory — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Open Broadcaster Software theory

+

This page describes the theory around OBS. For practical steps to +run a course, see Broadcaster.

+

Open Broadcaster Software is an amazing open-source audio/video +production tool. It’s probably not professional grade, but is used in +serious events and will make a non-professional feel professional. +The main point is that, instead of being limited to what your meeting +software can do, you can:

+
    +
  • create more advanced mixes of screens/video/etc, without having to +do post-processing.

  • +
  • do more with the (local recording, streaming)

  • +
  • do this all better, for example, exclude the audience speaking from +the recording.

  • +
+

It is a GUI application, so is not that hard to figure out, but there are a +lot of initial concepts. This page isn’t a comprehensive tutorial, +but will introduce the basic concepts and what you can get out of it, +and you can either figure out the rest or read other tutorials.

+
+

Vision

+

When teaching online, we are usually limited by our online meeting +software. This forces us to make certain trade-offs to fit the +limitations of the software, so that we can’t reach our full +potential. By using more advanced technology, we can do more: have +interactive sessions while also recording and preserving privacy. For +more information, see the online teaching guide.

+
+
+

Basics

+ +
+

User interface basics

+

OBS is a graphical program. Once you start it up, you see various +user interface features:

+
+../_images/obs--controls.png +

Basic OBS control layout

+
+

Of primary note are the following concepts:

+
+
Preview area

Shows what is currently being broadcasted or recorded, or will be +if you turn it on. There is also a separate “Studio mode” with a +preview area, and live area. The preview area is used to prepare +the stream, you can make it live when you want.

+
+
Scenes

A certain layout that can be broadcasted. On the lower left is +your scene collection, and you can add, delete, reorder, and rename +scenes. By clicking on a scene, you switch to it and it begins +broadcasting/recording.

+
+
Sources

An image source which can be composed together in a scene. Scenes +can be added, deleted, recorded. Via the preview area, sources can +be graphically moved around to your liking. There is a +comprehensive set of positional and image effect transforms you can +make.

+

Sources can have filters applied to them, which do some sort of +video transformation (for example, background removal). There are +also transformations, which affect the position in the scene. +Put together, you can do almost anything you would like.

+
+
Audio sources

You can take audio input from various sources: mainly, microphones +or as a monitor of a computer audio device (to, for example, play +sound). Audio sources are configured in settings, but can be +muted/have volume adjusted in the respective area of the screen.

+

Audio sources also have filters.

+
+
Control buttons

There are buttons to start/stop recording/streaming. The output +locations are configured in the settings.

+
+
+
+
+
+

Configuration

+

Here, we will go over the main parts of configuration. We won’t say +everything, since this is graphical program and you can mostly click +around and find your own customization you would like.

+

Because of the popularity of streaming, it is easy to find more +tutorials and recommendations for anything here. Add “streaming” or +“OBS” to your search.

+
+

Basic configuration

+

These options are found in the “Settings” dialog. These are just +generally suggested defaults and when you might want to tone them.

+
+
File → Settings → Stream

Here, you would configure the streaming service, if any.

+
+
File → Settings → Output

Here, you configure streaming/recording output parameters.

+

If you use Simple, you pretty much can’t go wrong. If you are +mainly screensharing and don’t have much action video, you can +make the bitrate much lower, for example 2500 Kbps. The slower +“encoder preset” is, the more CPU power that will be spent to get +that quality, so the less space it will use. The better your CPU +is, the slower you can make it; “fast” to “slow” are reasonable.

+

If you use advanced you have more options:

+

Streaming: Rate control=CBR, 2500 Kbps, other options don’t matter +so much, defaults should be fine. You can search for +recommendations online, but realize that most others stream +high-action games so their settings are much higher than you need.

+

Recording: Recording format, mp4 (mkv would be better, but we need +to check that it can be uploaded to common sites). Encoder=x264, +Rate control=CRF, CRF=22, Keyframe interval=auto, CPU +preset=medium (or slower, for better CPUs) +(slower=use more CPU to do better +encoding, either higher quality or lower bitrate. Veryfast–Slow +is a good range), +Profile=main, Tune=None

+
+
File → Settings → Video

Here, you set the base size of the picture you will be using. +You could do FullHD at 1920x1080, or HD at 1280x720. For vertical +recording, we recommend you do 840x1080. Use your chosen value +for both Base and Output resolutions. 30 FPS.

+

When setting your video size, traditionally people tell you to be +as large as possible (to attract viewers). However, this guide is +focused on teaching +and learning, and for that a) we want our content to be as +accessible as possible. There is no need for as many pixels as +possible, as we often say “present from your smallest screen”, and +you can do that by artificially restricting yourself. b) We have +found a vertical screen works well: a learner can have the +video/stream taking up half of their screen, and the other half +available for doing their own work.

+
+
+

Click around through the other menus in settings and see if there is +anything to configure to your own needs.

+
+
+

Scene configuration

+

After the above, you can set up scenes basically however you would +like. However, as a starting point I propose these scenes to get you +started (and I propose we standardize on these names, so that we +can make some uniform scripting tools):

+
    +
  • Title, the logos and titles of the event.

  • +
  • Gallery, a gallery of the people presenting (or the one). When +presenting from a Zoom meeting, this is a capture of the gallery +view in dual-monitor mode.

  • +
  • Local is a local screenshare, that you get by capturing your own +screen.

  • +
  • Remote is a screenshare by someone remote. If you are capturing +from a Zoom meeting, it is the capture of the second window of the +dual-monitor mode.

  • +
  • Notes is some HackMD or other material you might want to show +during discussion periods or breaks.

  • +
+

Common types of sources (scene elements) include:

+
    +
  • Static image (e.g. logo or background)

  • +
  • Desktop capture, for your local desktop. You can crop it (in the +source config) to share only a portion of your desktop.

  • +
  • Single-window capture. Note that this is smarter than Zoom, +since it can capture the full window even if is not on top.

  • +
  • Text (which works, but is not very powerful)

  • +
  • Solid colors

  • +
  • Other scenes. You can make one scene, then insert it into other +scenes to avoid duplication of scene elements scene elements.

  • +
+

The sources themselves can be moved around graphically, which is good for +setting things up. When there are more demanding needs, the source +transformation can be edited for more precise control (right click on +source in preview → edit transformation). There are +source filters, which can do video effects such as removing a color. +Some sources can be cropped in the source-specific config as well.

+
+
+

Audio configuration

+

Audio configuration is simpler than video configuration, since there +are fewer different sources. On the other hand, it is harder to +see what is going on (no preview) so it is harder to adjust it +perfectly, and easier to cause problems like loops.

+

The main concept is that your computer may have different input and +output sound devices (“cards”). For example, I can output sound from +some application on my monitor’s speakers, while sound from other +applications on the headphones at the same time. Find your computer’s +way to see and configure what is going on under the hood.

+

There are two types of audio inputs:

+
    +
  • Microphones, obviously recording from a microphone.

  • +
  • Monitors (as in, monitor a sound card), recording what is +currently being played on another +sound card. This is what is used to capture audio from a remote +meeting, such as Zoom.

  • +
+

You set the active audio input in the application settings. The +volumes of these can be independently adjusted - you want typical +volume to be in the yellow zone. Advice for various operating systems +include:

+
    +
  • Linux using PulseAudio: pavucontrol

  • +
  • Windows: ???

  • +
  • MacOS: ???

  • +
+

Under “advanced audio properties” (a menu item, also available from +the gear icon in the audio area) you have several more options.

+
    +
  • You can add various filters, such as noise reduction.

  • +
  • You can group audio sources into various audio tracks, and the +stream/recordings can use different tracks. For example, a person +may stream with music but leave that out of the recorded video. Or, +you might record a video with two different audio tracks, one just +the presenter and one with presenter + audience.

  • +
  • You can monitor the audio, which plays what is being recorded back +over the headphones and speakers for you to check. Make sure you +don’t make any loops!

  • +
+

Audio configuration is a big deal. You can look at thees other +guides:

+
    +
  • ???

  • +
+

High-quality audio is quite important. I’ve spent far too long +playing with it, and my conclusion is that I don’t know enough to make +it better than what I have now. I could use a better microphone, but +then I had to add noise reduction and the quality ended up the same as +a “worse” headset microphone that was close to my mouth that seemed to +have automatic noise reduction. Your environment (noise, amount of +echo) matters just as much as your microphone.

+

I propose a central recommendation: talk about audio quality. Start +meetings early and test it. Communicate about problems early, don’t +ignore and think it’s “good enough for now”.

+
+
+

Recording and streaming

+

Once you have done the above, you can record and stream by clicking +the buttons.

+

One piece of advice: always keep the recording going, and then +stop/restart it when you need to cut. It’s easier to delete the +unnecessary segments than realize you forgot to push “record”.

+
+
+

Projector and loopback output

+

Beyond recording and streaming, there are several more ways to use the +output that can feed into other applications.

+

With projectors you can display the scene locally on another +monitor or window.

+
    +
  • The fullscreen projector displays the scene to a monitor. As +the name says, this could be used to send it to an external +projector or capture card via HDMI. Or even preview locally, or +screenshared in an online meeting.

  • +
  • The windowed projector does similar, but makes a new window that +can be moved and resized. This can be captured as a single-window +screenshare in an online meeting.

  • +
+

The loopback output creates a virtual camera device. This +appears to other applications as a camera, just like the camera that +captures your video. +Other applications can use this as the input just like another +webcam. So, you could make a fancy scene that is used instead of your +normal camera’s picture. +Or, in Zoom you can share screen from “second camera” - +which would use this scene. (Note in Zoom it will interpret it as a +landscape picture, regardless of what aspect ration you actually use. +Thus, this isn’t very suitable for vertical screen sharing.)

+
+
+
+

Example configurations

+
+

Recording your own demo

+

Scenes: Title, Gallery, Local. Variable bitrate.

+
+
+

Online teaching event

+

Scenes:

+
    +
  • Title

  • +
  • Gallery - contains galleryCapture

  • +
  • Local - capture of your screen, when you need to teach. Has +galleryCapture in top-right corner

  • +
  • Remote: capture of Zoom second window (which has been +adjusted to be same resolution as your base canvas size). Also has +galleryCapture in top-right corner.

  • +
  • Notes: contains HackMD + galleryCapture

  • +
  • galleryCapture - contains the Zoom gallery capture. This gets +inserted into the other scenes above.

  • +
+

Audio:

+
    +
  • Microphone capture

  • +
  • Monitor of sound card which has the Zoom output

  • +
+

Outputs:

+
    +
  • Recorded locally. Start and restart recording after every +transition that you would want to publish separately. (Better to cut +more than less, to have logically organized shorter segments. Also, +always keep it recording, in case you forget to turn it back on!).

  • +
  • Stream to your preferred site.

  • +
  • Use windowed projector or Zoom capture to send the output directly +to a Zoom meeting. But, that requires careful audio routing.

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/online-training/index.html b/online-training/index.html new file mode 100644 index 00000000..b5357607 --- /dev/null +++ b/online-training/index.html @@ -0,0 +1,340 @@ + + + + + + Online training manual OLD — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Online training manual OLD

+
+

Note

+

This hasn’t been updated since we developed our MOOC strategy.

+
+

Also please read our lessons learned.

+

This manual covers general guidelines for conducting online +training as well as specific tips on using Zoom.

+
+

For the instructors

+

If you have an old spare laptop, connect to the call as a second “you” and you can +watch and verify your screensharing and fontsize to avoid “Am I sharing the screen? +Hopefully you see what I see.”

+
+
+

How to avoid “Zoom bombing”

+
    +
  • Either set a password or use waiting rooms

  • +
  • Share connection details only with participants and helpers, not on the web

  • +
  • Disable file transfer

  • +
  • Disable “Allow removed participants to rejoin”

  • +
+
+
+

Preparation

+
    +
  • Schedule the meeting/webinar in the online Zoom system

  • +
  • do not auto-mute participants’ microphones, as this also happens when you enter breakout rooms.

  • +
  • Decide roles:

    +
      +
    • Decide the Zoom host and co-hosts

    • +
    • Use panelists? (Zoom webinar feature)

    • +
    • Decide instructor and backup-instructor in case of network issues

    • +
    • Decide helpers. One helper should be responsible for monitoring +Zoom, i.e. the chat window, hand-raising and other feedback

    • +
    +
  • +
  • Co-hosts, breakout rooms and feedback controls need to be enabled (on +website) before the meeting starts. If options are reconfigured, the meeting +may need to be ended and restarted for them to take effect.

  • +
  • Create enough breakout rooms at the beginning since this cannot be easily changed during the meeting.

  • +
  • TODO: set up pre-lesson polling? (zoom feature) Maybe unnecessary in view of pre-workshop survey

  • +
  • Instructors and helpers should use a reliable camera and microphone. +Computer microphone might not be enough since audio quality will depend on +instructor’s head angle and proximity to screen.

  • +
  • Workshop owner creates a HackMD which will be used for collaborative note taking.

  • +
+
+
+

At the beginning of the session

+
    +
  • Allow time at the beginning of the session to debug video/audio and to +arrange windows. This takes few minutes so better do not start with teaching +from minute 1. Plan for an early 5-minute break to debug this.

  • +
  • We cannot assume that all Zoom participants have the same and up to date +client and some clients do not contain “sticky notes” feedback or a button to +raise hands so agree with participants on signals (e.g. typing \hand in the +chat window seems to be standard).-

  • +
  • We demonstrate how HackMD works and use it in an ice-breaker (roll call or asking a questions).

  • +
+
+
+

Recording of sessions

+

If you plan on recording and publishing the session, prepare in advance so that +you don’t have a difficult editing job later. +Make sure that you (or users) don’t show any personal or confidential information. +Think about what happens if users speak: do you ask for permission to publish +in advance (maybe encouraging people not to), or edit it out later (taking +your time later).

+

If you plan to record the session, make sure that everybody is aware that the +sessions is recorded, informed about how the recording will be used, and gives +consent to be recorded: +https://support.zoom.us/hc/en-us/articles/360026909191-Consent-to-be-Recorded

+

In Zoom it’s important to start recording in the form you want the video to be +in (e.g. start recording when screen is shared so that it stays there): +https://support.zoom.us/hc/en-us/articles/360025561091-Recording-layouts

+

Set screen background to black. We saw a glitch in Zoom which caused the +background image to flash above the screen, if it was pure black it would be +less distracting.

+
+
+

Zoom-specific installations instructions sent out before workshop/lesson

+
    +
  • Recommend to install Zoom app. Browser is possible but more limited

  • +
  • Test-launch zoom and test microphone, speaker and camera (lower left corner buttons)

  • +
  • Instruct participants to watch a zoom introduction (TODO: insert link), +and play around with zoom.us/test to get acquainted with interface.

  • +
  • Optional: set up virtual background

  • +
  • “During the workshop, you might be asked by a helper to share your screen. +Make sure to keep private information away from the screen you share.”

  • +
+
+

Contingency plans

+
    +
  • Be prepared for intermittent network problems.

  • +
  • There should be a backup instructor in case the main +instructors disconnects

  • +
  • Learners might occasionally experience lag and temporary +network hickups. This makes it particularly important to +speak slowly and repeat important topics.

  • +
+
+
+
+

Breakout rooms

+
    +
  • Breakout rooms can be used both by helpers to assist individual +learners during an exercise, or for multiple learners working on +a group exercise.

  • +
  • When creating groups, the host or co-hosts can choose automatic setup, +where only the number of groups is selected and the distribution into +groups is automatic, or manual setup where the host/co-hosts distribute +learners into groups.

  • +
  • Host needs to move helpers, co-hosts cannot enter rooms on their own.

  • +
  • Somebody asking for help gets assigned to a room together with a helper.

  • +
  • TODO: is it possible to create breakout room for only some participants, +leaving other learners unaffected? This is crucial for helping participants +during exercises who have raised their hand. Need to test this

  • +
  • Host and co-hosts can join any room and jump between rooms. This should be +used during collaborative exercises to see how the exercise is progressing +or participate in the group work.

  • +
  • When a collaborative exercise is about to end, the host/co-hosts can +broadcast a message into all groups.

  • +
  • When the host/co-hosts end a breakout room session, participants in groups +have 60 seconds to finish before the session terminates.

  • +
+
+
+

Exercises

+
    +
  • Just like in a regular workshop, demonstrations and type-along sessions +should be interspersed with frequent exercises

  • +
  • For pairwise or group work exercises, the instructor (or Zoom assistant) +should create breakout rooms with chosen number of participants in each

  • +
  • For single-person exercises, no breakout rooms are needed

  • +
  • Learners should be instructed to raise their hand when they need help. +This corresponds to putting up a red sticky note in in-person workshops.

  • +
  • TODO: what signal should be used for green sticky notes?

  • +
  • Polling can be used as formative assessment questions. The host creates +a poll based on a lesson template and requests learners to answer. +(TODO: polling seems not available in kth-se zoom subscription)

  • +
+
+
+

Breaks

+

Following an online event can be even more tiring than a physical event and +therefore also during online sessions we need to plan for breaks as we would +for an in-person event.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/online/index.html b/online/index.html new file mode 100644 index 00000000..525e8aab --- /dev/null +++ b/online/index.html @@ -0,0 +1,306 @@ + + + + + + Online teaching — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Online teaching

+

In 2020, we were forced to start teaching online. Is this good or +bad?

+

The promise of the Internet was that we could reach everyone in the +world. Instead, we immediately learned to hide or Zoom links from +anyone except the people who register in advance to hide from trolls. +We directly translate in-person to online, and wonder why we don’t +have as much engagement. It doesn’t have to be this way. +CodeRefinery has developed a vision of this teaching that can take the +best of both worlds.

+
+

Video: The future of teaching

+

“The future of teaching”, +https://www.youtube.com/watch?v=S9Jor12Cxdc (45:31) is a talk +describing many aspects of this strategy in a concise form.

+
+
+

What is different about online?

+

Online teaching requires a certain mindset.

+

First off, it is different, and different is not better or worse. +You must rethink your existing assumptions and design for the current world.

+

Some differences in mindset include:

+
    +
  • If the material is online, why pay attention now. Why not find +the same or similar material when you need it? If the course isn’t +online, still you realize you can do a web search and find something +equivalent later.

  • +
  • Why dedicate myself to this now? Why night attend a course +passively now, get the basics, and come back later when I need to +really understand something?

  • +
  • How to best use the tools? I might have only one screen to take the +course (and no projector to watch), but the instructor material is +also closer. Why type things myself, if my normal work is copying +from StackOverflow anyway?

  • +
  • Related to the above, you can’t use attendance as a proxy for +engagement. You have to actually engage people, or accept that +passive attendees are OK. Do you measure the benefit of people +watching the course later?

  • +
  • Everyone knows how to way of attending in-person courses. But there +are different ways to attend online courses, and you don’t get as +much feedback from others. You need to be explicit.

  • +
+

Once you learn to take advantage of online formats, you might never go +back!

+
+
+

Taxonomy of online teaching

+

This isn’t a strict division, but here is a rough vision of steps to +take, from simplest to more advanced.

+
+

(1) By yourself, in a meeting

+

It’s you and a group of students in a meeting (e.g. Zoom). This can +reach people, but it’s easy to lose the attention of attendees. +Because you need to avoid trolls and protect privacy, you may have a +private registration and you may not publish recordings. This gives +limited usefulness in the future.

+

Key aspects:

+ +
+
+

(2a) Group teaching, in a meeting

+

One of the advantages of online teaching is it doesn’t require +full-time physical attendance, so you can more easily bring in a +diverse set of helpers, which greatly reduces your load.

+ +

At the same time, you can start grouping learners together into small +groups. This is the equivalent of different tables in a physical +workshop.

+
    +
  • Zoom breakout rooms can group people together

  • +
  • You need to be explicit about how the groups work. Even in person, +many learners work independently even when forced into a group.

  • +
  • Add “team leaders” (helpers, former students) to guide each +group.

  • +
+
+
+

(2b) Higher production values

+

Now we reach the real promise of online teaching: by using streaming +platforms, you can reach everyone in the world. No registration is +needed and anyone can take part. The disadvantage is that you don’t +have close interaction with the learners (by design: removing these +close interactions how you can accept everyone).

+

This focuses on technical setup

+ +
+
+

(2c) Multiple ways of attending

+

One no longer has to limit yourself to interactive watching

+
    +
  • Streaming

  • +
  • Encourage in-person “watching parties”

  • +
  • Make videos available (Video editor)

  • +
  • Make videos available immediately, for catch-up purposes

  • +
+
+
+

(3) High-accessibly zen-level courses

+

Finally, we get to our final state: You can combine the contradictory +options: privacy for learners, but anyone can attend. Interactive +course, but people can refer to it later.

+

This is more a mindset thing, and combines everything from above.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/open-your-courses/index.html b/open-your-courses/index.html new file mode 100644 index 00000000..ef9c0816 --- /dev/null +++ b/open-your-courses/index.html @@ -0,0 +1,201 @@ + + + + + + Open your courses to others — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Open your courses to others

+

CodeRefinery strategies allow you to reach a larger audience without +much extra work from you. Once you open to other attendees, you also +naturally get co-instructors who want to help improve your material. +This allows you to reach the next level of quality and impact, even +for your own local audience.

+
+

Principles

+
    +
  • Thanks to the CodeRefinery MOOC strategy, +you can easily reach more people than you could otherwise.

  • +
  • It may seem hard, but there are many small steps to take and you can +gradually scale up.

  • +
+
+
+

How-to

+
    +
  • Learn by example: attend our courses, advertise our courses, and +volunteer, too.

  • +
  • Read all of the manuals here - we try to document everything we +can, but they are always going to be a work in progress.

  • +
  • Attend our community teaching +training to +network with others and learn from the experts.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/outreach/index.html b/outreach/index.html new file mode 100644 index 00000000..895434da --- /dev/null +++ b/outreach/index.html @@ -0,0 +1,485 @@ + + + + + + Outreach plan — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Outreach plan

+

This is a prototype the CodeRefinery outreach and marketing plan.

+

Since most of us are not very good at marketing, this is actually a +summary of the book The new rules of marketing and PR : how to use +content marketing, podcasting, social media, AI, live video, and +newsjacking to reach buyers directly (David Meerman Scott, 8th ed.) +with descriptions of how it can apply to CodeRefinery. The book is +available at my university’s O’Reilly Online Learning platform through +our library for free. If you like what you read here, consider +checking it out - the book was a very good inspiration for someone +that needs to outreach better, but is not at all that kind of person +and needs some inspiration for how to even think about it.

+

Perhaps this summary is useful to others outside of CodeRefinery as +well.

+

Currently, this page is one person’s description and their own +interpretation9 as it applies to CodeRefinery. Over time, it should +be adapted to represent a broader view, this paragraph updated, +possibly the current content archived, and the new plan made into a +new page.

+
+

Introduction

+

Many people need marketing and outreach: CodeRefinery isn’t trying to +sell things, but we are trying to encourage people to make a choice to +gain skills. It’s free, but it does have a cost: time. We think that +it does save more time in the long run, but then again, how many +businesses sell things that will save money in the long run?

+

We need to encourage people to make a specific choice, and we need to +tell them why we think that is the best choice for them.

+
+
+

1 The Old Rules of Marketing and PR Are Ineffective in an Online World

+

“Interruption advertising” doesn’t work (anymore?). Few people want +to have their life interrupted with a TV commercial, banner ad, or +email from university administrators telling them to make some +choice. People think of different things now.

+

For CodeRefinery, you could argue that flyers, emails from university +staff, etc. are all some form of interruption advertising.

+

There’s all kind of anecdotes about how advertisement, mentions in the +press, and so on aren’t useful, but we wouldn’t do those anyway. +Although, we do want press, that’s not the main way we get people to +take our courses. (maybe it helps our funding, though)

+
+
+

2 The New Rules of Marketing and PR

+

People do, however, take recommendations from people they know. Social +media lets people communicate. The match is clear. By making good +use of social media, we can reach people directly.

+

(this chapter starts off with an example of social media inspiring the +author to visit Saariselkä in Finnish Lapland, which was interesting +to see.)

+
+
+

3 Reaching Your Buyers Directly

+

Social media lets people reach buyers directly. This is obvious.

+

But, how to use social media. You don’t want to go doing interruption +advertising, trying to use it to directly sell your stuff. Instead, +produce good, free content which people will want to consume. Most of +your activity should be about this, which gets people interested, and +makes them want more. Then, when they want to go deeper or are ready +to make a purchase, they come to you.

+

CodeRefinery does nothing but make free content, so how does this +apply to us? Well, we have to think more. Our main content costs a +lot of time, so we need to think of content that is shorter and easier +to consume. For example:

+
    +
  • Short videos or pictures explaining things.

  • +
  • Short blog posts about tips or tricks, which have a clear, catchy, +immediately useful title.

  • +
  • Tweeting links to specific pages we have just made, which are +especially useful standalone.

  • +
  • Short “git hacks” or clever things, which people like and share, and +makes them want to attend a workshop.

  • +
  • “Research software minute” videos?

  • +
+

You have to think of buyer personas - backwards design all of your +material. Don’t make anything unless you know who it is for, and then +make sure it is suitable for that person. Know their goal, how they +speak, and where they are (what content do they consume?).

+

CodeRefinery buyer personas could include:

+
    +
  • Learners

  • +
  • team leaders

  • +
  • Group leaders or university staff who can recommend their audience +to attend a workshop

  • +
  • Prospective instructors and helpers

  • +
  • Funders and high-level leadership

  • +
+
+
+

4 Social Media and Your Targeted Audience

+

Descriptions of what social media is. A somewhat useful metaphor is +that the web is like a city. Social media are things like bars or +cafes. You don’t go there and start asking people to do something or +offering free samples and expect people to like it. You network, +talk, maybe tell some interesting stories. Maybe someone figures out +who you are and would want to know more about what you do.

+
+
+

5 The Content‐Rich Website

+

Websites matter - people will go there and check it out. Blogs are +good, they last longer than any single social media operator and +provide long-term web traffic. Websites (and everything) need +specific skills and a manager. The website needs a personality and +voice.

+

CodeRefinery should make sure that there is are clear target pages or +sections for each of our target personas below. We should make sure +we don’t use jargon that we would use, or have the website organized +by our own operations as opposed to learner personas. We should also +make sure the website is accessible and mobile-friendly.

+
+
+

6 Marketing and PR in Real Time

+

Following social media in real time can let you know what people +think. This can be an even better feedback method than surveys, etc. +By responding in real time (this can take effort), you can have +conversations there (in the open) which is also very good for +outreach.

+

CodeRefinery could consider monitoring more of social media. TODO: +how to do this?

+
+
+

7 Artificial Intelligence and Machine Learning for Marketing and PR

+

We know about AI and so on. We also know it’s not magic. There were +discussions about using AI to generate some content, such as tweets +from web pages.

+

I didn’t see much useful for CodeRefinery here, however some ideas +(run our webpages through a text summarizer to get the most important +sentences to help us make tweets) might be useful.

+
+
+

8 You Are What You Publish: Building Your Marketing and PR Plan

+

This is the chapter that puts everything above together, before it +goes off into details of the implementation next.

+
    +
  1. Understand what we want. Until a goal is clear, it is hard to +justify the effort (and also, I guess ask for others help do +it). (CR: we could say “better science” but it can also mean things +like “attend workshops” or “ensure funding for the project”)

    +
      +
    • More registrations?

    • +
    • More followers?

    • +
    • More views of videos?

    • +
    • More funding?

    • +
    • More team leaders?

    • +
    +
  2. +
  3. List the buyer personas relevant to us. (See chapter 3 for the list)

  4. +
  5. Create a persona around each of these buyers. (CR: see chapter 3 +above for the details).

    +
      +
    • What are their goals?

    • +
    • What do we want them to do?

    • +
    • What content do they consume?

    • +
    • How do they make their buying choices? (CR: how do you decide how +to spend your time?)

    • +
    • How do they speak, talk, and read?

    • +
    • Subscribe to and follow the media they follow.

    • +
    +
  6. +
  7. Develop (free) content that interests each of these buyers.

  8. +
  9. Develop a measuring plan. Think about how we can measure success, +both in immediate engagement and making the decision we want (what +we actually want).

  10. +
+
+
+

9 Growing Your Business: How Marketing and PR Drive Sales

+

Salespeople don’t mediate between buyers and companies anymore. +Instead, people can find so much information themselves, and make +purchases self-service. Websites and other material have to be target +to buyers (= potential learners) who are deciding if they want to +purchase (= attend a course). Websites and material should have a +personality (= our website shouldn’t be written as boring as a +scientific paper). It’s OK to do fun things. Social aspects to the +site is good - e.g. comments section, social media share buttons.

+
    +
  1. Begin with informational content (not necessarily about you).

  2. +
  3. Nudge towards what you want (= attend a course, etc.)

  4. +
  5. Make it easy to close the deal. (CR: clear “notify me” mailing list +link on every relevant page. Maybe even make sure we have +continually open registration for the next workshop - each workshop +is ready for registration when the previous one ends. When we have +multiple types of workshops, includeable html snippets that has links +to register for every upcoming workshop?)

  6. +
+

Don’t underestimate the value of figurehead leaders (~=CEOs) being +social - don’t just delegate it to separate marketers.

+

Is the analogy of salespeople even relevant for CodeRefinery? +Probably not, but maybe we could say that official requirement, +recommended courses, university staff aren’t so important. People +will check our websites and other material to see if they want to +attend.

+

Every website, lesson, and so on has to have very clear information +targeted to a possible reader right at the beginning, so that a +potential learner might see “is this git lesson right for me?” and +they will find “yes”.

+

Our website should be current.

+
+
+

10 Strategies for Creating Awesome Content

+

This section has different strategies and types of content. Types of +content include: blogs, audio, video, photos, infographics, charts, +email newsletters, presentations, long-form written content, research +reports, virtual events, e-books, white papers, apps.

+

Think about how you make the content: don’t just write about +yourself. Consider the problems your buyers face and make content +that solves those problems. Write for your personas. Advertise what +you do. Think what could possibly go viral. Don’t forget that it +should be accessible.

+

CodeRefinery: in addition to the above, we should take part in other +events, for example show up at Open Science days and give +presentations, various awareness weeks (in person or online?), +conference hashtags, etc.

+
+
+

11 How to Write for Your Buyers

+

Write like your buyers talk (we’ve said this before), and don’t use +pointless jargon or meaningless words to make you sound smarter. +Humor is OK. Think like a journalist (especially for some content +types).

+
+
+

12 Social Networking as Marketing

+

Facebook pages, Facebook groups. Linkedin profiles, companies, etc. +There are many more, but think about what is right for you, don’t do +something just because it is there. Consider your personal brand - +make sure your profile information says something. There is a +recommendation 85% sharing and engaging, 10% original content, 5% +promoting yourself. Social media is like exercise: you need to make +it part of your routine, or you will stop doing it. It can easily +take an hour per day.

+

For CodeRefinery, we know we should be more active on Twitter, which +seems like the most suitable network for us. Are there any types of +badges we can use for professional social networks? Can we declare +hashtags and publish them on our website permanently, so we don’t have +to decide them for every workshop?

+

Most people in CodeRefinery seem to be hesitant to use social network +sites heavily, for good reason. We should really encourage and +support those who do want to use them to do so on our behalf, as much +as possible.

+
+
+

13 Blogging to Reach Your Buyers

+

Blogs are very important - and unlike social networks, they stay under +your control long-term, and drive search traffic straight to you. +Consider who you want to reach - potential learners? existing +learners? other thought leaders? Blog about things that they are +interested in and you are passionate about.

+

Don’t forget to monitor other blogs from people who do similar things, +to keep up to date with what is going on. Comment on other blogs and +link back to you. Invite other bloggers to visit you and blog about +their experiences - this is good for both of you.

+

CodeRefinery probably knows that it should blog more. Some ideas +about what to blog about are in previous sections. We should make it +easier to share posts, and would we even want to try for a commenting +feature (might be too much, though…).

+
+
+

14 An Image Is Worth a Thousand Words

+
+
+

15 Video and Your Buyers

+
+
+

16 Audio Content via Podcasting and Social Audio

+
+
+

17 How to Use News Releases to Reach Buyers Directly

+
+
+

18 Your Newsroom: A Front Door for Much More Than the Media

+
+
+

19 The New Rules for Reaching the Media

+
+
+

20 Newsjacking Your Way into the Media

+

(I haven’t fully read this chapter yet)

+

The idea here is that when something interesting to your audience and +relevant to you comes up in the news, react to it / contribute +something to it, perhaps preferably in a way that can be re-shared. +Or in a way that other journalists. Be careful, don’t do this +dis-respectfully or spammily.

+

In CodeRefinery, different things in the science news could be +relevant to react to.

+
+
+

21 Search Engine Marketing

+
+
+

22 Make It Happen

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/presenting/index.html b/presenting/index.html new file mode 100644 index 00000000..67bba503 --- /dev/null +++ b/presenting/index.html @@ -0,0 +1,316 @@ + + + + + + Lesson presentation hints — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Lesson presentation hints

+

This is a checklist/hints on what to do when standing up and giving a +presentation. Also see Instructor technical setup.

+
+

Before each lesson

+
    +
  • Remember: sticky notes, water, extra whiteboard markers.

  • +
  • Make your text large enough to be seen in the back, then bigger. +Make your voice loud enough to be heard in the back, then louder.

  • +
  • As people are coming in, encourage them to sit next to someone with +a similar operating system - then, when helping each other, the +unimportant differences are minimized.

  • +
  • By the same token, don’t allow people to sit alone: ask everyone to +set next to at least one other person. That way, people can help +each other.

  • +
  • Have a pen and paper next to you. When you notice problems in the +material, write it down right away during breaks in the type-along +parts.

  • +
  • Set up feedback system (chat, questions, etc)

  • +
+
+
+

Starting off

+
    +
  • Don’t start off with tech details, say why this is important. Think +of what the emotional (“coolness”) appeal is and start off with +that.

  • +
  • Why will this be useful?

  • +
+
+
+

Team teaching

+
    +
  • Discuss with co-teachers and helpers about what each of you will do.

    +
      +
    • Hand signals for common situations: too fast/slow in general, +louder, time for a break, “good enough, move on”, “explain more +here”.

    • +
    +
  • +
  • It can be hard for one person to manage everything. How can +multiple instructors take part? Probably the most common ones are:

    +
      +
    • Teach teaching: alternating

      +
        +
      • Commander and navigator: conceptually divide roles of big +picture teaching and doing the details.

      • +
      • If “real” alternating, each section should be 10-15 min at +least, otherwise too much context switching is distracting.

      • +
      +
    • +
    • Teach and assist (master helper going around)

    • +
    • Teach and observe.

    • +
    • Asking directed questions to fill in gaps.

    • +
    +
  • +
  • Tell the students the way the teachers will work together, so that +it seems coordinated rather than someone is interrupting.

  • +
+
+
+

During the lessons

+
    +
  • Helpers can read the team leader guide. +Encourage helpers to stand and be +constantly walking around, people rarely flag helpers from across +the room.

  • +
  • Encourage the use of sticky notes (red=need help, green=I am done with the +solution). They can also be used for voting, e.g. red/green for two +answers of a multiple choice question.

  • +
  • Don’t touch the learner’s keyboard! This is very hard to do, since +it’s only natural to want to get things done quickly. The best idea +we have is to have a pen and sticky notes, when it’s hard to spell +out a command to type, write it instead.

  • +
  • If appropriate for your topic, create a cumulative +cheatsheet/diagram on the board as you are presenting.

  • +
  • Take advantage of the mistakes/typos you make when teaching! +When you do a mistake and get an error message and realize what you did wrong, +explain what happened since this can offer valuable insights to learners.

  • +
  • Ask “do you do X?” where X is what you are teaching. Instead, ask +“how do you do Y?”. The first question implies something you are +doing wrong, the second is open-ended.

  • +
+
+
+

Exercise sessions

+
    +
  • What to do during exercise sessions

  • +
  • never stop sharing screen, ask someone else to share instead.

  • +
  • Always go over the lesson with someone else the day before.

  • +
+
+
+

Try to stick to the material

+
    +
  • Don’t try to show everything, show less, but show it clearly.

  • +
  • Try not to completely deviate from the material. Ideally, rather influence the material before you teach. +Of course it is good to react to questions and to adapt the material to the audience, so sometimes an excursion can be very useful, +but make clear that you then deviate from the script +and be explicit about whether participants should follow what you do or only watch.

  • +
  • If you want to show some extra steps in the terminal, show them perhaps at the end of an exercise block to not +“mess up” the exercise half-way and change it with respect to the material.

  • +
  • It is good to mention an anecdote or two but be careful about mentioning too much new jargon which +only very few participants may relate to.

  • +
+
+
+

Wrap up

+
    +
  • Say what you taught and why.

  • +
  • Say what comes next. Say where to get that.

  • +
  • Update the instructor’s guide and file issues for any problems you +noticed.

  • +
  • Use the sticky notes to get good/bad feedback: have people write one +good and one to be improved thing, and leave the note on the door on +the way out.

  • +
  • Get instant feedback from your co-teachers and helpers (students +too, if they offer any).

    +
      +
    • Consider making notes on a 4-way diagram of +(content←→presentation) × (went well←→can be improved).

    • +
    +
  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/registration-coordinator/index.html b/registration-coordinator/index.html new file mode 100644 index 00000000..286d9252 --- /dev/null +++ b/registration-coordinator/index.html @@ -0,0 +1,176 @@ + + + + + + Registration coordinator — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Registration coordinator

+

The registration coordinator is responsible for the Indico registration page and the workshop homepage. +Usually the registration coordinator has the best position for sending emails. Drafting can be collaborated with outreach and marketing coordinator. +They keep and eye on the Helpdesk before, during and after every workshop and make sure everyone is registered and knows where to go. +After the workshop, they make sure the CodeRefinery webpage is up-to-date and all changes needed in the planning HackMD are ported to the template. +The registration coordinator also has the overview over statistics for reporting and adds those to the webpage after the workshop.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/roles-overview/index.html b/roles-overview/index.html new file mode 100644 index 00000000..d356492c --- /dev/null +++ b/roles-overview/index.html @@ -0,0 +1,419 @@ + + + + + + Roles overview — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Roles overview

+

CodeRefinery has been able to scale online workshops while maintaining +an interactive feeling. This page describes the roles that we use in our workshops.

+

Despite the many different roles documented here, in practice many +of them are occupied by the same people. +Best practices below tells more about what tends to happen. +One of the advantages of our large workshops is that we have many more +staff on hand (often 10-15), thus allowing much more specialization +than small workshop can have (thus, the large number of roles below). +Many of our instructors give feedback such as “this is so much easier: +we only show up and teach!”

+

A common pathway goes (Learner/team leader) → (Expert +helper/Instructor) → (More specialized roles). Note that thanks to +our team teaching or “co-teaching”, it is really easy to join as +an instructor!

+

You can also find the common tasks in checklist-format under each roles section in the Workshop playbook.

+
+

Workshop roles

+
+

Learner

+

Comes and learns.

+
    +
  • Does necessary preparation and attends the workshop

  • +
  • More info: Learners section

  • +
+
+
+

Team leader

+

Team leaders are only a small step above learners. They aren’t +expected to know everything, but mainly keep their breakout rooms on +track - they could even be a slightly more confident learner.

+
    +
  • Leads a breakout room

    +
      +
    • keeps on track

    • +
    • makes welcoming community

    • +
    • answers some questions

    • +
    • ask for more help when needed

    • +
    +
  • +
  • Attends a one-hour team leader preparation / onboarding session.

  • +
  • More info: Team leaders / Helpers / Exercise leaders

  • +
+
+
+

Instructor

+

Obviously, instructors teach. Uniquely in our system, they have a lot +of support and generally can focus on the teaching part.

+
    +
  • Prepares lesson and “just teaches” without worrying about other workshop matters

  • +
  • Team teaching, you are not alone

  • +
  • Attend instructor preparation calls

  • +
  • Usually receives one-on-one mentoring in advance

  • +
  • Other times during the workshop, usually serves as an expert helper

  • +
  • More info: Instructors

  • +
+
+
+

Expert helper

+

Expert helpers are generalists who don’t have other assigned roles. +Thanks to HackMD and breakout rooms, they have plenty to do.

+
    +
  • All-around generalist who assists wherever is needed

  • +
  • Answers questions in HackMD

  • +
  • Supports team leaders in breakout rooms: rotates between +breakout rooms and checks how things are going

  • +
  • Identifies important issues and raises them to the instructors, +“voice of the audience”

  • +
  • More info: Expert helpers

  • +
+
+
+

Behind the scenes

+
+

HackMD manager

+

The HackMD manager closely watches HackMD to keep it organized and by +reading it in detail, can serve as the “voice of the audience” to the +instructors.

+
    +
  • Ensures everything gets some answer quickly

    +
      +
    • Even if it is “will be answered later”

    • +
    • Can raise issues to instructors immediately if needed.

    • +
    • In general serves as the instructors’ “ear on the ground”

    • +
    +
  • +
  • Maintenance during the workshop

    +
      +
    • Copies old information to archive HackMD if too much traffic

    • +
    • Organizes sections and questions

    • +
    • Notes break and exercise times

    • +
    +
  • +
  • Processes and archives HackMD after the course.

  • +
  • More info: HackMD manager

  • +
+
+
+

Host

+

The Host serves as the manager of learners during the course.

+
    +
  • Learner Zoom meeting host (often). Often the registration +coordinator.

  • +
  • Helps learners with organizational issues during the course

    +
      +
    • Ensures that everyone is welcomed and knows what is going on

    • +
    • Assign learners to breakout rooms

    • +
    • Answers technical questions about the course itself

    • +
    +
  • +
  • Often the same person as the registration coordinator.

  • +
  • More info: Host

  • +
+
+
+

Director

+

The director manages the flow of the course: preparing and cueing +instructors, switching the livestream scenes, announcing schedule, +adjusting schedule as needed.

+
    +
  • Instructor Zoom meeting host (often). Often the instructor +coordinator.

  • +
  • Cues the sessions, makes sure they flow together well.

  • +
  • Adjusts the flow when things do not go according to schedule.

  • +
  • Has sufficient knowledge of the tech setup to do the scene +switching.

  • +
  • More info: Director

  • +
+
+
+

Broadcaster (livestream)

+

The broadcaster is responsible for the livestreaming tech.

+
    +
  • Only needed in livestream courses

  • +
  • Installs and manages OBS control for livestreams

    +
      +
    • Ideally is not teaching in the first session

    • +
    • Is around in case of problems, otherwise the director does most of +the scene switching.

    • +
    +
  • +
  • Makes sure videos get processed and to Youtube in a timely manner, +or at least saves them where someone else can do it.

  • +
  • More info: Broadcaster

  • +
+
+
+

Registration coordinator

+

Oversees registration and generally everything on the participant side.

+
    +
  • Communicate with participants

  • +
  • Organize installation help session

  • +
  • Contact person for learners

  • +
  • Collect feedback

  • +
  • Provide participation certificates

  • +
  • More info: Registration coordinator)

  • +
+
+
+

Instructor coordinator

+ +
+
+

Outreach and marketing coordinator

+
    +
  • Makes sure workshop gets advertised in different places

  • +
  • You can find a list of commonly advertised places in the bottom of the Workshop checklist template.

  • +
+
+
+
+

Team leader / Exercise coordinator

+
    +
  • Communicate with all team leaders, contact person for them

  • +
  • Makes sure all exercises are ready and commicated before and during the workshop

  • +
  • Organize the team leader onboarding session

  • +
  • Usually attends as an expert helper to generally be available and +support all leaders.

  • +
  • Collect feedback from team leaders

  • +
  • More info: Exercise coordinator

  • +
+
+
+

Video editor

+
    +
  • Watches videos and prepares for YouTube upload

  • +
  • Uses +ffmpeg-editlist +to process videos after the Broadcaster has made them available.

  • +
  • Work should be done the day/evening of of the course

  • +
+
+
+
+

Best practices

+

Roles that are often combined:

+
    +
  • Registration coordinator and Host

  • +
  • Instructor coordinator and Director

  • +
  • Expert helper and anything

  • +
  • Instructor and any other role (but not Host)

  • +
+

Roles that should not be combined:

+
    +
  • Registration coordinator and Instructor coordinator (these +two together tend to form the “core team”)

  • +
  • Broadcaster/Director and Instructor on the first sessions of each +day.

  • +
  • HackMD manager and other roles (so delegate HackMD while you do +something else! this is OK.)

  • +
  • Host and any active teaching (in big workshops at least - +learner management keeps you busy)

  • +
+

Other notes:

+
    +
  • HackMD manager can rotate between different people.

  • +
  • Expert helpers can replace team leaders if they cannot join the +full workshop

  • +
  • Coordinators delegate

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/search/index.html b/search/index.html new file mode 100644 index 00000000..95aa17a6 --- /dev/null +++ b/search/index.html @@ -0,0 +1,183 @@ + + + + + + Search — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 00000000..4ec5fb74 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["LICENSE", "broadcaster", "chat", "co-instructors", "coderefinery-mooc", "contributing", "director", "exercise-coordinator", "expert-helpers", "governance", "hackmd-helper", "hackmd-mechanics", "host", "how-to-attend-inperson", "how-to-attend-online", "how-to-attend-stream", "icebreakers", "index", "indico/hints", "indico/in-person", "indico/index", "indico/online", "indico/setup", "instructor-intro", "instructor-stream", "instructor-tech-online", "instructor-tech-setup", "instructors", "lesson-design", "lesson-review", "livestream-teaching", "local-breakout-rooms", "meeting-checklist", "obs", "online", "online-training", "open-your-courses", "outreach", "presenting", "registration-coordinator", "roles-overview", "teaching-tech-together", "team-leaders", "team-teaching", "tech-docs", "templates/advertising-workshop", "templates/looking-for-helpers", "templates/notify-me-announcement", "templates/post-workshop-survey", "templates/practical-info-to-online-participants", "templates/practical-info-to-participants", "templates/waitin-list-notification", "the-project", "video-checking", "video-editing", "video-editor", "workshop-administration", "workshop-marketing", "workshop-organizers", "workshop-playbook", "workshop-prep-call", "workshop-requirements-inperson", "zoom-mechanics", "zoom-mechanics-old"], "filenames": ["LICENSE.md", "broadcaster.rst", "chat.md", "co-instructors.md", "coderefinery-mooc.rst", "contributing.md", "director.md", "exercise-coordinator.md", "expert-helpers.md", "governance.md", "hackmd-helper.md", "hackmd-mechanics.md", "host.md", "how-to-attend-inperson.md", "how-to-attend-online.md", "how-to-attend-stream.md", "icebreakers.md", "index.md", "indico/hints.md", "indico/in-person.md", "indico/index.md", "indico/online.md", "indico/setup.md", "instructor-intro.md", "instructor-stream.md", "instructor-tech-online.md", "instructor-tech-setup.md", "instructors.md", "lesson-design.md", "lesson-review.md", "livestream-teaching.md", "local-breakout-rooms.md", "meeting-checklist.rst", "obs.rst", "online.md", "online-training.md", "open-your-courses.md", "outreach.rst", "presenting.md", "registration-coordinator.md", "roles-overview.md", "teaching-tech-together.md", "team-leaders.md", "team-teaching.rst", "tech-docs.md", "templates/advertising-workshop.md", "templates/looking-for-helpers.md", "templates/notify-me-announcement.md", "templates/post-workshop-survey.md", "templates/practical-info-to-online-participants.md", "templates/practical-info-to-participants.md", "templates/waitin-list-notification.md", "the-project.md", "video-checking.rst", "video-editing.rst", "video-editor.rst", "workshop-administration.md", "workshop-marketing.md", "workshop-organizers.md", "workshop-playbook.md", "workshop-prep-call.md", "workshop-requirements-inperson.md", "zoom-mechanics.md", "zoom-mechanics-old.md"], "titles": ["<no title>", "Broadcaster", "CodeRefinery Zulipchat", "Co-instructors", "CodeRefinery MOOC strategy", "Contributing to CodeRefinery", "Director", "Exercise coordinator", "Expert helpers", "CodeRefinery governance", "HackMD manager", "Collaborative document mechanics and controls", "Host", "Attending an in-person workshop", "Attending a Zoom workshop", "Attending an livestream workshop", "Icebreakers", "CodeRefinery operation manuals", "Indico hints", "Indico in-person workshop workflow", "Indico registration system", "Indico online workshop workflow", "Indico event setup", "Instructor introduction", "Being an instructor in livestreamed CodeRefinery workshop", "Instructor technical setup, online", "Instructor technical setup", "Instructors", "Lesson design", "Lesson review", "Teaching via livestreaming", "Local breakout rooms", "Meeting checklist", "Open Broadcaster Software theory", "Online teaching", "Online training manual OLD", "Open your courses to others", "Outreach plan", "Lesson presentation hints", "Registration coordinator", "Roles overview", "Summary of Teaching Tech Together", "Team leaders / Helpers / Exercise leaders", "Team teaching", "Writing technical docs", "Advertising workshop", "Looking for helpers", "Notify-me announcement", "Post-workshop survey", "Practical info (online)", "Practical info, in-person", "Waiting list", "About CodeRefinery", "Video checking OLD", "Video editing OLD", "Video editor", "Organizing a CodeRefinery workshop", "Workshop marketing", "Workshop organizers", "Workshop checklist template", "Workshop preparation meeting", "Workshop requirements - in person", "Zoom mechanics and controls", "Zoom mechanics and controls"], "terms": {"attribut": 0, "4": [0, 1, 8, 10, 28, 30, 38, 41, 54, 56, 59, 61], "0": [0, 2, 26, 33, 52], "intern": [0, 33, 59, 61], "creativ": [0, 2, 23], "common": [0, 2, 3, 23, 29, 33, 38, 40, 41, 49, 50, 56], "corpor": 0, "i": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 29, 30, 31, 33, 35, 38, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 58, 59, 60, 61, 62, 63], "law": 0, "firm": 0, "doe": [0, 1, 3, 4, 9, 21, 23, 26, 28, 29, 30, 33, 37, 40, 41, 42, 43, 44, 56, 59], "provid": [0, 3, 4, 6, 9, 11, 12, 15, 23, 24, 26, 30, 33, 37, 40, 41, 42, 48, 54, 57, 59], "legal": 0, "servic": [0, 15, 22, 33, 37], "advic": [0, 2, 6, 28, 33, 52], "distribut": [0, 16, 31, 33, 35, 45, 59], "public": [0, 2, 4, 11, 53], "licens": [0, 16, 17, 54, 56, 62, 63], "creat": [0, 10, 11, 13, 14, 15, 22, 28, 31, 32, 33, 35, 38, 41, 49, 54, 59], "lawyer": 0, "client": [0, 8, 35, 49, 60, 63], "other": [0, 1, 2, 3, 6, 8, 10, 11, 12, 13, 14, 15, 17, 21, 23, 24, 27, 29, 30, 31, 32, 33, 34, 35, 37, 38, 40, 41, 42, 43, 49, 50, 51, 54, 55, 59, 60], "relationship": 0, "make": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 18, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 41, 42, 43, 44, 48, 51, 52, 54, 55, 56, 57, 59, 61, 62, 63], "its": [0, 9, 26, 29, 42], "relat": [0, 28, 32, 34, 38, 49, 52, 54], "inform": [0, 1, 4, 10, 11, 15, 16, 20, 23, 24, 25, 26, 28, 29, 30, 33, 35, 37, 40, 41, 44, 45, 48, 49, 51, 53, 54, 55, 56, 59], "avail": [0, 1, 6, 15, 26, 30, 33, 34, 35, 37, 40, 42, 50, 61, 62], "an": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 16, 17, 22, 26, 28, 29, 30, 31, 33, 35, 38, 40, 41, 42, 43, 44, 46, 47, 48, 49, 52, 53, 54, 55, 56, 62, 63], "basi": 0, "give": [0, 1, 2, 3, 4, 5, 6, 12, 13, 14, 15, 23, 24, 26, 28, 33, 34, 35, 37, 38, 40, 41, 42, 43, 51, 52, 53, 54, 56, 59], "warranti": 0, "regard": [0, 48], "ani": [0, 2, 4, 5, 8, 10, 11, 15, 21, 22, 23, 24, 26, 28, 29, 30, 31, 32, 33, 35, 37, 38, 40, 43, 44, 49, 50, 53, 54, 55, 56, 59, 60, 61], "materi": [0, 3, 4, 10, 15, 17, 24, 27, 28, 29, 33, 34, 36, 37, 41, 42, 43, 44, 45, 48, 49, 50, 52, 54, 56, 59], "under": [0, 2, 33, 37, 40, 45, 49, 50, 56, 62, 63], "term": [0, 1, 2, 4, 33, 37, 41, 44, 56], "condit": [0, 41], "disclaim": 0, "all": [0, 1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15, 17, 18, 22, 23, 24, 25, 26, 27, 28, 30, 31, 33, 35, 36, 37, 39, 40, 41, 42, 43, 44, 46, 47, 48, 49, 50, 52, 53, 54, 55, 56, 57, 59, 60, 61], "liabil": 0, "damag": 0, "result": [0, 52, 56], "from": [0, 1, 2, 4, 5, 6, 8, 11, 12, 14, 15, 18, 20, 21, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 55, 58, 59, 60, 61, 62], "us": [0, 1, 2, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22, 23, 24, 25, 26, 28, 30, 33, 34, 35, 38, 40, 41, 42, 43, 44, 45, 46, 48, 49, 50, 52, 53, 54, 55, 56, 59, 61, 62], "fullest": 0, "extent": 0, "possibl": [0, 1, 10, 16, 23, 24, 25, 26, 27, 29, 31, 32, 33, 35, 37, 42, 43, 44, 49, 50, 56, 59, 60, 61], "standard": [0, 2, 4, 9, 15, 22, 25, 33, 35, 44, 54, 55], "set": [0, 1, 2, 13, 14, 15, 16, 21, 22, 23, 26, 27, 28, 30, 33, 34, 35, 38, 49, 59, 60, 63], "creator": 0, "right": [0, 1, 5, 9, 10, 11, 22, 25, 26, 28, 30, 33, 37, 38, 41, 54, 55, 63], "holder": 0, "mai": [0, 1, 2, 4, 6, 8, 9, 10, 11, 13, 14, 15, 21, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 38, 42, 43, 45, 54, 55, 59, 61, 63], "share": [0, 1, 2, 4, 5, 6, 8, 10, 12, 14, 23, 24, 26, 27, 30, 33, 34, 35, 37, 38, 42, 44, 49, 54, 56, 59], "origin": [0, 12, 37], "work": [0, 1, 2, 4, 5, 6, 8, 12, 13, 14, 16, 18, 23, 25, 26, 27, 28, 30, 31, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 45, 48, 51, 52, 54, 55, 59, 61], "authorship": 0, "subject": [0, 46, 48], "copyright": 0, "certain": [0, 2, 6, 9, 28, 33, 34, 41, 42, 44], "specifi": 0, "below": [0, 2, 10, 22, 25, 26, 27, 28, 29, 30, 31, 37, 40, 42, 43, 53, 54], "The": [0, 1, 2, 3, 6, 7, 9, 10, 11, 15, 16, 17, 21, 22, 23, 25, 26, 28, 29, 30, 31, 33, 35, 38, 39, 40, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63], "follow": [0, 2, 4, 10, 11, 14, 15, 16, 23, 24, 25, 26, 28, 29, 30, 32, 33, 35, 37, 38, 42, 43, 49, 50, 54, 56, 59], "consider": [0, 28, 33], "ar": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62], "purpos": [0, 25, 33, 34, 49, 50, 53, 54], "onli": [0, 1, 2, 4, 5, 10, 14, 15, 18, 21, 22, 23, 24, 26, 28, 29, 30, 32, 33, 34, 35, 38, 40, 41, 42, 43, 52, 54, 61, 63], "exhaust": [0, 52], "do": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 21, 22, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 37, 38, 40, 41, 43, 44, 49, 50, 52, 53, 54, 56, 59, 61, 63], "form": [0, 4, 11, 18, 21, 22, 24, 28, 31, 32, 34, 35, 37, 40, 41, 42, 43, 46, 48, 56, 59, 63], "part": [0, 1, 2, 4, 9, 10, 11, 13, 14, 15, 16, 23, 25, 28, 30, 33, 34, 37, 38, 40, 41, 42, 43, 46, 52, 54, 56, 58, 59, 63], "our": [0, 2, 4, 8, 9, 13, 14, 15, 18, 23, 24, 25, 26, 28, 30, 31, 32, 33, 34, 35, 36, 37, 40, 42, 43, 44, 45, 48, 52, 54, 55, 59], "licensor": 0, "intend": [0, 12, 56], "those": [0, 1, 6, 11, 21, 23, 37, 39, 41, 42, 48, 52, 54, 56, 59], "author": [0, 37, 41], "permiss": [0, 10, 12, 22, 32, 35, 56], "wai": [0, 2, 3, 4, 5, 9, 12, 13, 14, 15, 23, 24, 26, 27, 28, 29, 30, 33, 38, 41, 42, 43, 48, 52, 55], "otherwis": [0, 2, 9, 18, 26, 31, 36, 38, 40, 42, 46, 55, 63], "restrict": [0, 33, 42], "irrevoc": 0, "should": [0, 1, 2, 4, 6, 8, 9, 10, 12, 13, 14, 15, 16, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 35, 37, 38, 40, 41, 42, 43, 49, 50, 52, 53, 54, 56, 57, 59, 60, 61, 63], "read": [0, 1, 3, 4, 5, 9, 10, 13, 14, 15, 22, 23, 24, 26, 28, 29, 30, 33, 35, 36, 37, 38, 40, 41, 42, 43, 44, 49, 50, 52, 59], "understand": [0, 4, 16, 26, 27, 28, 34, 37, 41, 42, 43, 44], "thei": [0, 1, 2, 4, 5, 6, 7, 8, 10, 12, 15, 16, 17, 21, 22, 23, 26, 27, 28, 29, 31, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 53, 54, 55, 56, 57, 59, 61, 63], "choos": [0, 22, 35, 42, 54], "befor": [0, 4, 5, 6, 7, 11, 13, 14, 15, 16, 18, 23, 27, 28, 29, 30, 31, 37, 39, 40, 41, 42, 49, 50, 55, 58, 59], "appli": [0, 25, 26, 28, 33, 37, 41, 42, 44], "also": [0, 2, 5, 7, 8, 9, 10, 11, 12, 14, 15, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 49, 50, 54, 55, 56, 57, 59, 60, 61, 63], "secur": [0, 11], "necessari": [0, 6, 10, 12, 29, 40, 42], "so": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 14, 15, 16, 21, 22, 23, 25, 26, 28, 30, 32, 33, 34, 35, 37, 38, 40, 41, 42, 43, 46, 48, 49, 50, 52, 53, 54, 55, 56, 59, 61], "can": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 46, 49, 50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63], "reus": [0, 28, 46, 62, 63], "expect": [0, 1, 4, 6, 8, 9, 14, 15, 21, 23, 28, 37, 40, 42, 49, 50, 54, 56, 59, 60], "clearli": [0, 23, 24, 28, 31, 38, 42], "mark": [0, 16, 29, 43], "thi": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 60, 61, 62, 63], "includ": [0, 1, 2, 4, 6, 10, 12, 15, 24, 25, 28, 29, 32, 33, 34, 37, 41, 42, 53, 54, 56, 59, 61], "cc": [0, 17, 54, 56, 62, 63], "except": [0, 2, 34], "limit": [0, 1, 14, 15, 33, 34, 35, 42, 44, 47], "more": [0, 1, 2, 4, 5, 6, 9, 10, 11, 13, 14, 15, 16, 20, 21, 23, 24, 26, 28, 30, 31, 32, 33, 34, 36, 38, 40, 41, 42, 43, 44, 45, 46, 51, 52, 54, 57, 59, 60, 61, 62, 63], "wiki": 0, "creativecommon": 0, "org": [0, 9, 16, 18, 22, 35, 42, 45, 48, 49, 50, 51, 56, 59], "considerations_for_licensor": 0, "By": [0, 5, 14, 15, 27, 30, 33, 37, 38, 63], "one": [0, 1, 2, 3, 4, 5, 6, 8, 10, 15, 16, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 33, 34, 37, 38, 40, 41, 42, 43, 44, 48, 53, 54, 55, 59, 60, 61, 63], "grant": [0, 22], "If": [0, 1, 2, 4, 5, 7, 8, 10, 12, 13, 14, 15, 16, 18, 21, 22, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 41, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 54, 56, 58, 59, 62, 63], "": [0, 1, 2, 4, 5, 8, 10, 11, 13, 14, 15, 16, 21, 22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 37, 38, 41, 42, 43, 44, 48, 49, 50, 52, 53, 54, 55, 56, 59, 60, 62, 63], "reason": [0, 2, 4, 10, 28, 32, 33, 37, 42, 55], "exampl": [0, 1, 2, 3, 4, 8, 15, 21, 23, 28, 30, 31, 32, 36, 37, 41, 42, 43, 44, 53, 54, 55, 56, 59], "becaus": [0, 2, 6, 9, 14, 15, 23, 25, 28, 30, 31, 32, 33, 34, 37, 41, 42, 43, 47, 55], "applic": [0, 1, 28, 33, 41, 42, 62], "regul": 0, "ha": [0, 1, 4, 12, 22, 23, 25, 26, 28, 30, 33, 34, 37, 39, 40, 41, 42, 43, 45, 47, 52, 53, 54, 59, 62], "still": [0, 2, 11, 15, 21, 23, 26, 29, 31, 34, 42, 43, 56], "have": [0, 1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 49, 50, 53, 54, 55, 56, 59, 60, 61, 62], "A": [0, 1, 4, 5, 8, 10, 15, 21, 23, 24, 25, 28, 30, 31, 33, 40, 42, 43, 44, 45, 54, 56, 59, 61, 63], "special": [0, 4, 25, 28, 29, 40, 41, 43], "request": [0, 2, 5, 8, 9, 32, 35, 42, 51, 52, 56, 59, 63], "ask": [0, 2, 3, 4, 6, 8, 10, 13, 14, 15, 16, 23, 24, 25, 28, 30, 31, 35, 37, 38, 40, 41, 42, 43, 48, 49, 53, 54, 56, 59, 62], "chang": [0, 1, 4, 10, 12, 22, 26, 29, 32, 35, 38, 39, 41, 42, 54, 59], "describ": [0, 4, 5, 16, 20, 21, 26, 33, 34, 40, 42, 53, 56, 63], "although": [0, 37, 56], "requir": [0, 2, 4, 14, 15, 22, 26, 27, 29, 33, 34, 37, 41, 42, 44, 49, 50, 56, 58, 59], "you": [0, 1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28, 29, 30, 32, 33, 34, 35, 36, 38, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 58, 59, 61, 62], "encourag": [0, 2, 23, 34, 35, 37, 38, 41, 42, 49, 56, 62, 63], "respect": [0, 33, 38, 54], "where": [0, 2, 4, 13, 14, 15, 16, 23, 29, 31, 33, 35, 37, 38, 39, 40, 42, 43, 44, 49, 53, 56, 59, 61, 63], "considerations_for_license": 0, "exercis": [0, 3, 4, 6, 8, 10, 13, 14, 15, 17, 21, 23, 24, 27, 29, 30, 31, 34, 37, 43, 44, 46, 49, 54, 61, 63], "defin": [0, 23, 27, 43, 44], "accept": [0, 5, 6, 19, 21, 34, 42, 52, 54], "agre": [0, 2, 11, 32, 35, 43, 54], "bound": 0, "To": [0, 1, 6, 8, 22, 23, 25, 30, 42, 48, 56], "interpret": [0, 10, 33], "contract": [0, 2], "your": [0, 1, 2, 4, 5, 6, 8, 10, 11, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 27, 28, 29, 30, 32, 34, 35, 38, 41, 42, 43, 44, 45, 46, 48, 49, 50, 52, 54, 56, 57, 59], "benefit": [0, 3, 29, 34, 43, 44, 56], "receiv": [0, 4, 22, 40, 47], "section": [0, 10, 11, 23, 26, 28, 29, 33, 37, 38, 40, 42, 43, 53, 56, 60, 62], "1": [0, 2, 8, 10, 11, 22, 26, 35, 41, 42, 46, 53, 54, 59], "definit": [0, 34, 44], "adapt": [0, 22, 23, 28, 37, 38, 52, 59], "mean": [0, 4, 12, 21, 23, 27, 31, 37, 41, 43, 52, 56, 59, 61], "similar": [0, 1, 2, 10, 25, 26, 30, 33, 34, 37, 38, 41, 44, 53, 56, 61], "deriv": 0, "base": [0, 6, 16, 18, 26, 28, 29, 30, 33, 35, 52, 63], "upon": 0, "which": [0, 1, 2, 3, 4, 5, 8, 9, 11, 12, 15, 16, 20, 22, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 37, 38, 41, 42, 43, 45, 49, 50, 52, 53, 54, 56, 63], "translat": [0, 34], "alter": 0, "arrang": [0, 6, 10, 13, 23, 25, 35, 42, 60, 61], "transform": [0, 33], "modifi": [0, 28, 29, 56, 59], "manner": [0, 31, 40], "held": [0, 32, 47, 55, 56], "For": [0, 1, 4, 10, 11, 22, 23, 25, 26, 28, 30, 33, 37, 42, 49, 50, 52, 54, 55, 56, 60], "music": [0, 33], "perform": [0, 33], "sound": [0, 1, 26, 33, 37, 48], "record": [0, 1, 15, 25, 30, 34, 42, 53, 54, 59], "alwai": [0, 1, 2, 4, 5, 8, 11, 12, 15, 23, 25, 27, 29, 30, 33, 36, 38, 42, 43, 46, 48, 52], "produc": [0, 23, 32, 33, 34, 37, 53, 55], "synch": 0, "time": [0, 1, 2, 4, 5, 6, 8, 9, 10, 11, 12, 16, 21, 22, 23, 24, 26, 27, 28, 30, 31, 33, 34, 35, 38, 40, 41, 42, 43, 44, 46, 48, 49, 50, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63], "move": [0, 8, 21, 26, 30, 33, 35, 38, 42, 43, 59], "imag": [0, 33, 35], "b": [0, 8, 33, 41, 42, 43], "contribut": [0, 16, 17, 37, 42, 52, 56, 59, 62, 63], "accord": [0, 6, 40], "c": [0, 8, 16, 41, 42, 59], "close": [0, 11, 15, 22, 23, 33, 34, 37, 40, 56, 59], "without": [0, 1, 2, 4, 5, 10, 11, 14, 15, 16, 26, 29, 33, 36, 40, 42, 54, 55, 56], "broadcast": [0, 4, 6, 17, 23, 30, 34, 35, 55, 62], "sui": 0, "generi": 0, "databas": 0, "how": [0, 1, 4, 6, 8, 10, 11, 12, 13, 14, 16, 25, 26, 28, 29, 31, 33, 34, 38, 40, 41, 48, 49, 50, 52, 53, 54, 56, 59], "label": [0, 28, 29, 41, 54], "categor": 0, "2": [0, 2, 8, 10, 22, 28, 41, 42, 46, 52, 54, 59], "d": [0, 15, 23, 41], "effect": [0, 12, 28, 33, 35, 41], "technolog": 0, "measur": [0, 28, 33, 34, 37, 56], "absenc": 0, "proper": [0, 28, 29], "circumv": 0, "fulfil": 0, "oblig": 0, "articl": [0, 3, 28, 35, 41, 49], "11": [0, 8, 46], "wipo": 0, "treati": 0, "adopt": [0, 5, 13, 14, 15, 43], "decemb": 0, "20": [0, 1, 10, 22, 23, 28, 33, 43, 50, 59, 61], "1996": 0, "agreement": [0, 2, 9], "e": [0, 1, 4, 6, 8, 9, 16, 22, 26, 28, 33, 34, 35, 37, 38, 41, 43, 52, 54, 55, 56, 61], "fair": 0, "deal": [0, 33, 37], "f": [0, 26, 41], "artist": 0, "literari": 0, "g": [0, 1, 4, 6, 8, 16, 22, 28, 33, 34, 35, 37, 38, 41, 43, 54, 55, 56, 61], "h": [0, 41, 62, 63], "individu": [0, 4, 15, 24, 35, 42, 59, 61], "entiti": [0, 57], "process": [0, 12, 20, 21, 26, 28, 33, 40, 44, 52, 53, 55, 56, 59], "reproduct": 0, "displai": [0, 6, 10, 22, 26, 33], "dissemin": [0, 59, 61], "commun": [0, 2, 4, 23, 27, 30, 31, 32, 33, 36, 37, 40, 42, 45, 57, 58, 59, 60], "import": [0, 1, 2, 4, 8, 9, 10, 11, 13, 20, 23, 24, 26, 28, 30, 33, 35, 37, 38, 40, 41, 42, 43, 44, 46, 49, 50, 53, 54, 56, 59], "member": [0, 2, 4, 9, 42], "access": [0, 4, 22, 26, 33, 37, 41, 42], "place": [0, 2, 8, 11, 14, 15, 16, 23, 29, 30, 40, 46, 49, 51, 53, 54, 57, 59, 63], "chosen": [0, 33, 35], "them": [0, 1, 4, 5, 8, 10, 12, 13, 14, 15, 18, 21, 23, 24, 26, 28, 29, 33, 35, 37, 38, 40, 41, 42, 43, 46, 53, 54, 55, 59, 61], "j": [0, 41], "than": [0, 1, 4, 5, 8, 10, 14, 15, 21, 23, 25, 26, 28, 30, 31, 33, 35, 36, 38, 40, 41, 42, 43, 44, 46, 53, 54, 55, 59, 60], "direct": [0, 4, 10, 31, 38, 52, 61], "96": 0, "9": [0, 26, 30, 42, 46], "ec": 0, "european": 0, "parliament": 0, "council": [0, 9], "march": [0, 22], "protect": [0, 22, 34], "amend": 0, "succeed": 0, "well": [0, 2, 6, 8, 10, 12, 13, 14, 23, 25, 28, 29, 30, 31, 32, 33, 35, 37, 38, 40, 41, 42, 43, 58, 59, 61, 62], "essenti": [0, 24, 26, 28, 42], "equival": [0, 26, 34, 52], "anywher": 0, "world": [0, 1, 4, 28, 31, 34], "k": [0, 41], "correspond": [0, 6, 35, 52], "scope": [0, 11], "herebi": 0, "worldwid": 0, "royalti": 0, "free": [0, 1, 2, 3, 13, 16, 17, 21, 23, 24, 25, 30, 37, 42, 51, 59], "non": [0, 1, 11, 21, 23, 30, 33, 44, 54], "sublicens": 0, "exclus": 0, "reproduc": [0, 16, 44, 59], "whole": [0, 4, 13, 24, 30, 32, 42, 43, 52], "avoid": [0, 1, 2, 5, 10, 25, 26, 33, 34, 41, 56], "doubt": [0, 26, 43, 56], "need": [0, 1, 2, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 18, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33, 34, 35, 37, 38, 39, 40, 41, 43, 44, 46, 49, 50, 52, 53, 54, 55, 56, 57, 59, 60, 61, 62, 63], "compli": 0, "3": [0, 8, 10, 30, 41, 47, 53, 56, 59], "6": [0, 28, 31, 33, 59], "media": [0, 33, 43], "format": [0, 4, 11, 33, 34, 40, 43, 56], "technic": [0, 1, 3, 17, 23, 24, 27, 34, 38, 40, 41, 42, 49, 61, 62], "modif": [0, 62, 63], "allow": [0, 1, 4, 9, 10, 15, 23, 24, 28, 31, 35, 36, 38, 40, 42, 43, 49], "whether": [0, 5, 15, 31, 38, 48, 63], "now": [0, 1, 3, 4, 9, 10, 22, 23, 25, 26, 33, 34, 37, 42, 43, 44, 45, 47, 56, 59, 62], "known": [0, 32, 33, 57, 59, 62], "hereaft": 0, "waiv": 0, "assert": 0, "forbid": 0, "simpli": [0, 5, 14, 15], "never": [0, 1, 11, 23, 24, 25, 32, 34, 38, 42, 44, 55], "5": [0, 1, 4, 8, 10, 22, 23, 25, 31, 33, 35, 41, 46, 48, 52, 53, 59], "downstream": 0, "recipi": [0, 22], "offer": [0, 15, 37, 38, 41, 49, 50], "everi": [0, 1, 4, 10, 14, 15, 21, 26, 28, 29, 30, 33, 37, 39, 42, 43, 52, 53, 59], "automat": [0, 1, 11, 15, 22, 30, 33, 35, 41, 54, 62], "No": [0, 8, 16, 21, 34, 42, 55], "impos": 0, "addit": [0, 22, 37], "differ": [0, 1, 4, 5, 6, 8, 11, 23, 24, 26, 28, 30, 33, 37, 38, 40, 41, 42, 43, 44, 57], "endors": 0, "noth": [0, 1, 22, 26, 37, 41, 42, 53, 56, 62], "constitut": 0, "constru": 0, "impli": [0, 33, 38, 42], "connect": [0, 1, 23, 28, 29, 30, 32, 35, 41, 42, 49, 61], "sponsor": [0, 9], "offici": [0, 37], "statu": [0, 10, 22, 42], "design": [0, 1, 4, 15, 16, 29, 31, 34, 37, 42, 44], "moral": 0, "integr": [0, 28, 41, 52], "nor": [0, 30, 42], "privaci": [0, 15, 25, 33, 34, 53], "person": [0, 1, 2, 3, 7, 8, 10, 14, 15, 16, 17, 20, 23, 24, 26, 27, 31, 33, 34, 35, 37, 38, 40, 41, 42, 43, 44, 47, 53, 54, 56, 58, 59], "howev": [0, 1, 9, 13, 14, 15, 24, 33, 37, 52, 56], "patent": 0, "trademark": 0, "collect": [0, 1, 4, 24, 29, 33, 40, 56], "directli": [0, 4, 6, 30, 33, 34, 59, 61], "through": [0, 1, 3, 4, 5, 8, 15, 16, 28, 29, 31, 33, 37, 41, 42, 43, 46, 49, 50, 52, 54, 56, 61], "societi": 0, "voluntari": 0, "waivabl": 0, "statutori": 0, "compulsori": 0, "scheme": [0, 54], "In": [0, 1, 6, 9, 12, 14, 15, 22, 23, 24, 26, 27, 28, 30, 31, 33, 34, 35, 37, 40, 42, 43, 46, 49, 51, 52, 53, 54, 55, 62, 63], "case": [0, 1, 2, 3, 10, 15, 25, 26, 29, 33, 35, 40, 43, 44, 51, 55], "expressli": 0, "reserv": [0, 14, 15, 23, 31, 56], "made": [0, 1, 5, 9, 16, 21, 26, 28, 32, 37, 40], "must": [0, 16, 28, 34, 41, 42], "retain": 0, "suppli": 0, "identif": 0, "pseudonym": 0, "ii": 0, "notic": [0, 30, 38, 41, 43, 52, 61], "iii": 0, "refer": [0, 4, 8, 11, 17, 28, 29, 30, 34, 41, 43, 44, 54, 58], "iv": 0, "v": [0, 4, 30, 34, 41, 42, 57], "uri": 0, "hyperlink": 0, "practic": [0, 3, 4, 5, 6, 13, 14, 15, 23, 26, 28, 30, 33, 41, 42, 52, 55, 60], "indic": [0, 11, 53, 59], "previou": [0, 22, 30, 37, 52, 61], "text": [0, 4, 10, 11, 18, 25, 26, 29, 32, 33, 37, 38, 44, 54, 56, 59], "satisfi": 0, "medium": [0, 33], "context": [0, 10, 38], "resourc": [0, 41], "remov": [0, 10, 11, 22, 29, 30, 33, 34, 35, 49, 50, 54, 55, 59], "prevent": [0, 1, 21, 30, 42, 54], "extract": 0, "substanti": 0, "portion": [0, 23, 24, 25, 26, 30, 33], "content": [0, 1, 2, 25, 26, 33, 38, 41, 44, 53, 54, 55, 59], "supplement": 0, "replac": [0, 28, 40, 41], "unless": [0, 32, 37, 54, 62, 63], "separ": [0, 1, 4, 12, 23, 24, 26, 31, 33, 34, 37, 41, 43, 53, 59, 60, 62, 63], "undertaken": 0, "BY": [0, 17, 54, 56, 62, 63], "THE": 0, "TO": [0, 54], "AS": 0, "AND": 0, "NO": 0, "represent": 0, "OR": [0, 42], "OF": 0, "kind": [0, 33, 37], "concern": 0, "express": [0, 2], "titl": [0, 1, 6, 10, 22, 26, 30, 32, 33, 37, 41, 49, 53], "merchant": 0, "fit": [0, 1, 6, 15, 30, 33, 41], "FOR": 0, "particular": [0, 1, 5, 6, 8, 41, 43, 56], "infring": 0, "latent": 0, "defect": 0, "accuraci": 0, "presenc": [0, 4], "error": [0, 38], "NOT": 0, "discover": 0, "IN": 0, "full": [0, 1, 18, 24, 25, 26, 30, 33, 34, 40, 42, 51, 52, 53, 54, 63], "event": [0, 2, 20, 21, 26, 32, 35, 37, 40, 41, 42, 46, 48, 56, 61], "WILL": 0, "BE": 0, "liabl": 0, "ON": 0, "theori": [0, 1, 17, 34, 41, 43], "neglig": 0, "indirect": 0, "incident": 0, "consequenti": 0, "punit": 0, "exemplari": 0, "loss": 0, "cost": [0, 5, 23, 24, 37], "expens": 0, "aris": 0, "out": [0, 1, 4, 8, 10, 12, 13, 14, 15, 22, 23, 26, 28, 29, 33, 37, 38, 41, 42, 44, 45, 49, 50, 51, 53, 54, 55, 56, 59, 60], "even": [0, 2, 3, 4, 5, 10, 13, 14, 15, 21, 23, 28, 29, 31, 33, 34, 35, 36, 37, 40, 41, 42, 43, 44, 55, 56, 60, 63], "IF": 0, "been": [0, 1, 12, 22, 26, 33, 35, 40, 42, 43, 46, 47], "advis": 0, "SUCH": 0, "abov": [0, 1, 6, 10, 21, 22, 25, 26, 28, 29, 33, 34, 35, 37, 40, 43, 44, 62], "shall": 0, "most": [0, 1, 3, 4, 12, 13, 14, 15, 16, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 37, 38, 40, 41, 42, 43, 44, 45, 52, 54, 59, 60, 61, 62], "approxim": [0, 9], "absolut": [0, 15, 25], "waiver": 0, "termin": [0, 2, 3, 16, 23, 25, 35, 38], "here": [0, 2, 4, 11, 14, 23, 25, 27, 28, 30, 32, 33, 34, 36, 37, 38, 40, 43, 44, 45, 54, 56, 59], "fail": [0, 13, 14, 41], "reinstat": 0, "date": [0, 12, 22, 23, 26, 35, 37, 39, 45, 47, 49, 50, 56], "violat": 0, "cure": 0, "within": [0, 2, 4, 8, 10, 17, 22, 23, 31, 41, 42, 52, 53], "30": [0, 1, 33, 42, 43, 54, 61], "dai": [0, 6, 10, 13, 14, 15, 16, 22, 23, 24, 26, 33, 37, 38, 40, 42, 47, 49, 52, 53, 54, 56, 59, 60], "discoveri": 0, "affect": [0, 33, 48, 52], "seek": [0, 42], "remedi": 0, "stop": [0, 1, 12, 23, 25, 30, 33, 37, 38, 54], "7": [0, 8, 26, 33, 41, 46], "8": [0, 8, 42, 43], "surviv": 0, "state": [0, 21, 24, 28, 29, 34], "herein": 0, "independ": [0, 4, 15, 16, 23, 28, 33, 34, 42], "reduc": [0, 10, 26, 28, 34, 43, 55], "could": [0, 4, 5, 8, 9, 10, 12, 14, 15, 16, 18, 21, 28, 31, 33, 34, 36, 37, 40, 42, 43, 46, 53, 54], "lawfulli": 0, "provis": 0, "deem": 0, "unenforc": 0, "reform": 0, "minimum": [0, 23, 26, 42, 60], "enforc": [0, 41], "cannot": [0, 35, 40, 42, 49, 50], "sever": [0, 3, 9, 30, 33, 42, 54], "remain": [0, 10, 21], "failur": 0, "consent": [0, 35, 59], "privileg": 0, "immun": 0, "jurisdict": 0, "parti": [0, 34], "notwithstand": 0, "elect": 0, "publish": [0, 11, 15, 30, 33, 34, 35, 54, 59], "instanc": 0, "consid": [0, 2, 9, 10, 11, 13, 14, 15, 24, 25, 26, 28, 37, 38, 41, 44, 46, 56], "dedic": [0, 1, 26, 34], "domain": [0, 42, 43], "cc0": 0, "permit": 0, "polici": 0, "logo": [0, 17, 33], "prior": 0, "written": [0, 4, 16, 23, 37, 44], "unauthor": 0, "paragraph": [0, 37], "contact": [0, 7, 22, 40, 42, 45, 59, 61], "page": [1, 3, 4, 10, 11, 12, 13, 14, 15, 17, 22, 23, 27, 33, 37, 39, 40, 41, 53, 54, 59, 60], "explain": [1, 2, 3, 23, 27, 29, 37, 38, 41, 43], "guid": [1, 5, 13, 14, 15, 17, 27, 28, 31, 33, 34, 38, 41, 42, 46, 54, 56, 59, 61, 62], "ob": [1, 4, 30, 33, 34, 40, 53], "manag": [1, 3, 4, 8, 16, 17, 22, 23, 30, 34, 37, 38, 41, 43, 45, 46, 57, 63], "thu": [1, 13, 14, 16, 21, 23, 28, 32, 33, 40, 44, 52], "stream": [1, 4, 6, 15, 23, 24, 25, 27, 30, 31, 32, 34, 42, 53, 54, 58, 59], "often": [1, 4, 10, 13, 14, 15, 26, 33, 40, 53], "director": [1, 12, 17, 43], "todo": [1, 6, 12, 19, 23, 35, 37, 52], "link": [1, 10, 11, 22, 23, 27, 28, 32, 34, 35, 37, 41, 42, 44, 53, 54, 56], "who": [1, 2, 4, 8, 10, 11, 15, 18, 21, 22, 23, 27, 30, 32, 34, 35, 36, 37, 40, 41, 43, 44, 48, 52, 53, 54, 56, 57, 59, 61], "switch": [1, 8, 11, 21, 22, 23, 25, 30, 33, 38, 40, 42, 43, 62], "scene": [1, 23, 30], "after": [1, 6, 8, 10, 12, 13, 14, 15, 21, 22, 23, 24, 26, 27, 29, 31, 32, 33, 39, 40, 41, 42, 44, 49, 50, 58, 59], "start": [1, 3, 4, 5, 6, 10, 12, 13, 14, 15, 16, 17, 22, 27, 28, 29, 33, 34, 35, 37, 41, 42, 43, 44, 49, 50, 52, 53, 54, 55, 62], "As": [1, 4, 5, 8, 11, 26, 31, 33, 38, 42, 43, 54, 55], "captur": [1, 6, 26, 30, 33], "zoom": [1, 4, 6, 7, 8, 12, 15, 17, 21, 24, 25, 26, 27, 30, 31, 33, 34, 40, 42, 49, 53, 54, 56, 59, 60], "send": [1, 2, 10, 18, 22, 32, 33, 39, 42, 43, 48, 56, 59], "overal": [1, 3, 6, 26, 28, 29, 30, 43], "flow": [1, 3, 4, 6, 10, 11, 20, 28, 40, 42, 63], "workshop": [1, 2, 4, 5, 7, 8, 11, 12, 20, 22, 23, 26, 27, 30, 31, 32, 34, 37, 39, 43, 46, 47, 49, 50, 51, 52, 53, 55, 63], "cue": [1, 6, 40], "instructor": [1, 5, 6, 7, 8, 10, 11, 17, 28, 29, 30, 34, 36, 37, 38, 42, 43, 46, 48, 54, 56, 57, 58, 61], "when": [1, 2, 3, 4, 5, 6, 8, 10, 14, 15, 16, 21, 23, 24, 25, 26, 27, 28, 29, 30, 33, 34, 35, 37, 38, 40, 42, 43, 44, 54, 56, 59, 61, 62], "talk": [1, 2, 3, 4, 8, 10, 14, 15, 23, 24, 28, 30, 31, 33, 34, 37, 41, 42, 43], "hackmd": [1, 3, 4, 6, 8, 11, 15, 17, 23, 24, 25, 27, 31, 32, 33, 34, 35, 39, 43, 54, 56, 59, 60, 62], "break": [1, 4, 6, 8, 10, 14, 15, 23, 24, 30, 31, 33, 38, 40, 42, 53, 54, 55, 56, 60, 61], "clariti": 1, "we": [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 42, 43, 44, 46, 47, 48, 49, 50, 51, 52, 53, 56, 58, 59, 60, 61, 62, 63], "precis": [1, 33, 54], "host": [1, 4, 6, 7, 17, 27, 30, 34, 35, 43, 60, 61, 62], "interfac": [1, 32, 35, 42], "between": [1, 3, 8, 9, 10, 11, 21, 23, 25, 26, 28, 29, 30, 33, 35, 37, 40, 42, 43, 60], "audienc": [1, 3, 5, 6, 9, 15, 23, 29, 31, 33, 34, 36, 38, 40, 41, 42, 43, 45, 53, 56, 59], "announc": [1, 2, 5, 6, 9, 22, 31, 32, 40, 52, 54], "keep": [1, 4, 6, 10, 11, 12, 23, 26, 29, 33, 35, 37, 39, 40, 42, 43, 46, 48, 49, 56, 59, 63], "schedul": [1, 13, 14, 15, 31, 35, 40, 42, 50, 56, 59], "etc": [1, 2, 10, 24, 25, 26, 29, 33, 37, 38, 42, 43, 45, 46, 55, 56, 57, 60, 61], "veri": [1, 2, 3, 4, 5, 8, 9, 11, 13, 14, 15, 16, 23, 25, 26, 28, 31, 33, 37, 38, 41, 42, 44, 46, 48, 49, 52, 53], "same": [1, 2, 4, 8, 13, 14, 15, 23, 25, 26, 29, 30, 33, 34, 35, 38, 40, 41, 42, 43, 44, 54, 55, 61], "teach": [1, 2, 6, 15, 23, 25, 27, 28, 29, 31, 35, 36, 40, 42, 44, 46, 48, 54, 56, 57, 59, 60, 61], "least": [1, 6, 13, 28, 30, 38, 40, 41, 42, 43, 52, 54, 56, 61], "know": [1, 2, 4, 5, 6, 8, 16, 23, 26, 28, 29, 31, 32, 33, 34, 37, 39, 40, 41, 42, 43, 44, 49, 50, 51, 61, 63], "bit": [1, 15, 21, 24, 25, 42, 56], "about": [1, 2, 3, 4, 5, 6, 10, 11, 13, 14, 15, 16, 20, 23, 24, 26, 27, 28, 30, 33, 35, 37, 38, 40, 41, 42, 43, 44, 45, 46, 48, 49, 50, 51, 54, 56, 59, 61], "lot": [1, 2, 4, 5, 6, 8, 9, 13, 14, 15, 24, 26, 30, 31, 33, 37, 40, 42, 45, 52, 53, 58, 61, 63], "prepar": [1, 5, 6, 13, 14, 15, 17, 22, 26, 28, 30, 33, 40, 49, 50, 55, 59], "first": [1, 2, 10, 11, 16, 18, 22, 23, 25, 26, 28, 34, 38, 40, 42, 44, 49, 52, 53, 54, 59, 63], "get": [1, 2, 4, 5, 8, 9, 10, 12, 13, 14, 15, 21, 22, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 59, 61], "up": [1, 2, 3, 4, 6, 8, 9, 10, 12, 13, 14, 15, 22, 23, 25, 26, 27, 28, 29, 30, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 46, 47, 49, 50, 51, 52, 54, 59, 60, 62, 63], "futur": [1, 5, 9, 12, 16, 17, 22, 23, 26, 42, 46, 48], "cours": [1, 2, 3, 4, 6, 8, 10, 11, 13, 15, 16, 17, 23, 24, 25, 26, 27, 28, 30, 31, 33, 37, 38, 40, 41, 42, 43, 44, 45, 48, 51, 53, 54, 55, 59, 62], "aren": [1, 2, 4, 5, 8, 10, 26, 28, 37, 40, 41, 42, 44, 52, 54], "t": [1, 2, 4, 5, 6, 8, 10, 12, 13, 14, 15, 16, 17, 18, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 40, 41, 42, 43, 44, 47, 48, 49, 50, 52, 53, 54, 56, 62], "bad": [1, 34, 38, 41, 43, 44, 54], "some": [1, 2, 3, 4, 5, 8, 9, 10, 11, 13, 14, 15, 16, 23, 25, 26, 27, 28, 30, 31, 33, 34, 35, 37, 38, 40, 41, 42, 43, 44, 46, 49, 50, 52, 54, 55, 56, 57, 59, 61], "panick": 1, "fix": [1, 11, 12, 15, 28, 29, 30, 41, 56], "stuff": [1, 2, 14, 15, 23, 25, 26, 33, 37, 41, 44, 54], "themselv": [1, 2, 4, 23, 28, 33, 37, 41, 42, 56, 61], "mainli": [1, 4, 8, 13, 14, 21, 28, 33, 40, 43, 52, 53], "sit": [1, 13, 38, 42, 56, 61], "back": [1, 4, 8, 10, 11, 22, 23, 27, 33, 34, 37, 38, 41, 42, 54], "sure": [1, 3, 4, 5, 6, 7, 8, 10, 14, 15, 16, 18, 23, 24, 25, 26, 28, 29, 32, 33, 35, 37, 39, 40, 41, 42, 43, 51, 54, 56, 57, 59, 62], "prerequisit": [1, 23, 29, 44], "somewhat": [1, 12, 33, 37, 50], "power": [1, 33], "comput": [1, 2, 3, 4, 6, 12, 14, 15, 16, 22, 29, 33, 35, 42, 49, 52, 57, 59], "much": [1, 2, 4, 6, 8, 10, 13, 14, 15, 23, 25, 26, 28, 30, 31, 33, 34, 36, 38, 40, 41, 42, 43, 44, 54, 55, 56, 63], "complic": [1, 24], "stabl": [1, 61], "internet": [1, 33, 34], "speed": [1, 15], "too": [1, 2, 4, 8, 10, 11, 12, 13, 15, 23, 25, 26, 28, 30, 33, 36, 37, 38, 40, 41, 42, 43, 44, 47, 51, 54, 55, 56, 61], "download": [1, 10, 12, 17, 22, 49, 54], "upload": [1, 12, 33, 40, 53, 54, 55, 59], "mbp": 1, "probabl": [1, 6, 22, 23, 29, 33, 37, 38, 42, 44, 53, 54, 59, 62, 63], "plenti": [1, 2, 4, 6, 23, 40], "good": [1, 3, 4, 5, 6, 8, 13, 14, 15, 16, 23, 24, 25, 26, 27, 28, 30, 32, 33, 34, 37, 38, 41, 42, 43, 44, 54, 55, 59, 61], "100": [1, 26, 42], "10": [1, 10, 13, 14, 15, 23, 28, 33, 38, 40, 41, 42, 50, 53, 56, 60], "far": [1, 16, 29, 33, 44, 52, 54], "wire": [1, 25], "rather": [1, 10, 15, 38, 41, 45, 54], "wireless": [1, 25, 56, 61], "better": [1, 3, 8, 13, 14, 15, 22, 23, 25, 26, 28, 29, 30, 31, 33, 34, 35, 37, 41, 42, 43, 44, 53, 54, 55], "wifi": 1, "cellular": 1, "uplink": 1, "stabil": [1, 23], "best": [1, 6, 13, 14, 15, 23, 26, 28, 31, 34, 37, 38, 39, 42, 43, 44, 49, 50, 51, 63], "want": [1, 2, 4, 8, 9, 13, 14, 15, 16, 18, 19, 21, 23, 24, 26, 27, 28, 31, 32, 33, 35, 36, 37, 38, 41, 42, 43, 44, 47, 48, 49, 51, 58, 59, 61, 62, 63], "continu": [1, 12, 15, 16, 24, 31, 33, 37, 42, 48, 54], "smooth": [1, 6], "jitter": 1, "tune": [1, 33], "larger": [1, 4, 25, 26, 36, 42], "buffer": [1, 33], "handl": [1, 21, 31, 33, 42, 43], "softwar": [1, 2, 8, 16, 17, 26, 27, 32, 34, 37, 41, 42, 45, 46, 49, 50, 54, 56, 59, 61], "instal": [1, 2, 8, 23, 26, 31, 40, 41, 49, 50, 56, 59], "linux": [1, 10, 16, 33], "mac": [1, 54], "window": [1, 11, 13, 14, 15, 16, 24, 25, 30, 33, 35, 42, 61, 62, 63], "mass": [1, 57], "market": [1, 17, 39], "product": [1, 4, 33, 54], "support": [1, 7, 15, 18, 22, 26, 31, 35, 37, 40, 42, 44, 48, 49, 50, 54, 56, 59], "websocket": 1, "fairli": [1, 54], "widespread": [1, 33], "slightli": [1, 3, 4, 11, 21, 23, 26, 40, 43, 59], "less": [1, 23, 24, 25, 26, 33, 35, 38, 41, 43, 44, 56], "like": [1, 4, 5, 11, 13, 14, 15, 16, 23, 25, 26, 27, 30, 31, 32, 33, 35, 37, 41, 42, 43, 44, 46, 52, 53, 54, 56, 61, 63], "alreadi": [1, 4, 6, 16, 23, 28, 29, 32, 41, 48, 49, 50, 58, 61], "There": [1, 3, 4, 8, 9, 10, 11, 13, 14, 15, 25, 27, 28, 30, 31, 33, 35, 37, 42, 43, 44, 52, 58, 61, 63], "gener": [1, 2, 3, 4, 5, 17, 22, 23, 25, 26, 30, 31, 33, 34, 35, 37, 38, 40, 41, 42, 43, 52, 54, 59], "dual": [1, 12, 25, 30, 33, 41, 62], "monitor": [1, 4, 8, 12, 14, 15, 23, 25, 30, 33, 35, 37, 62], "ye": [1, 5, 6, 8, 14, 15, 16, 21, 30, 37, 63], "despit": [1, 9, 14, 40], "name": [1, 10, 11, 16, 18, 22, 32, 33, 42, 45, 47, 53, 54, 55, 56, 59], "two": [1, 3, 4, 10, 22, 23, 24, 26, 27, 28, 33, 38, 40, 41, 42, 43, 53, 54, 56, 59, 61], "galleri": [1, 6, 12, 25, 30, 33], "view": [1, 2, 3, 6, 10, 11, 12, 22, 25, 26, 30, 33, 35, 37, 43, 59, 62], "screenshar": [1, 3, 6, 10, 15, 23, 25, 26, 33, 35, 60, 62], "activ": [1, 2, 5, 6, 15, 22, 23, 24, 30, 33, 37, 40, 42, 43, 44, 52, 56, 63], "speaker": [1, 12, 14, 15, 33, 35], "enter": [1, 22, 26, 35, 63], "screen": [1, 3, 4, 6, 8, 12, 14, 15, 23, 24, 27, 30, 33, 34, 35, 38, 41, 42, 43, 49, 54, 59, 61], "join": [1, 2, 4, 8, 10, 12, 13, 14, 15, 24, 26, 27, 30, 31, 32, 35, 40, 46, 48, 49, 57, 58, 60, 62, 63], "meet": [1, 5, 9, 14, 15, 17, 20, 24, 26, 33, 35, 40, 42, 43, 62], "fals": [1, 41], "particip": [1, 4, 22, 35, 38, 40, 46, 48, 54, 59, 61, 62, 63], "scale": [1, 4, 25, 30, 31, 36, 40, 46], "true": 1, "clone": [1, 22, 56], "repositori": [1, 5, 16, 17, 22, 52, 59], "contain": [1, 17, 22, 28, 29, 33, 35, 41, 42, 49, 50, 54, 56], "pre": [1, 6, 14, 22, 28, 30, 32, 35, 42, 49, 50, 56, 61], "nice": [1, 8, 10, 43], "teachingstream": 1, "profil": [1, 26, 33, 37], "teaching_stream": 1, "thing": [1, 2, 4, 5, 6, 8, 9, 11, 13, 14, 15, 16, 23, 26, 27, 28, 29, 30, 32, 33, 34, 37, 38, 40, 41, 42, 43, 52, 54, 55, 60], "audio": [1, 4, 26, 35, 55], "encod": [1, 33], "adjust": [1, 4, 6, 10, 16, 21, 22, 23, 25, 26, 27, 29, 30, 31, 32, 33, 40, 43, 56, 63], "situat": [1, 28, 38, 43], "At": [1, 4, 11, 28, 32, 34, 43], "file": [1, 22, 26, 28, 29, 32, 33, 35, 38, 53, 54, 55, 56], "path": [1, 16, 32], "look": [1, 3, 8, 10, 11, 12, 13, 16, 18, 22, 23, 26, 29, 33, 42, 43, 44, 49, 50, 53, 54, 55, 56, 58], "readm": [1, 28, 32], "importantli": [1, 26, 42], "840": [1, 4, 25, 30], "horizont": [1, 25, 26], "1080": [1, 4, 25, 30], "vertic": [1, 4, 24, 25, 33, 54], "portrait": [1, 3, 15, 23, 25, 26, 30], "mode": [1, 11, 12, 22, 24, 25, 26, 30, 33, 62], "teaching_streaming_zoomcaptur": 1, "configur": [1, 6, 14, 15, 22, 23, 26, 49, 50, 56, 63], "tell": [1, 2, 13, 15, 26, 28, 33, 37, 38, 40, 42, 43, 53, 57], "_gallerycaptur": 1, "hidden": [1, 2, 26, 30], "sourc": [1, 2, 4, 5, 16, 20, 33, 52, 54, 61], "zoommeet": 1, "click": [1, 2, 8, 18, 21, 22, 33, 62, 63], "properti": [1, 33], "select": [1, 2, 6, 11, 18, 22, 35, 59, 63], "me": [1, 13, 14, 15, 32, 37, 43, 46, 51, 56], "size": [1, 6, 16, 22, 25, 33, 54], "until": [1, 10, 24, 25, 37, 42, 53], "larg": [1, 6, 8, 14, 15, 16, 20, 23, 25, 26, 30, 31, 33, 38, 40, 42, 43, 61], "_screenshar": 1, "secondwindow": 1, "fill": [1, 22, 23, 28, 32, 38, 41, 43, 48, 49, 50, 53, 58], "preview": [1, 18, 33, 54], "pane": [1, 26], "ideal": [1, 9, 23, 26, 28, 32, 38, 40, 53], "option": [1, 4, 8, 10, 22, 26, 28, 29, 31, 32, 33, 34, 35, 42, 49, 54, 56, 60, 62, 63], "_hackmd": 1, "_broadcast": 1, "local": [1, 5, 6, 15, 17, 26, 33, 36, 44, 53, 56, 57, 59, 61], "desktop": [1, 2, 25, 33], "default": [1, 2, 26, 33, 42, 59, 60], "explicit": [1, 2, 4, 34, 38, 42], "devic": [1, 11, 13, 14, 15, 33, 41], "what": [1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 22, 23, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 38, 40, 41, 43, 52, 53, 56, 58, 59, 60, 61, 63], "headphon": [1, 14, 15, 33], "note": [1, 2, 3, 4, 6, 8, 11, 12, 19, 21, 22, 23, 24, 25, 26, 28, 30, 33, 35, 38, 40, 41, 42, 49, 50, 53, 54, 56, 59], "feedback": [1, 13, 14, 15, 24, 26, 28, 29, 34, 35, 37, 38, 40, 41, 42, 54, 56, 59], "Be": [1, 26, 34, 35, 37, 42], "care": [1, 26, 28, 33, 37, 38, 41, 54, 56], "microphon": [1, 6, 14, 15, 25, 26, 33, 35, 41, 63], "would": [1, 4, 11, 13, 14, 15, 16, 31, 33, 35, 37, 42, 43, 44, 46, 48, 51, 52, 53, 54, 61], "hear": [1, 4, 13, 14, 15, 23, 28, 48], "mic": [1, 6], "aux": 1, "whatev": [1, 26, 27, 49, 50, 55], "speak": [1, 3, 4, 14, 15, 23, 25, 33, 35, 37, 43, 52, 56, 62, 63], "peopl": [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 14, 15, 16, 19, 20, 21, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 44, 45, 46, 54, 57, 60, 61, 63], "main": [1, 3, 8, 11, 26, 28, 33, 35, 37, 41, 42, 43, 54, 59, 62, 63], "renam": [1, 12, 33, 62, 63], "bottom": [1, 10, 11, 25, 28, 29, 40, 42, 44, 54, 57, 62, 63], "panel": [1, 26, 43], "mixer": [1, 33], "gear": [1, 2, 25, 33], "icon": [1, 2, 33, 63], "broadcasterm": 1, "listen": [1, 13, 14, 15, 43], "socket": 1, "authent": [1, 41], "tool": [1, 2, 5, 15, 16, 23, 24, 28, 33, 34, 41, 42, 46, 49, 50], "server": [1, 26], "enabl": [1, 10, 22, 35], "port": [1, 6, 39, 59], "someth": [1, 2, 4, 10, 13, 14, 15, 23, 24, 26, 28, 29, 32, 34, 37, 38, 40, 41, 42, 43, 46, 53, 54, 56, 59, 63], "password": [1, 6, 35, 49], "ip": 1, "address": [1, 22, 42], "outsid": [1, 2, 5, 26, 27, 32, 37, 41, 44], "On": [1, 4, 15, 33, 45, 47, 48, 49, 59], "ngrok": 1, "forward": [1, 22, 32, 43, 54], "ssl": 1, "document": [1, 4, 9, 10, 16, 17, 24, 28, 30, 31, 34, 36, 40, 41, 42, 44, 45, 46, 62], "http": [1, 4, 6, 9, 10, 16, 20, 22, 26, 30, 32, 33, 34, 35, 42, 45, 46, 48, 49, 50, 51, 53, 54, 55, 56, 59], "github": [1, 5, 6, 10, 16, 22, 26, 29, 32, 42, 46, 49, 50, 53, 54, 55, 56, 59], "com": [1, 2, 4, 6, 16, 22, 26, 30, 32, 34, 48, 55, 56, 59], "obsproject": 1, "blob": 1, "x": [1, 28, 38, 42, 43, 44, 45, 62], "current": [1, 2, 4, 12, 25, 28, 30, 32, 33, 34, 37, 43, 51, 52, 54, 60], "tunnel": 1, "md": [1, 29, 44, 56], "plan": [1, 2, 3, 4, 5, 6, 11, 12, 15, 17, 23, 25, 27, 30, 34, 39, 41, 42, 43, 45, 51, 56, 58, 59, 61], "simultan": 1, "restart": [1, 33, 35], "great": [1, 6, 24, 30, 42, 48, 52], "router": 1, "firewal": 1, "incom": 1, "extern": [1, 13, 14, 15, 33], "verifi": [1, 22, 35, 59], "tablet": 1, "remot": [1, 23, 26, 33, 42], "twitch": [1, 4, 12, 15, 33, 53, 54, 59], "data": [1, 2, 10, 11, 15, 16, 22, 33, 42, 59], "descript": [1, 3, 4, 22, 28, 30, 37, 42, 43, 53, 54, 55, 59], "channel": [1, 2, 4, 8, 41, 52, 53, 54, 56, 57, 59, 61], "check": [1, 3, 6, 7, 8, 10, 11, 13, 14, 15, 22, 28, 30, 32, 33, 37, 40, 41, 42, 43, 44, 54, 55, 58, 59, 62, 63], "test": [1, 16, 18, 22, 26, 27, 28, 33, 35, 41, 45, 46, 49, 56, 59], "everyth": [1, 2, 4, 8, 18, 23, 26, 30, 33, 34, 36, 37, 38, 40, 41, 42, 43, 59, 60], "basic": [1, 2, 4, 10, 13, 14, 15, 16, 20, 26, 34, 44, 49, 50, 53, 54, 58, 59, 61], "privat": [1, 2, 4, 6, 10, 11, 24, 32, 34, 35, 42, 49, 56], "messag": [1, 2, 32, 33, 35, 38, 41, 42], "info": [1, 10, 14, 22, 32, 34, 40, 56], "attende": [1, 31, 34, 36], "live": [1, 10, 11, 15, 16, 22, 24, 30, 33, 37, 41, 43], "control": [1, 2, 4, 16, 22, 24, 26, 31, 33, 34, 35, 37, 40, 43, 45, 49, 50], "rkd": 1, "zgib": 1, "net": [1, 42], "auto": [1, 6, 33, 35, 59], "config": [1, 6, 26, 29, 33], "raw": [1, 6, 33, 53, 54, 55], "githubusercont": [1, 6], "coderefineri": [1, 3, 6, 10, 16, 18, 20, 22, 23, 25, 27, 30, 31, 32, 34, 36, 37, 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 58, 61], "master": [1, 6, 28, 38, 41], "json": [1, 6, 22], "ensur": [1, 6, 10, 12, 18, 37, 40, 42, 43, 53, 54], "anyth": [1, 2, 10, 16, 19, 23, 24, 28, 29, 33, 37, 40, 42], "done": [1, 2, 5, 10, 21, 23, 24, 26, 28, 29, 30, 32, 33, 38, 40, 41, 42, 44, 52, 54, 55, 60], "layout": [1, 6, 15, 23, 26, 33, 35], "correctli": 1, "flip": [1, 6, 41], "wait": [1, 8, 10, 15, 22, 26, 30, 32, 35, 42, 47, 49, 50, 55, 56], "disabl": [1, 22, 35, 63], "video": [1, 6, 15, 17, 24, 25, 26, 35, 41, 43, 49, 58, 59], "hide": [1, 34, 42], "three": [1, 43], "order": [1, 22, 27, 28, 29, 41, 42, 43, 49, 56, 61], "fewer": [1, 33], "browser": [1, 2, 3, 15, 23, 24, 25, 35, 62], "co": [1, 4, 5, 12, 17, 23, 24, 26, 27, 30, 35, 36, 38, 40, 41, 43, 45, 56, 59, 60], "minut": [1, 4, 8, 10, 13, 14, 15, 23, 35, 37, 42, 43, 48, 49, 50, 53, 56, 59, 60], "advanc": [1, 9, 10, 13, 14, 15, 23, 25, 26, 28, 29, 30, 33, 34, 35, 40, 42, 44, 51], "mute": [1, 2, 4, 6, 23, 24, 30, 33, 35, 62], "card": [1, 6, 33], "don": [1, 2, 4, 6, 8, 10, 12, 13, 14, 15, 16, 17, 18, 22, 23, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 37, 38, 40, 41, 42, 43, 44, 47, 48, 49, 50, 53, 54, 56, 62], "forget": [1, 23, 24, 33, 37, 59], "hand": [1, 2, 7, 13, 14, 15, 22, 23, 24, 28, 33, 35, 38, 40, 41, 43, 46, 60, 61, 62, 63], "off": [1, 4, 6, 24, 26, 28, 29, 30, 33, 34, 37, 42, 43, 52, 54, 56, 57], "yourself": [1, 2, 5, 8, 11, 15, 18, 24, 25, 27, 28, 32, 33, 37, 41, 42, 53, 62, 63], "onc": [1, 2, 4, 9, 12, 14, 15, 22, 26, 28, 33, 34, 36, 41, 43, 53, 63], "icebreak": [1, 6, 10, 13, 14, 15, 58], "mess": [1, 38], "becom": [1, 5, 15, 16, 21, 26, 28, 41, 42, 43, 46, 61], "old": [1, 2, 17, 32, 40, 41, 55, 58, 62], "disappear": 1, "instead": [1, 3, 10, 23, 25, 26, 27, 28, 29, 30, 33, 34, 37, 38, 42, 43, 62], "But": [1, 3, 4, 8, 10, 11, 23, 26, 28, 33, 34, 37, 43, 53, 58], "recommend": [1, 11, 26, 28, 33, 35, 37, 42, 43, 49, 54, 56, 59, 61], "instruct": [1, 5, 15, 20, 24, 25, 26, 41, 42, 55, 56, 59], "might": [1, 2, 6, 8, 12, 15, 22, 23, 25, 26, 27, 28, 30, 33, 34, 35, 37, 42, 43, 44, 49, 54, 55, 63], "front": 1, "emerg": 1, "goe": [1, 4, 10, 15, 25, 31, 37, 40, 43, 63], "down": [1, 2, 14, 25, 38], "crash": 1, "while": [1, 3, 4, 8, 11, 14, 15, 24, 26, 29, 33, 40, 43, 44, 49, 50, 54, 55, 56], "happen": [1, 2, 3, 4, 6, 10, 27, 29, 35, 38, 40, 43, 44, 52, 55], "being": [1, 2, 9, 12, 24, 25, 26, 27, 28, 33, 37, 42, 48, 52, 59], "observ": [1, 38, 41, 59], "mayb": [1, 10, 16, 27, 28, 29, 35, 37, 42], "quit": [1, 8, 11, 23, 33], "wrong": [1, 2, 22, 23, 28, 33, 38, 41, 42, 43], "input": [1, 6, 28, 33, 41, 54], "qualiti": [1, 5, 25, 26, 27, 33, 35, 36, 54, 55, 59], "wa": [1, 5, 12, 16, 26, 32, 33, 34, 35, 37, 42, 44, 46, 48, 52], "horribl": [1, 10], "It": [1, 4, 6, 10, 11, 12, 13, 14, 15, 22, 26, 28, 31, 32, 33, 34, 36, 38, 41, 42, 43, 48, 49, 52, 53, 54, 55, 63], "turn": [1, 4, 6, 23, 24, 26, 28, 30, 33, 41, 42, 49, 50, 62], "system": [1, 2, 16, 24, 26, 30, 33, 35, 38, 40, 42, 56, 58, 59], "got": [1, 26], "confus": [1, 16, 26, 42, 56], "actual": [1, 3, 4, 21, 22, 25, 28, 30, 33, 34, 37, 41, 42, 43, 44, 52, 58, 59], "reflect": 1, "solv": [1, 30, 37], "go": [1, 2, 3, 4, 5, 6, 8, 10, 11, 12, 14, 15, 16, 18, 22, 23, 26, 28, 29, 30, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 48, 49, 50, 52, 53, 54, 56, 60, 62, 63], "ongo": 1, "possibli": [1, 2, 29, 30, 34, 37, 43, 44, 53], "save": [1, 18, 21, 22, 23, 25, 26, 31, 33, 37, 40, 46, 49, 50, 53, 54, 59], "open": [1, 2, 5, 6, 10, 12, 15, 17, 20, 23, 25, 28, 31, 34, 37, 38, 42, 47, 52, 56, 57, 59, 61], "edit": [1, 11, 16, 21, 22, 25, 27, 32, 33, 35, 53, 55, 58, 59], "seem": [1, 2, 8, 33, 35, 36, 37, 38, 43, 44, 54], "try": [1, 3, 4, 8, 10, 11, 12, 13, 14, 15, 23, 26, 27, 28, 36, 37, 41, 42, 43, 44, 46, 54, 56, 59, 62], "run": [1, 3, 4, 5, 6, 20, 23, 26, 27, 31, 33, 37, 42, 43, 49, 50, 59, 60], "onlin": [1, 3, 4, 11, 14, 15, 20, 22, 23, 24, 26, 27, 31, 40, 42, 46, 47, 54, 56], "sinc": [1, 3, 4, 8, 11, 14, 15, 23, 26, 31, 33, 35, 37, 38, 42, 43, 44, 47, 49, 50, 54, 56], "big": [1, 3, 4, 8, 25, 27, 28, 29, 33, 38, 40, 41, 42, 43], "busi": [1, 40, 63], "find": [1, 2, 4, 5, 8, 9, 10, 14, 15, 22, 24, 26, 27, 28, 32, 33, 34, 37, 40, 41, 42, 44, 45, 49, 50, 52, 53, 54, 56, 57, 63], "answer": [1, 4, 8, 10, 11, 15, 16, 23, 24, 28, 30, 35, 38, 40, 41, 42, 43, 46, 48, 53, 56, 59], "question": [1, 2, 3, 4, 8, 10, 13, 14, 15, 22, 23, 24, 26, 28, 30, 31, 34, 35, 38, 40, 41, 43, 46, 49, 50, 56, 58, 59, 62], "primari": [2, 25, 26, 28, 33, 52, 59], "discuss": [2, 4, 6, 9, 10, 11, 13, 14, 15, 23, 27, 28, 30, 33, 34, 37, 38, 41, 42, 43, 46, 52, 53, 56, 59, 60, 63], "action": [2, 9, 18, 32, 33], "take": [2, 6, 8, 9, 10, 12, 22, 23, 24, 25, 26, 28, 33, 34, 35, 36, 37, 38, 41, 42, 43, 46, 49, 52, 54, 55, 56, 59, 61], "mani": [2, 4, 5, 6, 12, 15, 16, 26, 27, 29, 30, 31, 33, 34, 36, 37, 40, 41, 42, 43, 44, 46, 57, 61], "via": [2, 5, 9, 10, 15, 21, 22, 24, 27, 28, 31, 32, 33, 42, 43, 45, 52, 53, 54, 56, 60, 62], "chat": [2, 4, 5, 6, 9, 11, 15, 17, 23, 24, 25, 27, 30, 31, 32, 34, 35, 38, 42, 48, 54, 58, 60, 62, 63], "everybodi": [2, 35, 59], "welcom": [2, 5, 22, 40], "invit": [2, 32, 37, 52, 59, 61], "explicitli": [2, 23, 28, 43], "anyon": [2, 5, 10, 15, 31, 33, 34, 55, 56, 59], "idea": [2, 4, 5, 7, 14, 15, 23, 25, 26, 27, 29, 30, 33, 37, 38, 41, 42, 43, 49, 50, 54, 58, 61], "thread": [2, 11], "joint": 2, "nordichpc": 2, "infrastructur": [2, 9, 42, 52], "nordic": [2, 9, 32, 52, 54], "rse": [2, 32, 59], "usag": [2, 33, 44], "project": [2, 5, 16, 17, 37, 45, 48, 52, 54, 56], "scientif": [2, 20, 37, 59, 61], "togeth": [2, 4, 5, 13, 14, 15, 17, 24, 28, 31, 32, 33, 34, 35, 37, 38, 40, 42, 43, 44, 45], "network": [2, 13, 14, 15, 33, 35, 36, 42, 46, 48, 59], "aspect": [2, 4, 25, 27, 30, 33, 34, 37, 44, 56], "modern": [2, 45, 46], "unlik": [2, 13, 14, 37, 41, 43], "slack": 2, "heavili": [2, 37], "easi": [2, 5, 10, 11, 13, 14, 15, 18, 23, 28, 33, 34, 37, 40, 41, 42], "along": [2, 3, 4, 8, 10, 15, 23, 28, 30, 35, 38, 43, 63], "respond": [2, 37], "topic": [2, 26, 27, 28, 35, 38, 42, 43, 52, 54, 56, 59], "relev": [2, 26, 28, 29, 30, 37, 43, 44, 59, 62], "new": [2, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 21, 22, 24, 26, 27, 28, 30, 32, 33, 34, 38, 41, 42, 43, 46, 48, 54, 56, 59, 60, 61], "sometim": [2, 8, 14, 15, 26, 38, 42, 44, 54, 63], "reviv": 2, "worri": [2, 4, 6, 10, 11, 18, 23, 24, 30, 40, 43, 54], "flexibl": 2, "ll": [2, 8, 13, 14, 15, 28, 31, 42, 48, 54], "quickli": [2, 4, 10, 26, 32, 38, 40, 41, 49, 50, 53, 55, 59], "learn": [2, 4, 12, 13, 14, 15, 16, 23, 26, 28, 29, 33, 34, 35, 36, 40, 46, 54, 56, 57, 59, 61], "watch": [2, 3, 4, 5, 8, 10, 12, 13, 14, 15, 23, 24, 30, 31, 34, 35, 38, 40, 41, 42, 53, 54, 60, 62], "subscrib": [2, 37, 52], "depend": [2, 4, 10, 13, 23, 27, 33, 35, 42, 44], "interest": [2, 4, 16, 26, 27, 28, 29, 37, 42, 48, 59], "steam": 2, "list": [2, 13, 14, 15, 16, 18, 22, 25, 27, 28, 31, 32, 37, 40, 42, 43, 44, 47, 48, 49, 50, 52, 54, 56, 57, 59, 61, 62, 63], "left": [2, 6, 11, 22, 25, 26, 33, 35, 42, 63], "side": [2, 5, 12, 15, 25, 26, 30, 40, 52, 61], "see": [2, 8, 9, 10, 11, 12, 14, 15, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 37, 38, 41, 43, 45, 47, 49, 50, 53, 55, 56, 58, 59, 63], "won": [2, 4, 6, 11, 26, 33, 42], "notif": [2, 10, 22], "later": [2, 4, 10, 11, 12, 13, 14, 15, 23, 25, 26, 32, 33, 34, 35, 40, 42, 46, 54, 60], "unmut": [2, 24, 30, 62], "email": [2, 4, 20, 22, 32, 37, 39, 42, 47, 52, 59], "random": [2, 28, 41, 54], "itself": [2, 14, 15, 30, 40, 41, 42, 43, 54], "carpentri": [2, 23, 26, 28, 42, 61], "lesson": [2, 3, 4, 5, 6, 10, 13, 14, 15, 23, 24, 25, 27, 37, 40, 42, 43, 44, 52, 53, 54, 59, 60], "program": [2, 16, 26, 28, 33, 41, 42, 46, 54], "each": [2, 3, 4, 10, 15, 22, 23, 28, 29, 31, 33, 34, 35, 37, 40, 41, 42, 43, 44, 49, 50, 52, 53, 56, 59, 60, 61], "maintain": [2, 4, 5, 28, 29, 40, 41, 49, 50, 56], "organ": [2, 4, 7, 8, 9, 17, 21, 22, 31, 32, 33, 37, 40, 42, 45, 52, 54, 57, 61, 63], "One": [2, 26, 28, 33, 34, 35, 40, 42, 43, 54, 56], "coordin": [2, 4, 6, 17, 22, 27, 38, 43, 57], "major": [2, 32, 33, 42, 52, 54], "python": [2, 16, 26, 42], "scicomp": 2, "kickstart": [2, 25, 26, 55], "aalto": [2, 4, 59], "high": [2, 5, 25, 28, 30, 33, 37, 54, 57, 59], "volum": [2, 4, 25, 33], "staff": [2, 8, 9, 10, 12, 21, 22, 30, 37, 40, 52, 53, 55, 56, 57, 59, 60], "dure": [2, 3, 4, 6, 10, 11, 15, 16, 21, 23, 24, 26, 29, 30, 31, 33, 34, 35, 39, 40, 43, 49, 50, 59, 60, 63], "typic": [2, 5, 28, 33, 44, 52, 56, 61, 62], "leav": [2, 8, 11, 12, 15, 21, 33, 35, 38, 56, 62], "flood": [2, 11, 15], "help": [2, 4, 6, 8, 10, 12, 13, 14, 15, 21, 24, 26, 27, 28, 31, 34, 35, 36, 37, 38, 40, 41, 42, 43, 46, 48, 49, 50, 52, 54, 55, 56, 58, 59, 61, 63], "til": 2, "feel": [2, 4, 5, 16, 17, 23, 28, 33, 40, 43, 44, 56, 59], "introduc": [2, 3, 4, 6, 30, 33, 42, 43, 44, 56], "gitlab": [2, 16], "research": [2, 13, 14, 15, 16, 26, 32, 37, 41, 42, 45, 48, 54, 56, 57, 59, 61], "engin": [2, 43, 61], "hpc": [2, 25, 26, 44, 59], "just": [2, 4, 5, 6, 10, 11, 13, 14, 15, 16, 22, 23, 26, 28, 29, 30, 32, 33, 35, 37, 40, 41, 42, 43, 47, 48, 54], "misc": 2, "sphere": 2, "influenc": [2, 38], "rshour": 2, "hour": [2, 4, 10, 32, 37, 40, 41, 49, 53, 56, 60], "finland": 2, "complain": 2, "univers": [2, 37, 57, 59], "reach": [2, 4, 5, 24, 31, 33, 34, 36, 45, 57, 59], "web": [2, 3, 15, 16, 23, 25, 32, 34, 35, 37, 62], "show": [2, 4, 5, 13, 14, 15, 22, 23, 26, 28, 30, 33, 35, 37, 38, 40, 42, 43, 56, 59], "group": [2, 5, 8, 13, 14, 15, 23, 24, 33, 35, 37, 41, 42, 43, 46, 49, 52, 57], "significantli": 2, "overlap": [2, 9, 14, 15, 44], "zulip": [2, 4, 8, 27, 42, 58], "admin": [2, 22], "add": [2, 6, 10, 11, 16, 26, 30, 31, 33, 34, 39, 43, 53, 56, 59], "app": [2, 35, 37], "mobil": [2, 11, 37], "pip": [2, 26], "everyon": [2, 3, 4, 8, 11, 12, 15, 16, 21, 23, 24, 31, 32, 34, 38, 39, 40, 41, 42, 43, 58, 60], "thought": [2, 4, 28, 29, 37, 57], "pointless": [2, 37], "repli": [2, 32, 47, 59], "reaction": [2, 5, 24, 52], "disagr": 2, "thumb": 2, "sentiment": 2, "octopu": 2, "awesom": 2, "amaz": [2, 28, 33], "ac": 2, "obviou": [2, 8, 10, 15, 37], "concret": [2, 8, 28, 41], "empow": [2, 6, 9], "difficult": [2, 8, 35, 42, 43], "decis": [2, 6, 9, 37], "formal": [2, 9, 44, 52], "necessarili": [2, 37, 41, 42, 54], "bind": [2, 26], "realli": [2, 4, 5, 6, 10, 14, 15, 23, 27, 28, 34, 37, 40, 42, 44, 54, 63], "intermedi": [2, 54], "young": 2, "propos": [2, 4, 33, 43, 52], "sai": [2, 3, 4, 6, 8, 10, 22, 23, 26, 28, 29, 30, 33, 37, 38, 41, 42, 43, 44, 56, 63], "uncertain": [2, 51], "think": [2, 8, 11, 13, 14, 15, 16, 21, 23, 29, 30, 33, 35, 37, 38, 41, 42, 43, 44, 53, 56], "let": [2, 4, 10, 15, 22, 23, 27, 28, 31, 32, 37, 42, 43, 49, 50, 51, 59, 61, 63], "u": [2, 4, 5, 9, 11, 13, 14, 15, 24, 26, 27, 31, 33, 35, 37, 42, 43, 44, 48, 49, 50, 54, 57, 59, 61, 63], "left_right": 2, "am": [2, 8, 16, 35, 38, 45, 59], "neutral": [2, 44], "upvot": 2, "downvot": 2, "disagre": 2, "double_up": 2, "double_down": 2, "willing": [2, 4, 30, 41], "altern": [2, 4, 10, 38, 41, 42, 56], "opinion": [2, 43], "posit": [2, 33, 39, 52, 61], "emoji": [2, 5], "number": [2, 5, 6, 12, 21, 22, 24, 35, 40, 42, 47, 62, 63], "realiz": [2, 4, 33, 34, 38], "neg": 2, "why": [2, 5, 10, 23, 28, 29, 32, 34, 37, 38, 42, 43, 44, 53, 56], "weight": 2, "decid": [2, 3, 4, 6, 8, 9, 23, 28, 35, 37, 43, 52, 56, 59, 61], "enough": [2, 4, 6, 8, 13, 14, 15, 23, 25, 27, 28, 29, 32, 33, 35, 38, 41, 43, 44, 54, 56, 60, 61], "That": [2, 23, 29, 31, 38, 42], "usual": [2, 4, 6, 13, 14, 15, 23, 24, 29, 30, 33, 39, 40, 42, 43, 52], "guarante": 2, "confidenti": [2, 35], "focu": [3, 4, 5, 10, 23, 24, 34, 40, 41, 44, 50], "team": [3, 7, 8, 9, 13, 14, 15, 17, 21, 23, 34, 37, 45, 47, 48, 56, 57, 58], "almost": [3, 33, 43, 55], "focus": [3, 29, 33, 34, 49, 52], "onboard": [3, 7, 24, 40, 42, 59], "point": [3, 10, 11, 16, 17, 23, 25, 28, 32, 33, 41, 42, 43, 44, 53, 54, 55, 56, 59], "type": [3, 4, 20, 23, 24, 26, 27, 28, 33, 34, 35, 37, 38, 42, 43, 44, 56, 63], "small": [3, 9, 11, 16, 23, 25, 26, 29, 33, 34, 36, 40, 41, 43, 53], "dream": 3, "interact": [3, 13, 14, 15, 24, 30, 33, 34, 40, 42, 43, 49, 56, 61, 62], "hard": [3, 8, 9, 23, 26, 33, 36, 37, 38, 41, 42, 43, 54, 55], "achiev": 3, "quiet": [3, 14, 15, 25, 26, 63], "someon": [3, 4, 8, 9, 10, 11, 13, 14, 15, 16, 21, 23, 25, 27, 28, 30, 32, 33, 37, 38, 40, 42, 43, 44, 49, 50, 53, 54, 56], "fraction": 3, "found": [3, 33, 45, 59, 62], "build": [3, 7, 28], "straight": [3, 5, 28, 37], "convers": [3, 10, 37, 43], "student": [3, 4, 28, 29, 30, 34, 38, 41, 42, 45, 57, 59], "among": [3, 4, 6, 23, 43, 60], "easier": [3, 4, 11, 24, 28, 33, 37, 40, 41, 42, 63], "present": [3, 23, 24, 26, 27, 28, 29, 30, 32, 33, 37, 41, 42, 44, 55, 56, 63], "develop": [3, 5, 16, 17, 23, 28, 34, 35, 37, 41, 42, 44, 45, 46, 48, 54, 59, 61], "starter": 3, "suggest": [3, 5, 8, 32, 33, 43, 59], "approach": [3, 24, 31, 46, 49, 50], "demonstr": [3, 26, 35, 41], "session": [3, 4, 6, 10, 12, 13, 14, 15, 16, 24, 26, 28, 29, 31, 33, 40, 43, 46, 49, 54, 56, 59, 60], "walk": [3, 14, 15, 38, 42, 61], "step": [3, 5, 10, 12, 20, 23, 27, 28, 29, 32, 33, 34, 36, 38, 40, 43, 49, 50, 59, 61, 63], "beauti": [3, 23, 26], "orient": [3, 23], "half": [3, 4, 14, 15, 23, 25, 26, 28, 30, 33, 38, 49, 59], "learner": [3, 4, 6, 10, 12, 21, 23, 24, 26, 27, 28, 29, 30, 31, 33, 34, 35, 37, 38, 41, 42, 43, 46, 53, 54, 56, 57, 59, 60, 61], "own": [3, 4, 5, 8, 10, 11, 13, 14, 15, 16, 22, 23, 24, 25, 28, 31, 35, 36, 37, 41, 42, 59], "dark": [3, 23, 25, 26], "light": [3, 23, 26], "minim": [3, 10, 15, 23, 26, 28, 38, 41, 44], "prompt": [3, 6, 23, 25], "fanci": [3, 23, 33], "shell": [3, 13, 14, 15, 23, 25, 26, 28, 56], "distract": [3, 11, 14, 15, 23, 26, 35, 38, 41], "histori": [3, 17, 23, 25], "visibl": [3, 18, 21, 23, 49, 53], "distinct": [3, 23], "color": [3, 23, 25, 33], "setup": [3, 13, 14, 15, 20, 23, 27, 29, 34, 35, 38, 40, 42, 56, 60], "clean": 3, "environ": [3, 23, 33, 41, 63], "match": [3, 23, 28, 37, 41, 59], "livestream": [3, 5, 6, 17, 21, 23, 25, 27, 31, 33, 42, 43, 54, 62], "explan": [3, 30], "model": [3, 4, 28, 31, 44], "rel": [3, 4, 26, 33], "quick": [3, 10, 28, 41, 44, 54], "rememb": [3, 23, 28, 29, 38, 41, 44, 49, 59], "alon": [3, 4, 5, 10, 23, 24, 28, 38, 40, 42, 43, 56, 60], "intro": [3, 23, 26, 29, 42, 53, 54, 56, 59], "introduct": [3, 6, 10, 16, 24, 27, 29, 34, 35, 43, 44, 54, 60], "massiv": 4, "real": [4, 11, 14, 18, 28, 33, 34, 38, 56], "yet": [4, 6, 22, 26, 28, 32, 37, 43], "www": [4, 30, 34, 59], "youtub": [4, 15, 30, 34, 40, 53, 54, 55], "s9jor12cxdc": [4, 34], "45": [4, 10, 34, 53], "31": [4, 22, 34], "concis": [4, 34], "disconnect": [4, 28, 35], "Or": [4, 10, 16, 23, 26, 33, 37, 41, 42, 43], "mental": [4, 10, 13, 14, 44], "tv": [4, 15, 37, 42, 59], "period": [4, 11, 31, 33, 42, 53], "intermiss": 4, "clear": [4, 16, 29, 37, 38, 41, 42, 43, 52, 54], "Of": [4, 5, 8, 33, 38, 43, 44], "respons": [4, 23, 30, 35, 39, 40, 42, 43, 59], "smoothli": 4, "compar": [4, 25, 30], "classic": 4, "style": 4, "advantag": [4, 6, 15, 34, 38, 40], "freed": 4, "convei": [4, 29], "opportun": [4, 11, 23, 42], "come": [4, 5, 8, 9, 10, 11, 13, 14, 15, 23, 27, 28, 32, 34, 37, 38, 40, 41, 42, 44, 56, 60], "next": [4, 5, 6, 8, 13, 14, 15, 22, 23, 26, 28, 29, 30, 36, 37, 38, 43, 44, 51, 55, 56, 59, 60, 63], "disadvantag": [4, 34, 41, 43], "lose": [4, 11, 18, 34, 41], "anywai": [4, 15, 25, 30, 31, 34, 37, 41, 43, 44], "mind": [4, 5, 10, 23, 29, 43, 56], "track": [4, 10, 26, 33, 40, 42, 43, 53, 56, 59], "kei": [4, 26, 34, 43, 44], "maximum": [4, 22], "immedi": [4, 10, 12, 13, 14, 15, 28, 34, 37, 40, 42, 56], "perhap": [4, 8, 12, 14, 15, 28, 29, 37, 38, 43, 44, 55], "both": [4, 13, 22, 24, 25, 30, 33, 34, 35, 37, 41, 43, 44, 45], "paus": [4, 43], "greatli": [4, 34], "increas": [4, 9, 12, 33], "profession": [4, 26, 33, 37, 44], "room": [4, 5, 7, 8, 10, 11, 14, 15, 17, 22, 24, 25, 34, 38, 40, 42, 46, 49, 54, 59, 60, 63], "poll": [4, 23, 30, 35], "though": [4, 8, 10, 12, 15, 18, 27, 37, 41, 42, 43, 44, 54], "presemo": 4, "fi": [4, 59], "regist": [4, 5, 13, 14, 15, 18, 19, 21, 22, 24, 31, 34, 37, 39, 42, 46, 47, 51, 56, 59, 62], "anoth": [4, 16, 23, 30, 33, 56], "watcher": [4, 34, 43], "physic": [4, 13, 14, 15, 31, 34, 35, 42, 49], "els": [4, 8, 10, 13, 14, 19, 21, 23, 25, 26, 27, 32, 38, 40, 41, 42, 51, 54, 59], "awar": [4, 6, 35, 37, 42, 49, 50], "divers": [4, 15, 28, 34, 41, 45, 61], "slowli": [4, 8, 35, 41], "repeat": [4, 6, 8, 35], "across": [4, 38, 42], "natur": [4, 36, 38, 43, 45, 54], "timezon": [4, 32], "resum": 4, "50": [4, 60], "past": [4, 5, 16, 17, 22, 44, 53, 55, 59], "write": [4, 11, 15, 17, 22, 30, 38, 41, 42, 48, 56, 59], "xx": [4, 10, 60], "attempt": 4, "passiv": [4, 5, 13, 14, 15, 24, 34, 44], "demo": [4, 10, 15, 23, 26, 30, 42, 54], "lectur": [4, 10, 13, 14, 27, 41, 43, 54, 63], "cycl": [4, 28, 41], "short": [4, 9, 23, 28, 29, 31, 37, 41, 43, 53, 56], "outcom": [4, 56], "faster": [4, 5, 8, 24, 41, 62, 63], "ok": [4, 8, 13, 14, 15, 23, 26, 28, 32, 34, 37, 40, 41, 42, 43, 54, 60, 62, 63], "perfect": [4, 10, 43, 53, 54, 55], "rest": [4, 28, 33], "job": [4, 8, 35, 41, 52], "push": [4, 26, 33, 43, 56], "hint": [4, 11, 20, 23, 24, 27, 28, 41, 54, 56], "detail": [4, 10, 22, 28, 30, 32, 35, 37, 38, 40, 41, 42, 43, 49, 55, 56, 59, 60], "multipl": [4, 10, 13, 14, 15, 23, 25, 28, 35, 37, 38, 41, 42, 43, 54, 59, 63], "attend": [4, 5, 12, 17, 21, 23, 24, 31, 32, 36, 37, 40, 42, 45, 46, 47, 48, 49, 50, 54, 57, 61], "stai": [4, 8, 12, 14, 15, 23, 24, 30, 35, 37, 41, 42, 54, 62, 63], "pretti": [4, 33], "emphasi": [4, 44], "comment": [4, 5, 8, 11, 23, 30, 37, 43, 52, 59], "relai": [4, 24, 30], "voic": [4, 10, 15, 23, 37, 38, 40, 44, 54], "logic": [4, 10, 28, 29, 33, 43], "role": [4, 5, 8, 9, 17, 27, 34, 35, 38, 41, 42, 43, 44, 56, 58, 60], "regular": [4, 22, 35, 56], "signific": [4, 25, 33], "risk": [4, 11, 15, 42, 43], "troubl": [4, 8], "attent": [4, 8, 15, 30, 34, 41, 42, 43], "self": [4, 28, 29, 37, 41, 56, 59], "classroom": [4, 24, 28, 56], "class": [4, 13, 24, 28, 33, 41], "locat": [4, 31, 33, 45, 47, 50, 61], "archiv": [4, 11, 37, 40, 59], "afterward": [4, 8, 11], "cognit": [4, 28], "effort": [4, 31, 37, 41, 42, 44], "did": [4, 16, 38], "januari": 4, "februari": 4, "pick": [4, 59], "were": [4, 12, 22, 34, 37, 53, 54, 59], "few": [4, 10, 15, 23, 26, 27, 28, 32, 35, 37, 38, 44, 49], "complaint": 4, "end": [4, 10, 12, 15, 23, 26, 28, 31, 33, 35, 37, 38, 42, 44, 49, 52, 53, 54], "spam": [4, 48], "late": [4, 15, 33], "had": [4, 16, 24, 28, 32, 33, 52], "troll": [4, 34], "problem": [4, 8, 10, 11, 14, 23, 26, 28, 29, 30, 33, 35, 37, 38, 40, 41, 49, 50, 56, 59, 62], "transit": [4, 6, 33], "backup": [4, 11, 25, 35, 53, 54, 59], "q": [4, 10, 15, 23, 28, 30, 43, 54, 59], "Will": 4, "wjmttanizx8": [4, 30], "carefulli": [4, 30, 53], "success": [5, 37, 46, 56], "hang": [5, 52], "readi": [5, 6, 13, 14, 15, 22, 23, 26, 32, 37, 40, 42], "lurk": 5, "These": [5, 17, 21, 23, 25, 27, 28, 32, 33, 42, 43, 52, 53], "manual": [5, 22, 28, 32, 36, 41, 59], "lead": [5, 23, 28, 40, 41, 43, 57, 58, 59], "again": [5, 27, 29, 37, 48], "improv": [5, 8, 9, 23, 26, 28, 36, 38, 48, 52, 59], "submit": [5, 52], "monthli": [5, 9], "call": [5, 7, 9, 30, 35, 40, 42, 46, 53, 56, 59, 60], "broad": [5, 16, 31], "weekli": 5, "collabor": [5, 9, 15, 16, 23, 24, 31, 34, 35, 39, 41, 42, 45, 52, 56], "isn": [5, 10, 15, 16, 25, 33, 34, 37, 41, 44, 60], "ourselv": [5, 14, 15, 52], "task": [5, 23, 24, 28, 40, 41, 56, 59, 62], "re": [5, 29, 37, 48, 49, 50, 56], "invent": 5, "rate": [5, 33], "further": [5, 42, 48], "breakout": [5, 7, 8, 10, 15, 17, 24, 34, 40, 46, 54, 59, 60, 63], "helper": [5, 10, 12, 17, 23, 29, 30, 31, 34, 35, 37, 38, 48, 49, 56, 57, 58, 60, 62], "overview": [5, 8, 17, 23, 28, 34, 39, 42, 56, 59], "level": [5, 6, 10, 28, 36, 37, 41, 57], "strategi": [5, 17, 24, 30, 31, 34, 35, 36, 41, 43], "littl": [5, 15], "impact": [5, 31, 36, 56], "soon": [5, 10, 49, 50], "wonder": [5, 26, 34, 42, 43], "ever": [5, 26, 43], "bother": 5, "surprisingli": 5, "mainten": [5, 40], "notifi": [5, 13, 14, 15, 37, 46, 51, 56], "issu": [5, 27, 32, 35, 38, 40, 42, 49, 50, 52, 53, 54, 56, 59], "pull": [5, 9, 42, 52, 56], "review": [5, 12, 13, 14, 15, 16, 17, 27, 41, 42, 44, 54, 56], "wrap": [6, 44, 56], "negoti": [6, 23, 60], "appropri": [6, 38, 56], "randomli": [6, 8], "longer": [6, 8, 13, 14, 15, 23, 28, 34, 37], "matter": [6, 26, 28, 29, 31, 33, 37, 40, 42, 52], "confid": [6, 8, 27, 40], "consult": 6, "around": [6, 8, 13, 14, 15, 24, 28, 33, 35, 37, 38, 40, 41, 42, 48, 52, 56, 59, 61], "choic": [6, 8, 28, 37, 38, 41], "updat": [6, 9, 10, 11, 20, 28, 29, 35, 37, 38, 41, 44, 47, 56, 59, 60], "variou": [6, 17, 27, 33, 37, 41], "mix": [6, 28, 33, 41], "extra": [6, 8, 14, 15, 25, 26, 36, 38, 42], "overhead": [6, 23, 61], "zero": 6, "normal": [6, 13, 14, 15, 25, 26, 30, 33, 34, 43, 54, 60], "button": [6, 22, 32, 33, 35, 37, 62, 63], "graphic": [6, 33, 41, 42], "arriv": [6, 13], "upper": [6, 26], "overlaid": 6, "pictur": [6, 25, 27, 28, 29, 30, 33, 37, 38, 41, 43, 54], "crop": [6, 33], "url": [6, 10, 45, 47, 50], "io": [6, 10, 32, 46, 49, 50, 53, 54, 56, 59], "4444": 6, "none": [6, 33, 53], "leader": [7, 8, 13, 14, 15, 17, 21, 23, 24, 34, 37, 38, 57], "preserv": [7, 29, 33], "remind": [7, 10, 28, 32, 42, 56, 59], "report": [7, 8, 9, 15, 31, 37, 39, 42], "wish": [7, 16, 47, 49, 50, 51], "registr": [7, 15, 17, 18, 21, 34, 37, 47, 56, 58], "summon": 8, "whose": [8, 33], "doesn": [8, 10, 14, 15, 16, 22, 23, 25, 26, 28, 29, 30, 32, 33, 34, 37, 41, 43, 53], "abl": [8, 11, 15, 23, 26, 28, 33, 40, 42, 59, 61], "newer": 8, "15": [8, 28, 33, 38, 40, 41, 42, 54], "octob": [8, 56, 60], "2020": [8, 34, 46, 54, 60], "arbitrari": 8, "put": [8, 10, 11, 23, 26, 28, 32, 33, 35, 37, 41, 42, 54, 59], "swap": 8, "puls": 8, "zulipchat": [8, 30, 48, 52, 59, 60], "behind": [8, 10, 13, 14, 16, 42], "finish": [8, 35, 42, 60], "earli": [8, 13, 14, 15, 28, 33, 35, 41, 56], "bring": [8, 9, 10, 13, 14, 15, 23, 34, 42, 43, 57], "train": [8, 17, 23, 36, 41, 42, 46, 56, 59, 60], "envis": 8, "stand": [8, 38, 41, 42, 61], "jump": [8, 35, 43, 55], "proactiv": [8, 61], "assign": [8, 12, 14, 15, 35, 40, 42, 56, 62, 63], "initi": [8, 10, 33], "divid": [8, 23, 38, 41, 43, 54], "catch": [8, 15, 34], "promot": [8, 29, 37, 61], "familiar": [8, 49, 50], "rotat": [8, 40, 41], "head": [8, 10, 35, 44], "spend": [8, 16, 37, 49, 50, 56], "second": [8, 14, 15, 16, 33, 35, 38, 52], "struggl": 8, "slow": [8, 14, 33, 38, 41], "kindli": [8, 48], "over": [8, 9, 12, 22, 23, 25, 26, 33, 37, 38, 39, 41, 42, 52, 53, 54, 60, 62, 63], "especi": [8, 23, 25, 28, 31, 37, 41, 43, 44, 54], "begin": [8, 15, 26, 27, 28, 33, 37, 44, 54], "beforehand": 8, "proport": 9, "week": [9, 16, 37, 52, 59], "rough": [9, 34, 52, 54], "consensu": [9, 52], "factor": [9, 28, 33], "asynchron": [9, 15, 24, 42], "vote": [9, 38], "perspect": 9, "broader": [9, 32, 37], "advisori": 9, "taken": [9, 32], "sort": [9, 25, 29, 33, 42, 43, 52], "board": [9, 38, 56, 59, 61], "partner": [9, 41, 59, 61], "repres": [9, 37], "fund": [9, 37, 52, 57], "parallel": [9, 41], "shouldn": [10, 29, 37, 41], "meta": [10, 23], "login": [10, 11, 22], "top": [10, 11, 22, 25, 29, 31, 33, 42, 43], "consist": [10, 12, 43, 54], "tag": [10, 32], "xxx": [10, 45], "accomplish": [10, 23, 44], "structur": 10, "episod": [10, 23, 27, 53, 55, 56, 60], "sens": [10, 15, 23, 28, 29], "bullet": [10, 11], "deepli": 10, "nest": 10, "long": [10, 14, 15, 23, 26, 28, 33, 37, 42, 44, 47, 53, 56], "deep": [10, 41], "easili": [10, 26, 30, 31, 34, 35, 36, 37, 49, 50, 56], "introductori": [10, 42], "said": [10, 37, 42, 43], "durat": 10, "goal": [10, 26, 28, 37, 42, 44, 54], "unclear": [10, 23, 42], "latest": [10, 20, 23], "seen": [10, 22, 28, 38, 41, 42, 43, 44, 52], "awai": [10, 26, 30, 35, 38, 49], "intens": 10, "overload": [10, 15, 25, 30, 41], "balanc": [10, 12, 23, 25, 26, 33, 42], "delai": [10, 33], "wall": 10, "valuabl": [10, 26, 38, 42, 45, 48, 49, 50], "energi": 10, "progress": [10, 29, 35, 36, 41, 42, 49, 50, 56], "ones": [10, 13, 14, 15, 16, 27, 28, 38, 44, 53, 54, 56], "figur": [10, 29, 33, 37, 41, 42, 44, 54], "root": 10, "declar": [10, 37], "webpag": [10, 13, 14, 15, 22, 37, 39, 47, 49, 50, 56, 59], "amount": [10, 33, 42, 61], "strip": 10, "rigor": 10, "complet": [10, 21, 22, 23, 24, 26, 27, 28, 31, 38, 43, 56, 59, 62], "cr": [10, 32, 37, 57, 59], "pr": 10, "ad": [10, 26, 29, 33, 37, 41, 42, 56], "01": [10, 54], "anwser": 10, "danger": [10, 59], "sooner": [10, 42], "hopefulli": [10, 12, 35, 44], "markdown": [10, 11, 44, 56], "search": [10, 33, 34, 53], "usernam": [10, 56], "hedgedoc": [11, 59], "editor": [11, 17, 34, 54], "interrupt": [11, 15, 30, 37, 38, 43], "equal": [11, 41, 43, 55], "account": [11, 22, 49, 50], "split": [11, 12, 26, 41, 54, 55], "syntax": 11, "pleas": [11, 13, 14, 15, 16, 22, 26, 29, 31, 35, 43, 46, 47, 48, 49, 50, 51, 54, 59, 62], "older": [11, 22], "mynam": [11, 49], "statement": 11, "blank": [11, 26, 28, 41, 54], "line": [11, 13, 14, 15, 16, 28, 42, 43], "highlight": [11, 32], "instant": [11, 12, 38], "demand": [11, 33], "ey": [11, 26, 39, 42], "beyond": [11, 26, 33, 42], "scan": [11, 44], "assum": [11, 23, 25, 27, 28, 35, 43], "websit": [11, 15, 26, 35, 42, 45, 56, 59], "yournam": 11, "warn": [12, 18], "expert": [12, 16, 17, 23, 27, 30, 34, 36, 41, 42, 58, 60], "spreadsheet": 12, "sampl": [12, 37], "easiest": [12, 22], "middl": [12, 63], "drop": 12, "rejoin": [12, 35], "merg": [12, 32, 59], "constantli": [12, 38], "empti": [12, 33], "miss": [12, 13, 26, 28, 41, 49, 50, 59], "cover": [12, 25, 28, 35, 41, 43, 46, 52, 60], "spotlight": 12, "dayn": 12, "lessonnam": 12, "mp4": [12, 33, 54], "googl": [12, 15, 53, 54, 56], "drive": [12, 53, 54], "fact": [12, 15, 32, 41, 43, 60], "feed": [12, 33], "glad": [13, 14, 15], "academ": [13, 14, 41, 42, 44, 45], "specif": [13, 14, 15, 25, 28, 32, 33, 37, 41, 44, 59], "skill": [13, 14, 15, 28, 37, 41, 42, 46, 48, 54], "command": [13, 14, 15, 16, 28, 38, 42, 56, 59], "target": [13, 14, 28, 33, 41, 57], "last": [13, 14, 15, 28, 34, 37, 41, 48, 59], "uptak": [13, 14, 15], "laptop": [13, 16, 35, 50, 61], "charger": 13, "mice": 13, "earlier": [13, 21, 28], "breath": [13, 14, 15], "stick": [13, 14, 15, 56], "sign": [13, 14, 15, 22, 42, 46, 47, 59], "doubl": [14, 15, 41], "fall": 14, "entir": [14, 15, 28, 33, 54], "timeslot": [14, 15], "calendar": [14, 15, 32, 52, 59], "comfort": [14, 15, 16, 43], "disturb": [14, 15], "token": [14, 15, 30, 38], "ear": [14, 15, 40, 42], "tire": [14, 15, 28, 35], "somewher": [14, 15, 27, 28, 63], "interfer": [14, 15], "offic": [14, 15], "home": [14, 15, 28, 59], "freeli": [14, 15], "seat": [14, 15, 47, 49, 50, 51], "space": [14, 15, 25, 26, 31, 33, 41, 61], "conflict": [14, 15, 26], "harder": [14, 25, 33, 41, 42], "minimz": 14, "trap": [14, 15, 26], "fast": [14, 15, 26, 33, 38, 41, 53, 54], "coffe": [14, 15, 56, 61], "eat": [14, 15], "food": [14, 15, 29], "anonym": [15, 22, 24, 54], "ten": [15, 28, 41], "assist": [15, 35, 38, 40, 41], "silent": [15, 31], "projector": [15, 26, 34, 61], "central": [15, 31, 32, 33, 59], "And": [15, 33, 43], "exclud": [15, 33], "spot": [15, 21, 41, 42, 55], "pai": [15, 30, 34, 43], "believ": [15, 23, 42], "wide": [15, 30, 41], "varieti": [15, 41, 42], "succe": 15, "strictli": [15, 43, 52], "post": [15, 32, 33, 37, 53, 55, 59], "pace": [15, 42, 56], "afraid": [15, 28], "technologi": [15, 33, 41], "plugin": 15, "font": [15, 25, 26], "extens": [15, 16, 26, 42, 56], "caption": 15, "chrome": 15, "releas": [15, 16, 28, 54, 55], "cooki": 15, "block": [15, 38, 43], "strateg": 15, "inclus": [16, 28, 41], "background": [16, 25, 26, 33, 35, 41, 46, 49, 56, 58], "museumhack": 16, "suppos": [16, 29, 43], "yesterdai": 16, "told": [16, 62], "oper": [16, 30, 33, 37, 38, 42, 43, 56], "maco": [16, 33], "version": [16, 28, 45, 49, 50, 54, 56, 59, 62], "haven": [16, 37, 43, 49, 50], "git": [16, 26, 37, 42, 44, 46, 49, 50, 52, 53, 54, 56, 59], "mercuri": 16, "subvers": 16, "cv": 16, "perforc": 16, "bazaar": 16, "languag": [16, 42], "matlab": [16, 42], "r": [16, 42], "perl": 16, "fortran": [16, 42], "77": 16, "90": 16, "julia": [16, 42], "haskel": 16, "rust": 16, "autom": [16, 45], "platform": [16, 33, 34, 37, 46, 54], "travi": 16, "ci": 16, "jenkin": 16, "emploi": 16, "code": [16, 28, 30, 33, 41, 44, 45, 48, 49, 50, 59], "jupyt": [16, 25, 54, 59], "notebook": 16, "m": [16, 42, 45], "bitbucket": 16, "redmin": 16, "experi": [16, 24, 26, 35, 37, 42, 45, 56, 59, 61], "minor": [16, 44, 60], "my": [16, 33, 34, 37, 42, 45], "simpl": [16, 28, 31, 33, 54], "complex": [16, 33, 41, 42, 45], "unix": 16, "cd": 16, "l": [16, 26], "cat": 16, "mv": 16, "rm": 16, "chmod": 16, "man": 16, "mkdir": 16, "cp": 16, "ssh": [16, 26], "modular": [16, 59], "branch": [16, 42], "weather": 16, "happi": 16, "iphon": 16, "dinner": 16, "todai": 16, "cool": [16, 28, 29, 38], "discov": [16, 23], "oliv": 16, "annoi": 16, "anaconda": 16, "favourit": 16, "pizza": 16, "pineappl": 16, "pineapl": 16, "belong": [16, 42], "breakfast": 16, "favorit": 16, "nap": 16, "identifi": [16, 28, 40, 41, 56, 59], "came": 16, "mega": 16, "site": [17, 33, 37, 61], "dictat": 17, "adventur": [17, 26], "mechan": [17, 24, 31, 34, 42], "signal": [17, 35, 38, 41, 42, 43, 62], "checklist": [17, 27, 28, 29, 38, 40, 41, 57, 58, 61], "templat": [17, 32, 35, 39, 40, 41, 53, 57], "yyyi": [17, 32], "mm": [17, 32], "dd": 17, "mooc": [17, 24, 30, 31, 35, 36, 41], "tutori": [17, 28, 33, 41, 44, 54], "doc": [17, 50, 56], "summari": [17, 24, 28, 37, 59], "book": [17, 28, 37, 41, 56, 61], "govern": 17, "outreach": [17, 39, 57], "artwork": 17, "singl": [17, 25, 33, 35, 37, 43, 53], "html": [17, 37], "pdf": [17, 59], "epub": 17, "filter": [18, 20, 33], "confirm": [18, 19, 21, 22, 41, 59], "box": [18, 21, 22, 32, 63], "count": 18, "compos": [18, 33], "sent": [18, 22, 56, 59], "draft": [18, 39, 59], "copi": [18, 20, 26, 28, 34, 40, 44, 53, 54, 55, 56, 59], "placehold": 18, "field": [18, 21, 22, 56], "suitabl": [20, 33, 37], "neic": [20, 22, 45, 46, 48, 52, 56], "routin": [20, 37], "survei": [20, 35, 37, 42, 46, 49, 50, 59], "export": [20, 26, 54], "workflow": 20, "moder": [21, 22], "approv": [21, 22, 52], "featur": [21, 33, 35, 37, 60], "soft": 21, "deadlin": [21, 42], "log": [21, 22, 26, 54], "declin": 21, "given": [21, 28, 41], "Then": [21, 22, 26, 28, 37, 42, 43], "categori": [21, 22, 57], "conveni": [21, 42], "withdrawn": 21, "radovan": 22, "metadata": 22, "visit": [22, 23, 37, 42, 49, 50], "pen": [22, 38, 41, 42], "symbol": [22, 63], "toolbar": [22, 25, 26], "area": [22, 29, 33, 43, 54], "acl": 22, "uncheck": 22, "refresh": [22, 49, 50, 61], "user": [22, 29, 35, 49, 59], "venu": 22, "administr": [22, 37, 58, 62], "menu": [22, 26, 33, 59], "function": [22, 26], "implement": [22, 33, 37, 43, 44], "max": 22, "capac": [22, 42], "eg": [22, 59], "40": [22, 42], "60": [22, 35], "unconfirm": 22, "outdat": 22, "22": [22, 33], "24": [22, 46], "29": [22, 54], "coupl": [22, 50], "submiss": 22, "newli": 22, "questionnair": [22, 48], "blue": [22, 63], "twitter": [22, 32, 37, 56, 59], "csv": 22, "directori": [22, 25, 26, 53, 59], "read_csv": 22, "py": 22, "pars": [22, 54], "print": [22, 26], "sidebar": [23, 42], "motiv": [23, 28, 29, 42, 54], "elsewher": 23, "rare": [23, 29, 38, 42, 54], "revis": 23, "increment": [23, 54], "experienc": [23, 46, 60], "transfer": [23, 35], "knowledg": [23, 28, 40, 41, 42, 43], "tradition": [23, 33, 42], "mostli": [23, 26, 28, 33, 43, 58], "explor": [23, 61], "lost": [23, 26], "halfwai": 23, "imagin": 23, "acquaint": [23, 35], "debug": [23, 24, 26, 28, 35, 41, 42, 43], "slower": [23, 33, 62, 63], "cut": [23, 33, 53, 54], "skip": [23, 28, 42, 60], "Not": [23, 28, 44, 60], "prep": 23, "combin": [23, 34, 40, 43, 54], "duplic": [23, 29, 33], "sad": 23, "teacher": [23, 26, 30, 38, 41, 42, 43], "nearbi": [23, 61], "phrase": 23, "fullscreen": [23, 33, 62], "840x1080": [23, 33], "addition": 24, "breakoutroom": [24, 42], "either": [24, 25, 30, 33, 35, 42, 43, 56], "fulli": [24, 29, 37, 43, 52], "tech": [24, 25, 26, 28, 38, 40, 42, 44, 56, 60], "hangout": 24, "chanc": [24, 25, 41, 43], "stress": 24, "typo": [24, 38], "unlimit": 24, "shown": [24, 25, 26, 45], "postproduct": 24, "critic": [25, 26, 42], "low": [25, 33, 41], "higher": [25, 33, 41], "dynam": [25, 27, 43], "rang": [25, 26, 33], "bare": 25, "headset": [25, 26, 33, 63], "reliabl": [25, 35], "bluetooth": 25, "latenc": [25, 33], "built": 25, "protocol": [25, 33], "game": [25, 33], "bandwidth": 25, "invest": [25, 28, 41], "duck": 25, "word": [25, 29, 41, 42, 44, 45], "silenc": [25, 42], "nois": [25, 33], "cancel": [25, 51, 56], "detect": 25, "smallest": [25, 33], "1920x1080": [25, 33], "pixel": [25, 30, 33], "wast": [25, 42], "forc": [25, 33, 34, 49], "ration": [25, 33], "43": 25, "width": 25, "height": [25, 26], "fullhd": [25, 33], "disrupt": 25, "s1": 25, "s2": 25, "s3": 25, "gui": [25, 33, 42], "s4": 25, "s5": 25, "s8": 25, "fish": [25, 26], "s9": 25, "tmux": [25, 26], "plu": 25, "s10": [25, 26], "contrast": [25, 26], "smaller": [25, 26, 28], "titlebar": [25, 26], "l1": 25, "instructur": 25, "l2": 25, "l3": 25, "particularli": [25, 35, 48, 56], "i1": 25, "unconfigur": 26, "bashrc": 26, "gitconfig": 26, "conda": 26, "virtualenv": 26, "bore": [26, 32, 37, 43], "tail": 26, "output": [26, 28, 41, 54], "simpler": [26, 33, 44], "bash": 26, "loud": [26, 38], "appear": [26, 30, 33, 53, 54, 63], "plain": [26, 56], "shortcut": 26, "wors": [26, 33, 34], "weird": 26, "behavior": 26, "authorized_kei": 26, "principl": [26, 30, 43, 44, 54], "widescreen": 26, "bar": [26, 30, 37], "lower": [26, 30, 33, 35, 42, 54, 63], "resolut": [26, 33, 54, 61], "theme": [26, 28, 41], "strongli": 26, "resiz": [26, 33], "safeti": [26, 42], "blocker": 26, "unneed": 26, "decor": 26, "firefox": 26, "css": 26, "devpixelsperpx": 26, "valu": [26, 28, 33, 37, 41], "75": 26, "recov": 26, "compens": 26, "greater": 26, "emul": [26, 44], "grei": 26, "satur": 26, "pure": [26, 28, 35], "white": [26, 37], "yellow": [26, 33], "red": [26, 35, 38, 62, 63], "elimin": 26, "un": 26, "ctrl": 26, "keyboard": [26, 38, 42], "column": 26, "wider": 26, "viewabl": 26, "ps1": 26, "entri": 26, "n": 26, "charact": [26, 29], "recent": 26, "rkdarst": 26, "return": [26, 62], "screenshot": 26, "sabryr": 26, "prompt_command": 26, "n0": 26, "bash_histori": 26, "subshel": 26, "script": [26, 33, 38, 43], "bash_log": 26, "bash_log_command": 26, "superus": 26, "175799": 26, "comp_lin": 26, "bash_command": 26, "caus": [26, 33, 35], "preexec": 26, "this_command": 26, "histtimeformat": 26, "sed": 26, "echo": [26, 33], "zsh": 26, "cmd_log": 26, "fish_preexec": 26, "argv": 26, "tmuxp": 26, "programm": 26, "session_nam": 26, "window_nam": 26, "shell_command": 26, "touch": [26, 38, 48, 49, 50], "tmp": 26, "powershel": 26, "press": [26, 37], "shift": 26, "psreadlineopt": 26, "historysavepath": 26, "unfortun": 26, "execut": [26, 28, 41], "untest": 26, "fish_histori": 26, "cmd": 26, "tty": 26, "zsh_histori": 26, "awk": 26, "nf": 26, "printf": 26, "notabl": 27, "Being": [27, 42, 46], "triag": 27, "dry": 27, "prefer": [27, 30, 33, 37, 42, 53, 56, 59, 61], "pathwai": [27, 40], "solid": [27, 33], "eventu": 27, "involv": [27, 43], "emphas": [27, 30, 56, 60], "primarili": 28, "chapter": [28, 30, 37, 41, 42, 54], "12": [28, 46, 53], "tip": [28, 35, 37, 41, 56], "final": [28, 34, 54], "curriculum": 28, "handbook": 28, "life": [28, 37], "timelin": 28, "pointer": 28, "driven": [28, 41, 44], "gap": [28, 38, 43], "brainstorm": [28, 29, 41], "persona": [28, 29, 37, 41], "depth": [28, 41], "summ": 28, "assess": [28, 35, 41], "checkpoint": 28, "min": [28, 38, 41, 42, 59], "misconcept": [28, 41], "advertis": [28, 36, 37, 40, 54, 56, 57, 59, 61], "emotion": 28, "agenc": 28, "compet": [28, 41], "related": [28, 41], "suffici": [28, 40, 55, 61], "crowd": 28, "fortun": 28, "factual": 28, "ground": [28, 40, 43], "ahead": [28, 29, 41, 56], "redo": 28, "object": [28, 29, 41], "solut": [28, 38, 42, 56], "frame": [28, 29], "hardest": 28, "taxonomi": [28, 41], "highli": [28, 56], "outlin": [28, 43], "studi": [28, 41], "difficulti": [28, 29, 43], "taught": [28, 29, 38, 56], "abil": [28, 41], "uncoordin": [28, 43], "cold": 28, "affair": 28, "serv": [28, 30, 40, 43, 52, 56, 57], "abstract": [28, 41, 52], "conceptu": [28, 38, 44], "load": [28, 34, 43, 54], "frequent": [28, 35, 46, 54], "stori": [28, 29, 37], "sequenc": 28, "stuck": [28, 61], "inspir": [28, 37], "sophist": 28, "tradit": 28, "invert": [28, 41], "parson": [28, 41], "trace": [28, 41], "revers": [28, 41], "broken": 28, "variat": [28, 41], "refactor": [28, 41], "draw": [28, 41], "diagram": [28, 38, 41], "bloom": [28, 41], "hierarch": [28, 41], "grow": [28, 42], "analyz": [28, 29, 41], "evalu": [28, 41], "fink": [28, 41], "complementari": 28, "foundat": [28, 35, 41], "human": [28, 41], "dimens": [28, 41, 54], "exist": [29, 34, 37, 41, 43, 52, 53, 56], "roughli": 29, "occasion": [29, 30, 35, 41, 43], "derail": 29, "highest": 29, "prioriti": [29, 31], "lowest": 29, "tracker": 29, "pitfal": [29, 56], "philosophi": 29, "intrins": [29, 41], "emot": [29, 38], "somehow": [29, 43], "conclus": [29, 33, 44], "growth": 29, "unnecessari": [29, 33, 35], "shorter": [29, 33, 37, 59], "backward": [29, 37, 41, 44], "rewrit": 29, "embark": 29, "pitch": 29, "hold": [29, 61], "ve": [30, 33, 37, 42, 61], "concept": [30, 33, 41, 43, 44, 46], "proce": 30, "camera": [30, 33, 35, 42], "overlai": 30, "fine": [30, 33, 53, 54], "relax": 30, "segment": [30, 33, 43], "pressur": 30, "backchannel": 30, "ratio": 30, "landscap": [30, 33], "exactli": 30, "oppos": [30, 37, 54], "properli": 30, "16": [30, 56], "black": [30, 35], "unexpectedli": 30, "revert": 30, "biggest": 30, "typer": 30, "reli": [30, 32, 42, 43], "cleverli": 30, "o": [30, 37], "graph": 30, "oooooooo": 30, "oooo": 30, "huge": 31, "decentr": 31, "friend": [31, 42, 57], "cater": [31, 56], "retent": 31, "knew": 31, "statist": [31, 39, 59], "simplic": 31, "institut": [31, 59], "recruit": [31, 48, 56, 61], "bias": 31, "toward": [31, 37], "weren": 32, "underwai": 32, "mail": [32, 37, 56], "shy": 32, "tab": 32, "picker": 32, "react": [32, 37, 38, 43], "tweet": [32, 37, 59], "aaltoscicomp": [32, 55], "backspac": 32, "year": 32, "month": [32, 59], "cest": 32, "rseng": 32, "quot": [32, 43], "grade": [33, 41], "seriou": [33, 54], "comprehens": 33, "trade": [33, 57], "potenti": [33, 37, 57], "studio": [33, 34], "multi": 33, "streamer": 33, "flexibli": 33, "shot": 33, "deliv": 33, "popular": [33, 42], "gamer": 33, "codec": 33, "decod": 33, "noun": 33, "algorithm": 33, "compress": 33, "cpu": 33, "insid": [33, 41], "bitrat": 33, "megabit": 33, "byte": 33, "unit": 33, "netflix": 33, "mainstream": 33, "mbit": 33, "movi": 33, "static": 33, "movement": [33, 43], "constant": [33, 43], "cbr": 33, "method": [33, 37, 45, 46, 48], "vari": 33, "With": [33, 43, 54], "congest": 33, "sudden": 33, "instantan": 33, "vbr": 33, "lag": [33, 35], "playback": 33, "embed": 33, "optim": 33, "tend": [33, 40, 43, 52], "variabl": 33, "x264": 33, "crf": 33, "countless": 33, "transmiss": 33, "hardwar": 33, "strike": 33, "encodign": 33, "backend": 33, "51": 33, "23": 33, "rtmp": 33, "proprietari": 33, "hl": 33, "delet": 33, "reorder": 33, "plai": [33, 35, 59], "custom": [33, 56], "dialog": 33, "tone": 33, "paramet": 33, "2500": 33, "kbp": 33, "preset": 33, "spent": [33, 61], "mkv": 33, "keyfram": 33, "interv": 33, "veryfast": 33, "hd": [33, 54], "1280x720": 33, "fp": 33, "attract": 33, "viewer": 33, "artifici": 33, "uniform": 33, "element": 33, "smarter": [33, 37], "insert": [33, 35], "perfectli": [33, 43], "loop": 33, "hood": 33, "obvious": [33, 40], "zone": 33, "pulseaudio": 33, "pavucontrol": 33, "item": [33, 61], "reduct": 33, "thee": 33, "mouth": 33, "ignor": 33, "piec": 33, "forgot": 33, "hdmi": 33, "virtual": [33, 35, 37, 42, 49, 63], "webcam": [33, 49], "regardless": [33, 42], "gallerycaptur": 33, "corner": [33, 35, 63], "canva": 33, "rout": 33, "promis": [34, 42], "engag": [34, 37, 41, 42, 43, 46], "vision": 34, "mindset": [34, 44], "rethink": 34, "assumpt": 34, "myself": 34, "night": 34, "closer": [34, 43], "stackoverflow": 34, "proxi": 34, "strict": [34, 53], "divis": [34, 43], "simplest": 34, "tabl": [34, 54, 55], "former": [34, 60], "contradictori": 34, "hasn": 35, "guidelin": [35, 44], "conduct": [35, 41, 49, 50], "spare": 35, "fontsiz": 35, "webinar": 35, "panelist": 35, "rais": [35, 40, 42, 62, 63], "reconfigur": 35, "angl": 35, "proxim": 35, "owner": 35, "sticki": [35, 38, 41, 42, 56], "ic": [35, 56, 59], "breaker": [35, 56, 59], "roll": 35, "hc": [35, 49], "en": [35, 49], "360026909191": 35, "360025561091": 35, "saw": [35, 54], "glitch": 35, "flash": 35, "launch": 35, "intermitt": 35, "temporari": 35, "hickup": 35, "somebodi": [35, 51], "unaffect": 35, "crucial": [35, 42], "interspers": 35, "pairwis": [35, 61], "green": [35, 38, 62, 63], "kth": [35, 52], "se": 35, "subscript": 35, "therefor": [35, 42], "mozilla": 35, "blog": [35, 59], "gather": 35, "thank": [36, 40, 42, 51], "gradual": 36, "volunt": [36, 42, 53, 54], "prototyp": [37, 54], "ai": 37, "david": 37, "meerman": 37, "scott": 37, "8th": 37, "ed": 37, "reilli": 37, "librari": 37, "interpretation9": 37, "sell": 37, "gain": [37, 45], "monei": 37, "anymor": 37, "commerci": 37, "banner": 37, "argu": 37, "flyer": 37, "anecdot": [37, 38], "mention": [37, 38, 42, 44], "wouldn": 37, "saariselk\u00e4": 37, "finnish": 37, "lapland": 37, "consum": 37, "deeper": 37, "purchas": 37, "trick": 37, "catchi": 37, "standalon": 37, "hack": 37, "clever": 37, "prospect": 37, "funder": 37, "leadership": 37, "metaphor": [37, 41], "citi": [37, 45, 50, 56], "cafe": 37, "traffic": [37, 40], "jargon": [37, 38], "friendli": 37, "magic": 37, "didn": [37, 54], "summar": [37, 59], "sentenc": [37, 56], "justifi": 37, "guess": 37, "scienc": [37, 61], "bui": 37, "salespeopl": 37, "mediat": 37, "compani": 37, "paper": [37, 38, 41], "fun": [37, 42, 46], "nudg": 37, "snippet": 37, "upcom": [37, 46, 47, 51, 52, 59], "underestim": 37, "figurehead": 37, "ceo": 37, "deleg": [37, 40, 56, 57], "analogi": [37, 42], "reader": 37, "photo": 37, "infograph": 37, "chart": 37, "newslett": [37, 46, 59], "face": [37, 41, 56, 61], "viral": 37, "confer": 37, "hashtag": 37, "meaningless": 37, "humor": 37, "journalist": 37, "facebook": 37, "linkedin": [37, 59], "brand": [37, 54], "85": 37, "per": [37, 41, 54, 55, 59, 61], "badg": 37, "perman": 37, "hesit": [37, 49, 50], "behalf": [37, 45, 47, 48], "passion": [37, 61], "blogger": 37, "di": 37, "respectfulli": [37, 49, 50], "spammili": 37, "water": [38, 56], "whiteboard": 38, "marker": 38, "bigger": 38, "heard": [38, 41, 42], "louder": 38, "unimport": 38, "appeal": 38, "navig": [38, 43], "flag": 38, "spell": 38, "cumul": 38, "cheatsheet": [38, 56], "mistak": [38, 41, 42], "insight": 38, "y": [38, 42, 44], "deviat": [38, 43], "excurs": [38, 56], "door": 38, "went": 38, "indico": [39, 46, 48, 56, 58, 59], "homepag": 39, "helpdesk": 39, "occupi": 40, "playbook": [40, 59], "uniqu": 40, "mentor": [40, 42, 46], "generalist": 40, "wherev": 40, "organiz": [40, 44], "overse": 40, "certif": [40, 56], "commonli": [40, 57], "commic": 40, "ffmpeg": [40, 53, 54, 55, 59], "editlist": [40, 53, 54, 55, 59], "core": 40, "compil": 41, "greg": 41, "wilson": 41, "pedagogi": 41, "intuit": 41, "citat": 41, "appendic": 41, "novic": 41, "scratch": [41, 59], "determin": [41, 54], "blind": 41, "map": 41, "deliber": 41, "fade": 41, "micromanu": 41, "german": 41, "extran": 41, "claim": [41, 43], "tho": 41, "subgoal": 41, "complimentari": 41, "redund": 41, "six": 41, "retriev": 41, "interleav": 41, "abcbac": 41, "aabbcc": 41, "elabor": 41, "peer": 41, "resampl": 41, "lack": 41, "born": 41, "western": 41, "cultur": 41, "embrac": 41, "predict": 41, "mirror": 41, "wise": 41, "improvis": 41, "drawback": 41, "skeleton": 41, "transpar": 41, "station": 41, "inact": 41, "beginn": [41, 42], "extrins": 41, "driver": 41, "autonomi": 41, "adult": 41, "unpredict": 41, "indiffer": 41, "unfair": 41, "contemptu": [41, 42], "attitud": [41, 42], "worthless": 41, "pretend": [41, 42], "imposs": 41, "challeng": 41, "domin": 41, "autograd": 41, "school": 41, "heart": 42, "hoc": 42, "idl": [42, 53, 54], "ruin": 42, "publicli": 42, "educ": 42, "shortli": 42, "laid": 42, "career": 42, "stage": [42, 54], "postdoc": [42, 45, 59], "professor": [42, 45], "industri": 42, "scientist": 42, "IT": 42, "sport": 42, "greet": 42, "exact": 42, "anytim": [42, 43], "colleagu": 42, "stranger": 42, "tipp": 42, "evryon": 42, "acknowledg": 42, "round": [42, 52, 60], "whichev": 42, "barrier": 42, "distrurb": 42, "her": 42, "hi": 42, "dare": 42, "shrink": 42, "homework": 42, "monopol": 42, "sorri": [42, 48], "neither": 42, "demotiv": 42, "muscl": 42, "memori": 42, "pad": 42, "excel": 42, "scorn": 42, "shortcom": 42, "convinc": 42, "disdain": 42, "dive": 42, "trust": 42, "frank": 42, "trivial": 42, "stupid": 42, "feign": 42, "surpris": 42, "tri": [42, 43, 57], "effici": [42, 43, 45], "workhop": 42, "act": 42, "invidu": 42, "infint": 42, "bond": 42, "rearrang": 42, "mutual": 43, "wisdom": 43, "choreographi": 43, "ship": 43, "ambigu": 43, "rudder": 43, "tackl": 43, "conn": 43, "jame": 43, "alden": 43, "barber": 43, "2005": 43, "naval": 43, "shiphandl": 43, "p": 43, "templeton": 43, "wikipedia": 43, "continuum": 43, "spotter": 43, "tendenc": 43, "negat": 43, "hope": [43, 47, 48, 51, 56], "solo": 43, "strong": [43, 50], "debat": 43, "layer": 43, "wari": 43, "disori": 43, "pair": [43, 59], "charg": [43, 61], "stronger": 43, "imperfect": 43, "excit": 43, "impress": 43, "infra": 44, "partial": 44, "brief": [44, 48, 56, 59], "spread": [44, 45], "throughout": 44, "bold": 44, "stash": 44, "ital": 44, "worst": 44, "imper": 44, "tens": 44, "skimmabl": 44, "gender": 44, "worth": 44, "hobbyist": 44, "refineri": 44, "sphinx": 44, "dear": [45, 47, 48, 49, 50, 51], "yyi": 45, "zzz": 45, "aim": 45, "advoc": 45, "phd": [45, 59], "junior": [45, 57], "senior": [45, 57], "snic": [46, 59], "tutor": 46, "nov": 46, "17": [46, 54], "19": 46, "26": 46, "00": [46, 53, 54], "trainer": 46, "tricki": 46, "previous": [46, 47], "expand": [46, 48], "novemb": 46, "135": 46, "36": [46, 53], "pleasur": 47, "unsubscrib": 47, "alumnu": 48, "enjoi": 48, "semest": 48, "benefici": 48, "apologi": 48, "couldn": 48, "109": 48, "extrem": 48, "averag": 48, "thor": [48, 50], "followup": 48, "cheer": 48, "zoomid": 49, "iron": 49, "id": 49, "zoompassword": 49, "210707503": 49, "workshopurl": 49, "deactiv": [49, 50], "occur": [49, 50], "troubleshoot": [49, 50], "surveyurl": 49, "strive": [49, 50], "treat": [49, 50], "nnn": 51, "course_her": 51, "love": 51, "cccc": 51, "began": 52, "stockholm": 52, "2016": 52, "2018": 52, "2021": 52, "paid": 52, "center": 52, "evolv": 52, "steer": 52, "commit": [52, 56], "brought": 52, "unclaim": 53, "filenam": 53, "day1": [53, 54], "25": [53, 54], "13": 53, "42": 53, "02": [53, 54], "collab": [53, 59], "dump": 53, "apart": 53, "irrelev": 54, "masterpiec": 54, "imprecis": 54, "shape": 54, "topic1": 54, "topic2": 54, "accident": 54, "rule": 54, "imovi": 54, "openshot": 54, "cross": 54, "perfectionist": 54, "maek": 54, "render": [54, 56], "subdirectori": 54, "ethic": 54, "playlist": 54, "jun": 54, "seri": 54, "june": 54, "clickabl": 54, "slider": 54, "38": 54, "04": 54, "youtu": 54, "r1tf2x5olna": 54, "dead": 55, "chunk": 55, "repo": [55, 59], "asc": [55, 59], "2022": 55, "winter": 55, "yaml": 55, "debrief": 56, "forgotten": [56, 59], "affili": 56, "ticket": [56, 59], "2019": 56, "somec": 56, "index": 56, "accordingli": 56, "fork": 56, "_workshop": 56, "permalink": 56, "18": 56, "unsolv": 56, "memor": 56, "tea": 56, "fruit": 56, "sweet": 56, "cabl": 56, "eduroam": 56, "global": 56, "ly": 56, "cacl": 56, "rush": 56, "problemat": 56, "polit": 56, "interject": 56, "clarif": 56, "credit": [56, 59], "outro": 56, "sub": 57, "lifelong": 57, "sci": 57, "300": 59, "toc": 59, "arrow_up": 59, "collabior": 59, "social": 59, "circl": [59, 63], "unansw": 59, "organis": 59, "spoiler": 59, "stakehold": 59, "ofc": 59, "ca": 59, "customis": 59, "freshdesk": 59, "anybodi": 59, "stat": 59, "mar": 59, "2023": 59, "lo": 59, "ondico": 59, "daili": 59, "distil": 59, "de": 59, "tinylett": 59, "crnewsletter_1_2023": 59, "03": 59, "21": 59, "tree": 59, "narrow": 59, "119815": 59, "toot": 59, "mastodon": 59, "coderefineryworkshopmarch21": 59, "23a7031623728480272384": 59, "chcaa": 59, "aarhu": 59, "retweet": 59, "sigma2": 59, "naiss": 59, "encc": 59, "csc": 59, "uib": 59, "au": 59, "stem": 59, "triton": 59, "delta": 59, "doctor": 59, "nersc": 59, "bergen": 59, "bjerkn": 59, "oslo": 59, "biologi": 59, "dcinc": 59, "countri": 59, "poster": 59, "nbe": 59, "phy": 59, "vaar": 59, "scip": 59, "_at_": 59, "esupport": 59, "folder": 59, "obtain": 59, "ect": 59, "descuss": 60, "mid": 60, "extend": 60, "indefinit": 60, "op": 60, "phase": 61, "flat": 61, "ventil": 61, "warm": 61, "desir": 61, "electr": 61, "outlet": 61, "male": 61, "femal": 61, "candid": 61, "hover": [62, 63], "atmospher": 62, "correct": 62, "appreci": [62, 63], "smoother": 63, "myteam": 63, "clock": 63, "hit": 63, "briefli": 63, "resolv": 63, "inconveni": 63}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"broadcast": [1, 33, 40, 59], "role": [1, 40, 59], "initi": 1, "setup": [1, 4, 22, 24, 25, 26, 30], "befor": [1, 10, 26, 32, 35, 38, 54, 56], "each": [1, 38], "dai": [1, 32], "dure": [1, 38, 42, 54, 56], "common": [1, 8, 42, 60], "problem": [1, 42, 63], "see": [1, 3, 4, 6, 42, 44, 62], "also": [1, 3, 4, 6, 42, 44, 62], "coderefineri": [2, 4, 5, 9, 17, 24, 42, 52, 56, 59, 60], "zulipchat": 2, "stream": [2, 12, 14, 33], "client": 2, "react": 2, "vote": 2, "privaci": [2, 11], "co": 3, "instructor": [3, 4, 23, 24, 25, 26, 27, 35, 40, 59, 60], "why": [3, 24, 41], "teach": [3, 4, 5, 17, 24, 26, 30, 33, 34, 38, 41, 43], "how": [3, 5, 15, 23, 35, 36, 37, 42, 63], "work": [3, 15, 56], "guid": [3, 29, 43, 44], "demo": [3, 33, 43], "giver": [3, 43], "prepar": [3, 23, 35, 42, 43, 56, 60], "your": [3, 26, 31, 33, 36, 37, 62, 63], "first": [3, 48, 56], "time": [3, 13, 14, 15, 32, 37], "top": [3, 23], "issu": [3, 4, 8, 23, 29], "new": [3, 23, 37], "face": [3, 23], "mooc": 4, "strategi": [4, 37, 42], "video": [4, 30, 33, 34, 37, 40, 53, 54, 55, 62], "The": [4, 34, 37], "futur": [4, 34], "technic": [4, 25, 26, 44, 63], "summari": [4, 31, 41, 42], "diagram": 4, "director": [4, 6, 40, 59], "expert": [4, 8, 40, 59], "helper": [4, 8, 27, 40, 42, 46, 59, 61, 63], "other": [4, 5, 16, 26, 28, 36, 44, 53, 56, 61, 62, 63], "staff": 4, "audienc": [4, 28, 30, 37], "team": [4, 24, 27, 31, 38, 40, 42, 43, 52, 59, 62, 63], "leader": [4, 27, 31, 40, 42, 59], "In": [4, 41], "main": [4, 23], "meet": [4, 30, 32, 34, 52, 60], "breakout": [4, 12, 23, 31, 35, 62], "via": [4, 6, 30, 37], "livestream": [4, 15, 24, 30, 40, 55], "live": [4, 14], "record": [4, 12, 33, 35, 55], "open": [4, 22, 33, 36], "contribut": 5, "take": [5, 13, 14, 15], "part": 5, "action": [5, 41], "join": [5, 42, 52], "our": 5, "commun": [5, 9, 15, 41, 52, 56], "train": [5, 35], "advertis": [5, 45], "help": 5, "out": [5, 35], "onlin": [5, 17, 21, 25, 33, 34, 35, 37, 41, 49], "cours": [5, 34, 36], "openli": 5, "allow": 5, "type": [5, 21, 41], "manag": [6, 10, 13, 14, 15, 40, 59], "schedul": 6, "switch": 6, "scene": [6, 33, 40, 59], "audio": [6, 25, 33, 37, 62], "pip": 6, "exampl": [6, 10, 25, 33], "ob": 6, "remot": 6, "control": [6, 11, 62, 63], "tablet": 6, "exercis": [7, 28, 35, 38, 40, 41, 42, 56, 59], "coordin": [7, 39, 40, 56, 59], "task": [8, 63], "solut": 8, "govern": [9, 52], "neic": 9, "project": [9, 42], "hackmd": [10, 30, 40], "workshop": [10, 13, 14, 15, 16, 17, 19, 21, 24, 35, 40, 42, 45, 48, 54, 56, 57, 58, 59, 60, 61, 62], "most": 10, "thing": [10, 44], "edit": [10, 54], "everyon": 10, "gener": [10, 13, 14, 15, 16], "practic": [10, 40, 49, 50, 56], "format": 10, "post": [10, 48, 56], "websit": [10, 37], "collabor": [11, 59], "document": [11, 56, 59], "mechan": [11, 62, 63], "basic": [11, 21, 22, 24, 28, 30, 33, 43, 62], "ask": [11, 63], "question": [11, 16, 42, 63], "don": [11, 60], "t": [11, 60, 63], "get": [11, 23], "overwhelm": 11, "host": [12, 40], "room": [12, 23, 31, 35, 56, 61, 62], "attend": [13, 14, 15, 34], "an": [13, 15, 23, 24, 27, 37], "person": [13, 19, 50, 61], "prerequisit": [13, 14, 15], "softwar": [13, 14, 15, 33], "instal": [13, 14, 15, 35], "etc": [13, 14, 15], "serious": [13, 14, 15], "social": [13, 14, 15, 37], "comput": 13, "equip": 13, "final": [13, 14, 15, 25, 26], "note": [13, 14, 15], "zoom": [14, 35, 55, 62, 63], "workspac": [14, 15], "access": 15, "icebreak": 16, "refer": [16, 56], "relev": 16, "adapt": 16, "from": [16, 22, 27, 63], "pre": 16, "survei": [16, 22, 48, 56], "credit": 16, "oper": 17, "manual": [17, 35], "learner": [17, 25, 40, 55], "playbook": 17, "lesson": [17, 28, 29, 35, 38, 41, 56], "design": [17, 28, 41], "misc": 17, "about": [17, 22, 34, 52], "indico": [18, 19, 20, 21, 22], "hint": [18, 38, 43], "email": [18, 21, 48, 56], "peopl": 18, "workflow": [19, 21], "flow": [19, 21], "registr": [20, 22, 31, 39, 40, 59], "system": [20, 63], "filter": 21, "event": [22, 33, 59], "step": [22, 31, 56], "instruct": [22, 35], "copi": 22, "latest": 22, "updat": 22, "inform": 22, "more": [22, 27, 35, 37], "process": [22, 41, 54], "import": 22, "export": 22, "introduct": [23, 28, 37, 41, 56], "do": [23, 24, 42], "you": [23, 26, 31, 37, 42, 63], "start": [23, 26, 38, 56], "materi": [23, 38], "As": [23, 32, 56], "session": [23, 35, 38, 42], "Being": 24, "i": [24, 28, 32, 34, 37, 41, 42, 55], "am": 24, "what": [24, 34, 37, 42, 44, 54], "need": [24, 42], "know": 24, "checklist": [25, 26, 32, 56, 59], "screen": [25, 26, 63], "share": [25, 63], "layout": 25, "simpl": 26, "fanci": 26, "check": [26, 53], "someon": [26, 63], "clean": 26, "environ": [26, 42], "arrang": 26, "window": 26, "well": 26, "desktop": 26, "web": 26, "browser": 26, "termin": 26, "color": 26, "scheme": 26, "clear": 26, "size": 26, "prompt": 26, "command": 26, "line": 26, "histori": [26, 52], "tool": 26, "respons": 27, "backward": 28, "emot": 28, "intrins": 28, "appeal": 28, "who": [28, 42], "plan": [28, 35, 37], "write": [28, 37, 44], "conclus": 28, "think": 28, "review": 29, "overview": [29, 40, 53], "episod": 29, "detail": 29, "major": 29, "refactor": 29, "screenshar": 30, "feedback": [30, 63], "local": 31, "principl": [31, 36], "1": [31, 34, 37, 43, 48, 56], "2": [31, 37, 43, 56], "2b": [31, 34], "joint": 31, "2c": [31, 34], "provid": 31, "soon": 32, "topic": [32, 60], "decid": 32, "archiv": 32, "agenda": 32, "theori": 33, "vision": 33, "glossari": 33, "user": 33, "interfac": 33, "configur": 33, "projector": 33, "loopback": 33, "output": 33, "own": 33, "differ": 34, "taxonomi": 34, "By": 34, "yourself": 34, "2a": 34, "group": 34, "higher": 34, "product": 34, "valu": 34, "multipl": 34, "wai": [34, 37], "3": [34, 37], "high": 34, "accessibli": 34, "zen": 34, "level": 34, "old": [35, 37, 53, 54], "For": 35, "avoid": 35, "bomb": 35, "At": [35, 56], "begin": 35, "specif": 35, "sent": 35, "conting": 35, "break": 35, "resourc": 35, "outreach": [37, 40, 59], "rule": 37, "market": [37, 40, 41, 57, 59], "pr": 37, "ar": [37, 63], "ineffect": 37, "world": 37, "reach": 37, "buyer": 37, "directli": 37, "4": 37, "media": 37, "target": 37, "5": 37, "content": 37, "rich": 37, "6": 37, "real": [37, 63], "7": 37, "artifici": 37, "intellig": 37, "machin": 37, "learn": [37, 41, 42], "8": 37, "publish": 37, "build": [37, 41], "9": 37, "grow": 37, "busi": 37, "drive": 37, "sale": 37, "10": 37, "creat": [37, 42, 56], "awesom": 37, "11": 37, "12": 37, "network": 37, "13": 37, "blog": 37, "14": 37, "imag": 37, "worth": 37, "thousand": 37, "word": 37, "15": 37, "16": 37, "podcast": 37, "17": 37, "us": [37, 63], "releas": 37, "18": 37, "newsroom": 37, "A": [37, 41], "front": 37, "door": 37, "much": 37, "than": 37, "19": 37, "20": 37, "newsjack": 37, "21": 37, "search": 37, "engin": 37, "22": 37, "make": 37, "It": 37, "happen": [37, 42], "present": [38, 43], "off": [38, 62], "try": 38, "stick": 38, "wrap": 38, "up": [38, 56], "behind": [40, 59], "editor": [40, 55], "best": 40, "tech": 41, "togeth": 41, "ch1": 41, "ch2": 41, "mental": 41, "model": [41, 43], "ch3": 41, "expertis": 41, "memori": 41, "ch4": 41, "cognit": 41, "load": 41, "ch5": 41, "individu": 41, "ch6": 41, "ch7": 41, "approxim": 41, "truth": 41, "ch8": 41, "perform": 41, "art": 41, "ch9": 41, "classroom": 41, "ch10": 41, "motiv": 41, "demotiv": 41, "ch11": 41, "ch12": 41, "ch13": 41, "ch14": 41, "ch15": 41, "partnership": 41, "ch16": 41, "tl": 42, "dr": 42, "thi": 42, "page": [42, 56], "code": 42, "conduct": 42, "can": 42, "ani": 42, "path": 42, "ahead": 42, "tip": 42, "trick": 42, "posit": 42, "lead": 42, "solv": 42, "pleas": [42, 63], "background": 42, "hierarch": 42, "scale": 42, "interview": 43, "doc": 44, "kind": 44, "recommend": 44, "section": 44, "includ": 44, "style": 44, "suggest": 44, "idea": 44, "look": 46, "notifi": 47, "me": 47, "announc": [47, 56], "remind": 48, "week": [48, 56], "after": [48, 54, 61], "info": [49, 50], "wait": 51, "list": 51, "method": [52, 55], "chat": 52, "github": 52, "decis": 52, "core": 52, "segment": 53, "report": 53, "comment": 53, "we": 54, "want": 54, "immedi": 54, "public": 54, "overal": 55, "prioriti": 55, "modern": 55, "If": 55, "organ": [56, 58, 59], "templat": [56, 59], "select": 56, "lectur": [56, 61], "set": [56, 62], "distribut": 56, "particip": 56, "right": 56, "repositori": 56, "arriv": 56, "talk": 56, "end": 56, "yyyi": 59, "mm": 59, "dd": 59, "link": 59, "certif": 59, "forget": 60, "convent": 60, "rememb": 60, "requir": 61, "name": [62, 63], "should": 62, "indic": [62, 63], "reaction": 62, "mute": 63, "unmut": 63, "instead": 63, "default": 63, "usernam": 63, "statu": 63, "signal": 63, "awai": 63, "keyboard": 63, "when": 63, "complet": 63, "successfulli": 63, "got": 63, "stuck": 63, "give": 63, "speed": 63, "point": 63, "doesn": 63, "have": 63, "fullscreen": 63, "dual": 63, "monitor": 63, "mode": 63}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 57}, "alltitles": {"Broadcaster": [[1, "broadcaster"], [59, "broadcaster"]], "Role of the broadcaster": [[1, "role-of-the-broadcaster"]], "Initial setup": [[1, "initial-setup"]], "Before each day": [[1, "before-each-day"]], "Before each broadcast": [[1, "before-each-broadcast"]], "During the broadcast": [[1, "during-the-broadcast"]], "Common problems": [[1, "common-problems"]], "See also": [[1, "see-also"], [3, "see-also"], [4, "see-also"], [6, "see-also"], [42, "see-also"], [44, "see-also"], [62, "see-also"]], "CodeRefinery Zulipchat": [[2, "coderefinery-zulipchat"]], "Streams": [[2, "streams"]], "Clients": [[2, "clients"]], "Reacting and voting": [[2, "reacting-and-voting"]], "Privacy": [[2, "privacy"], [11, "privacy"]], "Co-instructors": [[3, "co-instructors"]], "Why co-teaching?": [[3, "why-co-teaching"]], "How co-teaching works: guide and demo-giver": [[3, "how-co-teaching-works-guide-and-demo-giver"]], "Preparing for your first time": [[3, "preparing-for-your-first-time"]], "Top issues new co-instructors face": [[3, "top-issues-new-co-instructors-face"]], "CodeRefinery MOOC strategy": [[4, "coderefinery-mooc-strategy"]], "Video: The future of teaching": [[4, null], [34, null]], "Technical setup summary": [[4, "technical-setup-summary"]], "Summary diagram": [[4, "summary-diagram"]], "Instructors": [[4, "instructors"], [27, "instructors"], [59, "instructors"]], "Director": [[4, "director"], [6, "director"], [40, "director"]], "Expert helpers and other staff": [[4, "expert-helpers-and-other-staff"]], "Audience and team leaders": [[4, "audience-and-team-leaders"]], "In the main meeting with breakouts": [[4, "in-the-main-meeting-with-breakouts"]], "Via livestream": [[4, "via-livestream"]], "Live": [[4, "live"]], "Recording": [[4, "recording"], [12, "recording"]], "Open issues": [[4, "open-issues"]], "Contributing to CodeRefinery": [[5, "contributing-to-coderefinery"]], "How to take part": [[5, "how-to-take-part"]], "Action: Join our \u201ccommunity teaching training\u201d": [[5, "action-join-our-community-teaching-training"]], "Action: Advertise and/or help out in our online courses": [[5, "action-advertise-and-or-help-out-in-our-online-courses"]], "Action: Teach openly and allow others to join": [[5, "action-teach-openly-and-allow-others-to-join"]], "Other types of contributions": [[5, "other-types-of-contributions"]], "Managing the schedule": [[6, "managing-the-schedule"]], "Switching scenes and audio": [[6, "switching-scenes-and-audio"]], "PiP example": [[6, null]], "OBS remote control via obs-tablet-remote": [[6, "obs-remote-control-via-obs-tablet-remote"]], "Exercise coordinator": [[7, "exercise-coordinator"]], "Expert helpers": [[8, "expert-helpers"], [59, "expert-helpers"]], "Tasks": [[8, "tasks"]], "Common issues and solutions": [[8, "common-issues-and-solutions"]], "CodeRefinery governance": [[9, "coderefinery-governance"]], "CodeRefinery Community": [[9, "coderefinery-community"]], "NeIC project": [[9, "neic-project"]], "HackMD manager": [[10, "hackmd-manager"], [40, "hackmd-manager"]], "Before the workshop": [[10, "before-the-workshop"], [56, "before-the-workshop"]], "Most things to edit (everyone)": [[10, "most-things-to-edit-everyone"]], "General HackMD practices": [[10, "general-hackmd-practices"]], "HackMD format example": [[10, "hackmd-format-example"]], "Posting HackMD to website": [[10, "posting-hackmd-to-website"]], "Collaborative document mechanics and controls": [[11, "collaborative-document-mechanics-and-controls"]], "Basic controls": [[11, "basic-controls"]], "Asking questions": [[11, "asking-questions"]], "Don\u2019t get overwhelmed": [[11, "don-t-get-overwhelmed"]], "Host": [[12, "host"], [40, "host"]], "Breakout rooms": [[12, "breakout-rooms"], [35, "breakout-rooms"], [62, "breakout-rooms"]], "Streaming": [[12, "streaming"]], "Attending an in-person workshop": [[13, "attending-an-in-person-workshop"]], "General prerequisites, software installation, etc.": [[13, "general-prerequisites-software-installation-etc"], [14, "general-prerequisites-software-installation-etc"], [15, "general-prerequisites-software-installation-etc"]], "Take the workshop seriously": [[13, "take-the-workshop-seriously"], [14, "take-the-workshop-seriously"], [15, "take-the-workshop-seriously"]], "Social": [[13, "social"], [14, "social"], [15, "social"]], "Computer and equipment": [[13, "computer-and-equipment"]], "Time management": [[13, "time-management"], [14, "time-management"], [15, "time-management"]], "Final notes": [[13, "final-notes"], [14, "final-notes"], [15, "final-notes"]], "Attending a Zoom workshop": [[14, "attending-a-zoom-workshop"]], "Workspace": [[14, "workspace"], [15, "workspace"]], "Live streaming": [[14, "live-streaming"]], "Attending an livestream workshop": [[15, "attending-an-livestream-workshop"]], "How it works": [[15, "how-it-works"]], "Accessibility": [[15, "accessibility"]], "Communication": [[15, "communication"]], "Icebreakers": [[16, "icebreakers"]], "Other references": [[16, "other-references"]], "Relevant to workshop": [[16, "relevant-to-workshop"]], "Adapted from pre-workshop survey": [[16, "adapted-from-pre-workshop-survey"]], "General questions": [[16, "general-questions"]], "Credits": [[16, "credits"]], "CodeRefinery operation manuals": [[17, "coderefinery-operation-manuals"]], "Learners": [[17, null]], "Workshop playbook": [[17, null]], "Online teaching": [[17, null], [34, "online-teaching"]], "Lesson design": [[17, null], [28, "lesson-design"]], "Misc": [[17, null]], "About CodeRefinery": [[17, null], [52, "about-coderefinery"]], "Indico hints": [[18, "indico-hints"]], "Emailing people": [[18, "emailing-people"]], "Indico in-person workshop workflow": [[19, "indico-in-person-workshop-workflow"]], "Flow": [[19, "flow"], [21, "flow"]], "Indico registration system": [[20, "indico-registration-system"]], "Indico online workshop workflow": [[21, "indico-online-workshop-workflow"]], "Basic types": [[21, "basic-types"]], "Email filters": [[21, "email-filters"]], "Indico event setup": [[22, "indico-event-setup"]], "Step-by-step instructions:": [[22, "step-by-step-instructions"]], "Copy basics from latest event": [[22, "copy-basics-from-latest-event"]], "Update copied event information": [[22, "update-copied-event-information"]], "More information about the registration process": [[22, "more-information-about-the-registration-process"]], "Import survey": [[22, "import-survey"]], "Open registration": [[22, "open-registration"]], "Exporting registrations": [[22, "exporting-registrations"]], "Instructor introduction": [[23, "instructor-introduction"]], "How do you get started?": [[23, "how-do-you-get-started"]], "Starting materials": [[23, "starting-materials"]], "As an instructor": [[23, "as-an-instructor"]], "in the main session": [[23, "in-the-main-session"]], "Preparing for the breakouts (in the main room)": [[23, "preparing-for-the-breakouts-in-the-main-room"]], "Top issues new instructors face": [[23, "top-issues-new-instructors-face"]], "Being an instructor in livestreamed CodeRefinery workshop": [[24, "being-an-instructor-in-livestreamed-coderefinery-workshop"]], "Basic setup": [[24, "basic-setup"]], "I am teaching in a workshop, what do I need to know/do?": [[24, "i-am-teaching-in-a-workshop-what-do-i-need-to-know-do"]], "Why team teaching?": [[24, "why-team-teaching"]], "Why livestream?": [[24, "why-livestream"]], "Instructor technical setup, online": [[25, "instructor-technical-setup-online"]], "Final checklist": [[25, null], [26, null]], "Audio": [[25, "audio"]], "Screen sharing": [[25, "screen-sharing"]], "Screen share examples": [[25, "screen-share-examples"]], "Screen layout: learners": [[25, "screen-layout-learners"]], "Screen layout: instructors": [[25, "screen-layout-instructors"]], "Instructor technical setup": [[26, "instructor-technical-setup"]], "Simple or fancy screen?": [[26, "simple-or-fancy-screen"]], "Check with someone before you start teaching": [[26, "check-with-someone-before-you-start-teaching"]], "Clean your environment": [[26, "clean-your-environment"]], "Arrange your windows well": [[26, "arrange-your-windows-well"]], "Desktop environment": [[26, "desktop-environment"]], "Web browser": [[26, "web-browser"]], "Terminal": [[26, "terminal"]], "Terminal color schemes": [[26, "terminal-color-schemes"]], "Clearing the terminal": [[26, "clearing-the-terminal"]], "Terminal size": [[26, "terminal-size"]], "Prompt": [[26, "prompt"]], "Command line history": [[26, "command-line-history"]], "Other command line history tools": [[26, null]], "Responsibilities of an instructor": [[27, "responsibilities-of-an-instructor"]], "From team leader/helper to more": [[27, "from-team-leader-helper-to-more"]], "Backwards lesson design": [[28, "backwards-lesson-design"]], "Emotional and intrinsic appeal, other basics": [[28, "emotional-and-intrinsic-appeal-other-basics"]], "Who is the audience?": [[28, "who-is-the-audience"]], "Planning": [[28, "planning"]], "Writing": [[28, "writing"]], "Introduction (and conclusion)": [[28, "introduction-and-conclusion"]], "Thinking of exercises": [[28, "thinking-of-exercises"]], "Lesson review": [[29, "lesson-review"]], "Issues": [[29, "issues"]], "Lesson guides": [[29, "lesson-guides"]], "Lesson overview": [[29, "lesson-overview"]], "Episode overview": [[29, "episode-overview"]], "Episode details": [[29, "episode-details"]], "Major Refactorings": [[29, "major-refactorings"]], "Teaching via livestreaming": [[30, "teaching-via-livestreaming"]], "Video": [[30, null]], "Basic meeting setup": [[30, "basic-meeting-setup"]], "Screensharing": [[30, "screensharing"]], "HackMD and audience feedback": [[30, "hackmd-and-audience-feedback"]], "Local breakout rooms": [[31, "local-breakout-rooms"]], "Principles": [[31, "principles"], [36, "principles"]], "Step 1: Local breakout room": [[31, "step-1-local-breakout-room"]], "Step 2: Registration": [[31, "step-2-registration"]], "Step 2b: Joint registration": [[31, "step-2b-joint-registration"]], "Step 2c: Joint registration, you provide team leaders for your teams": [[31, "step-2c-joint-registration-you-provide-team-leaders-for-your-teams"]], "Summary": [[31, "summary"]], "Meeting checklist": [[32, "meeting-checklist"]], "As soon as meeting topic/time is decided": [[32, "as-soon-as-meeting-topic-time-is-decided"]], "Days before the meeting": [[32, "days-before-the-meeting"]], "Archive meeting agenda": [[32, "archive-meeting-agenda"]], "Open Broadcaster Software theory": [[33, "open-broadcaster-software-theory"]], "Vision": [[33, "vision"]], "Basics": [[33, "basics"], [43, "basics"], [62, "basics"]], "Basic audio/video glossary": [[33, null]], "User interface basics": [[33, "user-interface-basics"]], "Configuration": [[33, "configuration"]], "Basic configuration": [[33, "basic-configuration"]], "Scene configuration": [[33, "scene-configuration"]], "Audio configuration": [[33, "audio-configuration"]], "Recording and streaming": [[33, "recording-and-streaming"]], "Projector and loopback output": [[33, "projector-and-loopback-output"]], "Example configurations": [[33, "example-configurations"]], "Recording your own demo": [[33, "recording-your-own-demo"]], "Online teaching event": [[33, "online-teaching-event"]], "What is different about online?": [[34, "what-is-different-about-online"]], "Taxonomy of online teaching": [[34, "taxonomy-of-online-teaching"]], "(1) By yourself, in a meeting": [[34, "by-yourself-in-a-meeting"]], "(2a) Group teaching, in a meeting": [[34, "a-group-teaching-in-a-meeting"]], "(2b) Higher production values": [[34, "b-higher-production-values"]], "(2c) Multiple ways of attending": [[34, "c-multiple-ways-of-attending"]], "(3) High-accessibly zen-level courses": [[34, "high-accessibly-zen-level-courses"]], "Online training manual OLD": [[35, "online-training-manual-old"]], "For the instructors": [[35, "for-the-instructors"]], "How to avoid \u201cZoom bombing\u201d": [[35, "how-to-avoid-zoom-bombing"]], "Preparation": [[35, "preparation"], [43, "preparation"]], "At the beginning of the session": [[35, "at-the-beginning-of-the-session"]], "Recording of sessions": [[35, "recording-of-sessions"]], "Zoom-specific installations instructions sent out before workshop/lesson": [[35, "zoom-specific-installations-instructions-sent-out-before-workshop-lesson"]], "Contingency plans": [[35, "contingency-plans"]], "Exercises": [[35, "exercises"]], "Breaks": [[35, "breaks"]], "More resources": [[35, "more-resources"]], "Open your courses to others": [[36, "open-your-courses-to-others"]], "How-to": [[36, "how-to"]], "Outreach plan": [[37, "outreach-plan"]], "Introduction": [[37, "introduction"]], "1 The Old Rules of Marketing and PR Are Ineffective in an Online World": [[37, "the-old-rules-of-marketing-and-pr-are-ineffective-in-an-online-world"]], "2 The New Rules of Marketing and PR": [[37, "the-new-rules-of-marketing-and-pr"]], "3 Reaching Your Buyers Directly": [[37, "reaching-your-buyers-directly"]], "4 Social Media and Your Targeted Audience": [[37, "social-media-and-your-targeted-audience"]], "5 The Content\u2010Rich Website": [[37, "the-contentrich-website"]], "6 Marketing and PR in Real Time": [[37, "marketing-and-pr-in-real-time"]], "7 Artificial Intelligence and Machine Learning for Marketing and PR": [[37, "artificial-intelligence-and-machine-learning-for-marketing-and-pr"]], "8 You Are What You Publish: Building Your Marketing and PR Plan": [[37, "you-are-what-you-publish-building-your-marketing-and-pr-plan"]], "9 Growing Your Business: How Marketing and PR Drive Sales": [[37, "growing-your-business-how-marketing-and-pr-drive-sales"]], "10 Strategies for Creating Awesome Content": [[37, "strategies-for-creating-awesome-content"]], "11 How to Write for Your Buyers": [[37, "how-to-write-for-your-buyers"]], "12 Social Networking as Marketing": [[37, "social-networking-as-marketing"]], "13 Blogging to Reach Your Buyers": [[37, "blogging-to-reach-your-buyers"]], "14 An Image Is Worth a Thousand Words": [[37, "an-image-is-worth-a-thousand-words"]], "15 Video and Your Buyers": [[37, "video-and-your-buyers"]], "16 Audio Content via Podcasting and Social Audio": [[37, "audio-content-via-podcasting-and-social-audio"]], "17 How to Use News Releases to Reach Buyers Directly": [[37, "how-to-use-news-releases-to-reach-buyers-directly"]], "18 Your Newsroom: A Front Door for Much More Than the Media": [[37, "your-newsroom-a-front-door-for-much-more-than-the-media"]], "19 The New Rules for Reaching the Media": [[37, "the-new-rules-for-reaching-the-media"]], "20 Newsjacking Your Way into the Media": [[37, "newsjacking-your-way-into-the-media"]], "21 Search Engine Marketing": [[37, "search-engine-marketing"]], "22 Make It Happen": [[37, "make-it-happen"]], "Lesson presentation hints": [[38, "lesson-presentation-hints"]], "Before each lesson": [[38, "before-each-lesson"]], "Starting off": [[38, "starting-off"]], "Team teaching": [[38, "team-teaching"], [43, "team-teaching"]], "During the lessons": [[38, "during-the-lessons"]], "Exercise sessions": [[38, "exercise-sessions"], [42, "exercise-sessions"]], "Try to stick to the material": [[38, "try-to-stick-to-the-material"]], "Wrap up": [[38, "wrap-up"]], "Registration coordinator": [[39, "registration-coordinator"], [40, "registration-coordinator"], [59, "registration-coordinator"]], "Roles overview": [[40, "roles-overview"]], "Workshop roles": [[40, "workshop-roles"], [59, "workshop-roles"]], "Learner": [[40, "learner"]], "Team leader": [[40, "team-leader"]], "Instructor": [[40, "instructor"]], "Expert helper": [[40, "expert-helper"]], "Behind the scenes": [[40, "behind-the-scenes"]], "Broadcaster (livestream)": [[40, "broadcaster-livestream"]], "Instructor coordinator": [[40, "instructor-coordinator"], [59, "instructor-coordinator"]], "Outreach and marketing coordinator": [[40, "outreach-and-marketing-coordinator"], [59, "outreach-and-marketing-coordinator"]], "Team leader / Exercise coordinator": [[40, "team-leader-exercise-coordinator"]], "Video editor": [[40, "video-editor"], [55, "video-editor"]], "Best practices": [[40, "best-practices"]], "Summary of Teaching Tech Together": [[41, "summary-of-teaching-tech-together"]], "Ch1: Introduction": [[41, "ch1-introduction"]], "Ch2: Building mental models": [[41, "ch2-building-mental-models"]], "Ch3: Expertise and memory": [[41, "ch3-expertise-and-memory"]], "Ch4: Cognitive load": [[41, "ch4-cognitive-load"]], "Ch5: Individual learning": [[41, "ch5-individual-learning"]], "Ch6: A lesson design process": [[41, "ch6-a-lesson-design-process"]], "Ch7: Actionable approximations of the truth": [[41, "ch7-actionable-approximations-of-the-truth"]], "Ch8: Teaching as performance art": [[41, "ch8-teaching-as-performance-art"]], "Ch9: In the classroom": [[41, "ch9-in-the-classroom"]], "Ch10: Motivation and demotivation": [[41, "ch10-motivation-and-demotivation"]], "Ch11: Teaching online": [[41, "ch11-teaching-online"]], "Ch12: Exercise types": [[41, "ch12-exercise-types"]], "Ch13: Building community": [[41, "ch13-building-community"]], "Ch14: Marketing": [[41, "ch14-marketing"]], "Ch15: Partnerships": [[41, "ch15-partnerships"]], "Ch16: Why I teach": [[41, "ch16-why-i-teach"]], "Team leaders / Helpers / Exercise leaders": [[42, "team-leaders-helpers-exercise-leaders"]], "TL;DR (Summary of this page)": [[42, "tl-dr-summary-of-this-page"]], "Code of Conduct": [[42, "code-of-conduct"]], "CodeRefinery project": [[42, "coderefinery-project"]], "..and you?": [[42, "and-you"]], "What is needed to be a team leader?": [[42, "what-is-needed-to-be-a-team-leader"]], "Who is joining this workshop?": [[42, "who-is-joining-this-workshop"]], "What will happen during workshop?": [[42, "what-will-happen-during-workshop"]], "What can I do to prepare for the workshop?": [[42, "what-can-i-do-to-prepare-for-the-workshop"]], "Any questions?": [[42, "any-questions"]], "Path ahead": [[42, "path-ahead"]], "Tips and Tricks": [[42, "tips-and-tricks"]], "How to create a positive learning environment?": [[42, "how-to-create-a-positive-learning-environment"]], "Strategies for leading a team": [[42, "strategies-for-leading-a-team"]], "How to solve common problems in teams?": [[42, "how-to-solve-common-problems-in-teams"]], "Please do not \u2026": [[42, "please-do-not"]], "Background": [[42, "background"]], "Hierarchical workshops to scale": [[42, "hierarchical-workshops-to-scale"]], "Teams": [[42, "teams"]], "Model 1: Guide and demo-giver": [[43, "model-1-guide-and-demo-giver"]], "Model 2: Presenter and interviewer": [[43, "model-2-presenter-and-interviewer"]], "Hints": [[43, "hints"]], "Writing technical docs": [[44, "writing-technical-docs"]], "What kind of doc?": [[44, "what-kind-of-doc"]], "Recommended sections/things to include": [[44, "recommended-sections-things-to-include"]], "Style suggestions": [[44, "style-suggestions"]], "Style guide": [[44, "style-guide"]], "Other ideas": [[44, "other-ideas"]], "Advertising workshop": [[45, "advertising-workshop"]], "Looking for helpers": [[46, "looking-for-helpers"]], "Notify-me announcement": [[47, "notify-me-announcement"]], "Post-workshop survey": [[48, "post-workshop-survey"], [56, "post-workshop-survey"]], "First email": [[48, "first-email"]], "Reminder 1 week after first email": [[48, "reminder-1-week-after-first-email"]], "Practical info (online)": [[49, "practical-info-online"]], "Practical info, in-person": [[50, "practical-info-in-person"]], "Waiting list": [[51, "waiting-list"]], "History": [[52, "history"]], "Governance": [[52, "governance"]], "Communication methods": [[52, "communication-methods"]], "Chat": [[52, "chat"]], "Team meetings": [[52, "team-meetings"]], "Github": [[52, "github"]], "Decisions": [[52, "decisions"]], "Core team": [[52, "core-team"]], "Joining": [[52, "joining"]], "Video checking OLD": [[53, "video-checking-old"]], "Overview": [[53, "overview"]], "Segment report": [[53, "segment-report"]], "Other comments": [[53, "other-comments"]], "Video editing OLD": [[54, "video-editing-old"]], "What we want": [[54, "what-we-want"]], "Before/during/immediately after the workshop": [[54, "before-during-immediately-after-the-workshop"]], "Processing": [[54, "processing"]], "Publication": [[54, "publication"]], "Overall priorities": [[55, "overall-priorities"]], "Modern: livestream method": [[55, "modern-livestream-method"]], "If the learner Zoom is recorded": [[55, "if-the-learner-zoom-is-recorded"]], "Organizing a CodeRefinery workshop": [[56, "organizing-a-coderefinery-workshop"]], "Email templates": [[56, "email-templates"]], "Select a workshop coordinator": [[56, "select-a-workshop-coordinator"]], "Other documents and references": [[56, "other-documents-and-references"]], "First steps": [[56, "first-steps"]], "Lecture room": [[56, "lecture-room"], [61, "lecture-room"]], "Set up workshop page": [[56, "set-up-workshop-page"]], "Announcing the workshop": [[56, "announcing-the-workshop"]], "Distribute the work": [[56, "distribute-the-work"]], "Preparing lessons": [[56, "preparing-lessons"]], "Prepare practicals": [[56, "prepare-practicals"]], "Communication with participants": [[56, "communication-with-participants"]], "1-2 weeks before the workshop": [[56, "weeks-before-the-workshop"]], "Right before the workshop starts": [[56, "right-before-the-workshop-starts"]], "Create exercise repositories": [[56, "create-exercise-repositories"]], "Workshop preparation checklist": [[56, "workshop-preparation-checklist"]], "As participants arrive": [[56, "as-participants-arrive"]], "Introduction talk": [[56, "introduction-talk"]], "During workshop": [[56, "during-workshop"]], "At the end of workshop": [[56, "at-the-end-of-workshop"]], "Post-workshop": [[56, "post-workshop"]], "Workshop marketing": [[57, "workshop-marketing"]], "Workshop organizers": [[58, "workshop-organizers"]], "Workshop checklist template": [[59, "workshop-checklist-template"]], "CodeRefinery workshop YYYY-MM-DD": [[59, "coderefinery-workshop-yyyy-mm-dd"]], "Links": [[59, "links"]], "Managing collaborative document": [[59, "managing-collaborative-document"]], "Workshop organization; roles \u201cbehind the scenes\u201d": [[59, "workshop-organization-roles-behind-the-scenes"]], "Event director": [[59, "event-director"]], "Exercise and team leader coordinator": [[59, "exercise-and-team-leader-coordinator"]], "Certificate coordinator": [[59, "certificate-coordinator"]], "Workshop preparation meeting": [[60, "workshop-preparation-meeting"]], "Topics of workshop instructor meeting": [[60, "topics-of-workshop-instructor-meeting"]], "Don\u2019t forget": [[60, "don-t-forget"]], "Common CodeRefinery conventions to remember": [[60, "common-coderefinery-conventions-to-remember"]], "Workshop requirements - in person": [[61, "workshop-requirements-in-person"]], "Helpers": [[61, "helpers"]], "Other requirements": [[61, "other-requirements"]], "After the workshop": [[61, "after-the-workshop"]], "Zoom mechanics and controls": [[62, "zoom-mechanics-and-controls"], [63, "zoom-mechanics-and-controls"]], "Audio/video on or off?": [[62, "audio-video-on-or-off"]], "Workshops with teams: your name should indicate your breakout room": [[62, "workshops-with-teams-your-name-should-indicate-your-breakout-room"]], "Reactions": [[62, "reactions"]], "Other settings": [[62, "other-settings"]], "How to mute and unmute": [[63, "how-to-mute-and-unmute"]], "Please use your real name (instead of a system default username)": [[63, "please-use-your-real-name-instead-of-a-system-default-username"]], "Indicate in your name if you are in a team and/or if you are a helper": [[63, "indicate-in-your-name-if-you-are-in-a-team-and-or-if-you-are-a-helper"]], "Indicating your status": [[63, "indicating-your-status"]], "How to signal if you are away from keyboard": [[63, "how-to-signal-if-you-are-away-from-keyboard"]], "How to signal when you completed a task successfully": [[63, "how-to-signal-when-you-completed-a-task-successfully"]], "How to ask a question": [[63, "how-to-ask-a-question"]], "How to signal a technical problem or that you got stuck": [[63, "how-to-signal-a-technical-problem-or-that-you-got-stuck"]], "How to give feedback on the speed": [[63, "how-to-give-feedback-on-the-speed"]], "Other points": [[63, "other-points"]], "Zoom doesn\u2019t have to fullscreen when someone shares their screen.": [[63, "zoom-doesn-t-have-to-fullscreen-when-someone-shares-their-screen"]], "Dual monitor mode": [[63, "dual-monitor-mode"]]}, "indexentries": {}}) \ No newline at end of file diff --git a/teaching-tech-together/index.html b/teaching-tech-together/index.html new file mode 100644 index 00000000..4ae6badd --- /dev/null +++ b/teaching-tech-together/index.html @@ -0,0 +1,430 @@ + + + + + + Summary of Teaching Tech Together — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Summary of Teaching Tech Together

+

Teaching Tech Together is a book +compiled by Greg Wilson which is about the pedagogy and practical +hints of teaching technology in informal environments. It is a very +good resource, and the main point is that research does back up +teaching, it’s not all intuition. Many citations are included.

+

This page contains a summary of the most important points. The point +is that one can quickly refer to this before writing a new lesson or +teaching a course. The article Ten quick tips for creating an +effective lesson is +also a good summary of the main lesson design points of this book.

+

Useful appendices:

+ +
+

Ch1: Introduction

+
    +
  • Novice = no good mental model of what they are learning, “not even +wrong”

  • +
  • A manual is not equal to a tutorial - a tutorial needs to build a +mental model from scratch.

  • +
  • Formative assessment = determine what the misconceptions are.

  • +
+
+
+

Ch2: Building mental models

+
    +
  • “Expert blind spot” = experts have more links, so don’t see what +links are missing.

  • +
  • Concept maps as a metaphor for connections

  • +
  • 7+/-2 concepts can fit in short term memory at once

  • +
  • Get feedback from others, then give feedback to others, then +self-feedback (last one is “deliberate practice”)

  • +
+
+
+

Ch3: Expertise and memory

+
    +
  • Cognitive load: too much is bad and makes learning slow

  • +
  • Faded example: blank out certain things in an example which are +added as an exercise/example (what you want to progressively +teach). Seeing examples is good, debugging as an example.

  • +
  • “I want to do something, not learn how to do everything”

  • +
  • Parsons problems - give working code but in random order, +students must put it into the right order.

  • +
  • Minimal manual: one page micromanuals on specific tasks. Helps +training but loses content.

  • +
  • The last exercise of this chapter has some good hints for making +useful graphics.

  • +
+
+
+

Ch4: Cognitive load

+
    +
  • Cognitive load is divided into intrinsic load (background required +learn), germane load (mental effort to link new to old), and +extraneous load (everything else that distracts from learning). +(this is “cognitive load theory”)

  • +
  • A paper claimed that self-guided learning is less effective, because +people are overloaded: you have to both learn new facts and learn +how to use them at the same time.

  • +
  • Strategies: use exercises well that minimize tho load. a) parsons +problems, b) labeled subgoals, c) split attention (separate +channels, but complimentary rather than redundant), d) minimal +manuals

  • +
+
+
+

Ch5: Individual learning

+

(chapter about how people can help themselves)

+
    +
  • Six strategies: a) spaced practice, b) retrieval practice, c) +interleaving (abcbac better than aabbcc), d) elaboration (explain to +self), e) concrete examples, f) dual coding (e.g. words and +pictures, or different forms of same material).

  • +
  • Manage time well

  • +
  • Peer assessment

  • +
+
+
+

Ch6: A lesson design process

+
    +
  • Backwards lesson design, similar to test-driven development: 1) +brainstorm ideas for what to cover, 2) create learner personas to +figure out who you want to teach, 3) create formative assessments to +give learners a chance to exercise what they are trying to learn +(3-4 per hour), 4) put formative exercises in order, 5) write the +teaching material around this.

  • +
  • Learner persons, to guide your design process: a) general +background, b) what they already know, c) what they think they +want to know, d) how course will help, e) special needs.

  • +
  • Learning objectives: write objectives and think of what depth of +understanding you are getting too. Consider Bloom’s taxonomy: a) +remember, b) understand, c) apply, d) analyze, e) evaluate, f) +create.

  • +
  • Fink’s taxonomy (unlike Bloom’s, complimentary not hierarchical): a) +foundational knowledge, b) application, c) integration, d) human +dimension, e) caring, f) learning how to learn.

  • +
  • Maintainability: is it easier to update than replace? a) You have to +document the lesson design process, b) technical collaboration, c) +are people willing to collaborate? Or do teachers resample rather +than update?

  • +
+
+
+

Ch7: Actionable approximations of the truth

+

(chapter about learning programming specifically… title comes from +not necessarily having clear research that says what you should do, +but you have to do something anyway)

+
    +
  • Experts know what and how, novices lack both but most teachers +focus on what only.

  • +
  • Think about teaching debugging and using it as examples - the how.

  • +
  • If you are teaching programming specifically, just read the +chapter.

  • +
+
+
+

Ch8: Teaching as performance art

+
    +
  • Get feedback on your teaching. People aren’t born teachers, and +feedback isn’t in the western teaching culture enough.

  • +
  • Use live coding. It’s much more effective, especially because it’s +two way and you can demonstrate making mistakes. a) embrace your +mistakes, b) ask for predictions, c) take it slow, d) be seen and +heard (stand + microphone), e) mirror your learner’s environment, f) +use the screen wisely (make it big enough), g) double devices (one +to present, one for notes), h) use diagrams, i) avoid distractions, +j) improvise after you know the material, k) face the screen only +occasionally

  • +
  • Drawbacks of live coding, which you can minimize over time: a) going +too slow, b) exercises can be too deep and have too much cognitive +load (give skeleton code).

  • +
+
+
+

Ch9: In the classroom

+
    +
  • Code of conduct: teaching isn’t for those that are already “in”, +it’s for those that aren’t. If you don’t notice problems and +enforce it transparently, it means nothing though.

  • +
  • Peer instruction. Discuss in groups. e.g. multiple choice +question, if there is a wide variety of wrong answers, have them +discuss in groups.

  • +
  • Teach teaching: different strategies, consider what you want to do: +a) teach teaching (taking turns) b) teach and assist (going around +helping) c) alternative teaching (group with more specialized +instruction), d) teacher and observer, e) parallel teaching (two +groups, same material), f) station teaching (rotate through +stations).

  • +
  • If co-teaching, plan ahead: a) confirm roles at start, b) work out +some hand signals for common conditions, c) each person should talk +at least 10-15 min at a time, d) person who isn’t teaching shouldn’t +distract, though leading questions OK, e) check what your partner +will teach after you are done, f) inactive teacher stays engaged, +not doing own stuff.

  • +
  • Plan for mixed abilities, especially false beginners who have +studied the material before.

  • +
  • Can you make a collaborative not online document?

  • +
  • Sticky notes

  • +
  • Don’t start from blank pages, give some starting point. +Many other good points in the chapter +itself.

  • +
+
+
+

Ch10: Motivation and demotivation

+
    +
  • Extrinsic vs intrinsic motivation. Extrinsic: have to do it for job +or something. Intrinsic: do it for self, you want to encourage +intrinsic motivation. Drivers of intrinsic motivation: a) +competence, b) autonomy, c) relatedness (connection to others).

  • +
  • Consider usefulness and time to master. Focus on useful and fast. +Useful = authentic tasks, things people will actually use.

  • +
  • Avoid demotivation: for adults, a) unpredictability, b) +indifference, c) unfairness. Specific examples: a) contemptuous +attitude, b) saying existing skills are worthless, c) complex or +detailed technical discussion, d) pretending you know more than +they do, e) the word “just” as in, it’s “just easy”, f) software +installation problems, g) giving impossible challenges to fail at to +try to learn something, if not understanding.

  • +
  • Consider accessibility and inclusivity - consider things are harder +for others, try to understand diversity of backgrounds.

  • +
+
+
+

Ch11: Teaching online

+
    +
  • Disadvantage of MOOCs: can’t clear up individual misconceptions

  • +
  • The chapter has various good ideas, including how to make sure +everyone is heard (certain group doesn’t dominate online +discussions), short cycles and short exercises, require some small +group work, use videos to engage rather than instruct (people can +read faster), identify and clear up misconceptions early.

  • +
  • Flipped classroom: watch lectures on own time, do exercises and +discuss in class time.

  • +
+
+
+

Ch12: Exercise types

+
    +
  • Multiple choice, code yourself, code+multiple choice, inverted +coding (given code, test and debug), fill in the blanks, Parsons +problems (given questions but in wrong order).

  • +
  • Tracing execution, tracing values, reverse execution (find input for +output), minimal fix, theme and variations, refactoring exercise. +Pen and paper exercises.

  • +
  • Diagrams and connection: draw diagram, label diagram, matching +problems.

  • +
  • Autograding is hard, in particular most automatic grading tools +don’t provide useful feedback messages. Also, automatic grading can +only test low-level skills, not higher abstractions like code +review.

  • +
+
+
+

Ch13: Building community

+

(Chapter about forming a community of teachers and learners working +together)

+
+
+

Ch14: Marketing

+
    +
  • Think about what you are offering to who. Who are the target +audiences and why should they be care and become invested?

  • +
+
+
+

Ch15: Partnerships

+
    +
  • Main two points are work within schools or outside of schools. If +inside, part of academic programs? Academic programs and especially +teachers change very slowly.

  • +
+
+
+

Ch16: Why I teach

+

(A note from the author)

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/team-leaders/index.html b/team-leaders/index.html new file mode 100644 index 00000000..2054915c --- /dev/null +++ b/team-leaders/index.html @@ -0,0 +1,540 @@ + + + + + + Team leaders / Helpers / Exercise leaders — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Team leaders / Helpers / Exercise leaders

+

We use this page during team leader onboarding.

+

Thanks for being a team leader :heart:! +Without you, these large online workshops would not be possible.

+
+

TL;DR (Summary of this page)

+
    +
  • Everyone watches the CodeRefinery stream (how to attend via livestream)

  • +
  • Communication happens via collaborative document (Collaborative document mechanics)

  • +
  • Exercises can be done individually, in a pre-formed or ad-hoc team online or in person

  • +
  • Team leads are between the instructors and learners, please

    +
      +
    • Keep track of things like learner progress, instructions and time and report them via collaborative document

    • +
    • Be available for learners to ask their questions and lead discussions

    • +
    • If idle, check the collaborative document for open questions and answer them

    • +
    +
  • +
+

If you want to contact us before the workshop you can send an email to our general email address support@coderefinery.org or you can join the +CodeRefinery chat (we recommend the #workshops stream, +and if you can’t find it then #general is good).

+

If you have fun being a team leader for the workshop, please visit our +contributing page page, to find out about further +volunteering possibilities within CodeRefinery.

+
+
+

Code of Conduct

+

We follow a code of +conduct for all our +interactions before, during and after workshops, also for this session.

+

We’ve designed the workshop so that it is very hard for one person to +ruin it for everyone. Within your team, you will need to take on the +role of ensuring a good environment.

+

If you see anything that is not supporting an positive learning +environment, let us know!

+
    +
  • If it’s a general issue that can be mentioned publicly, write it +immediately in the collaborative document.

  • +
  • Send a message to support@coderefinery.org if it is private and can +be handled asynchronously.

  • +
+
+
+

CodeRefinery project

+

We teach all the essential tools which are usually skipped in +academic education so everyone can make full use of software, computing, and +data. We don’t just give courses, but we are a training network that you can +join to share the effort and bring better courses to your community.

+
+
+

..and you?

+

Shortly introduce yourself in the collaborative document of the onboarding session:

+
    +
  • Who are you?

  • +
  • What do you do?

  • +
  • Where are you connecting from?

  • +
+
+
+

What is needed to be a team leader?

+

Most importantly, you do not have to know everything (we don’t, either), but you are expected to:

+
    +
  • Have been to a CodeRefinery before and used git some since then, OR have some general experience with git (branching, +pull requests) and command line work, OR be able to generally follow +the path of the exercises that we have laid out.

  • +
  • Be present in your teams physical/virtual room at least during exercise sessions of the workshop.

  • +
  • Show a positive, motivating attitude to learners.

  • +
  • Keep exercises going and let us know when there are difficult questions!

  • +
+
+

If you aren’t sure if you can be a team leader: you probably can be one!

+
+
+
+

Who is joining this workshop?

+

Be aware of the different

+
    +
  • career stages (students, postdoc, researcher, professor, industry),

  • +
  • backgrounds (computer scientist, IT, domain scientist, coding beginners,…),

  • +
  • infrastructure (operating system, access restrictions, preferences on graphical vs command line interfaces, …) and

  • +
  • preferred programming languages (Python, R, Matlab, Julia, Fortran, …) of your learners.

  • +
+

There is also usually a great variety of pre- knowledge on the different topics of the workshop.

+

Overview from the pre-workshop survey

+
+
+

What will happen during workshop?

+

The workshop schedule on the main workshop page contains +links to lesson material, including lists of exercises.

+

The best analogy is watching a popular sporting event on TV. +There are periods of lots of activity, and clear periods of breaks where you +do your own thing.

+
    +
  • Everyone follows stream during lessons - lessons, demos, exercise +intros, going over solutions, etc.

  • +
  • For questions and instructions we use a collaborative document (more below).

  • +
  • Exercises during the lessons are done individually or in teams and there is many +ways to do this:

    +
      +
    • Watch and work alone

    • +
    • Watch together and interact during exercises/breaks (in-person or +online)

    • +
    • Reviewing/doing exercises later

    • +
    +
  • +
+
+../_images/exercise_options.png +

Overview of the different options of doing the exercises individually or in a team.

+
+
+
+

Exercise sessions

+

We try our best to be very explicit about what is going on. +Your first goal should be to make sure the learners are engaged and no one is left behind.

+

The instructors should clearly tell which exercises and for how long (minimum 10-15 min); +if anything is unclear please ask via collaborative document, you are our safety net.

+

Make it easy for learners to ask for help:

+
    +
  • Make sure your group knows your name and that you are their team lead.

  • +
  • Always start by greeting people and ask how the lesson is going; report back if there is something instructors should be aware of.

  • +
  • Encourage your team to also put answered questions in the collaborative document, someone else might be wondering the same thing.

  • +
+

Want extra help?

+
    +
  • It is OK to not know something!

  • +
  • Use the collaborative document if there is questions that you cannot answer. +Our instructors and expert helpers are watching it and try to answer every question.

  • +
+

Major problems?

+
    +
  • Exercise time is limited, watch the time and keep things moving.

  • +
  • If some debugging takes to long, it’s reasonable to describe the problem in the +collaborative document. An expert helper may have seen the problem +before.

  • +
  • If any one problem takes too long, it’s OK to say “we don’t have +time, let’s come back”

  • +
+
+../_images/team_status.png +

Example of collaborative document during an exercise session. a) clear description of +topics of the exercises. b) team status. c) as always, +questions at the bottom.

+
+
+
+

What can I do to prepare for the workshop?

+

As a team leader, we do not expect you to know all our CodeRefinery training material, but if you have time:

+
    +
  • Take a look at the exercises in advance of each day (the exact +plan is on the workshop page. Lessons have an “exercise list” page that shows everything), check that you understand the general point of each of them.

  • +
  • If you are interested, also read through the instructor guides for the lessons (there is a link at the top or sidebar of each lesson).

  • +
  • Use github issues on the lesson github page to point out issues with exercises and the materials

  • +
+
+
+

Any questions?

+
    +
  • Send us an email to support@coderefinery.org

  • +
  • If you want to, sign up for our Zulip chat to ask us anything, anytime. Use +#tools-workshop during the workshop itself (you need to join the stream, it is not default for new chat members).

  • +
  • During the workshop, please use the collaborative document.

  • +
+
+
+

Path ahead

+

Would you like to

+ +

See our website and Contributing to CodeRefinery. +Best way to get started is to join the Zulip chat.

+
+
+

Tips and Tricks

+

This section provides some tips and tricks for being a team leader. Be aware that there are different types of team leads (online/in-person/team of colleagues/team of strangers) and these tipps may not apply to evryone.

+
+

How to create a positive learning environment?

+

As a team leader, you have a crucial role during workshops:

+
    +
  • You are between the learners and the organizers and instructors, please use the collaborative document to communicate.

  • +
  • Encourage learners to learn from each other.

  • +
  • Acknowledge that some of the material can be difficult and that people in your team will +learn more working together.

  • +
  • Acknowledge when learners are confused and raise it to the instructors. +Understanding why learners are confused provides useful feedback for +instructors. You are our eyes and ears.

  • +
  • As we said, you don’t have to know everything, just like learners don’t +necessarily know everything (we don’t know everything, either). It’s more +important to be responsive and work together.

  • +
  • If you meet virtually: Turn on your camera, and encourage everyone else to do so as well. Have an introductory round in the first exercise session, to get to know your group. Whichever strategy you choose for your team, be present and encourage learners to ask questions.

  • +
  • In an in-person workshop: Stand up and walk around, try to make rounds by everyone. If you are +convenient, students will ask. If you are sitting in the back, student’s +won’t. Students rarely try to get your attention from across the room if you +don’t look ready.

  • +
+
+
+

Strategies for leading a team

+

There are several strategies you can use to run your team, no matter if you meet in a physical or virtual room (Physical room would need a larger screen for every one to see though):

+

Strategy 1:

+
    +
  • Everyone does the exercises themselves until someone has a question

  • +
  • Encourage learners to ask multiple times; if necessary share your/learners screen and discuss.

  • +
  • If everyone is active, this can be good, but there is a risk that the barrier for distrurbing the silence is too big.

  • +
+

Strategy 2:

+
    +
  • To start things off, team leader can share the screen.

  • +
  • Do not try to hide mistakes (they make good learning opportunities, “can you spot my mistake?”) and discuss your solutions.

  • +
  • It might be good to give learners some lead first, and use this only +if no one volunteers.

  • +
+

Strategy 2:

+
    +
  • Team leader asks someone to share the screen and go through the exercise.

  • +
  • You can encourage the others to guide the one who is sharing the +screen. Or let the person go on her/his own pace.

    +
      +
    • If no one dares at first, you can also start sharing your screen and let the room tell you what to write.

    • +
    • That way they see how it can go and the barrier shrinks.

    • +
    +
  • +
  • Try to alternate who is sharing the screen for each session.

  • +
  • When someone has an issue, it is a good idea to switch screen share to them +and maybe even continue from there

  • +
+

You don’t actually have to do the exercises. You could apply +lesson material to your own team’s work, review what was just said, +have a free-form discussion, etc. - if those are more valuable. You +can always come back to exercises later, or let learners do them as homework.

+
+
+

How to solve common problems in teams?

+
    +
  • One learner asks very many questions, ends up monopolizing all of +the time. Other learners are left without help, and the whole group +may not get the exercises done

    +
      +
    • Encourage them to ask in the collaborative document

    • +
    • It can be very hard to say “no”, but it’s more important to have +balance than answer every question you are asked. If you need +to say no, you can try things such as “I’m sorry, but in order +to finish we need to go on now. We can keep working on it +later - would you like to watch?”

    • +
    +
  • +
  • There is some sort of problem that ends up taking a lot of time

    +
      +
    • Work on it for a minute or two.

    • +
    • Encourage to describe the problem in the collaborative document. Our expert helpers may be able to help. +Nothing wrong with this, because there is no deadline or time limit.

    • +
    +
  • +
  • No one asks any questions

    +
      +
    • Make sure people know that you are there for them if they need help

      +
        +
      • Some exercises are easier than others and people really may not need any help with some of them

      • +
      • Remind that the recording can also be watched later, if people cannot keep up

      • +
      +
    • +
    • Use your time answering questions the collaborative document

    • +
    +
  • +
+
+
+

Please do not …

+
    +
  • Take over the learner’s keyboard (neither physically nor remotely). It is rarely a good idea to type anything +for your learners and it can be demotivating for the learner because it +implies you don’t think they can do it themselves or that you don’t want to +wait for them. It also wastes a valuable opportunity for them to develop muscle +memory and other skills that are essential for independent work. Instead, try +to have a sticky note pad and pen / use the collaborative document and write the commands that they should type.

  • +
  • Criticize certain programs, operating systems, or GUI applications, or +learners who use them. (Excel, Windows, etc.)

  • +
  • Talk contemptuously or with scorn about any tool. Regardless of its +shortcomings, many of your learners may be using that tool. Convincing +someone to change their practices is much harder when they think you disdain +them.

  • +
  • Dive into complex or detailed technical discussion with the one or two people +in the audience who have advanced knowledge and may not actually need to be +at the workshop.

  • +
  • Pretend to know more than you do. People will actually trust you more if you +are frank about the limitations of your knowledge, and will be more likely to +ask questions and seek help.

  • +
  • Use “just”, “easy”, or other demotivating words. These signal to the learner +that the instructor thinks their problem is trivial and by extension that +they therefore must be stupid for not being able to figure it out.

  • +
  • Feign surprise at learners not knowing something. Saying things like “I can’t +believe you don’t know X” or “You’ve never heard of Y?” signals to the +learner that they do not have some required pre-knowledge of the material you +are teaching, that they don’t belong at the workshop, and it may prevent them +from asking questions in the future.

  • +
+
+
+
+

Background

+

The following section provides some background on our workshop setup.

+
+

Hierarchical workshops to scale

+

Traditionally, a workshop has instructors and team leaders/helpers, but the +capacity is limited by instructors, so we are limited to ~30-40 people +at most. Then, we tried to scale to larger numbers: even up to and beyond 100 +people. For this, we have to rely on team leaders . A team leader does not have to be an expert in the +material, but should be able to keep things flowing.

+

Team leaders are an essential part of the CodeRefinery workshop team and +allow CodeRefinery to scale to many more people than we could otherwise handle. +Team leaders will guide their team through the course, keep +time, and let us know when more help/time is needed during the exercise sessions. +Instructors and expert helpers are always available via the collaborative document. It is very +likely that you’ll grow as a mentor and learn how to be a more efficient +teacher.

+
+
+

Teams

+

A team could be for example a +group of colleagues/friends where one of the team members has a bit of knowledge +on the tools presented in the workhop. This person can act as team leader +for the workshop, but may still learn a thing or two themselves. In that way +you can work with people you know and the barrier for asking questions and +discuss together may be a bit lower than in a group of strangers.

+

Sometimes we also allow learners to register as invidual learner with interest in being in a team. We then try to arrange those people in teams which stay together for all exercise sessions on all days and provide a zoom breakoutroom with a team/exercise leader. Since this is dependent on our team leader capacities, we cannot accept infinte amount of learners. +Being assigned a team as a learner allows people to form a bond and get the +rooms started sooner. We will try to keep you in the same team +room as long as we can, but we give no promises and will rearrange as +needed when people can’t attend.

+
+
+
+

See also

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/team-teaching/index.html b/team-teaching/index.html new file mode 100644 index 00000000..f0f991c8 --- /dev/null +++ b/team-teaching/index.html @@ -0,0 +1,430 @@ + + + + + + Team teaching — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Team teaching

+

Listening to only one person talk can be boring. Listening to a discussion is +much less so. “Team teaching” can mean many things, but in this case we +are referring to two instructors are both actively +involved in lecturing at the same time, as some sort of conversation +between them. It is a form of co-teaching.

+

When it works well, it makes a lecture much more dynamic and +engaging, and reduces the load for each person to plan everything +because you can rely on two minds to do it live. +The difficulty is that you need to coordinate and it is our nature to +keep talking while teaching, making a conversation difficult.

+
+

See also

+

Demo of CodeRefinery livestream teaching. This shows a +demo of many parts of team teaching on a livestream - read the +video description for details.

+
+
+

Basics

+
+../_images/teach-teaching--screenshot.png +

Demo of team teaching. Two people are speaking, in this case one +is typing and giving the small point of view, and one is explaining +the big point of view.

+
+

We can’t claim to know the best way to do this yet, but we have seen ways +that work and don’t work.

+

The basic idea is that you want to keep a constant conversation +going. This can be a mutual discussion, one person explaining big +concepts and one the details, one person asking +questions and the other answering, or some other combination. This +is different that two people teaching different sections.

+

There is less need for the instructors to prepare every single thing, +since you can rely +on the wisdom of the group to get you through areas you haven’t +perfectly prepared. In fact, this is good, because then your learners will +see things go slightly wrong and your live debugging. +Still it can be useful to agree with your co-instructor on the choreography +of your session (more about this below).

+
+

One of the most important principles of ship handling is that there +be no ambiguity as to who is controlling the movements of the +ship. One person gives orders to the ship’s engine, rudder, lines, +and ground tackle. This person is said to have the “conn.”

+

— James Alden Barber, 2005, “Introduction”, The Naval +Shiphandler’s Guide, p. 8. Mark B. Templeton, via wikipedia

+
+

As the quote says, in any large enough operation, multiple people are +involved, but responsibilities should be clear. At least, the team +should know who is pushing things forward (even if, to make it seem +live, they still discuss among each other anyway).

+

We propose two basic models, but of course there is a constant +continuum. +And in either model it can be good to switch roles every 20-30 minutes.

+
+
+

Model 1: Guide and demo-giver

+

One person serves the role of guide, explaining the big picture +and possibly even the examples. The demo-giver shows the typing +and does the examples, and could take the role of a learner who is +asking about what is going on, the person who actually explains the +details, or an occasional commenter. Anyway, the guide is the one +navigating through the course and bringing up material in a logical +order for the audience and “has the conn”.

+

Hands-on demos and exercises work especially well like this. Here, +the guide would follow the outline and serve as the director (see +below).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Guide

Demo-giver

Introduces most material

Goes through theory

Asks questions that a learner may ask

Introduces type-along

Explains steps of type-along

Types during type-along

Asks questions to Demo-giver during type-along

Explains details what they are typing and what happens

Looks at HackMD during type-along

Looks at HackMD during theory

Discusses during Q&A

Discusses during Q&A

+
+
+

Model 2: Presenter and interviewer

+

In this case, it is the presenter who is mostly explaining and +giving the demos, and generally trying to move the forward through the +material. The interviewer serves as a learner or spotter, fills +in gaps by asking relevant questions, and tries to comment to the +presenter when things are going off track. The interviewer “has the +conn”.

+

This is closer to normal teaching, so feels more natural to do. The +big disadvantage is that it’s the tendency of the presenter to keep +talking, and the tendency of the interviewer to be nice and not +interrupt. This negates most of the benefit you would hope to have, +but is much better than solo teaching.

+

Here, the presenter would follow the outline and serve as the +director (see below).

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Presenter

Interviewer

Asks questions to presenter

Answers questions using their special knowledge

Follows up with learner questions

Pushes forward though the material

Asks questions that a learner may ask

Introduces type-along

Explains type-along and material

Explains type-along and material

Looks at HackMD when possible

Looks at HackMD most of the time

Discusses during Q&A

Discusses during Q&A

+
+
+

Hints

+

With more than one person, there is a risk of seeming uncoordinated +when the team doesn’t know who is supposed to move the lesson forward. +It’s not bad to have short discussions to decide what to do next, it +makes the show seem interactive. But if it happens too +much, it becomes noticeable. As quoted above, you could adopt a +principle which exists +in many domains: at any time, only one person is +in control. Implemented in team teaching, it becomes: you explicitly +know who is in control (the director). The director is +responsible for understanding the current situation and checking with other +instructors, but in when you just need to something and no one has +strong opinions, you don’t debate, the director decides. The main +difference of Model 1 and Model 2 above is “is the director the one +mainly explaining new material, or the one asking questions”. There +are also multiple layers of director: there may be the director for +the whole course, and the director/”conn” for the lesson.

+

We can’t tell you what works best for you. But the models above and +thinking about who the director is should let you have an efficient +discussion to decide your model. The need for a director is why we +don’t recommend fully equal co-teachers. Instead, divide the course +into parts and use the two models for each part.

+
    +
  • Of course, there are other roles in a workshop.

    +
      +
    • The HackMD watcher pays particular attention to the audience +questions. They might be a different person from the co-teachers +and they can interrupt anytime.

    • +
    • The Meeting host manages the meeting itself.

    • +
    • The Director could be completely separate from the people on +screen, and somehow sending signals to the teachers as needed. +But, unlike scripted media, the course reacts more to the audience +and it is better for the director to be in the lecture.

    • +
    +
  • +
  • If you ever go off-plan, that’s OK. You can discuss during the +lecture so the audience can know what you are doing and why. You +want to adjust to the audience more than you would in a solo +course. But at the same time, be wary of deviating too much from +the material that the watchers have, since it will be disorienting.

  • +
  • Two people works well. With three, it’s hard to allow everyone to +speak equally and people tend to jump on top of each other in the +gaps - or no one talks, to give others a chance to say something. +You could have particular segments where different pairs of +people adopt the main roles, and others speak up if they want. Or, +at that point, make it a panel discussion format (multiple +presenters and one interviewer)

  • +
  • Of course, it helps to have a good plan of what you are going to +do. But if only one person knows that plan, this strategy can still +work, especially if that person is the presenter in model 2.

  • +
  • The less preparation you have, the more useful it is to strictly +define the roles of each person (to ensure someone is in charge of +moving it forward).

  • +
+

Please send us more suggestions to add to this list.

+
+
+

Preparation

+

This is one proposed model for preparing for team teaching:

+
    +
  • Talk with your co-teacher. These hints assume a two-person team.

  • +
  • Decide what material will be covered, overall timing, strategy, etc.

  • +
  • Divide up the material. In each section, decide the model to use +and roles. If in doubt, starting with the guide/demo-giver division +with the stronger instructor as guide works well.

  • +
  • Decide who will be the director for each part. Perhaps a good idea +is to keep it consistent: the guide is always the director.

  • +
  • At least one person prepares the outline (the order of topics to be +presented, key questions to ask, etc.) - usually the guide or +interviewer. The guide or interviewer +should be comfortable with it (and could even do it mostly alone), +everyone can give comments and make sure to read it at least once.

  • +
  • Run as above.

  • +
  • You don’t need to plan every step in detail but it can be useful to prepare +the session together and step through the choreography (e.g. “now I will show +this and then give you the screen and then ask you to do this … you will +lead this 20 minute block and then I will lead that 20 minute block and +please ask me questions while I present X”).

  • +
+

Then, just go! Don’t worry if it’s not perfect, if either person +wonders what to do next, just pause some or ask the other. This +imperfection is what makes it more dynamic and exciting, and in almost +all cases the audience has been impressed with the co-teaching +strategy, even if it’s not perfect.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/tech-docs/index.html b/tech-docs/index.html new file mode 100644 index 00000000..80132e9a --- /dev/null +++ b/tech-docs/index.html @@ -0,0 +1,276 @@ + + + + + + Writing technical docs — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Writing technical docs

+

This is a guideline for non-teaching technical documentation, for +example HPC infra usage. Since many of us overlap with HPC or other +support roles and our CodeRefinery mindset partially overlaps, we have +some brief guidelines here.

+

There is far too much professional information for us to reproduce +here, but hopefully this is useful quick reference for a typical +person to get started. Check the links at the bottom for more.

+
+

What kind of doc?

+
    +
  • Tutorial - emphasis on concepts and mental model, after reading +you can do limited things.

  • +
  • Reference - more likely to read if you know the concepts and +want to know more advanced stuff.

  • +
  • Example - example of one specific thing. Good for copying and +pasting if you know enough to understand it.

  • +
+

“A good tutorial is different from a good reference. Very few things +are good at both at the same time.” - (I don’t remember who, seen in +Teaching Tech Together). Thus, both tutorials and reference are +useful. Sometimes, we need a tutorial for our stuff and can point to +outside material as a reference. People also really want examples +they can copy - is your infra similar enough that outside examples can +be copied?

+
+ +
+

Style suggestions

+

(not standards, since of course people do what they want anyway. Not +all things apply in all cases)

+
    +
  • Bold for definitions or the first time a concept is introduced. +Basically, a time where someone is likely to scan up the document to +remember what a certain concept is, such as “what’s a git stash?”

  • +
  • Italics for local emphasis.

  • +
  • Never feel bad to use simpler text, in the best case someone can +now understand, in the worst case there’s less mental effort.

  • +
  • Use an active/imperative voice (Y does X, do X to get Y), not +passive (X can be done by Y). Try to use present tense.

  • +
  • Make the docs skimmable - by looking at headings and first words in +each section, can you figure out what you need to focus on?

  • +
  • Use gender neutral text, of course.

  • +
+
+
+

Style guide

+

(Is it worth making a minimal academic HPC/tech doc style guide? The +benefit would be that we can share stuff better. There’s no need to +emulate or reproduce actual professional ones, since we probably +aren’t that formal.)

+
+
+

Other ideas

+

Consider documentation-driven development. Write basic docs, review, +then implement it.

+
+
+

See also

+

Of course, there is far more professional information than you can +find above.

+
    +
  • The Write the Docs guide +seems useful - especially about organizational aspects.

    + +
  • +
  • lesson-design.md might be useful to understand. +The “backwards lesson design process” is especially important to +think about: while you don’t have exercises, you do have goals to +accomplish you can design to.

  • +
  • Code Refinery lesson on Sphinx and Markdown

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/templates/advertising-workshop/index.html b/templates/advertising-workshop/index.html new file mode 100644 index 00000000..4bda3e07 --- /dev/null +++ b/templates/advertising-workshop/index.html @@ -0,0 +1,211 @@ + + + + + + Advertising workshop — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

Advertising workshop

+

Dear Professor X,

+

My name is NAME and I work as a XXX in YYY. I’m contacting you now to spread the word about a workshop which I am co-organizing in LOCATION together with the CodeRefinery project (http://coderefinery.org/) organized under the NeIC organization. I found your contact information via ZZZ…

+

CodeRefinery (http://coderefinery.org) aims to reach out to diverse academic communities which use and develop software in their research, and advocate more modern and efficient software development methods (such as collaborative distributed version control, automated testing, code documentation, managing code complexity, etc). CodeRefinery is not about efficient code, but rather efficient coding, and experience has shown that researchers have a lot to gain from our course material!

+

A CodeRefinery workshop is planned for LOCATION in CITY on DATE, see the website here: URL

+

The most natural audience for our workshops is PhD students and postdocs, but both more junior and senior people may find it valuable to attend.

+

On behalf of the CodeRefinery team, +NAME

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/templates/looking-for-helpers/index.html b/templates/looking-for-helpers/index.html new file mode 100644 index 00000000..969ce027 --- /dev/null +++ b/templates/looking-for-helpers/index.html @@ -0,0 +1,234 @@ + + + + + + Looking for helpers — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

Looking for helpers

+

This was part of a SNIC training newsletter. Saving it so that we can reuse +in future:

+
Engage as a tutor on the CodeRefinery online workshop, Nov 17-19 and 24-26,
+9:00-12:00
+
+Engage in the successful CodeRefinery workshop program, by becoming a tutor for
+the exercise sessions and discussion groups.  If you have been to a
+CodeRefinery workshop, you will have experienced  a very hands-on approach to
+training with frequent exercise sessions and group discussions.  In online
+workshops these sessions take place in breakout rooms with 5-7 participants and
+1-2 workshop tutors.  Tutors answer questions from the learners, guide them
+through the exercises and try to keep time.  If needed, tutors can call on
+experienced trainers in the background to help answer tricky questions.  The
+tutors are an important part of the CodeRefinery teaching concept and all the
+workshops to scale to many more people than the instructors could  otherwise
+manage!
+
+If you have previously attended a CodeRefinery workshop, and/or use some of the
+tools and methods covered in a workshop (Git, software testing, modern
+documentation platforms etc.), then please consider joining a CodeRefinery
+workshop as a tutor! Being a tutor is fun, it expands your network and develops
+your teaching and mentoring skills.  You always learn something new about a
+subject by teaching it!
+
+If you would like to help on the upcoming workshop in November, please sign up
+as a tutor on https://coderefinery.github.io/2020-11-17-online/.  If you would
+like to engage in later workshops, please register as a tutor on the notify-me
+form (https://indico.neic.no/event/135/surveys/36).
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/templates/notify-me-announcement/index.html b/templates/notify-me-announcement/index.html new file mode 100644 index 00000000..790ff6fb --- /dev/null +++ b/templates/notify-me-announcement/index.html @@ -0,0 +1,215 @@ + + + + + + Notify-me announcement — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Notify-me announcement

+

Dear all,

+

You are receiving this email because you have previously signed up for the “notify-me” list to get updates +on upcoming online or in-person CodeRefinery workshops.

+

We now have the pleasure to announce that an [in-person/online] 3-day workshop will be held on LOCATION, on DATE. +Registration has just been opened, see the workshop webpage: +URL

+

If you want to attend, don’t wait too long to register since the number of seats is limited.

+

If you wish to unsubscribe from these announcements, please reply to this email.

+

Hope to see you there!

+

On behalf of the CodeRefinery team, +NAME

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/templates/post-workshop-survey/index.html b/templates/post-workshop-survey/index.html new file mode 100644 index 00000000..0a3e9860 --- /dev/null +++ b/templates/post-workshop-survey/index.html @@ -0,0 +1,246 @@ + + + + + + Post-workshop survey — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

Post-workshop survey

+
+

First email

+
Subject:  [CodeRefinery] 5-minute post-workshop survey
+
+Dear CodeRefinery alumnus,
+
+We hope that you enjoyed participating in a CodeRefinery workshop last semester and that it was 
+beneficial for your work and research! We don’t keep an attendance list, so apologies to those 
+of you who couldn't make it to the workshop...
+
+Please help us to improve our course material and teaching methods by answering our very brief questionnaire at 
+https://indico.neic.no/event/109/
+about whether and how the CodeRefinery workshop affected how you develop code. 
+All information you provide will be useful. Your participation is extremely valuable 
+and will help us to develop the project further. The average time to fill the form is around 5 minutes.
+
+Would you be interested in being a helper or instructor in future workshops? It's a great way to continue 
+developing your skills and expanding your network! We're always interested in recruiting new helpers 
+and instructors. If this sounds interesting to you, please get in touch by writing to 
+support@coderefinery.org or join our chat: https://coderefinery.zulipchat.com
+
+On behalf of the CodeRefinery team,
+Thor 
+
+
+
+
+

Reminder 1 week after first email

+
Dear all,
+
+It's us, CodeRefinery, again. We just want to send this one reminder to kindly ask you to participate 
+in our 5-minute workshop-followup survey. To participate, please go to:  
+https://indico.neic.no/event/109/
+
+Sorry for spamming (particularly to those of you who already participated), this is the last 
+you'll hear from us regarding the survey!
+
+Cheers,
+Thor 
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/templates/practical-info-to-online-participants/index.html b/templates/practical-info-to-online-participants/index.html new file mode 100644 index 00000000..cc46a7fa --- /dev/null +++ b/templates/practical-info-to-online-participants/index.html @@ -0,0 +1,233 @@ + + + + + + Practical info (online) — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Practical info (online)

+

Dear all,

+

The online CodeRefinery workshop TITLE is approaching! It will take place on DATE at START - END in Zoom room ZOOMID. +On the first day, we also have an optional session starting half an hour before START where you can connect, +test your video client and iron out any technical issues (we recommend attending this if you haven’t used Zoom before).

+

If it turns out that you cannot attend, please let us know as soon as possible so that we can offer your seat to someone on the waiting list.

+

We will be using a Zoom room with ID ZOOMID. We recommend that you install the Zoom client (https://zoom.us/download). +In order to join the room you will need the password ZOOMPASSWORD. +You will be encouraged (but not forced) to use a webcam during the workshop. +If you don’t want the physical room you’re in to be visible on the webcam, Zoom allows users to set up a virtual background: +https://support.zoom.us/hc/en-us/articles/210707503-Virtual-Background +You might also be asked to share your screen during group exercises or in interactions with a workshop helper. +Remember to keep private information away from the screen you share!

+

You are expected to install some software on your computers before the workshop starts. +Please visit the workshop webpage WORKSHOPURL and go through each tool under “Software requirements”, +and install whatever you’re missing before the workshop starts. Note that you also need to create some accounts. +Note that each of these tools/accounts can easily be removed/deactivated after the workshop, if you so wish (see https://coderefinery.github.io/installation/accounts/).

+

Don’t hesitate to get in touch (support@coderefinery.org) if you run into any installation problems or have questions relating +to Zoom or other practical details. Note that we maintain a list of common installation issues that can occur at https://coderefinery.github.io/installation/troubleshooting/

+

If you haven’t already filled the pre-workshop survey, please do that soon since it helps us with workshop preparation. +You can find it at: SURVEYURL.

+

The workshop will be very focused on version control with Git. Some of you are already familiar with Git, but not all. +While we will be starting from the basics, we will be progressing quickly so it’s useful if you spend a few minutes to read up on the basic idea of Git. +For this purpose, we have prepared this “refresher” material: https://coderefinery.github.io/git-refresher/ +Note that this material also contains important Git configuration steps which all of you should go through before the workshop starts, to save valuable time during the workshop.

+

CodeRefinery strives to follow a Code of Conduct. Please have a look at +https://coderefinery.org/about/code-of-conduct/ so that we all are aware of how to treat each other respectfully.

+

Don’t hesitate to get in touch if you have any questions!

+

Best, +MYNAME

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/templates/practical-info-to-participants/index.html b/templates/practical-info-to-participants/index.html new file mode 100644 index 00000000..693e36f0 --- /dev/null +++ b/templates/practical-info-to-participants/index.html @@ -0,0 +1,235 @@ + + + + + + Practical info, in-person — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Practical info, in-person

+

Dear all,

+

The CodeRefinery CITY workshop on DATE is approaching! The location and schedule +is available on the workshop webpage: URL

+

If it turns out that you cannot attend, please let us know as soon as possible +so that we can offer your seat to someone on the waiting list.

+

You are expected to install some software on your laptops before the workshop +starts. Please visit the workshop webpage (URL) and go through each tool under +“Software requirements”, and install whatever you’re missing before the workshop +starts. Note that you also need a couple of accounts (GitHub and Read the Docs). +Note that each of these tools/accounts can easily be removed/deactivated after +the workshop, if you so wish (see https://coderefinery.github.io/installation/accounts/).

+

Don’t hesitate to get in touch (support@coderefinery.org) if you run into any +installation problems. We also maintain a list of common installation issues +that can occur at https://coderefinery.github.io/installation/troubleshooting/

+

If you haven’t already filled the pre-workshop survey, please do that soon since +it helps us with workshop preparation. You can find it at: URL

+

The workshop will have a strong focus on version control with Git. Some of you +are already somewhat familiar with Git, but not all. While we will be starting +from the basics, we will be progressing quickly so it’s useful if you spend +10-20 minutes to read up on the basic idea of Git. For this purpose, we have +prepared this “refresher” material: +https://coderefinery.github.io/git-refresher/

+

Please have a look at this material before the workshop starts. Note that it +also contains important Git configuration steps which all of you should go +through before the workshop starts, to save valuable time during the workshop.

+

CodeRefinery strives to follow a Code of Conduct. Please have a look at +https://coderefinery.org/about/code-of-conduct/ so that +we all are aware of how to treat each other respectfully.

+

Don’t hesitate to get in touch if you have any questions!

+

Best, +Thor

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/templates/waitin-list-notification/index.html b/templates/waitin-list-notification/index.html new file mode 100644 index 00000000..3ff278d9 --- /dev/null +++ b/templates/waitin-list-notification/index.html @@ -0,0 +1,213 @@ + + + + + + Waiting list — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

Waiting list

+

Dear NNN,

+

thank you for request about the course:

+

https://coderefinery.org/workshops/COURSE_HERE/ +The workshop is currently full but you are placed on the waiting list and I will inform you in case somebody else cancels and a seat frees up.

+

In case this is too uncertain for you and you make other plans, please let me know.

+

If you want to make sure to get a seat on the next workshop near you, please register on the “notify-me” list: https://coderefinery.org/workshops/upcoming/

+

We would love to give more courses and hope it works out for you.

+

Thank you in advance and best wishes, +CCCC

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/the-project/index.html b/the-project/index.html new file mode 100644 index 00000000..25231b62 --- /dev/null +++ b/the-project/index.html @@ -0,0 +1,265 @@ + + + + + + About CodeRefinery — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

About CodeRefinery

+
+

History

+

CodeRefinery began as a Nordic e-Infrastructure Collaboration (NeIC) +based off of some previous workshops at the KTH, Stockholm. The first +round of funding was from 2016 - 2018, and a second round is going from +2018-2021. Thus, so far, it has always had some paid staff (each up +to 0.5 full-time equivalent of their primary jobs). Most of these +staff are from some sort of computing center.

+

Over time, it has evolved into a more open project direction.

+
+
+

Governance

+

There is a steering group within NeIC which governs the CodeRefinery +project. However, strictly speaking that mainly covers activities done +via NeIC funding. The materials and open-source project is open to all.

+

There are currently no formal decision making processes. Typically, +decisions related to some repository go through the process of…

+
    +
  • Submit an issue or pull request

  • +
  • Discuss in the issue and/or

  • +
  • Discuss in a CodeRefinery team meeting

  • +
  • If there is rough consensus, then commit it.

  • +
+

In general, most decisions (of the open project) result in some sort +of commit in git. If the reaction is positive in a CodeRefinery +meeting, then it’s accepted. (Most day-to-day things aren’t discussed +in the meetings, only major things affecting the whole project.) +In general, if you are open and discuss, then do what will improve the +project for you.

+
+
+

Communication methods

+

This is an exhaustive list of our communication methods

+
    +
  • CodeRefinery zulipchat

  • +
  • CodeRefinery team meetings (announced in zulipchat)

  • +
  • Team email list (in practice, only used for calendar invites)

  • +
  • Github repositories issues and pull requests

  • +
+
+

Chat

+

Zulipchat is our primary means of communication. Subscribe to +at least the #coderefinery, #lessons, and #workshops, #general, #announce, and +#help channels to fully integrate to the CodeRefinery side of things.

+
+
+

Team meetings

+

These tend to happen every ~2 weeks. Mainly, we discuss NeIC project, +workshop organization matters, and how to organize ourselves. Most +work on actual lessons happens in Github issues.

+

You can find upcoming meetings by TODO.

+
+
+

Github

+

We are focused around the material we make, and for that, most +discussion happens in Github issues. For more abstract discussion on +lessons, there is a topic in the #lessons chat corresponding to each +lesson.

+
+
+
+

Decisions

+

There is no formal process of decisions. It should be brought up in +chat, then brought up in a meeting. In the meeting, be very clear +about what you need a decision or advice on.

+
+
+

Core team

+

There is currently no formal “core team” - only those who are most +active. If you hang around, contribute a lot, you will end up being +seen as “core”.

+
+
+

Joining

+

There is currently no formal joining process. Take part, and +contribute as you would like.

+

The usual way of joining would be to decide how CodeRefinery has to +adapt to serve your needs, and start proposing ways to do that. +Reading existing pull requests and giving a comment of “approve” is a +great way to get noticed.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/video-checking/index.html b/video-checking/index.html new file mode 100644 index 00000000..52a7844f --- /dev/null +++ b/video-checking/index.html @@ -0,0 +1,278 @@ + + + + + + Video checking OLD — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Video checking OLD

+
+

Note

+

This is old information, these days we use ffmpeg-editlist and ensure +that no learners are in the videos in the first place.

+
+
+

See also

+

Video editing OLD tells how to edit yourself. This page +describes how to check a video for processing.

+
+

The purpose of this page is to give video processing volunteers a +starting point. CodeRefinery produces a lot of videos, and learner +privacy is important: we can’t post videos until they are checked. +These videos are mainly useful to the learners of the very workshop, +so we need them quickly (and for every workshop).

+
+

Overview

+
    +
  • Ask for the directory of videos. It is on Google Drive or something +similar, but is not public.

  • +
  • Look at the tracking issue. Find a unclaimed section of the course.

  • +
  • Watch the video.

    +
      +
    • Carefully look for any appearances of learner video within the +video.

    • +
    +
  • +
  • Copy the template below.

  • +
  • Fill out the template.

  • +
  • Paste the answers into an issue.

  • +
+
+
+

Segment report

+

Template:

+
* [ ] Title:
+* Filename:
+* Start:
+* End:
+* Segments to cut:
+* Audience visible:
+Other notes for channel description:
+
+
+

Example:

+
* Title: git-intro basics
+* Filename: day1-obs
+* Start: 25:13
+* End: 45:00
+* Segments to cut: 36:12 - 42:10
+* Audience visible:  none
+
+Other notes for channel description:
+
+In this first episode, we go over the basics of using git for a single
+local directory.
+https://coderefinery.github.io/git-intro/02-basics/
+
+
+

Why do we ask all this? It saves time for the person who has to +upload it to YouTube.

+
    +
  • Title: what would it be called? You don’t need to include the +workshop name, someone will add it.

  • +
  • Filename: you don’t need the full filename but indicate what +file you were searching (often we have a recording and backup +recording for each day)

  • +
  • Start, end: start time of the segment

  • +
  • Segments to cut: Segments which should be cut out. Don’t be +strict, it is better to get it out fast than cut out every 3-minute +break. But if there is a ~10 minute break or idle time, then we can +cut it.

  • +
  • Audience visible: Time periods where any audience (not including +staff).

  • +
  • Other notes for channel description: Describe the content of the +video, include any links. You can think what is useful for someone +to find this (but it doesn’t have to be perfect).

  • +
+
+
+

Other comments

+
    +
  • How small should segments be? First, it’s better for videos to exist +than be perfect, so the 3-hour segment is better than nothing. Short +lessons (1.5 hour) are probably fine to be at once, and long ones (git +intro/collab) could possibly be each episode separately. Discuss with +others to see what you would like.

  • +
  • Ideally, there are two videos from each day: one recorded by Twitch +(raw dump of the stream), and one recorded by OBS/Zoom (local +recording). The OBS/Zoom recording is preferable. You can tell +them apart via the filenames.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/video-editing/index.html b/video-editing/index.html new file mode 100644 index 00000000..d78f3bf1 --- /dev/null +++ b/video-editing/index.html @@ -0,0 +1,370 @@ + + + + + + Video editing OLD — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Video editing OLD

+
+

Note

+

This is old information, these days we use ffmpeg-editlist and ensure +that no learners are in the videos in the first place.

+
+
+

See also

+

Video checking OLD for how to check a video and give an +edit-list to someone else to do the editing.

+
+

The purpose of this page is to give video processing volunteers a +starting point. (It also has some hints for workshop organizers).

+

For some of our online lessons, we release videos on YouTube. This is +not necessarily for brand new people to watch and learn the material +(though they may), but especially for people who attended the workshop +to review what they saw. As such, it’s more important to get them +published fast, than make them perfect.

+
+

What we want

+

Our workshops consist of lectures, demo, and exercises in breakout +rooms. We record the main Zoom room, and also livestream the main +room via Twitch. We would like the video of the workshop to be +processed so that it can be released on YouTube. This should not be a +major production: it is more useful to those who want to review what +they saw in person, rather than a new person watching.

+

We will provide the following:

+
    +
  • Raw video files (probably two copies one recorded from Zoom and one +from Twitch - so there is a backup.)

  • +
  • List of lessons (= final videos) and which raw files contain them +and when.

  • +
  • List of instructors

  • +
+

We want out:

+
    +
  • One processed video file per lesson.

  • +
  • With irrelevant breaks removed.

  • +
  • Without any video from learners. We use Zoom so that learners +should not appear in the stream, but we can’t be sure it works so +this needs to be checked.

  • +
+

The rough process is:

+
    +
  • Load up the right video files in the editor.

  • +
  • Find the start of the lesson (hint: look for a change of +instructor - ask us if you need help!) and cut off the stuff before.

  • +
  • Watch through the videos. Most of the lecture parts are fairly +standard and can be fast-forwarded through (it’s rare for a +learner’s picture to appear here).

  • +
  • Cut out the idle time during breaks.

  • +
  • In exercise sessions, learners go to breakout rooms, which are not +recorded. This part can be cut out, but sometimes the instructor +stays in the main room to do the exercises for the stream.

  • +
  • Don’t be too precise. We aren’t trying to make a masterpiece to end +all masterpieces, but a something for those who were at the workshop +to refer back to. So:

    +
      +
    • Imprecise start/stop/break times are fine

    • +
    • Other random off-topic chat is fine

    • +
    • Voices of learners is fine and expected

    • +
    • Video of learners is not ok (really, this is the only +thing that needs care).

    • +
    +
  • +
+
+
+

Before/during/immediately after the workshop

+
    +
  • From day 1, advertise that “the workshop may be recorded and put on +YouTube. We will prevent any pictures and names from going there, +but your voice may be. Please don’t include your name in hackmd +unless you accept it may be published. We support your right to be +anonymous in this workshop.”

  • +
  • Same announcement at the start of the workshop.

  • +
  • Record in zoom. Note: when you start the recording, make sure that +someone is currently sharing the screen, and the screen is a good +size (e.g. normal Full HD, as opposed to some vertical shape). The +dimensions when the sharing first starts determines the dimensions +for the entire course.

  • +
  • Immediately after workshop, go to Twitch and download the raw +streamed version. You have to be logged in as the channel, then the +option is naturally provided to you.

  • +
  • Choose some standard, shared place and immediately upload videos +there. Recommended naming scheme:

    +
    day1-topic1-topic2-zoom.mp4
    +day1-topic1-topic2-twitch.mp4
    +
    +
    +
  • +
+
+
+

Processing

+

Processing principles:

+
    +
  • Remove any participant videos, if they accidentally make it into +the video file. This is really the only serious rule in the +processing, if we didn’t have to check this we could just upload the +raw ones and it would be good enough.

  • +
  • Create one final video per lesson in the workshop

  • +
  • Work incrementally, upload processed ones when you can, get quick +feedback.

  • +
+

If it’s not clear, the course organizers will provide a list of the +lessons (final outputs) and the respective inputs (which source files +go into it).

+

You can generally:

+
    +
  • Use some video editor

    +
      +
    • iMovie on Mac

    • +
    • OpenShot is a simple cross-platform editor (tutorial)

    • +
    • (please give more ideas here)

    • +
    +
  • +
  • (so far, this is not a general “how to edit video” guide… you will +need to find one for your editing program)

  • +
  • Create a new project for the output (e.g. the Jupyter lesson)

  • +
  • Import the raw video files which contain Jupyter (e.g. day 4). If +one lesson is split over multiple files, combine them.

  • +
  • Cut off the part before and after the lesson itself (saving +frequently). You’ll have to figure out the start and end times, +this may be hard when there are several files.

  • +
  • Begin watching the lesson. Look for the following things:

    +
      +
    • Break time? Exercise session with irrelevant stuff in the video? +Cut the time out.

    • +
    • Any non-instructors pictures in the stream? Cut it out. +Sometimes you might need to blank the picture while

    • +
    • Don’t be too perfectionist - the goal is to get something done, +not maek the perfect videos.

    • +
    +
  • +
  • Export the videos with a high quality, e.g. jupyter.mp4. It +will go to YouTube which will render lower resolutions, so you don’t +need to worry about this so much.

  • +
  • Upload the videos to the processed subdirectory of the google +drive. Do this immediately, video by video. It’s better to get +continuous feedback on this. You are done!

  • +
+
+
+

Publication

+

We upload them to YouTube (not that we agree with all the ethics of +YouTube, but it seems like the least bad and most useful of the +options).

+
    +
  • Preview the processed videos, do a quick check for any issues.

  • +
  • Upload to the channel. For one workshop, put all related videos +into a playlist. CC-BY license.

  • +
  • This is a prototype channel description you can copy:

    +
    git-intro 1/2, CodeRefinery 25.may-4.jun 2020 day 1
    +
    +Day 1: git-intro: LINK-TO-LESSON
    +
    +Part of a series of video recordings of the CodeRefinery workshop,
    +25.may-4.june.  CodeRefinery teaches intermediate software
    +development skills to researchers in the Nordics.
    +
    +Workshop page: LINK-TO-WORKSHOP
    +Q&A for day 1: LINK-TO-HACKMD
    +
    +(table of contents below)
    +
    +
    +
  • +
  • Create a table of contents (can be done later, after uploading). +This divides the videos into chapters, with clickable links in the +description and labels in the video’s time slider. In the bottom of +the description, put this text and it is automatically parsed:

    +
    00:15 Introduction
    +02:30 Motivation - https://coderefinery.github.io/git-intro/01-motivation/
    +17:17 Basics - https://coderefinery.github.io/git-intro/02-basics/
    +38:29 Staging - https://coderefinery.github.io/git-intro/04-staging-area/
    +...
    +
    +
    +

    You may want to ask someone for help with this, since it can take +some time to go through the videos.

    +

    Example with table of contents: https://youtu.be/r1tF2x5OLNA

    +
  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/video-editor/index.html b/video-editor/index.html new file mode 100644 index 00000000..f33f7cc3 --- /dev/null +++ b/video-editor/index.html @@ -0,0 +1,213 @@ + + + + + + Video editor — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Video editor

+

The video editor takes the raw recorded files from the broadcaster, +processes them, and uploads them to YouTube (or whatever).

+
+

Overall priorities

+
    +
  1. No learner (or anyone not staff) video, audio, names, etc. are +present in the recordings.

  2. +
  3. Good descriptions.

  4. +
  5. Removing breaks and other dead time.

  6. +
  7. Splitting videos into useful chunks (e.g. per-episode), perhaps +equal with the next one:

  8. +
  9. Good Table of Contents information so learners can jump to the +right spots (this also helps with “good description”.)

  10. +
+
+
+

Modern: livestream method

+

Modern livestream courses produce videos without any learners in +them. In this case, using +https://github.com/coderefinery/ffmpeg-editlist is sufficient. Look +at that repo for instructions. As an example, check out +https://github.com/AaltoSciComp/video-editlists-asc for some past +workshops. For example, kickstart-2022-winter.yaml is a +reasonable starting point to copy.

+

It’s our standard to have these videos on YouTube by the same evening +the course is held. It may be hard, but it’s better to reduce the +quality to make it happen quickly than wait a while to get it perfect +(otherwise it might not happen at all).

+
+
+

If the learner Zoom is recorded

+

If learners may be in the recordings, they need detailed checking +before they can be posted. See Video checking OLD for the +preparation work and Video editing OLD for the processing work.

+

In practice, if things are recorded this way, they are almost never +released because it is too much work and it never gets done.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshop-administration/index.html b/workshop-administration/index.html new file mode 100644 index 00000000..3bafa63c --- /dev/null +++ b/workshop-administration/index.html @@ -0,0 +1,481 @@ + + + + + + Organizing a CodeRefinery workshop — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Organizing a CodeRefinery workshop

+

Anyone can organize a CodeRefinery workshop and teach the CodeRefinery lessons which are +licensed under CC-BY. +However, making it a successful workshop requires careful planning and preparation. Here we will go +through practical aspects of organizing a workshop.

+
+

Email templates

+

A collection of email templates:

+ +

When adding new ones, add to an existing page (make a new section) +or. Try to avoid too much markdown formatting, so that a rendered +version can be copied to plain text email easily still.

+
+
+

Select a workshop coordinator

+

One or two persons coordinate the workshop preparation and debrief. This does +not mean that they do all the work - they are encouraged to delegate tasks - +but they make sure that nothing gets forgotten.

+
+
+

Other documents and references

+ +
+
+

Before the workshop

+
+

First steps

+ +
+
+

Lecture room

+
    +
  • Start looking for an appropriate lecture room early.

  • +
  • See this list of requirements for +the lecture room.

  • +
+
+
+

Set up workshop page

+
    +
  • Import the template at https://github.com/coderefinery/template-workshop-webpage to your username +or the coderefinery organization, and name it like “2019-10-16-somecity”.

  • +
  • Update the required fields in index.md and push the commits. +The page should now be served at username.github.io/2019-10-16-somecity/.

  • +
  • If the workshop will be customized to the needs of a particular audience, modify the schedule accordingly.

  • +
  • If the workshop should be listed on https://coderefinery.org:

    +
      +
    • (Fork and) clone https://github.com/coderefinery/coderefinery.org

    • +
    • Under coderefinery.org/_workshops/, add a file named like 2019-10-16-somecity.md which contains +the fields permalink, city and dates. For example:

      +
      ---
      +permalink: https://username.github.io/2019-10-16-city/
      +city: Somecity
      +dates: October 16-18, 2019
      +---
      +
      +
      +
    • +
    • send a pull request with your new file.

    • +
    +
  • +
  • Create a registration form following Indico event setup.

  • +
  • Open and test registration

  • +
+
+
+

Announcing the workshop

+
    +
  • Twitter

  • +
  • Email persons who registered to notify-me form

  • +
  • Use local mailing lists and all channels possible

  • +
+

For self-organized workshops:

+
    +
  • Write an email to support@coderefinery.org to get a pre-workshop survey link and registration form on +https://indico.neic.no

  • +
+
+
+

Distribute the work

+
    +
  • Make sure lessons are distributed

  • +
+
+
+

Preparing lessons

+
    +
  • Go through the lesson material you will be teaching and think about how you +intend to teach it, and how much time you will be spending on each episode.

  • +
  • Are there any unsolved issues that you can fix?

  • +
  • Go through the instructor guides of the lessons you will be teaching.

    +
      +
    • Review the intended learning outcomes, and try to keep these in mind while teaching.

    • +
    • Try to memorize the typical pitfalls and common questions.

    • +
    +
  • +
  • Go through the lesson presentation hints.

  • +
  • Go through the helping and teaching guide, +and request all helpers to go through it too.

  • +
+
+
+

Prepare practicals

+
    +
  • Order catering (coffee, tea, water, fruit, something sweet, etc.)

  • +
  • Organize sticky notes

  • +
  • Organize extension cables if needed

  • +
  • Organize alternative wireless for those without Eduroam (if any)

  • +
+
+
+

Communication with participants

+
    +
  • Send out practical information, including installation instructions, around 2 weeks ahead. +Here is a template.

  • +
  • Emphasize that all software should be installed before the workshop starts, and point out +the configuration problems and solutions.

  • +
  • Remind registered participants that they are either expected to show up or to cancel participation

  • +
  • Also ask those without Eduroam to speak up.

  • +
  • Maintain waiting list if needed

  • +
  • Make sure we have enough pre-survey answers

  • +
  • Close registration on the workshop page

  • +
+
+
+

1-2 weeks before the workshop

+
    +
  • Workshop coordinator organizes a call with all instructors and helpers to discuss the schedule to leave no doubts about timing. Also +discuss the survey results.

  • +
  • Point helpers (and instructors) to the tips for helpers.

  • +
+
+
+

Right before the workshop starts

+
    +
  • Prepare a shared Google doc or https://hackmd.io with global write permissions, +consider creating a memorable short-link (e.g. bit.ly)

  • +
+
+
+
+

Create exercise repositories

+
    +
  • The collaborative Git lesson requires exercise repositories to +be set up. For this follow the instructor guide in the lesson material.

  • +
+
+
+

Workshop preparation checklist

+
    +
  • This checklist can be set up as an issue under +https://github.com/coderefinery/coderefinery.org/ or on another +repository to keep track of the progress

    +
    - [ ] reserve dates
    +- [ ] decide workshop organizer
    +- [ ] (online) prepare Zoom link or (in-person) book lecture room
    +- [ ] announce (twitter, notify-me, mailing lists)
    +- [ ] team of instructors complete
    +- [ ] workshop website up
    +- [ ] lessons distributed
    +- [ ] prepare lessons
    +- [ ] create exercise repositories
    +- [ ] (in-person) prepare practicals (coffee/tea, sticky notes, extension cacles)
    +- [ ] (online) Zoom roles distributed
    +- [ ] registration open
    +- [ ] team of helpers complete
    +- [ ] registration closed
    +- [ ] enough pre-survey answers
    +- [ ] install instructions sent
    +- [ ] pre-workshop briefing held, helper training
    +- [ ] survey results shared with co-instructors/helpers
    +
    +
    +
  • +
+
+
+

As participants arrive

+
    +
  • Emphasize to participants that you need to sit with someone - don’t work alone.

  • +
  • Try to have participants sit next to someone with a similar operating +system if they have no preference, since they will face similar +problems.

  • +
+
+
+

Introduction talk

+
    +
  • See https://github.com/coderefinery/workshop-intro

  • +
  • Have a 10 minute ice-breaker session where participants and instructors introduce themselves +and either describe their research in 2-3 sentences or what they hope to get out of the workshop.

  • +
+
+
+

During workshop

+
    +
  • While teaching, keep these tips in mind

  • +
  • Don’t start off with tech details, say why this is important.

  • +
  • Try to stick to the material, +although some excursions are useful.

  • +
  • Keep up interactive feel by encouraging and asking questions

  • +
  • Keep time

  • +
  • For presentations which have shell commands, create a +cheatsheet/reference on the board in real time.

  • +
  • Remind participants about sticky notes.

  • +
  • Make sure we take regular breaks (at least a short break each hour)

  • +
  • Give participants some time to also experiment (do not rush the classroom through exercises)

  • +
  • Encourage optional feedback at the end of each day or end of each lesson +on sticky notes. Process the feedback immediately and adjust your teaching +(pace etc) accordingly

  • +
  • Create GitHub issues for points which are confusing or problematic

  • +
  • Take active part even in the lessons you’re not teaching, e.g. by asking +questions and (politely) interject with clarifications when you think +something is confusing to the learners

  • +
  • Wrap up, +say what you taught and why, and what comes next.

  • +
+
+
+

At the end of workshop

+ +
+
+

Post-workshop

+
    +
  • Process and distribute feedback to co-instructors and others (e.g. type up in shared document)

  • +
  • Debrief with instructors

  • +
  • Process certificate requests

  • +
+
+
+

Post-workshop survey

+

To measure the long-term impact of CodeRefinery workshops it’s useful to send out a +post-workshop survey. This survey can identify which topics taught in workshops are +particularly useful and which have less benefits for the participants.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshop-marketing/index.html b/workshop-marketing/index.html new file mode 100644 index 00000000..2c1a6dea --- /dev/null +++ b/workshop-marketing/index.html @@ -0,0 +1,183 @@ + + + + + + Workshop marketing — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop marketing

+

The workshop marketing and outreach coordinator makes sure (by delegation) that the workshops are advertised in all known channels. +They also coordinate mass communications with all entities of the workshop.

+

Some thoughts on target groups that should be tried to be reached:

+
    +
  • Learners (many sub-categories with different time vs need trade-offs: students, junior researchers, senior researchers, lifelong learning) (join a workshop)

  • +
  • team leaders (bring your friends, join to learn more and lead groups)

  • +
  • Research leaders (people who can tell their students they need to attend CR)

  • +
  • University staff (Computing, open sci, etc.) (people who can serve as local organizers and serve as local helpers)

  • +
  • Potential instructors (teach, etc.)

  • +
  • High-level management (provide us funding)

  • +
+

You can find a list of commonly advertised places in the bottom of the Workshop checklist template.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshop-organizers/index.html b/workshop-organizers/index.html new file mode 100644 index 00000000..3e6bdb8e --- /dev/null +++ b/workshop-organizers/index.html @@ -0,0 +1,192 @@ + + + + + + Workshop organizers — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop organizers

+

Everyone can be part of the workshop organizing team. But we are mostly looking for help from the community for team leads, expert helpers and instructors. +If you want to help ‘in the background’, join the ´#workshops´ stream in the coderefinery Zulip chat and see what is planned. +There is a lot of roles to fill already before the actual workshop, as well as after:

+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshop-playbook/index.html b/workshop-playbook/index.html new file mode 100644 index 00000000..7aa6eaed --- /dev/null +++ b/workshop-playbook/index.html @@ -0,0 +1,611 @@ + + + + + + Workshop checklist template — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop checklist template

+

This page is a checklist that we use when planning a CodeRefinery workshop +with 300 or more participants but may be useful in organizing other workshops as well.

+

Let’s keep this brief and copy-paste-able to HackMD/HedgeDoc for the actual planning.

+
+
+
+

CodeRefinery workshop YYYY-MM-DD

+

[toc]

+ +
+

Workshop roles

+
    +
  • Overview of the roles: https://coderefinery.github.io/manuals/roles-overview/

  • +
+

If you want to take part, add your name here, sign up in Indico and select “I +am interest in being a helper, co-instructor, or observer”, and you will be +contacted.

+
+

Instructors

+

(Description)

+

Two names per lesson, first is primary

+
    +
  • [ ] day 1 - git-intro: ???, ???

  • +
  • [ ] day 2 - git-intro: ???, ???

  • +
  • [ ] day 3 - git-collabiorative: ???, ???

  • +
  • [ ] day 4 - reproducible research: ???, ???

  • +
  • [ ] day 4 - social coding: ???, ???

  • +
  • [ ] day 5 - jupyter: ???, ???

  • +
  • [ ] day 5 - documentation: ???, ???

  • +
  • [ ] day 6 - testing: ???, ???

  • +
  • [ ] day 6 - modular code development: ???, ???

  • +
+
+
+

Expert helpers

+

(description)

+

If a central Zoom exercise room is provided: Help in our learner zoom, circle +around breakout rooms; there will probably be 2 or 3 rooms where we need to +provide the helper. Else: Help answering questions in Collaborative Q&A +document.

+
    +
  • [ ] day 1 - git-intro: ???, ???, …

  • +
  • [ ] day 2 - git-intro: ???, ???, …

  • +
  • [ ] day 3 - git-collab: ???, ???, …

  • +
  • [ ] day 4 - reproducible research: ???, ???, …

  • +
  • [ ] day 4 - social coding: ???, ???, …

  • +
  • [ ] day 5 - jupyter: ???, ???, …

  • +
  • [ ] day 5 - documentation: ???, ???, …

  • +
  • [ ] day 6 - testing: ???, ???, …

  • +
  • [ ] day 6 - modular code development: ???, ???, …

  • +
+
+
+

Managing collaborative document

+

(description)

+

Keep the document organized, check for unanswered questions, and archive notes each day.

+
    +
  • [ ] preparation before workshop:

  • +
  • [ ] day 1 - git-intro: ???, ???, …

  • +
  • [ ] day 2 - git-intro: ???, ???, …

  • +
  • [ ] day 3 - git-collab: ???, ???, …

  • +
  • [ ] day 4 - reproducible research: ???, ???, …

  • +
  • [ ] day 4 - social coding: ???, ???, …

  • +
  • [ ] day 5 - jupyter: ???, ???, …

  • +
  • [ ] day 5 - documentation: ???, ???, …

  • +
  • [ ] day 6 - testing: ???, ???, …

  • +
  • [ ] day 6 - modular code development: ???, ???, …

  • +
+
+
+
+

Workshop organization; roles “behind the scenes”

+

Organiser roles and their responsibilities. This does not mean that a person will do +everything that is part of their responsibility, but they will make sure that +their responsibilities are followed-up and not forgotten.

+
+

Event director

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • Before workshop

    +
      +
    • [ ] Create planning document by copying this template

    • +
    • [ ] Distribute roles using this document

      +
        +
      • [ ] Ask collaborators/stakeholders to pick roles

      • +
      +
    • +
    • [ ] Add all sessions to CodeRefinery calendar separately

    • +
    • [ ] Send calendar invite to all organizers, instructors, expert helpers, with all relevant links

    • +
    • [ ] Decide if certificates will be possible and what is needed for getting a certificate/credits (ask from partner universities)

    • +
    • [ ] Remind co-organizers to register

    • +
    • [ ] Send summary email to all co-organizers will all important links in one place

    • +
    +
  • +
  • After the workshop:

    + +
  • +
+
+
+

Registration coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+ +
+

Broadcaster

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Prepare ice-breakers for each day

  • +
  • [ ] Create instructor Zoom and communicate it (with exercise coordinator and outreach and marketing coordinator)

  • +
  • [ ] Publish recordings (does not do all the work but coordinates it)

    +
      +
    • [ ] Prepare for upload (use ffmpeg-editlist and collaborate)

    • +
    • [ ] Upload videos and communicate (with outreach and marketing coordinator) +:::

    • +
    +
  • +
+
+
+
+

Instructor coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Confirm that each lesson and session has co-instructors

  • +
  • [ ] Schedule calls with each instructor pair to distill most important questions and tasks to them

    +
      +
    • [ ] Show where the detailed schedule is and recommend to move it to instructor guide

    • +
    • [ ] Discuss that the detailed schedule can and should be improved

    • +
    • [ ] Show where Q&A and feedback from past workshop can be found

    • +
    • [ ] Discuss plans for exercises: try 3 exercises each half-day, each not shorter than 20 mins

    • +
    • [ ] Ask them to check their lesson’s exercise list

    • +
    • [ ] Ask for any software requirements changes

    • +
    • [ ] Inform about audience (at the time of writing half of registrants prefer to follow on their own) - adapt exercise expectations to audience

    • +
    • [ ] Check/test for high-quality screen share

    • +
    • [ ] Discuss how we can give learners get a good experience

    • +
    +
  • +
  • [ ] Test software install instructions

  • +
  • [ ] List instructors on the website (with exercise coordinator)

  • +
  • [ ] Organize team leader on-boarding sessions (with exercise coordinator)

  • +
  • [ ] After the workshop copy detailed schedule to the individual lesson repos as issues +:::

  • +
+
+
+

Exercise and team leader coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • Before the workshop

    +
      +
    • [ ] Make sure exercise list is communicated (with outreach and marketing coordinator)

    • +
    • [ ] List all team leads (who consent to being listed) on the website (with instructor coordinator)

    • +
    • [ ] List expert helpers on the website (with instructor coordinator)

    • +
    • [ ] Organize staff & helpers on-boarding sessions (with instructor coordinator)

    • +
    • [ ] Send team leader onboarding summary email + save it to the website (with outreach and marketing coordinator)

    • +
    +
  • +
  • After the workshop

    +
      +
    • [ ] Organize a de-briefing call with team leads to learn about their experiences and suggestions

    • +
    • [ ] Help other roles in putting everybody who contributed and consents on the website as credit

    • +
    • [ ] After the workshop remove the exercise repositories

    • +
    • [ ] Help event director with post-workshop survey +:::

    • +
    +
  • +
+
+
+

Outreach and marketing coordinator

+

(description)

+
    +
  • lead:

  • +
  • backup:

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Create/update advertising texts and relevant news on the workshop page

  • +
  • [ ] Newsletter

    +
      +
    • https://tinyletter.com/coderefinery/archive

    • +
    • draft: https://hackmd.io/@coderefinery/CRnewsletter_1_2023

    • +
    +
  • +
  • [ ] Advertising texts on the workshop page

    +
      +
    • https://coderefinery.github.io/2023-03-21-workshop/communication/

    • +
    • https://github.com/coderefinery/2023-03-21-workshop/tree/main/content/communication

    • +
    +
  • +
  • [ ] CodeRefinery Twitter

    +
      +
    • https://coderefinery.zulipchat.com/#narrow/stream/119815-general/topic/tweet-toot-suggestions

    • +
    +
  • +
  • [ ] CodeRefinery Mastodon

    +
      +
    • https://coderefinery.zulipchat.com/#narrow/stream/119815-general/topic/tweet-toot-suggestions

    • +
    +
  • +
  • [ ] CodeRefinery LinkedIn

    +
      +
    • https://www.linkedin.com/events/coderefineryworkshopmarch21-23a7031623728480272384/comments/

    • +
    +
  • +
  • [ ] CHCAA LinkedIn (Aarhus University)

  • +
  • [ ] Partner Twitter, retweet and own tweets

    +
      +
    • [ ] Aalto Scientific Computing

    • +
    +
  • +
  • [ ] Partner newsletters

    +
      +
    • [ ] Sigma2

    • +
    • [ ] SNIC/NAISS

    • +
    • [ ] ENCCS

    • +
    • [ ] CSC

    • +
    +
  • +
  • [ ] Partner websites training calendars

    +
      +
    • [ ] CSC

    • +
    • [ ] ENCCS

    • +
    • [ ] UiB

    • +
    • [ ] AU (Aarhus University)

    • +
    +
  • +
  • [ ] Partner and other email lists

    +
      +
    • [ ] Aalto STEM students

    • +
    • [ ] Aalto triton users

    • +
    • [ ] Delta doctoral network

    • +
    • [ ] UiB researcher

    • +
    • [ ] UiB HPC

    • +
    • [ ] NERSC Bergen

    • +
    • [ ] Bjerknes Bergen

    • +
    • [ ] University of Oslo computational biology

    • +
    • [ ] University of Oslo Phd and Postdocs

    • +
    • [ ] University of Oslo Dcince contact (?)

    • +
    • [ ] Research institutes in all countries

    • +
    +
  • +
  • [ ] Partner posters

    +
      +
    • [ ] Aalto (CS,U,NBE,PHYS,VAARE) +:::

    • +
    +
  • +
+
+
+

Certificate coordinator

+

https://coderefinery.github.io/2023-03-21-workshop/certificates/

+
    +
  • lead:

  • +
  • backup: ASC team (the process can be run by anyone and we are now using a ticketing system to track requests)

  • +
+

:::spoiler Checklist

+
    +
  • [ ] Make sure that instructions on certificates are disseminated multiple times

    +
      +
    • [ ] Workshop page, emails

      +
      - Learner sends materials to scip _at_ aalto.fi. This opens a ticket in Aalto "esupport" system
      +- The person who generates the certificate verifies quickly that the tasks were completed.
      +- We then work with https://github.com/coderefinery/generate-certificates to generate PDF certificates
      +- Certificate is sent to the person and ticket is closed
      +- Aalto specific:
      +    - The local version of that repository is at /scratch/rse/generate-certificates/. The commands were slightly modified so that the default working directory is not the home folder
      +    - Aalto students can also obtain directly the 1 ECTS credit. See internal process at ASC pages.
      +
      +
      +
    • +
    +
  • +
+

:::

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshop-prep-call/index.html b/workshop-prep-call/index.html new file mode 100644 index 00000000..c0b74153 --- /dev/null +++ b/workshop-prep-call/index.html @@ -0,0 +1,231 @@ + + + + + + Workshop preparation meeting — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop preparation meeting

+

Each workshop should have a preparation call among instructors, +experts, hosts, etc. This is separate from the helper training call.

+
+

Topics of workshop instructor meeting

+
    +
  • Introduction round

  • +
  • Go over Instructor introduction and other pages in this section

    +
      +
    • New staff: go over in more details.

    • +
    +
  • +
  • The role of expert helpers.

  • +
  • Everyone: discuss the roles in the workshop

  • +
  • For each lesson, a meeting between a former instructor and the +current one (even if current one is experienced teaching it).

    +
      +
    • Set up any possible co-teaching arrangements.

    • +
    +
  • +
  • Discuss hand-over times each day

  • +
  • Breaks should be descussed among instructors for each day, but +default is 10 minutes between xx:50 and xx:10 each hour.

  • +
  • Practice instructor tech setup (screenshare, etc): can also be done +in the one-on-one meeting.

  • +
  • Joining CodeRefinery: what comes next?

  • +
+
+
+

Don’t forget

+
    +
  • Update Zoom client (later than mid-October 2020) for breakout room +features. Zoom alone isn’t enough.

  • +
+
+
+

Common CodeRefinery conventions to remember

+
    +
  • Breaks are not negotiable, minimum 10 minutes

  • +
  • Sessions can’t be extended indefinitely, it’s OK to run out of time +and skip things (in fact, we expect this: all lessons have op. All +lessons have optional episodes. Not finishing is normal, in fact.

    +
      +
    • Emphasize to learners that we can’t cover everything and don’t +expect to.

    • +
    +
  • +
  • During workshop, we communicate via:

    +
      +
    • HackMD

    • +
    • Zulipchat

    • +
    • Zoom chat is minor and most people don’t need to watch.

    • +
    +
  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/workshop-requirements-inperson/index.html b/workshop-requirements-inperson/index.html new file mode 100644 index 00000000..8c78b71a --- /dev/null +++ b/workshop-requirements-inperson/index.html @@ -0,0 +1,247 @@ + + + + + + Workshop requirements - in person — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Workshop requirements - in person

+

This checklist is for the pre-planning phase of in-person CodeRefinery +workshops: where you are deciding if you can host one and what room to +use. Let us know about the items on this list when you contact us.

+
+

Lecture room

+
    +
  • The room needs to be sufficiently large (a typical workshop is attended by +around 20 learners and 4 instructors).

  • +
  • There needs to be enough space for instructors to walk around and interact +with learners individually (a “flat” room is required).

  • +
  • Learners should face the same direction, and learners should be able to sit +side-by-side for pairwise work.

  • +
  • The room should preferably have windows, and be ventilated well enough so +that 20-30 people (and same amount of laptops) will not make it too warm.

  • +
  • A coffee room (or similar) should be located nearby for the coffee breaks.

  • +
  • Two overhead projectors are desirable, but if only one is available that will +work too.

  • +
  • The projector screen needs to be large, and the resolution of the projector +needs to be good.

  • +
  • Stable wireless connectivity for 20-30 people.

  • +
  • Sufficiently many electricity outlets so that all participants can charge +their laptops.

  • +
  • Standing board for instructor.

  • +
+
+
+

Helpers

+

CodeRefinery workshops are hands-on and interactive, and a lot of time is +spent on exercises where participants learn by doing. Participants +explore themselves, and that means they need guides to help them if +they get stuck.

+

We recommend that each site takes proactive steps to recruit at least +two helpers per workshop. We’ve noticed that helper diversity +promotes learning, so we recommend that organizers also make proactive +steps to have diverse helpers (male/female, international, etc.). +Local organizers should directly contact possible helpers and invite them.

+

Good candidates are people who have any of:

+
    +
  • have attended a previous CodeRefinery workshop

  • +
  • have a passion for teaching, scientific software development, open +source, open science, etc.

  • +
  • are research software engineers or hold a similar technical research position

  • +
  • have experience from teaching e.g. Software Carpentry workshops

  • +
  • want to experience CodeRefinery but already have a good idea of most basics

  • +
+
+
+

Other requirements

+

When we organize a workshop or event at a new site, we may need help with some local arrangements, +including:

+
    +
  • Booking a lecture room.

  • +
  • Ordering coffee and refreshments.

  • +
  • Advertise the workshop through local dissemination channels.

  • +
+
+
+

After the workshop

+

Would you like to become a helper, instructor, or partner +and make more workshops possible?

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/zoom-mechanics-old/index.html b/zoom-mechanics-old/index.html new file mode 100644 index 00000000..be2c2677 --- /dev/null +++ b/zoom-mechanics-old/index.html @@ -0,0 +1,262 @@ + + + + + + Zoom mechanics and controls — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Zoom mechanics and controls

+
+

How to mute and unmute

+

In lower left corner of the client you can mute and unmute yourself:

+

unmute in lower left corner

+

In the main room during lectures, it is best to keep your microphone +muted in the main room unless you want to say something. It’s OK to +unmute and speak up.

+

If you are in a quiet place, it’s best to stay unmuted in breakout +rooms and during active discussions. This will make discussion much +smoother - a quiet environment or headset microphone helps with the +flow a lot.

+
+
+

Please use your real name (instead of a system default username)

+

First, click on “Participants” (bottom, middle):

+

participants list button at bottom

+

You can rename yourself by clicking the blue “Rename” next to your +name that appears when you hover over the button:

+

rename yourself button in participant list

+

A box to rename yourself appears:

+

rename yourself example

+
+
+

Indicate in your name if you are in a team and/or if you are a helper

+

If you are part of a team, please indicate your team name or number +like (myteam) Your Name:

+

team name in your Zoom name

+

If you are a helper, please indicate like (myteam, helper) Your Name +also. The workshop might use the form (myteam,H) Your Name instead, +check what it requests:

+

team name+helper in zoom name

+

This makes it easier for the workshop organizers to manage breakout rooms.

+
+
+

Indicating your status

+
+

How to signal if you are away from keyboard

+

Please select the “clock” symbol if you are away or otherwise busy. +You can find this under the “more” icon in at the bottom of the +participants list:

+

Away from keyboard clock button

+
+
+

How to signal when you completed a task successfully

+

We will sometimes ask you to signal to us once you have successfully completed +an exercise or type-along step. You can do this using the green “yes” +check symbol under the participant list:

+

Green yes under participant list

+
+
+

How to ask a question

+

If you want to ask a question please use the “raise hand” symbol +under participant list:

+

Raise hand under participant list

+

If this symbol is not present in your Zoom client, you can type “\hand” in the +chat window:

+

chat button at bottom of screen

+
+
+

How to signal a technical problem or that you got stuck

+

If you hit a technical problem or got stuck somewhere in an exercise +or type-along, please let us know with the red “no” circle symbol:

+

No button on participant list

+

We will then probably ask you to unmute and briefly describe the problem and then based +on the problem and timing we may assign you into a separate virtual room with a helper where +they can resolve the problem.

+

Once we have assigned you a helper we will ask you and the helper to “Join +Breakout Room” (bottom right):

+

Join Breakout Room button at bottom of screen

+
+
+

How to give feedback on the speed

+

There are also signals for go faster and go slower and with +this you can indicate to +us whether we should adjust the speed.

+
+
+
+

Other points

+
+

Zoom doesn’t have to fullscreen when someone shares their screen.

+

By default, when someone shares their screen, Zoom goes into +fullscreen mode. This can be inconvenient when you need to see +multiple windows at once. You can disable this with Settings → Screen +Share → “Enter full screen when participants share”.

+
+
+

Dual monitor mode

+

You can set the configuration option “dual monitor mode”, which is +really more like “dual window mode”: one window for screen sharing, +one for the people. It might be useful even with only one screen.

+
+

This is licensed under CC-BY +and we encourage and appreciate reuse, modifications, and contributions.

+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018-2023, The CodeRefinery team.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/zoom-mechanics/index.html b/zoom-mechanics/index.html new file mode 100644 index 00000000..c005fcbe --- /dev/null +++ b/zoom-mechanics/index.html @@ -0,0 +1,272 @@ + + + + + + Zoom mechanics and controls — CodeRefinery manuals documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Zoom mechanics and controls

+
+

Basics

+
    +
  • Most Zoom controls are probably well known by now, but if not, view +Zoom’s basic +guide

  • +
  • Mute and unmute yourself from the buttons on bottom.

  • +
  • You can rename yourself from the participants list (hover over +your name.

  • +
  • We don’t use Zoom chat for typical questions: use HackMD instead.

    +
      +
    • Chat OK for administrative questions.

    • +
    +
  • +
  • When joining, please use the name you used to register for the +course.

  • +
  • In livestream workshops, there is nothing in the main room: that +is broadcasted via livestream in a separate browser window, and you +switch as needed.

  • +
+
+
+

Audio/video on or off?

+
    +
  • Main room: Stay muted, video off, unless you want to speak up.

  • +
  • Breakout rooms: Try to leave on for most interactive +atmosphere.

  • +
+
+
+

Workshops with teams: your name should indicate your breakout room

+

You will be told if this section is relevant to you.

+
    +
  • Have your breakout room number in your name:

    +
      +
    • (number) Your Name

    • +
    • (number,H) The Name for helpers

    • +
    +

    Names with breakout room numbers

    +
  • +
  • Rename yourself in a meeting by starting participants list:

    +

    participants list button at bottom

    +

    Rename is found if you hover your name and click “more”

    +

    participants list button at bottom

    +
  • +
+
+
+

Breakout rooms

+
    +
  • Click the “breakout rooms” button at bottom and you can join a +room.

  • +
  • You can click “Join” to join your breakout room by yourself.

    +
      +
    • If you are joined via web, make sure your name is correct (see +above) and use Zoom chat to ask host to assign you to the room.

    • +
    +
  • +
  • Return to main room: “Leave” button at bottom has an option for +“Return to main room”.

  • +
+
+
+

Reactions

+

We watch the participant list and can see these reactions (in the +application):

+

Zoom reactions via the bottom bar

+
    +
  • Task completed: Green check

  • +
  • Technical problem: Red X

  • +
  • Need more time: Slower “<<”

  • +
  • You can signal go faster and go slower

  • +
  • You can Raise your hand

  • +
+
+
+

Other settings

+

Other zoom settings

+
    +
  • Automatic fullscreen when screenshare starts can be turned off

  • +
  • Dual monitor mode makes separate windows for screenshare and participants

  • +
+
+
+

See also

+ +
+

This is licensed under CC-BY +and we encourage and appreciate reuse, modifications, and contributions.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file